Message ID | 1434372497-17616-3-git-send-email-colin.king@canonical.com |
---|---|
State | Rejected |
Headers | show |
On 06/15/2015 08:48 PM, Colin King wrote: > From: Colin Ian King <colin.king@canonical.com> > > Add SPMI (Service Processor Management Interface Description Table) > test. > > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/spmi/spmi.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 254 insertions(+) > create mode 100644 src/acpi/spmi/spmi.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index ceeb45e..3fa679c 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -54,6 +54,7 @@ fwts_SOURCES = main.c \ > acpi/s3power/s3power.c \ > acpi/s4/s4.c \ > acpi/spcr/spcr.c \ > + acpi/spmi/spmi.c \ > acpi/srat/srat.c \ > acpi/syntaxcheck/syntaxcheck.c \ > acpi/wakealarm/wakealarm.c \ > diff --git a/src/acpi/spmi/spmi.c b/src/acpi/spmi/spmi.c > new file mode 100644 > index 0000000..6afc63e > --- /dev/null > +++ b/src/acpi/spmi/spmi.c > @@ -0,0 +1,253 @@ > +/* > + * Copyright (C) 2015 Canonical > + * > + * Portions of this code original from the Linux-ready Firmware Developer Kit > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > +#include "fwts.h" > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > + > +static fwts_acpi_table_info *table; > + > +static int spmi_init(fwts_framework *fw) > +{ > + > + if (fwts_acpi_find_table(fw, "SPMI", 0, &table) != FWTS_OK) { > + fwts_log_error(fw, "Cannot read ACPI tables."); > + return FWTS_ERROR; > + } > + if (table == NULL || (table && table->length == 0)) { > + fwts_log_error(fw, "ACPI SPMI table does not exist, skipping test"); > + return FWTS_SKIP; > + } > + > + return FWTS_OK; > +} > + > +/* > + * SPMI Service Processor Management Interface Description Table > + * see http://www.intel.com/content/www/us/en/servers/ipmi/ > + * ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.html > + * pages 600-606 > + */ > +static int spmi_test1(fwts_framework *fw) > +{ > + char *interface_type; > + bool passed = true; > + fwts_acpi_table_spmi *spmi = (fwts_acpi_table_spmi *)table->data; > + > + if (table->length < sizeof(fwts_acpi_table_spmi)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "SPMITooShort", > + "SPMI table too short, expecting %zu bytes, " > + "instead got %zu bytes", > + sizeof(fwts_acpi_table_spmi), table->length); > + goto done; > + } > + > + switch (spmi->interface_type) { > + case 0x01: > + interface_type = "Keyboard Controller Type (KCS)"; > + break; > + case 0x02: > + interface_type = "Server Management Interface Chip (SMIC)"; > + break; > + case 0x03: > + interface_type = "Block Transfer (BT)"; > + break; > + case 0x04: > + interface_type = "SMBus System Interface (SSIF)"; > + break; > + default: > + interface_type = "Reserved"; > + break; > + } > + > + fwts_log_info_verbatum(fw, "SPMI Service Processor Management Interface Description Table:"); > + fwts_log_info_verbatum(fw, " Interface Type: 0x%2.2" PRIx8 " (%s)", > + spmi->interface_type, interface_type); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved1); > + fwts_log_info_verbatum(fw, " Specification Revision: 0x%2.2" PRIx8, spmi->specification_revision); > + fwts_log_info_verbatum(fw, " Interrupt Type: 0x%2.2" PRIx8, spmi->interrupt_type); > + fwts_log_info_verbatum(fw, " GPE: 0x%2.2" PRIx8, spmi->gpe); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved2); > + fwts_log_info_verbatum(fw, " PCI Device Flag: 0x%2.2" PRIx8, spmi->pci_device_flag); > + fwts_log_info_verbatum(fw, " Global System Interrupt 0x%8.8" PRIx32, spmi->global_system_interrupt); > + fwts_log_info_verbatum(fw, " Base Address:"); > + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" PRIx8, spmi->base_address.address_space_id); > + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" PRIx8, spmi->base_address.register_bit_width); > + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" PRIx8, spmi->base_address.register_bit_offset); > + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" PRIx8, spmi->base_address.access_width); > + fwts_log_info_verbatum(fw, " Address 0x%16.16" PRIx64, spmi->base_address.address); > + fwts_log_info_verbatum(fw, " PCI Segment Group: 0x%2.2" PRIx8, spmi->pci_segment_group_number); > + fwts_log_info_verbatum(fw, " PCI Bus: 0x%2.2" PRIx8, spmi->pci_bus_number); > + fwts_log_info_verbatum(fw, " PCI Device: 0x%2.2" PRIx8, spmi->pci_device_number); > + fwts_log_info_verbatum(fw, " PCI Function: 0x%2.2" PRIx8, spmi->pci_function_number); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved3); > + fwts_log_nl(fw); > + > + if (spmi->interface_type < 1 || spmi->interface_type > 4) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInterfaceTypeReserved", > + "SPMI Interface Type is 0x%2.2" PRIx8 " which " > + "is a reserved type and probably incorrect.", > + spmi->interface_type); > + } > + > + if (spmi->reserved1 != 1) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIReserved1Not1", > + "SPMI reserved field (offset 37) must be 0x01, got " > + "0x%2.2" PRIx8 " instead", spmi->reserved1); > + } > + > + /* Only bottom 2 bits should be set */ > + if (spmi->interrupt_type & ~0x03) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIInterruptTypeReservedNonZero", > + "SPMI Interrupt Type reserved bits [7:2] must be 0, got " > + "0x%2.2" PRIx8 " instead", spmi->interrupt_type); > + } > + > + /* Check for zero GPE on specific condition of interrupt type */ > + if (((spmi->interrupt_type & 1) == 0) && > + (spmi->gpe != 0)) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIGPENotZero", > + "SPMI GPE is 0x%2.2" PRIx8 " and should be 0 if the Interrupt " > + "Type bit 0 (SCI triggered through GPE) is set to 0", > + spmi->gpe); > + } > + if (spmi->reserved2 != 0) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIReserved1NonZero", > + "SPMI reserved field (offset 42) must be 0x00, got " > + "0x%2.2" PRIx8 " instead", spmi->reserved2); > + } > + /* Only bottom 1 bit should be set */ > + if (spmi->pci_device_flag & ~0x01) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIPciDeviceFlag", > + "SPMI PCI Device Flag reserved bits [7:1] must be 0, got " > + "0x%2.2" PRIx8 " instead", spmi->pci_device_flag); > + } > + > + /* For SSIF interfaces, if device flag [0] is set then PCI semgment group number is zero */ > + if ((spmi->interface_type == 0x04) && > + (spmi->pci_device_flag & 0x01) && > + (spmi->pci_segment_group_number != 0)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIPciSegmentGroupNumber", > + "SPMI PCI Segment Group Number should be 0 for SSIF interface " > + "types when bit [0] of the PCI Device Flag is set"); > + } > + > + if (((spmi->interrupt_type & 2) == 0) && > + (spmi->global_system_interrupt != 0)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIGlobalSystemInterruptNonZero", > + "SPMI Global System Interrupt is 0x%" PRIx32 " and " > + "should be zero if bit [1] (I/O APIC/SAPIC interrupt) " > + "of the Interrupt Type is not set", > + spmi->global_system_interrupt); > + } > + > + /* Base address must be one of 3 types, System Memory, System I/O or SMBUS */ > + if ((spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) && > + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && > + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIBaseAddressSpaceID", > + "SPMI Base Address Space ID is 0x%2.2" PRIx8 " but should be one of " > + "0x%2.2" PRIx8 " (System Memory), " > + "0x%2.2" PRIx8 " (System I/O) or " > + "0x%2.2" PRIx8 " (SMBUS)", > + spmi->base_address.address_space_id, > + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY, > + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO, > + FWTS_GAS_ADDR_SPACE_ID_SMBUS); > + } > + /* > + * For SSIF: The Address_Space_ID is SMBUS and the address field of the GAS > + * holds the 7-bit slave address of the BMC on the host SMBus > + * in the least significant byte. Note that the slave address is > + * stored with the 7-bit slave address in the least significant 7- > + * bits of the byte, and the most significant bit of the byte set to > + */ > + if (spmi->interface_type == 0x04) { > + if (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInvalidAddressSpaceIDForSSIF", > + "SPMI Base Address Space ID is 0x%2.2" PRIx8 > + " but should be 0x%2.2" PRIx8 " (SMBUS) " > + " for a SSIF Interface Type", > + spmi->base_address.address_space_id, > + FWTS_GAS_ADDR_SPACE_ID_SMBUS); > + } > + if (spmi->base_address.address & ~0x7f) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInvalidBaseAddressForSSIF", > + "SPMI Base Address is 0x%16.16" PRIx64 > + " but should be 0..127 for a SSIF Interface Type", > + spmi->base_address.address); > + } > + } > + /* > + * Specification states that PCI device number bits [7:5] > + * are reserved if PCI device flag bit [0] is set, however, > + * it does not state if they should be zero or 1, so for > + * now don't check these > + * > + * Also, PCI function number bits [7] and [5:3] are > + * reserved, again, not sure if these need to be checked > + * so ignore these too. > + */ > +done: > + if (passed) > + fwts_passed(fw, "No issues found in SPMI table."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test spmi_tests[] = { > + { spmi_test1, "SPMI Service Processor Management Interface Description Table test." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops spmi_ops = { > + .description = "SPMI Service Processor Management Interface Description Table test.", > + .init = spmi_init, > + .minor_tests = spmi_tests > +}; > + > +FWTS_REGISTER("spmi", &spmi_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI) > Acked-by: Alex Hung <alex.hung@canonical.com>
On 2015年06月15日 20:48, Colin King wrote: > From: Colin Ian King <colin.king@canonical.com> > > Add SPMI (Service Processor Management Interface Description Table) > test. > > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/spmi/spmi.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 254 insertions(+) > create mode 100644 src/acpi/spmi/spmi.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index ceeb45e..3fa679c 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -54,6 +54,7 @@ fwts_SOURCES = main.c \ > acpi/s3power/s3power.c \ > acpi/s4/s4.c \ > acpi/spcr/spcr.c \ > + acpi/spmi/spmi.c \ > acpi/srat/srat.c \ > acpi/syntaxcheck/syntaxcheck.c \ > acpi/wakealarm/wakealarm.c \ > diff --git a/src/acpi/spmi/spmi.c b/src/acpi/spmi/spmi.c > new file mode 100644 > index 0000000..6afc63e > --- /dev/null > +++ b/src/acpi/spmi/spmi.c > @@ -0,0 +1,253 @@ > +/* > + * Copyright (C) 2015 Canonical > + * > + * Portions of this code original from the Linux-ready Firmware Developer Kit > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > +#include "fwts.h" > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > + > +static fwts_acpi_table_info *table; > + > +static int spmi_init(fwts_framework *fw) > +{ > + > + if (fwts_acpi_find_table(fw, "SPMI", 0, &table) != FWTS_OK) { > + fwts_log_error(fw, "Cannot read ACPI tables."); > + return FWTS_ERROR; > + } > + if (table == NULL || (table && table->length == 0)) { > + fwts_log_error(fw, "ACPI SPMI table does not exist, skipping test"); > + return FWTS_SKIP; > + } > + > + return FWTS_OK; > +} > + > +/* > + * SPMI Service Processor Management Interface Description Table > + * see http://www.intel.com/content/www/us/en/servers/ipmi/ > + * ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.html > + * pages 600-606 > + */ > +static int spmi_test1(fwts_framework *fw) > +{ > + char *interface_type; > + bool passed = true; > + fwts_acpi_table_spmi *spmi = (fwts_acpi_table_spmi *)table->data; > + > + if (table->length < sizeof(fwts_acpi_table_spmi)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_HIGH, > + "SPMITooShort", > + "SPMI table too short, expecting %zu bytes, " > + "instead got %zu bytes", > + sizeof(fwts_acpi_table_spmi), table->length); > + goto done; > + } > + > + switch (spmi->interface_type) { > + case 0x01: > + interface_type = "Keyboard Controller Type (KCS)"; > + break; > + case 0x02: > + interface_type = "Server Management Interface Chip (SMIC)"; > + break; > + case 0x03: > + interface_type = "Block Transfer (BT)"; > + break; > + case 0x04: > + interface_type = "SMBus System Interface (SSIF)"; > + break; > + default: > + interface_type = "Reserved"; > + break; > + } > + > + fwts_log_info_verbatum(fw, "SPMI Service Processor Management Interface Description Table:"); > + fwts_log_info_verbatum(fw, " Interface Type: 0x%2.2" PRIx8 " (%s)", > + spmi->interface_type, interface_type); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved1); > + fwts_log_info_verbatum(fw, " Specification Revision: 0x%2.2" PRIx8, spmi->specification_revision); > + fwts_log_info_verbatum(fw, " Interrupt Type: 0x%2.2" PRIx8, spmi->interrupt_type); > + fwts_log_info_verbatum(fw, " GPE: 0x%2.2" PRIx8, spmi->gpe); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved2); > + fwts_log_info_verbatum(fw, " PCI Device Flag: 0x%2.2" PRIx8, spmi->pci_device_flag); > + fwts_log_info_verbatum(fw, " Global System Interrupt 0x%8.8" PRIx32, spmi->global_system_interrupt); > + fwts_log_info_verbatum(fw, " Base Address:"); > + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" PRIx8, spmi->base_address.address_space_id); > + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" PRIx8, spmi->base_address.register_bit_width); > + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" PRIx8, spmi->base_address.register_bit_offset); > + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" PRIx8, spmi->base_address.access_width); > + fwts_log_info_verbatum(fw, " Address 0x%16.16" PRIx64, spmi->base_address.address); > + fwts_log_info_verbatum(fw, " PCI Segment Group: 0x%2.2" PRIx8, spmi->pci_segment_group_number); > + fwts_log_info_verbatum(fw, " PCI Bus: 0x%2.2" PRIx8, spmi->pci_bus_number); > + fwts_log_info_verbatum(fw, " PCI Device: 0x%2.2" PRIx8, spmi->pci_device_number); > + fwts_log_info_verbatum(fw, " PCI Function: 0x%2.2" PRIx8, spmi->pci_function_number); > + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved3); > + fwts_log_nl(fw); > + > + if (spmi->interface_type < 1 || spmi->interface_type > 4) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInterfaceTypeReserved", > + "SPMI Interface Type is 0x%2.2" PRIx8 " which " > + "is a reserved type and probably incorrect.", > + spmi->interface_type); > + } > + > + if (spmi->reserved1 != 1) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIReserved1Not1", > + "SPMI reserved field (offset 37) must be 0x01, got " > + "0x%2.2" PRIx8 " instead", spmi->reserved1); > + } > + > + /* Only bottom 2 bits should be set */ > + if (spmi->interrupt_type & ~0x03) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIInterruptTypeReservedNonZero", > + "SPMI Interrupt Type reserved bits [7:2] must be 0, got " > + "0x%2.2" PRIx8 " instead", spmi->interrupt_type); > + } > + > + /* Check for zero GPE on specific condition of interrupt type */ > + if (((spmi->interrupt_type & 1) == 0) && > + (spmi->gpe != 0)) { passed = false; here? > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIGPENotZero", > + "SPMI GPE is 0x%2.2" PRIx8 " and should be 0 if the Interrupt " > + "Type bit 0 (SCI triggered through GPE) is set to 0", > + spmi->gpe); > + } > + if (spmi->reserved2 != 0) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_LOW, > + "SPMIReserved1NonZero", > + "SPMI reserved field (offset 42) must be 0x00, got " > + "0x%2.2" PRIx8 " instead", spmi->reserved2); > + } > + /* Only bottom 1 bit should be set */ > + if (spmi->pci_device_flag & ~0x01) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIPciDeviceFlag", > + "SPMI PCI Device Flag reserved bits [7:1] must be 0, got " > + "0x%2.2" PRIx8 " instead", spmi->pci_device_flag); > + } > + > + /* For SSIF interfaces, if device flag [0] is set then PCI semgment group number is zero */ > + if ((spmi->interface_type == 0x04) && > + (spmi->pci_device_flag & 0x01) && > + (spmi->pci_segment_group_number != 0)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIPciSegmentGroupNumber", > + "SPMI PCI Segment Group Number should be 0 for SSIF interface " > + "types when bit [0] of the PCI Device Flag is set"); > + } I don't see the "PCI Segment Group number should be 0 for SSIF when bit0 of the PCI device flag is set" on spec. I only see the PCI device flag should be 0 for SSIF. Could you help to double check that? > + > + if (((spmi->interrupt_type & 2) == 0) && > + (spmi->global_system_interrupt != 0)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIGlobalSystemInterruptNonZero", > + "SPMI Global System Interrupt is 0x%" PRIx32 " and " > + "should be zero if bit [1] (I/O APIC/SAPIC interrupt) " > + "of the Interrupt Type is not set", > + spmi->global_system_interrupt); > + } > + > + /* Base address must be one of 3 types, System Memory, System I/O or SMBUS */ > + if ((spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) && > + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && > + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS)) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIBaseAddressSpaceID", > + "SPMI Base Address Space ID is 0x%2.2" PRIx8 " but should be one of " > + "0x%2.2" PRIx8 " (System Memory), " > + "0x%2.2" PRIx8 " (System I/O) or " > + "0x%2.2" PRIx8 " (SMBUS)", > + spmi->base_address.address_space_id, > + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY, > + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO, > + FWTS_GAS_ADDR_SPACE_ID_SMBUS); > + } > + /* > + * For SSIF: The Address_Space_ID is SMBUS and the address field of the GAS > + * holds the 7-bit slave address of the BMC on the host SMBus > + * in the least significant byte. Note that the slave address is > + * stored with the 7-bit slave address in the least significant 7- > + * bits of the byte, and the most significant bit of the byte set to > + */ > + if (spmi->interface_type == 0x04) { > + if (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInvalidAddressSpaceIDForSSIF", > + "SPMI Base Address Space ID is 0x%2.2" PRIx8 > + " but should be 0x%2.2" PRIx8 " (SMBUS) " > + " for a SSIF Interface Type", > + spmi->base_address.address_space_id, > + FWTS_GAS_ADDR_SPACE_ID_SMBUS); > + } > + if (spmi->base_address.address & ~0x7f) { > + passed = false; > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "SPMIInvalidBaseAddressForSSIF", > + "SPMI Base Address is 0x%16.16" PRIx64 > + " but should be 0..127 for a SSIF Interface Type", > + spmi->base_address.address); > + } > + } > + /* > + * Specification states that PCI device number bits [7:5] > + * are reserved if PCI device flag bit [0] is set, however, > + * it does not state if they should be zero or 1, so for > + * now don't check these > + * > + * Also, PCI function number bits [7] and [5:3] are > + * reserved, again, not sure if these need to be checked > + * so ignore these too. > + */ > +done: > + if (passed) > + fwts_passed(fw, "No issues found in SPMI table."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test spmi_tests[] = { > + { spmi_test1, "SPMI Service Processor Management Interface Description Table test." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops spmi_ops = { > + .description = "SPMI Service Processor Management Interface Description Table test.", > + .init = spmi_init, > + .minor_tests = spmi_tests > +}; > + > +FWTS_REGISTER("spmi", &spmi_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)
On 18/06/15 06:17, ivanhu wrote: > > > On 2015年06月15日 20:48, Colin King wrote: >> From: Colin Ian King <colin.king@canonical.com> >> >> Add SPMI (Service Processor Management Interface Description Table) >> test. >> >> Signed-off-by: Colin Ian King <colin.king@canonical.com> >> --- >> src/Makefile.am | 1 + >> src/acpi/spmi/spmi.c | 253 >> +++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 254 insertions(+) >> create mode 100644 src/acpi/spmi/spmi.c >> >> diff --git a/src/Makefile.am b/src/Makefile.am >> index ceeb45e..3fa679c 100644 >> --- a/src/Makefile.am >> +++ b/src/Makefile.am >> @@ -54,6 +54,7 @@ fwts_SOURCES = main.c \ >> acpi/s3power/s3power.c \ >> acpi/s4/s4.c \ >> acpi/spcr/spcr.c \ >> + acpi/spmi/spmi.c \ >> acpi/srat/srat.c \ >> acpi/syntaxcheck/syntaxcheck.c \ >> acpi/wakealarm/wakealarm.c \ >> diff --git a/src/acpi/spmi/spmi.c b/src/acpi/spmi/spmi.c >> new file mode 100644 >> index 0000000..6afc63e >> --- /dev/null >> +++ b/src/acpi/spmi/spmi.c >> @@ -0,0 +1,253 @@ >> +/* >> + * Copyright (C) 2015 Canonical >> + * >> + * Portions of this code original from the Linux-ready Firmware >> Developer Kit >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * as published by the Free Software Foundation; either version 2 >> + * of the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write to the Free Software >> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA >> 02110-1301, USA. >> + * >> + */ >> +#include "fwts.h" >> + >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <inttypes.h> >> +#include <string.h> >> + >> +static fwts_acpi_table_info *table; >> + >> +static int spmi_init(fwts_framework *fw) >> +{ >> + >> + if (fwts_acpi_find_table(fw, "SPMI", 0, &table) != FWTS_OK) { >> + fwts_log_error(fw, "Cannot read ACPI tables."); >> + return FWTS_ERROR; >> + } >> + if (table == NULL || (table && table->length == 0)) { >> + fwts_log_error(fw, "ACPI SPMI table does not exist, skipping >> test"); >> + return FWTS_SKIP; >> + } >> + >> + return FWTS_OK; >> +} >> + >> +/* >> + * SPMI Service Processor Management Interface Description Table >> + * see http://www.intel.com/content/www/us/en/servers/ipmi/ >> + * >> ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.html >> >> + * pages 600-606 >> + */ >> +static int spmi_test1(fwts_framework *fw) >> +{ >> + char *interface_type; >> + bool passed = true; >> + fwts_acpi_table_spmi *spmi = (fwts_acpi_table_spmi *)table->data; >> + >> + if (table->length < sizeof(fwts_acpi_table_spmi)) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_HIGH, >> + "SPMITooShort", >> + "SPMI table too short, expecting %zu bytes, " >> + "instead got %zu bytes", >> + sizeof(fwts_acpi_table_spmi), table->length); >> + goto done; >> + } >> + >> + switch (spmi->interface_type) { >> + case 0x01: >> + interface_type = "Keyboard Controller Type (KCS)"; >> + break; >> + case 0x02: >> + interface_type = "Server Management Interface Chip (SMIC)"; >> + break; >> + case 0x03: >> + interface_type = "Block Transfer (BT)"; >> + break; >> + case 0x04: >> + interface_type = "SMBus System Interface (SSIF)"; >> + break; >> + default: >> + interface_type = "Reserved"; >> + break; >> + } >> + >> + fwts_log_info_verbatum(fw, "SPMI Service Processor Management >> Interface Description Table:"); >> + fwts_log_info_verbatum(fw, " Interface Type: 0x%2.2" >> PRIx8 " (%s)", >> + spmi->interface_type, interface_type); >> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" >> PRIx8, spmi->reserved1); >> + fwts_log_info_verbatum(fw, " Specification Revision: 0x%2.2" >> PRIx8, spmi->specification_revision); >> + fwts_log_info_verbatum(fw, " Interrupt Type: 0x%2.2" >> PRIx8, spmi->interrupt_type); >> + fwts_log_info_verbatum(fw, " GPE: 0x%2.2" >> PRIx8, spmi->gpe); >> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" >> PRIx8, spmi->reserved2); >> + fwts_log_info_verbatum(fw, " PCI Device Flag: 0x%2.2" >> PRIx8, spmi->pci_device_flag); >> + fwts_log_info_verbatum(fw, " Global System Interrupt 0x%8.8" >> PRIx32, spmi->global_system_interrupt); >> + fwts_log_info_verbatum(fw, " Base Address:"); >> + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" >> PRIx8, spmi->base_address.address_space_id); >> + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" >> PRIx8, spmi->base_address.register_bit_width); >> + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" >> PRIx8, spmi->base_address.register_bit_offset); >> + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" >> PRIx8, spmi->base_address.access_width); >> + fwts_log_info_verbatum(fw, " Address 0x%16.16" >> PRIx64, spmi->base_address.address); >> + fwts_log_info_verbatum(fw, " PCI Segment Group: 0x%2.2" >> PRIx8, spmi->pci_segment_group_number); >> + fwts_log_info_verbatum(fw, " PCI Bus: 0x%2.2" >> PRIx8, spmi->pci_bus_number); >> + fwts_log_info_verbatum(fw, " PCI Device: 0x%2.2" >> PRIx8, spmi->pci_device_number); >> + fwts_log_info_verbatum(fw, " PCI Function: 0x%2.2" >> PRIx8, spmi->pci_function_number); >> + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" >> PRIx8, spmi->reserved3); >> + fwts_log_nl(fw); >> + >> + if (spmi->interface_type < 1 || spmi->interface_type > 4) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIInterfaceTypeReserved", >> + "SPMI Interface Type is 0x%2.2" PRIx8 " which " >> + "is a reserved type and probably incorrect.", >> + spmi->interface_type); >> + } >> + >> + if (spmi->reserved1 != 1) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_LOW, >> + "SPMIReserved1Not1", >> + "SPMI reserved field (offset 37) must be 0x01, got " >> + "0x%2.2" PRIx8 " instead", spmi->reserved1); >> + } >> + >> + /* Only bottom 2 bits should be set */ >> + if (spmi->interrupt_type & ~0x03) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_LOW, >> + "SPMIInterruptTypeReservedNonZero", >> + "SPMI Interrupt Type reserved bits [7:2] must be 0, got " >> + "0x%2.2" PRIx8 " instead", spmi->interrupt_type); >> + } >> + >> + /* Check for zero GPE on specific condition of interrupt type */ >> + if (((spmi->interrupt_type & 1) == 0) && >> + (spmi->gpe != 0)) { > > passed = false; here? > >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIGPENotZero", >> + "SPMI GPE is 0x%2.2" PRIx8 " and should be 0 if the >> Interrupt " >> + "Type bit 0 (SCI triggered through GPE) is set to 0", >> + spmi->gpe); >> + } >> + if (spmi->reserved2 != 0) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_LOW, >> + "SPMIReserved1NonZero", >> + "SPMI reserved field (offset 42) must be 0x00, got " >> + "0x%2.2" PRIx8 " instead", spmi->reserved2); >> + } >> + /* Only bottom 1 bit should be set */ >> + if (spmi->pci_device_flag & ~0x01) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIPciDeviceFlag", >> + "SPMI PCI Device Flag reserved bits [7:1] must be 0, got " >> + "0x%2.2" PRIx8 " instead", spmi->pci_device_flag); >> + } >> + >> + /* For SSIF interfaces, if device flag [0] is set then PCI >> semgment group number is zero */ >> + if ((spmi->interface_type == 0x04) && >> + (spmi->pci_device_flag & 0x01) && >> + (spmi->pci_segment_group_number != 0)) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIPciSegmentGroupNumber", >> + "SPMI PCI Segment Group Number should be 0 for SSIF >> interface " >> + "types when bit [0] of the PCI Device Flag is set"); >> + } > I don't see the "PCI Segment Group number should be 0 for SSIF when bit0 > of the PCI device flag is set" on spec. > I only see the PCI device flag should be 0 for SSIF. > Could you help to double check that? Yes, I somehow misunderstood some side notes I read. I will remove this test as it seems wrong in retrospect. Thanks for spotting this mistake. >> + >> + if (((spmi->interrupt_type & 2) == 0) && >> + (spmi->global_system_interrupt != 0)) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIGlobalSystemInterruptNonZero", >> + "SPMI Global System Interrupt is 0x%" PRIx32 " and " >> + "should be zero if bit [1] (I/O APIC/SAPIC interrupt) " >> + "of the Interrupt Type is not set", >> + spmi->global_system_interrupt); >> + } >> + >> + /* Base address must be one of 3 types, System Memory, System I/O >> or SMBUS */ >> + if ((spmi->base_address.address_space_id != >> FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) && >> + (spmi->base_address.address_space_id != >> FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && >> + (spmi->base_address.address_space_id != >> FWTS_GAS_ADDR_SPACE_ID_SMBUS)) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIBaseAddressSpaceID", >> + "SPMI Base Address Space ID is 0x%2.2" PRIx8 " but should >> be one of " >> + "0x%2.2" PRIx8 " (System Memory), " >> + "0x%2.2" PRIx8 " (System I/O) or " >> + "0x%2.2" PRIx8 " (SMBUS)", >> + spmi->base_address.address_space_id, >> + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY, >> + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO, >> + FWTS_GAS_ADDR_SPACE_ID_SMBUS); >> + } >> + /* >> + * For SSIF: The Address_Space_ID is SMBUS and the address field >> of the GAS >> + * holds the 7-bit slave address of the BMC on the host SMBus >> + * in the least significant byte. Note that the slave address is >> + * stored with the 7-bit slave address in the least >> significant 7- >> + * bits of the byte, and the most significant bit of the byte >> set to >> + */ >> + if (spmi->interface_type == 0x04) { >> + if (spmi->base_address.address_space_id != >> FWTS_GAS_ADDR_SPACE_ID_SMBUS) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIInvalidAddressSpaceIDForSSIF", >> + "SPMI Base Address Space ID is 0x%2.2" PRIx8 >> + " but should be 0x%2.2" PRIx8 " (SMBUS) " >> + " for a SSIF Interface Type", >> + spmi->base_address.address_space_id, >> + FWTS_GAS_ADDR_SPACE_ID_SMBUS); >> + } >> + if (spmi->base_address.address & ~0x7f) { >> + passed = false; >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "SPMIInvalidBaseAddressForSSIF", >> + "SPMI Base Address is 0x%16.16" PRIx64 >> + " but should be 0..127 for a SSIF Interface Type", >> + spmi->base_address.address); >> + } >> + } >> + /* >> + * Specification states that PCI device number bits [7:5] >> + * are reserved if PCI device flag bit [0] is set, however, >> + * it does not state if they should be zero or 1, so for >> + * now don't check these >> + * >> + * Also, PCI function number bits [7] and [5:3] are >> + * reserved, again, not sure if these need to be checked >> + * so ignore these too. >> + */ >> +done: >> + if (passed) >> + fwts_passed(fw, "No issues found in SPMI table."); >> + >> + return FWTS_OK; >> +} >> + >> +static fwts_framework_minor_test spmi_tests[] = { >> + { spmi_test1, "SPMI Service Processor Management Interface >> Description Table test." }, >> + { NULL, NULL } >> +}; >> + >> +static fwts_framework_ops spmi_ops = { >> + .description = "SPMI Service Processor Management Interface >> Description Table test.", >> + .init = spmi_init, >> + .minor_tests = spmi_tests >> +}; >> + >> +FWTS_REGISTER("spmi", &spmi_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | >> FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI) > >
diff --git a/src/Makefile.am b/src/Makefile.am index ceeb45e..3fa679c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,6 +54,7 @@ fwts_SOURCES = main.c \ acpi/s3power/s3power.c \ acpi/s4/s4.c \ acpi/spcr/spcr.c \ + acpi/spmi/spmi.c \ acpi/srat/srat.c \ acpi/syntaxcheck/syntaxcheck.c \ acpi/wakealarm/wakealarm.c \ diff --git a/src/acpi/spmi/spmi.c b/src/acpi/spmi/spmi.c new file mode 100644 index 0000000..6afc63e --- /dev/null +++ b/src/acpi/spmi/spmi.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2015 Canonical + * + * Portions of this code original from the Linux-ready Firmware Developer Kit + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "fwts.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <string.h> + +static fwts_acpi_table_info *table; + +static int spmi_init(fwts_framework *fw) +{ + + if (fwts_acpi_find_table(fw, "SPMI", 0, &table) != FWTS_OK) { + fwts_log_error(fw, "Cannot read ACPI tables."); + return FWTS_ERROR; + } + if (table == NULL || (table && table->length == 0)) { + fwts_log_error(fw, "ACPI SPMI table does not exist, skipping test"); + return FWTS_SKIP; + } + + return FWTS_OK; +} + +/* + * SPMI Service Processor Management Interface Description Table + * see http://www.intel.com/content/www/us/en/servers/ipmi/ + * ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.html + * pages 600-606 + */ +static int spmi_test1(fwts_framework *fw) +{ + char *interface_type; + bool passed = true; + fwts_acpi_table_spmi *spmi = (fwts_acpi_table_spmi *)table->data; + + if (table->length < sizeof(fwts_acpi_table_spmi)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_HIGH, + "SPMITooShort", + "SPMI table too short, expecting %zu bytes, " + "instead got %zu bytes", + sizeof(fwts_acpi_table_spmi), table->length); + goto done; + } + + switch (spmi->interface_type) { + case 0x01: + interface_type = "Keyboard Controller Type (KCS)"; + break; + case 0x02: + interface_type = "Server Management Interface Chip (SMIC)"; + break; + case 0x03: + interface_type = "Block Transfer (BT)"; + break; + case 0x04: + interface_type = "SMBus System Interface (SSIF)"; + break; + default: + interface_type = "Reserved"; + break; + } + + fwts_log_info_verbatum(fw, "SPMI Service Processor Management Interface Description Table:"); + fwts_log_info_verbatum(fw, " Interface Type: 0x%2.2" PRIx8 " (%s)", + spmi->interface_type, interface_type); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved1); + fwts_log_info_verbatum(fw, " Specification Revision: 0x%2.2" PRIx8, spmi->specification_revision); + fwts_log_info_verbatum(fw, " Interrupt Type: 0x%2.2" PRIx8, spmi->interrupt_type); + fwts_log_info_verbatum(fw, " GPE: 0x%2.2" PRIx8, spmi->gpe); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved2); + fwts_log_info_verbatum(fw, " PCI Device Flag: 0x%2.2" PRIx8, spmi->pci_device_flag); + fwts_log_info_verbatum(fw, " Global System Interrupt 0x%8.8" PRIx32, spmi->global_system_interrupt); + fwts_log_info_verbatum(fw, " Base Address:"); + fwts_log_info_verbatum(fw, " Address Space ID: 0x%2.2" PRIx8, spmi->base_address.address_space_id); + fwts_log_info_verbatum(fw, " Register Bit Width 0x%2.2" PRIx8, spmi->base_address.register_bit_width); + fwts_log_info_verbatum(fw, " Register Bit Offset 0x%2.2" PRIx8, spmi->base_address.register_bit_offset); + fwts_log_info_verbatum(fw, " Access Size 0x%2.2" PRIx8, spmi->base_address.access_width); + fwts_log_info_verbatum(fw, " Address 0x%16.16" PRIx64, spmi->base_address.address); + fwts_log_info_verbatum(fw, " PCI Segment Group: 0x%2.2" PRIx8, spmi->pci_segment_group_number); + fwts_log_info_verbatum(fw, " PCI Bus: 0x%2.2" PRIx8, spmi->pci_bus_number); + fwts_log_info_verbatum(fw, " PCI Device: 0x%2.2" PRIx8, spmi->pci_device_number); + fwts_log_info_verbatum(fw, " PCI Function: 0x%2.2" PRIx8, spmi->pci_function_number); + fwts_log_info_verbatum(fw, " Reserved: 0x%2.2" PRIx8, spmi->reserved3); + fwts_log_nl(fw); + + if (spmi->interface_type < 1 || spmi->interface_type > 4) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInterfaceTypeReserved", + "SPMI Interface Type is 0x%2.2" PRIx8 " which " + "is a reserved type and probably incorrect.", + spmi->interface_type); + } + + if (spmi->reserved1 != 1) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIReserved1Not1", + "SPMI reserved field (offset 37) must be 0x01, got " + "0x%2.2" PRIx8 " instead", spmi->reserved1); + } + + /* Only bottom 2 bits should be set */ + if (spmi->interrupt_type & ~0x03) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIInterruptTypeReservedNonZero", + "SPMI Interrupt Type reserved bits [7:2] must be 0, got " + "0x%2.2" PRIx8 " instead", spmi->interrupt_type); + } + + /* Check for zero GPE on specific condition of interrupt type */ + if (((spmi->interrupt_type & 1) == 0) && + (spmi->gpe != 0)) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIGPENotZero", + "SPMI GPE is 0x%2.2" PRIx8 " and should be 0 if the Interrupt " + "Type bit 0 (SCI triggered through GPE) is set to 0", + spmi->gpe); + } + if (spmi->reserved2 != 0) { + passed = false; + fwts_failed(fw, LOG_LEVEL_LOW, + "SPMIReserved1NonZero", + "SPMI reserved field (offset 42) must be 0x00, got " + "0x%2.2" PRIx8 " instead", spmi->reserved2); + } + /* Only bottom 1 bit should be set */ + if (spmi->pci_device_flag & ~0x01) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIPciDeviceFlag", + "SPMI PCI Device Flag reserved bits [7:1] must be 0, got " + "0x%2.2" PRIx8 " instead", spmi->pci_device_flag); + } + + /* For SSIF interfaces, if device flag [0] is set then PCI semgment group number is zero */ + if ((spmi->interface_type == 0x04) && + (spmi->pci_device_flag & 0x01) && + (spmi->pci_segment_group_number != 0)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIPciSegmentGroupNumber", + "SPMI PCI Segment Group Number should be 0 for SSIF interface " + "types when bit [0] of the PCI Device Flag is set"); + } + + if (((spmi->interrupt_type & 2) == 0) && + (spmi->global_system_interrupt != 0)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIGlobalSystemInterruptNonZero", + "SPMI Global System Interrupt is 0x%" PRIx32 " and " + "should be zero if bit [1] (I/O APIC/SAPIC interrupt) " + "of the Interrupt Type is not set", + spmi->global_system_interrupt); + } + + /* Base address must be one of 3 types, System Memory, System I/O or SMBUS */ + if ((spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY) && + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO) && + (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS)) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIBaseAddressSpaceID", + "SPMI Base Address Space ID is 0x%2.2" PRIx8 " but should be one of " + "0x%2.2" PRIx8 " (System Memory), " + "0x%2.2" PRIx8 " (System I/O) or " + "0x%2.2" PRIx8 " (SMBUS)", + spmi->base_address.address_space_id, + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_MEMORY, + FWTS_GAS_ADDR_SPACE_ID_SYSTEM_IO, + FWTS_GAS_ADDR_SPACE_ID_SMBUS); + } + /* + * For SSIF: The Address_Space_ID is SMBUS and the address field of the GAS + * holds the 7-bit slave address of the BMC on the host SMBus + * in the least significant byte. Note that the slave address is + * stored with the 7-bit slave address in the least significant 7- + * bits of the byte, and the most significant bit of the byte set to + */ + if (spmi->interface_type == 0x04) { + if (spmi->base_address.address_space_id != FWTS_GAS_ADDR_SPACE_ID_SMBUS) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInvalidAddressSpaceIDForSSIF", + "SPMI Base Address Space ID is 0x%2.2" PRIx8 + " but should be 0x%2.2" PRIx8 " (SMBUS) " + " for a SSIF Interface Type", + spmi->base_address.address_space_id, + FWTS_GAS_ADDR_SPACE_ID_SMBUS); + } + if (spmi->base_address.address & ~0x7f) { + passed = false; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "SPMIInvalidBaseAddressForSSIF", + "SPMI Base Address is 0x%16.16" PRIx64 + " but should be 0..127 for a SSIF Interface Type", + spmi->base_address.address); + } + } + /* + * Specification states that PCI device number bits [7:5] + * are reserved if PCI device flag bit [0] is set, however, + * it does not state if they should be zero or 1, so for + * now don't check these + * + * Also, PCI function number bits [7] and [5:3] are + * reserved, again, not sure if these need to be checked + * so ignore these too. + */ +done: + if (passed) + fwts_passed(fw, "No issues found in SPMI table."); + + return FWTS_OK; +} + +static fwts_framework_minor_test spmi_tests[] = { + { spmi_test1, "SPMI Service Processor Management Interface Description Table test." }, + { NULL, NULL } +}; + +static fwts_framework_ops spmi_ops = { + .description = "SPMI Service Processor Management Interface Description Table test.", + .init = spmi_init, + .minor_tests = spmi_tests +}; + +FWTS_REGISTER("spmi", &spmi_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV | FWTS_FLAG_TEST_ACPI)