diff mbox

[2/3] acpi: pcct: update PCCT table to ACPI 6.2 (mantis 1659 & 1755)

Message ID 1502995192-21160-2-git-send-email-alex.hung@canonical.com
State Accepted
Headers show

Commit Message

Alex Hung Aug. 17, 2017, 6:39 p.m. UTC
1. Added type 3 & type 4
2. Updated doorbell to platform in some cases
3. Fixed typos

Signed-off-by: Alex Hung <alex.hung@canonical.com>
---
 src/acpi/pcct/pcct.c        | 232 +++++++++++++++++++++++++-------------------
 src/lib/include/fwts_acpi.h |  40 ++++++--
 2 files changed, 167 insertions(+), 105 deletions(-)

Comments

Colin Ian King Aug. 22, 2017, 3:25 p.m. UTC | #1
On 17/08/17 19:39, Alex Hung wrote:
> 1. Added type 3 & type 4
> 2. Updated doorbell to platform in some cases
> 3. Fixed typos
> 
> Signed-off-by: Alex Hung <alex.hung@canonical.com>
> ---
>  src/acpi/pcct/pcct.c        | 232 +++++++++++++++++++++++++-------------------
>  src/lib/include/fwts_acpi.h |  40 ++++++--
>  2 files changed, 167 insertions(+), 105 deletions(-)
> 
> diff --git a/src/acpi/pcct/pcct.c b/src/acpi/pcct/pcct.c
> index 9d79dc5..5753325 100644
> --- a/src/acpi/pcct/pcct.c
> +++ b/src/acpi/pcct/pcct.c
> @@ -52,6 +52,64 @@ static bool subspace_length_equal(fwts_framework *fw, uint8_t type, uint8_t type
>  	return true;
>  }
>  
> +static void platform_interrupt_flags(fwts_framework *fw, uint8_t flags, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt Flags:    0x%2.2"   PRIx8, flags);
> +
> +	if (flags & ~0x3) {
> +		*passed = false;
> +		fwts_failed(fw, LOG_LEVEL_HIGH,
> +			"PCCTBadSubtypePlatformbInterruptlags",
> +			"PCCT Subspace Platform Interrupt Flags's bit [7:2] be zero, got "
> +			"0x%2.2" PRIx8 " instead", flags);
> +	}
> +}
> +
> +static void gas_messages(fwts_framework *fw, uint8_t type, fwts_acpi_gas *gas, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> +	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> +	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> +	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> +	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +
> +	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> +	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> +			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> +		*passed = false;
> +		fwts_failed(fw, LOG_LEVEL_HIGH,
> +			"PCCTSubspaceInvalidAddrSpaceID",
> +			"PCCT Subspace Type %" PRId8 " has space ID = %" PRId8
> +			" which is not System I/O, Memory or FFH", type, gas->address_space_id);
> +	}
> +}
> +
> +static void memory_length(fwts_framework *fw, uint8_t type, uint64_t memory_range, uint64_t min_length, bool *passed)
> +{
> +	switch (type) {
> +	case 0 ... 2:
> +		fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, memory_range);
> +		if (memory_range <= min_length) {
> +			*passed = false;
> +			fwts_failed(fw, LOG_LEVEL_HIGH,
> +				"PCCTBadSubtypeMemoryLength",
> +				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%16.16" PRIx64
> +				", got 0x%16.16" PRIx64 " instead", type, min_length, memory_range);
> +		}
> +		break;
> +	case 3 ... 4:
> +		fwts_log_info_verbatim(fw, "    Length:                      0x%8.8" PRIx32, (uint32_t)memory_range);
> +		if (memory_range <= min_length) {
> +			*passed = false;
> +			fwts_failed(fw, LOG_LEVEL_HIGH,
> +				"PCCTBadSubtypeMemoryLength",
> +				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%8.8" PRIx32
> +				", got 0x%8.8" PRIx32 " instead", type, (uint32_t)min_length, (uint32_t)memory_range);
> +		}
> +		break;
> +	}
> +}
> +
>  static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_0 *entry, bool *passed)
>  {
>  	fwts_acpi_gas *gas = &entry->doorbell_register;
> @@ -63,7 +121,7 @@ static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
>  
>  	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, reserved);
>  	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>  	fwts_log_info_verbatim(fw, "    Doorbell Register:");
>  	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
>  	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> @@ -82,113 +140,76 @@ static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
>  		fwts_failed(fw, LOG_LEVEL_HIGH,
>  			"PCCTSubspaceInvalidAddrSpaceID",
>  			"PCCT Subspace Type 0 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> +			" which is not System I/O or Memory",
>  			gas->address_space_id);
>  	}
>  }
>  
>  static void hw_reduced_comm_test_type1(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_1 *entry, bool *passed)
>  {
> -	fwts_acpi_gas *gas = &entry->doorbell_register;
> -	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
> -
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
>  	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
>  	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>  	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
>  	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
>  	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
>  	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
>  	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
>  	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> -
> -	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 1 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> -
> -	if (doorbell_int_flags & ~0x3) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTBadSubtypeDoorbellFlags",
> -			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
> -			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
> -	}
>  }
>  
>  static void hw_reduced_comm_test_type2(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_2 *entry, bool *passed)
>  {
> -	fwts_acpi_gas *gas = &entry->doorbell_register;
> -	fwts_acpi_gas *gas2 = &entry->doorbell_ack_register;
> -	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
> -
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
>  	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
>  	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>  	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
>  	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
>  	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
>  	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
>  	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
>  	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas2->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas2->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas2->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas2->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas2->address);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->doorbell_ack_preserve);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->doorbell_ack_write);
> -
> -	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> -
> -	if ((gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt Ack Register:");
> +	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
> +	fwts_log_info_verbatim(fw, "    Platform Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
> +	fwts_log_info_verbatim(fw, "    Platform Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
> +}
>  
> -	if (doorbell_int_flags & ~0x3) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTBadSubtypeDoorbellFlags",
> -			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
> -			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
> -	}
> +static void extended_pcc_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_3_4 *entry, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
> +	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved1);
> +	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> +	memory_length(fw, entry->header.type, entry->length, 16, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
> +	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
> +	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
> +	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
> +	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> +	fwts_log_info_verbatim(fw, "    Command Complete Check Register:");
> +	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
> +	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
> +	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, entry->reserved2);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Check Register:");
> +	gas_messages(fw, entry->header.type, &entry->cmd_complete_register, passed);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Check Mask:     0x%16.16" PRIx64, entry->cmd_complete_mask);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Update Register:");
> +	gas_messages(fw, entry->header.type, &entry->cmd_update_register, passed);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Update Mask:    0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Set Mask:       0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
> +	fwts_log_info_verbatim(fw, "    Error Status Register:");
> +	gas_messages(fw, entry->header.type, &entry->error_status_register, passed);
> +	fwts_log_info_verbatim(fw, "    Error Status Mask:           0x%16.16" PRIx64, entry->error_status_mask);
>  }
>  
>  static int pcct_test1(fwts_framework *fw)
> @@ -206,10 +227,10 @@ static int pcct_test1(fwts_framework *fw)
>  	if ((pcct->flags & ~0x01) != 0) {
>  		passed = false;
>  		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTReservedNonZero",
> +			"PCCTBadFlags",
>  			"PCCT flags field's bit 1..31 be zero, got "
>  			"0x%8.8" PRIx32 " instead", pcct->flags);
> -		}
> +	}
>  
>  	if (pcct->reserved != 0) {
>  		passed = false;
> @@ -223,7 +244,6 @@ static int pcct_test1(fwts_framework *fw)
>  	pcct_sub = (fwts_acpi_table_pcct_subspace_header *) (table->data + offset);
>  
>  	while (offset < table->length) {
> -		uint64_t addr_length = 8;
>  
>  		fwts_log_info_verbatim(fw, "  PCC Subspace Structure:");
>  		fwts_log_info_verbatim(fw, "    Type:                        0x%2.2"   PRIx8, pcct_sub->type);
> @@ -238,7 +258,6 @@ static int pcct_test1(fwts_framework *fw)
>  			}
>  
>  			generic_comm_test(fw, subspace, &passed);
> -			addr_length = subspace->length;
>  
>  		} else if (pcct_sub->type == 1) {
>  			fwts_acpi_table_pcct_subspace_type_1 *subspace = (fwts_acpi_table_pcct_subspace_type_1 *) pcct_sub;
> @@ -249,7 +268,6 @@ static int pcct_test1(fwts_framework *fw)
>  			}
>  
>  			hw_reduced_comm_test_type1(fw, subspace, &passed);
> -			addr_length = subspace->length;
>  
>  		} else if (pcct_sub->type == 2) {
>  			fwts_acpi_table_pcct_subspace_type_2 *subspace = (fwts_acpi_table_pcct_subspace_type_2 *) pcct_sub;
> @@ -260,26 +278,44 @@ static int pcct_test1(fwts_framework *fw)
>  			}
>  
>  			hw_reduced_comm_test_type2(fw, subspace, &passed);
> -			addr_length = subspace->length;
> +
> +		} else if (pcct_sub->type == 3) {
> +			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
> +
> +			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
> +				passed = false;
> +				break;
> +			}
> +
> +			extended_pcc_test(fw, subspace, &passed);
> +
> +		} else if (pcct_sub->type == 4) {
> +			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
> +
> +			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
> +				passed = false;
> +				break;
> +			}
> +
> +			if (!(pcct->flags & 0x01)) {
> +				passed = false;
> +				fwts_failed(fw, LOG_LEVEL_HIGH,
> +					"PCCTBadFlags",
> +					"PCCT Plaform Interrupt in flags must be set when subspace "
> +					"type 4 is present, got 0x%8.8" PRIx32 " instead", pcct->flags);
> +			}
> +
> +			extended_pcc_test(fw, subspace, &passed);
>  
>  		} else {
>  			passed = false;
>  			fwts_failed(fw, LOG_LEVEL_HIGH,
>  				"PCCTBadSubType",
> -				"PCCT Subspace Structure supports type 0..2, got "
> +				"PCCT Subspace Structure supports type 0..4, got "
>  				"0x%2.2" PRIx8 " instead", pcct_sub->type);
> +			break;
>  		}
>  
> -		if (addr_length <= 8) {
> -			passed = false;
> -			fwts_failed(fw, LOG_LEVEL_HIGH,
> -				"PCCTBadSubtypeMemoryLength",
> -				"PCCT Subspace Structure must have memory length > 8, got "
> -				"0x%16.16" PRIx64 " instead", addr_length);
> -		}
> -
> -
> -
>  		fwts_log_nl(fw);
>  
>  		offset += pcct_sub->length;
> diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h
> index 12d63aa..5484cf3 100644
> --- a/src/lib/include/fwts_acpi.h
> +++ b/src/lib/include/fwts_acpi.h
> @@ -1380,8 +1380,8 @@ typedef struct {
>  
>  typedef struct {
>  	fwts_acpi_table_pcct_subspace_header	header;
> -	uint32_t	doorbell_interrupt;
> -	uint8_t		doorbell_interrupt_flags;
> +	uint32_t	platform_interrupt;
> +	uint8_t		platform_interrupt_flags;
>  	uint8_t		reserved;
>  	uint64_t	base_address;
>  	uint64_t	length;
> @@ -1395,8 +1395,8 @@ typedef struct {
>  
>  typedef struct {
>  	fwts_acpi_table_pcct_subspace_header	header;
> -	uint32_t	doorbell_interrupt;
> -	uint8_t		doorbell_interrupt_flags;
> +	uint32_t	platform_interrupt;
> +	uint8_t		platform_interrupt_flags;
>  	uint8_t		reserved;
>  	uint64_t	base_address;
>  	uint64_t	length;
> @@ -1406,11 +1406,37 @@ typedef struct {
>  	uint32_t	nominal_latency;
>  	uint32_t	max_periodic_access_rate;
>  	uint16_t	min_request_turnaround_time;
> -	fwts_acpi_gas	doorbell_ack_register;
> -	uint64_t	doorbell_ack_preserve;
> -	uint64_t	doorbell_ack_write;
> +	fwts_acpi_gas	platform_ack_register;
> +	uint64_t	platform_ack_preserve;
> +	uint64_t	platform_ack_write;
>  } __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_2;
>  
> +typedef struct {
> +	fwts_acpi_table_pcct_subspace_header	header;
> +	uint32_t	platform_interrupt;
> +	uint8_t	platform_interrupt_flags;
> +	uint8_t	reserved1;
> +	uint64_t	base_address;
> +	uint32_t	length;
> +	fwts_acpi_gas	doorbell_register;
> +	uint64_t	doorbell_preserve;
> +	uint64_t	doorbell_write;
> +	uint32_t	nominal_latency;
> +	uint32_t	max_periodic_access_rate;
> +	uint32_t	min_request_turnaround_time;
> +	fwts_acpi_gas	platform_ack_register;
> +	uint64_t	platform_ack_preserve;
> +	uint64_t	platform_ack_write;
> +	uint64_t	reserved2;
> +	fwts_acpi_gas	cmd_complete_register;
> +	uint64_t	cmd_complete_mask;
> +	fwts_acpi_gas	cmd_update_register;
> +	uint64_t	cmd_update_preserve_mask;
> +	uint64_t	cmd_update_set_mask;
> +	fwts_acpi_gas	error_status_register;
> +	uint64_t	error_status_mask;
> +} __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_3_4;
> +
>  /*
>   * ACPI SPCR (Serial Port Console Redirection Table)
>   *  http://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> 
Acked-by: Colin Ian King <colin.king@canonical.com>
Ivan Hu Aug. 23, 2017, 7:02 a.m. UTC | #2
On 08/18/2017 02:39 AM, Alex Hung wrote:
> 1. Added type 3 & type 4
> 2. Updated doorbell to platform in some cases
> 3. Fixed typos
> 
> Signed-off-by: Alex Hung <alex.hung@canonical.com>
> ---
>   src/acpi/pcct/pcct.c        | 232 +++++++++++++++++++++++++-------------------
>   src/lib/include/fwts_acpi.h |  40 ++++++--
>   2 files changed, 167 insertions(+), 105 deletions(-)
> 
> diff --git a/src/acpi/pcct/pcct.c b/src/acpi/pcct/pcct.c
> index 9d79dc5..5753325 100644
> --- a/src/acpi/pcct/pcct.c
> +++ b/src/acpi/pcct/pcct.c
> @@ -52,6 +52,64 @@ static bool subspace_length_equal(fwts_framework *fw, uint8_t type, uint8_t type
>   	return true;
>   }
>   
> +static void platform_interrupt_flags(fwts_framework *fw, uint8_t flags, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt Flags:    0x%2.2"   PRIx8, flags);
> +
> +	if (flags & ~0x3) {
> +		*passed = false;
> +		fwts_failed(fw, LOG_LEVEL_HIGH,
> +			"PCCTBadSubtypePlatformbInterruptlags",
> +			"PCCT Subspace Platform Interrupt Flags's bit [7:2] be zero, got "
> +			"0x%2.2" PRIx8 " instead", flags);
> +	}
> +}
> +
> +static void gas_messages(fwts_framework *fw, uint8_t type, fwts_acpi_gas *gas, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> +	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> +	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> +	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> +	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +
> +	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> +	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> +			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> +		*passed = false;
> +		fwts_failed(fw, LOG_LEVEL_HIGH,
> +			"PCCTSubspaceInvalidAddrSpaceID",
> +			"PCCT Subspace Type %" PRId8 " has space ID = %" PRId8
> +			" which is not System I/O, Memory or FFH", type, gas->address_space_id);
> +	}
> +}
> +
> +static void memory_length(fwts_framework *fw, uint8_t type, uint64_t memory_range, uint64_t min_length, bool *passed)
> +{
> +	switch (type) {
> +	case 0 ... 2:
> +		fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, memory_range);
> +		if (memory_range <= min_length) {
> +			*passed = false;
> +			fwts_failed(fw, LOG_LEVEL_HIGH,
> +				"PCCTBadSubtypeMemoryLength",
> +				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%16.16" PRIx64
> +				", got 0x%16.16" PRIx64 " instead", type, min_length, memory_range);
> +		}
> +		break;
> +	case 3 ... 4:
> +		fwts_log_info_verbatim(fw, "    Length:                      0x%8.8" PRIx32, (uint32_t)memory_range);
> +		if (memory_range <= min_length) {
> +			*passed = false;
> +			fwts_failed(fw, LOG_LEVEL_HIGH,
> +				"PCCTBadSubtypeMemoryLength",
> +				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%8.8" PRIx32
> +				", got 0x%8.8" PRIx32 " instead", type, (uint32_t)min_length, (uint32_t)memory_range);
> +		}
> +		break;
> +	}
> +}
> +
>   static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_0 *entry, bool *passed)
>   {
>   	fwts_acpi_gas *gas = &entry->doorbell_register;
> @@ -63,7 +121,7 @@ static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
>   
>   	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, reserved);
>   	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>   	fwts_log_info_verbatim(fw, "    Doorbell Register:");
>   	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
>   	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> @@ -82,113 +140,76 @@ static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
>   		fwts_failed(fw, LOG_LEVEL_HIGH,
>   			"PCCTSubspaceInvalidAddrSpaceID",
>   			"PCCT Subspace Type 0 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> +			" which is not System I/O or Memory",
>   			gas->address_space_id);
>   	}
>   }
>   
>   static void hw_reduced_comm_test_type1(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_1 *entry, bool *passed)
>   {
> -	fwts_acpi_gas *gas = &entry->doorbell_register;
> -	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
> -
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
>   	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
>   	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>   	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
>   	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
>   	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
>   	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
>   	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
>   	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> -
> -	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 1 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> -
> -	if (doorbell_int_flags & ~0x3) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTBadSubtypeDoorbellFlags",
> -			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
> -			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
> -	}
>   }
>   
>   static void hw_reduced_comm_test_type2(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_2 *entry, bool *passed)
>   {
> -	fwts_acpi_gas *gas = &entry->doorbell_register;
> -	fwts_acpi_gas *gas2 = &entry->doorbell_ack_register;
> -	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
> -
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
> -	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
>   	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
>   	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> -	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
> +	memory_length(fw, entry->header.type, entry->length, 8, passed);
>   	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
>   	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
>   	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
>   	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
>   	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
>   	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Register:");
> -	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas2->address_space_id);
> -	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas2->register_bit_width);
> -	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas2->register_bit_offset);
> -	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas2->access_width);
> -	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas2->address);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->doorbell_ack_preserve);
> -	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->doorbell_ack_write);
> -
> -	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> -
> -	if ((gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
> -	    (gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
> -			(gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTSubspaceInvalidAddrSpaceID",
> -			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
> -			" which is not System I/O Space or System Memory Space",
> -			gas->address_space_id);
> -	}
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt Ack Register:");
> +	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
> +	fwts_log_info_verbatim(fw, "    Platform Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
> +	fwts_log_info_verbatim(fw, "    Platform Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
> +}
>   
> -	if (doorbell_int_flags & ~0x3) {
> -		*passed = false;
> -		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTBadSubtypeDoorbellFlags",
> -			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
> -			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
> -	}
> +static void extended_pcc_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_3_4 *entry, bool *passed)
> +{
> +	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
> +	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
> +	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved1);
> +	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
> +	memory_length(fw, entry->header.type, entry->length, 16, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Register:");
> +	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
> +	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
> +	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
> +	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
> +	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
> +	fwts_log_info_verbatim(fw, "    Command Complete Check Register:");
> +	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
> +	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
> +	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
> +	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, entry->reserved2);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Check Register:");
> +	gas_messages(fw, entry->header.type, &entry->cmd_complete_register, passed);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Check Mask:     0x%16.16" PRIx64, entry->cmd_complete_mask);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Update Register:");
> +	gas_messages(fw, entry->header.type, &entry->cmd_update_register, passed);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Update Mask:    0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
> +	fwts_log_info_verbatim(fw, "    Cmd Complete Set Mask:       0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
> +	fwts_log_info_verbatim(fw, "    Error Status Register:");
> +	gas_messages(fw, entry->header.type, &entry->error_status_register, passed);
> +	fwts_log_info_verbatim(fw, "    Error Status Mask:           0x%16.16" PRIx64, entry->error_status_mask);
>   }
>   
>   static int pcct_test1(fwts_framework *fw)
> @@ -206,10 +227,10 @@ static int pcct_test1(fwts_framework *fw)
>   	if ((pcct->flags & ~0x01) != 0) {
>   		passed = false;
>   		fwts_failed(fw, LOG_LEVEL_HIGH,
> -			"PCCTReservedNonZero",
> +			"PCCTBadFlags",
>   			"PCCT flags field's bit 1..31 be zero, got "
>   			"0x%8.8" PRIx32 " instead", pcct->flags);
> -		}
> +	}
>   
>   	if (pcct->reserved != 0) {
>   		passed = false;
> @@ -223,7 +244,6 @@ static int pcct_test1(fwts_framework *fw)
>   	pcct_sub = (fwts_acpi_table_pcct_subspace_header *) (table->data + offset);
>   
>   	while (offset < table->length) {
> -		uint64_t addr_length = 8;
>   
>   		fwts_log_info_verbatim(fw, "  PCC Subspace Structure:");
>   		fwts_log_info_verbatim(fw, "    Type:                        0x%2.2"   PRIx8, pcct_sub->type);
> @@ -238,7 +258,6 @@ static int pcct_test1(fwts_framework *fw)
>   			}
>   
>   			generic_comm_test(fw, subspace, &passed);
> -			addr_length = subspace->length;
>   
>   		} else if (pcct_sub->type == 1) {
>   			fwts_acpi_table_pcct_subspace_type_1 *subspace = (fwts_acpi_table_pcct_subspace_type_1 *) pcct_sub;
> @@ -249,7 +268,6 @@ static int pcct_test1(fwts_framework *fw)
>   			}
>   
>   			hw_reduced_comm_test_type1(fw, subspace, &passed);
> -			addr_length = subspace->length;
>   
>   		} else if (pcct_sub->type == 2) {
>   			fwts_acpi_table_pcct_subspace_type_2 *subspace = (fwts_acpi_table_pcct_subspace_type_2 *) pcct_sub;
> @@ -260,26 +278,44 @@ static int pcct_test1(fwts_framework *fw)
>   			}
>   
>   			hw_reduced_comm_test_type2(fw, subspace, &passed);
> -			addr_length = subspace->length;
> +
> +		} else if (pcct_sub->type == 3) {
> +			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
> +
> +			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
> +				passed = false;
> +				break;
> +			}
> +
> +			extended_pcc_test(fw, subspace, &passed);
> +
> +		} else if (pcct_sub->type == 4) {
> +			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
> +
> +			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
> +				passed = false;
> +				break;
> +			}
> +
> +			if (!(pcct->flags & 0x01)) {
> +				passed = false;
> +				fwts_failed(fw, LOG_LEVEL_HIGH,
> +					"PCCTBadFlags",
> +					"PCCT Plaform Interrupt in flags must be set when subspace "
> +					"type 4 is present, got 0x%8.8" PRIx32 " instead", pcct->flags);
> +			}
> +
> +			extended_pcc_test(fw, subspace, &passed);
>   
>   		} else {
>   			passed = false;
>   			fwts_failed(fw, LOG_LEVEL_HIGH,
>   				"PCCTBadSubType",
> -				"PCCT Subspace Structure supports type 0..2, got "
> +				"PCCT Subspace Structure supports type 0..4, got "
>   				"0x%2.2" PRIx8 " instead", pcct_sub->type);
> +			break;
>   		}
>   
> -		if (addr_length <= 8) {
> -			passed = false;
> -			fwts_failed(fw, LOG_LEVEL_HIGH,
> -				"PCCTBadSubtypeMemoryLength",
> -				"PCCT Subspace Structure must have memory length > 8, got "
> -				"0x%16.16" PRIx64 " instead", addr_length);
> -		}
> -
> -
> -
>   		fwts_log_nl(fw);
>   
>   		offset += pcct_sub->length;
> diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h
> index 12d63aa..5484cf3 100644
> --- a/src/lib/include/fwts_acpi.h
> +++ b/src/lib/include/fwts_acpi.h
> @@ -1380,8 +1380,8 @@ typedef struct {
>   
>   typedef struct {
>   	fwts_acpi_table_pcct_subspace_header	header;
> -	uint32_t	doorbell_interrupt;
> -	uint8_t		doorbell_interrupt_flags;
> +	uint32_t	platform_interrupt;
> +	uint8_t		platform_interrupt_flags;
>   	uint8_t		reserved;
>   	uint64_t	base_address;
>   	uint64_t	length;
> @@ -1395,8 +1395,8 @@ typedef struct {
>   
>   typedef struct {
>   	fwts_acpi_table_pcct_subspace_header	header;
> -	uint32_t	doorbell_interrupt;
> -	uint8_t		doorbell_interrupt_flags;
> +	uint32_t	platform_interrupt;
> +	uint8_t		platform_interrupt_flags;
>   	uint8_t		reserved;
>   	uint64_t	base_address;
>   	uint64_t	length;
> @@ -1406,11 +1406,37 @@ typedef struct {
>   	uint32_t	nominal_latency;
>   	uint32_t	max_periodic_access_rate;
>   	uint16_t	min_request_turnaround_time;
> -	fwts_acpi_gas	doorbell_ack_register;
> -	uint64_t	doorbell_ack_preserve;
> -	uint64_t	doorbell_ack_write;
> +	fwts_acpi_gas	platform_ack_register;
> +	uint64_t	platform_ack_preserve;
> +	uint64_t	platform_ack_write;
>   } __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_2;
>   
> +typedef struct {
> +	fwts_acpi_table_pcct_subspace_header	header;
> +	uint32_t	platform_interrupt;
> +	uint8_t	platform_interrupt_flags;
> +	uint8_t	reserved1;
> +	uint64_t	base_address;
> +	uint32_t	length;
> +	fwts_acpi_gas	doorbell_register;
> +	uint64_t	doorbell_preserve;
> +	uint64_t	doorbell_write;
> +	uint32_t	nominal_latency;
> +	uint32_t	max_periodic_access_rate;
> +	uint32_t	min_request_turnaround_time;
> +	fwts_acpi_gas	platform_ack_register;
> +	uint64_t	platform_ack_preserve;
> +	uint64_t	platform_ack_write;
> +	uint64_t	reserved2;
> +	fwts_acpi_gas	cmd_complete_register;
> +	uint64_t	cmd_complete_mask;
> +	fwts_acpi_gas	cmd_update_register;
> +	uint64_t	cmd_update_preserve_mask;
> +	uint64_t	cmd_update_set_mask;
> +	fwts_acpi_gas	error_status_register;
> +	uint64_t	error_status_mask;
> +} __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_3_4;
> +
>   /*
>    * ACPI SPCR (Serial Port Console Redirection Table)
>    *  http://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> 

Acked-by: Ivan Hu <ivan.hu@canonical.com>
diff mbox

Patch

diff --git a/src/acpi/pcct/pcct.c b/src/acpi/pcct/pcct.c
index 9d79dc5..5753325 100644
--- a/src/acpi/pcct/pcct.c
+++ b/src/acpi/pcct/pcct.c
@@ -52,6 +52,64 @@  static bool subspace_length_equal(fwts_framework *fw, uint8_t type, uint8_t type
 	return true;
 }
 
+static void platform_interrupt_flags(fwts_framework *fw, uint8_t flags, bool *passed)
+{
+	fwts_log_info_verbatim(fw, "    Platform Interrupt Flags:    0x%2.2"   PRIx8, flags);
+
+	if (flags & ~0x3) {
+		*passed = false;
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"PCCTBadSubtypePlatformbInterruptlags",
+			"PCCT Subspace Platform Interrupt Flags's bit [7:2] be zero, got "
+			"0x%2.2" PRIx8 " instead", flags);
+	}
+}
+
+static void gas_messages(fwts_framework *fw, uint8_t type, fwts_acpi_gas *gas, bool *passed)
+{
+	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
+	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
+	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
+	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
+	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
+
+	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
+	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
+			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
+		*passed = false;
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"PCCTSubspaceInvalidAddrSpaceID",
+			"PCCT Subspace Type %" PRId8 " has space ID = %" PRId8
+			" which is not System I/O, Memory or FFH", type, gas->address_space_id);
+	}
+}
+
+static void memory_length(fwts_framework *fw, uint8_t type, uint64_t memory_range, uint64_t min_length, bool *passed)
+{
+	switch (type) {
+	case 0 ... 2:
+		fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, memory_range);
+		if (memory_range <= min_length) {
+			*passed = false;
+			fwts_failed(fw, LOG_LEVEL_HIGH,
+				"PCCTBadSubtypeMemoryLength",
+				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%16.16" PRIx64
+				", got 0x%16.16" PRIx64 " instead", type, min_length, memory_range);
+		}
+		break;
+	case 3 ... 4:
+		fwts_log_info_verbatim(fw, "    Length:                      0x%8.8" PRIx32, (uint32_t)memory_range);
+		if (memory_range <= min_length) {
+			*passed = false;
+			fwts_failed(fw, LOG_LEVEL_HIGH,
+				"PCCTBadSubtypeMemoryLength",
+				"PCCT Subspace Type %" PRId8 " must have memory length > 0x%8.8" PRIx32
+				", got 0x%8.8" PRIx32 " instead", type, (uint32_t)min_length, (uint32_t)memory_range);
+		}
+		break;
+	}
+}
+
 static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_0 *entry, bool *passed)
 {
 	fwts_acpi_gas *gas = &entry->doorbell_register;
@@ -63,7 +121,7 @@  static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
 
 	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, reserved);
 	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
-	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
+	memory_length(fw, entry->header.type, entry->length, 8, passed);
 	fwts_log_info_verbatim(fw, "    Doorbell Register:");
 	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
 	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
@@ -82,113 +140,76 @@  static void generic_comm_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_
 		fwts_failed(fw, LOG_LEVEL_HIGH,
 			"PCCTSubspaceInvalidAddrSpaceID",
 			"PCCT Subspace Type 0 has space ID = 0x%2.2" PRIx8
-			" which is not System I/O Space or System Memory Space",
+			" which is not System I/O or Memory",
 			gas->address_space_id);
 	}
 }
 
 static void hw_reduced_comm_test_type1(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_1 *entry, bool *passed)
 {
-	fwts_acpi_gas *gas = &entry->doorbell_register;
-	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
-
-	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
-	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
+	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
+	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
 	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
 	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
-	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
+	memory_length(fw, entry->header.type, entry->length, 8, passed);
 	fwts_log_info_verbatim(fw, "    Doorbell Register:");
-	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
-	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
-	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
-	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
-	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
+	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
 	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
 	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
 	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
 	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
 	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
-
-	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
-	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
-			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
-		*passed = false;
-		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTSubspaceInvalidAddrSpaceID",
-			"PCCT Subspace Type 1 has space ID = 0x%2.2" PRIx8
-			" which is not System I/O Space or System Memory Space",
-			gas->address_space_id);
-	}
-
-	if (doorbell_int_flags & ~0x3) {
-		*passed = false;
-		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTBadSubtypeDoorbellFlags",
-			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
-			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
-	}
 }
 
 static void hw_reduced_comm_test_type2(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_2 *entry, bool *passed)
 {
-	fwts_acpi_gas *gas = &entry->doorbell_register;
-	fwts_acpi_gas *gas2 = &entry->doorbell_ack_register;
-	uint8_t doorbell_int_flags = entry->doorbell_interrupt_flags;
-
-	fwts_log_info_verbatim(fw, "    Doorbell Interrupt:          0x%8.8"   PRIx32, entry->doorbell_interrupt);
-	fwts_log_info_verbatim(fw, "    Doorbell Interrupt Flags:    0x%2.2"   PRIx8, entry->doorbell_interrupt_flags);
+	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
+	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
 	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved);
 	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
-	fwts_log_info_verbatim(fw, "    Length:                      0x%16.16" PRIx64, entry->length);
+	memory_length(fw, entry->header.type, entry->length, 8, passed);
 	fwts_log_info_verbatim(fw, "    Doorbell Register:");
-	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas->address_space_id);
-	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas->register_bit_width);
-	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas->register_bit_offset);
-	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas->access_width);
-	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas->address);
+	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
 	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
 	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
 	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
 	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
 	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
-	fwts_log_info_verbatim(fw, "    Doorbell Ack Register:");
-	fwts_log_info_verbatim(fw, "      Address Space ID           0x%2.2"   PRIx8, gas2->address_space_id);
-	fwts_log_info_verbatim(fw, "      Register Bit Width         0x%2.2"   PRIx8, gas2->register_bit_width);
-	fwts_log_info_verbatim(fw, "      Register Bit Offset        0x%2.2"   PRIx8, gas2->register_bit_offset);
-	fwts_log_info_verbatim(fw, "      Access Size                0x%2.2"   PRIx8, gas2->access_width);
-	fwts_log_info_verbatim(fw, "      Address                    0x%16.16" PRIx64, gas2->address);
-	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->doorbell_ack_preserve);
-	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->doorbell_ack_write);
-
-	if ((gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
-	    (gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
-			(gas->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
-		*passed = false;
-		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTSubspaceInvalidAddrSpaceID",
-			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
-			" which is not System I/O Space or System Memory Space",
-			gas->address_space_id);
-	}
-
-	if ((gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) &&
-	    (gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) &&
-			(gas2->address_space_id != FWTS_GAS_ADDR_SPACE_ID_FFH)) {
-		*passed = false;
-		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTSubspaceInvalidAddrSpaceID",
-			"PCCT Subspace Type 2 has space ID = 0x%2.2" PRIx8
-			" which is not System I/O Space or System Memory Space",
-			gas->address_space_id);
-	}
+	fwts_log_info_verbatim(fw, "    Platform Interrupt Ack Register:");
+	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
+	fwts_log_info_verbatim(fw, "    Platform Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
+	fwts_log_info_verbatim(fw, "    Platform Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
+}
 
-	if (doorbell_int_flags & ~0x3) {
-		*passed = false;
-		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTBadSubtypeDoorbellFlags",
-			"PCCT Subspace Doorbell Interrupt's bit 2..7 be zero, got "
-			"0x%2.2" PRIx8 " instead", doorbell_int_flags);
-	}
+static void extended_pcc_test(fwts_framework *fw, fwts_acpi_table_pcct_subspace_type_3_4 *entry, bool *passed)
+{
+	fwts_log_info_verbatim(fw, "    Platform Interrupt:          0x%8.8"   PRIx32, entry->platform_interrupt);
+	platform_interrupt_flags(fw, entry->platform_interrupt_flags, passed);
+	fwts_log_info_verbatim(fw, "    Reserved:                    0x%2.2"   PRIx8, entry->reserved1);
+	fwts_log_info_verbatim(fw, "    Base Address:                0x%16.16" PRIx64, entry->base_address);
+	memory_length(fw, entry->header.type, entry->length, 16, passed);
+	fwts_log_info_verbatim(fw, "    Doorbell Register:");
+	gas_messages(fw, entry->header.type, &entry->doorbell_register, passed);
+	fwts_log_info_verbatim(fw, "    Doorbell Preserve:           0x%16.16" PRIx64, entry->doorbell_preserve);
+	fwts_log_info_verbatim(fw, "    Doorbell Write:              0x%16.16" PRIx64, entry->doorbell_write);
+	fwts_log_info_verbatim(fw, "    Nominal Latency:             0x%8.8"   PRIx32, entry->nominal_latency);
+	fwts_log_info_verbatim(fw, "    Max Periodic Access Rate:    0x%8.8"   PRIx32, entry->max_periodic_access_rate);
+	fwts_log_info_verbatim(fw, "    Min Request Turnaround Time: 0x%8.8"   PRIx32, entry->min_request_turnaround_time);
+	fwts_log_info_verbatim(fw, "    Command Complete Check Register:");
+	gas_messages(fw, entry->header.type, &entry->platform_ack_register, passed);
+	fwts_log_info_verbatim(fw, "    Doorbell Ack Preserve:       0x%16.16" PRIx64, entry->platform_ack_preserve);
+	fwts_log_info_verbatim(fw, "    Doorbell Ack Write:          0x%16.16" PRIx64, entry->platform_ack_write);
+	fwts_log_info_verbatim(fw, "    Reserved:                    0x%16.16" PRIx64, entry->reserved2);
+	fwts_log_info_verbatim(fw, "    Cmd Complete Check Register:");
+	gas_messages(fw, entry->header.type, &entry->cmd_complete_register, passed);
+	fwts_log_info_verbatim(fw, "    Cmd Complete Check Mask:     0x%16.16" PRIx64, entry->cmd_complete_mask);
+	fwts_log_info_verbatim(fw, "    Cmd Complete Update Register:");
+	gas_messages(fw, entry->header.type, &entry->cmd_update_register, passed);
+	fwts_log_info_verbatim(fw, "    Cmd Complete Update Mask:    0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
+	fwts_log_info_verbatim(fw, "    Cmd Complete Set Mask:       0x%16.16" PRIx64, entry->cmd_update_preserve_mask);
+	fwts_log_info_verbatim(fw, "    Error Status Register:");
+	gas_messages(fw, entry->header.type, &entry->error_status_register, passed);
+	fwts_log_info_verbatim(fw, "    Error Status Mask:           0x%16.16" PRIx64, entry->error_status_mask);
 }
 
 static int pcct_test1(fwts_framework *fw)
@@ -206,10 +227,10 @@  static int pcct_test1(fwts_framework *fw)
 	if ((pcct->flags & ~0x01) != 0) {
 		passed = false;
 		fwts_failed(fw, LOG_LEVEL_HIGH,
-			"PCCTReservedNonZero",
+			"PCCTBadFlags",
 			"PCCT flags field's bit 1..31 be zero, got "
 			"0x%8.8" PRIx32 " instead", pcct->flags);
-		}
+	}
 
 	if (pcct->reserved != 0) {
 		passed = false;
@@ -223,7 +244,6 @@  static int pcct_test1(fwts_framework *fw)
 	pcct_sub = (fwts_acpi_table_pcct_subspace_header *) (table->data + offset);
 
 	while (offset < table->length) {
-		uint64_t addr_length = 8;
 
 		fwts_log_info_verbatim(fw, "  PCC Subspace Structure:");
 		fwts_log_info_verbatim(fw, "    Type:                        0x%2.2"   PRIx8, pcct_sub->type);
@@ -238,7 +258,6 @@  static int pcct_test1(fwts_framework *fw)
 			}
 
 			generic_comm_test(fw, subspace, &passed);
-			addr_length = subspace->length;
 
 		} else if (pcct_sub->type == 1) {
 			fwts_acpi_table_pcct_subspace_type_1 *subspace = (fwts_acpi_table_pcct_subspace_type_1 *) pcct_sub;
@@ -249,7 +268,6 @@  static int pcct_test1(fwts_framework *fw)
 			}
 
 			hw_reduced_comm_test_type1(fw, subspace, &passed);
-			addr_length = subspace->length;
 
 		} else if (pcct_sub->type == 2) {
 			fwts_acpi_table_pcct_subspace_type_2 *subspace = (fwts_acpi_table_pcct_subspace_type_2 *) pcct_sub;
@@ -260,26 +278,44 @@  static int pcct_test1(fwts_framework *fw)
 			}
 
 			hw_reduced_comm_test_type2(fw, subspace, &passed);
-			addr_length = subspace->length;
+
+		} else if (pcct_sub->type == 3) {
+			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
+
+			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
+				passed = false;
+				break;
+			}
+
+			extended_pcc_test(fw, subspace, &passed);
+
+		} else if (pcct_sub->type == 4) {
+			fwts_acpi_table_pcct_subspace_type_3_4 *subspace = (fwts_acpi_table_pcct_subspace_type_3_4 *) pcct_sub;
+
+			if(!subspace_length_equal(fw, 0, sizeof(fwts_acpi_table_pcct_subspace_type_3_4), pcct_sub->length)) {
+				passed = false;
+				break;
+			}
+
+			if (!(pcct->flags & 0x01)) {
+				passed = false;
+				fwts_failed(fw, LOG_LEVEL_HIGH,
+					"PCCTBadFlags",
+					"PCCT Plaform Interrupt in flags must be set when subspace "
+					"type 4 is present, got 0x%8.8" PRIx32 " instead", pcct->flags);
+			}
+
+			extended_pcc_test(fw, subspace, &passed);
 
 		} else {
 			passed = false;
 			fwts_failed(fw, LOG_LEVEL_HIGH,
 				"PCCTBadSubType",
-				"PCCT Subspace Structure supports type 0..2, got "
+				"PCCT Subspace Structure supports type 0..4, got "
 				"0x%2.2" PRIx8 " instead", pcct_sub->type);
+			break;
 		}
 
-		if (addr_length <= 8) {
-			passed = false;
-			fwts_failed(fw, LOG_LEVEL_HIGH,
-				"PCCTBadSubtypeMemoryLength",
-				"PCCT Subspace Structure must have memory length > 8, got "
-				"0x%16.16" PRIx64 " instead", addr_length);
-		}
-
-
-
 		fwts_log_nl(fw);
 
 		offset += pcct_sub->length;
diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h
index 12d63aa..5484cf3 100644
--- a/src/lib/include/fwts_acpi.h
+++ b/src/lib/include/fwts_acpi.h
@@ -1380,8 +1380,8 @@  typedef struct {
 
 typedef struct {
 	fwts_acpi_table_pcct_subspace_header	header;
-	uint32_t	doorbell_interrupt;
-	uint8_t		doorbell_interrupt_flags;
+	uint32_t	platform_interrupt;
+	uint8_t		platform_interrupt_flags;
 	uint8_t		reserved;
 	uint64_t	base_address;
 	uint64_t	length;
@@ -1395,8 +1395,8 @@  typedef struct {
 
 typedef struct {
 	fwts_acpi_table_pcct_subspace_header	header;
-	uint32_t	doorbell_interrupt;
-	uint8_t		doorbell_interrupt_flags;
+	uint32_t	platform_interrupt;
+	uint8_t		platform_interrupt_flags;
 	uint8_t		reserved;
 	uint64_t	base_address;
 	uint64_t	length;
@@ -1406,11 +1406,37 @@  typedef struct {
 	uint32_t	nominal_latency;
 	uint32_t	max_periodic_access_rate;
 	uint16_t	min_request_turnaround_time;
-	fwts_acpi_gas	doorbell_ack_register;
-	uint64_t	doorbell_ack_preserve;
-	uint64_t	doorbell_ack_write;
+	fwts_acpi_gas	platform_ack_register;
+	uint64_t	platform_ack_preserve;
+	uint64_t	platform_ack_write;
 } __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_2;
 
+typedef struct {
+	fwts_acpi_table_pcct_subspace_header	header;
+	uint32_t	platform_interrupt;
+	uint8_t	platform_interrupt_flags;
+	uint8_t	reserved1;
+	uint64_t	base_address;
+	uint32_t	length;
+	fwts_acpi_gas	doorbell_register;
+	uint64_t	doorbell_preserve;
+	uint64_t	doorbell_write;
+	uint32_t	nominal_latency;
+	uint32_t	max_periodic_access_rate;
+	uint32_t	min_request_turnaround_time;
+	fwts_acpi_gas	platform_ack_register;
+	uint64_t	platform_ack_preserve;
+	uint64_t	platform_ack_write;
+	uint64_t	reserved2;
+	fwts_acpi_gas	cmd_complete_register;
+	uint64_t	cmd_complete_mask;
+	fwts_acpi_gas	cmd_update_register;
+	uint64_t	cmd_update_preserve_mask;
+	uint64_t	cmd_update_set_mask;
+	fwts_acpi_gas	error_status_register;
+	uint64_t	error_status_mask;
+} __attribute__ ((packed)) fwts_acpi_table_pcct_subspace_type_3_4;
+
 /*
  * ACPI SPCR (Serial Port Console Redirection Table)
  *  http://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx