Implement SMBIOS Type 9 (System Slot). SMBIOS library will look for a subnode "system-slot" under "smbios" to construct the data of Type 9. [1] is an example for the expected pattern of "system-slot".
If "system-slot" node does not exist, or any of its properties are missing, as a fallback, SMBIOS library will try to get the values by scanning the device tree. SMBIOS Type 9 support is under GENERATE_SMBIOS_TABLE_VERBOSE to avoid increasing rom size for those platforms which only require basic SMBIOS support. [1] Example of a "system-slot" node which contains two slots: system-slot { isa { socket-design = ""; slot-type = <SMBIOS_SYSSLOT_TYPE_ISA>; slot-data-bus-width = <SMBIOS_SYSSLOT_WIDTH_16BIT>; current-usage = <SMBIOS_SYSSLOT_USAGE_NA>; slot-length = <SMBIOS_SYSSLOT_LENG_SHORT>; slot-id = <0>; slot-characteristics-1 = <(SMBIOS_SYSSLOT_CHAR_5V | SMBIOS_SYSSLOT_CHAR_3_3V)>; slot-characteristics-2 = <SMBIOS_SYSSLOT_CHAR_ASYNCRM>; segment-group-number = <0>; bus-number = <0x80>; device-function-number = <0x10>; data-bus-width = <0>; peer-grouping-count = <0>; slot-information = <0>; slot-physical-width = <0>; slot-characteristics-1 = <(SMBIOS_SYSSLOT_CHAR_5V | SMBIOS_SYSSLOT_CHAR_3_3V)>; slot-characteristics-2 = <SMBIOS_SYSSLOT_CHAR_ASYNCRM>; segment-group-number = <0>; bus-number = <0x80>; device-function-number = <0x10>; data-bus-width = <0>; peer-grouping-count = <0>; slot-information = <0>; slot-physical-width = <0>; slot-pitch = <0>; slot-height = <0>; }; pcmcia { socket-design = ""; slot-type = <SMBIOS_SYSSLOT_TYPE_PCMCIA>; slot-data-bus-width = <SMBIOS_SYSSLOT_WIDTH_32BIT>; current-usage = <SMBIOS_SYSSLOT_USAGE_AVAILABLE>; slot-length = <SMBIOS_SYSSLOT_LENG_SHORT>; slot-id = <1>; slot-characteristics-1 = <(SMBIOS_SYSSLOT_CHAR_5V | SMBIOS_SYSSLOT_CHAR_3_3V)>; slot-characteristics-2 = <SMBIOS_SYSSLOT_CHAR_ASYNCRM>; segment-group-number = <1>; bus-number = <0xa0>; device-function-number = <0x40>; data-bus-width = <0>; peer-grouping-count = <0>; slot-information = <0>; slot-physical-width = <0>; slot-pitch = <0>; slot-height = <0>; }; }; Signed-off-by: Raymond Mao <raymond....@linaro.org> --- Changes in v2: - Reuse sysinfo_to_dt and convert_sysinfo_to_dt() for mapping SMBIOS properties to DT. arch/arm/dts/smbios_generic.dtsi | 3 + cmd/smbios.c | 114 +++++++++++++ include/smbios.h | 45 ++++++ include/smbios_def.h | 89 +++++++++++ lib/smbios.c | 267 ++++++++++++++++++++++++++++++- 5 files changed, 515 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/smbios_generic.dtsi b/arch/arm/dts/smbios_generic.dtsi index fc168317c9e..4463dade217 100644 --- a/arch/arm/dts/smbios_generic.dtsi +++ b/arch/arm/dts/smbios_generic.dtsi @@ -77,6 +77,9 @@ SMBIOS_CACHE_OP_WB)>; }; }; + + system-slot { + }; }; }; }; diff --git a/cmd/smbios.c b/cmd/smbios.c index 562dd7959be..127e89ca914 100644 --- a/cmd/smbios.c +++ b/cmd/smbios.c @@ -119,6 +119,55 @@ static const struct str_lookup_table associativity_strings[] = { }; +static const struct str_lookup_table slot_type_strings[] = { + { SMBIOS_SYSSLOT_TYPE_OTHER, "Other" }, + { SMBIOS_SYSSLOT_TYPE_UNKNOWN, "Unknown" }, + { SMBIOS_SYSSLOT_TYPE_ISA, "ISA" }, + { SMBIOS_SYSSLOT_TYPE_PCI, "PCI" }, + { SMBIOS_SYSSLOT_TYPE_PCMCIA, "PC Card (PCMCIA)" }, + { SMBIOS_SYSSLOT_TYPE_PCIE, "PCI Express" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN2, "PCI Express Gen 2" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN3, "PCI Express Gen 3" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN3X16, "PCI Express Gen 3 x16" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN4, "PCI Express Gen 4" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN4X8, "PCI Express Gen 4 x8" }, + { SMBIOS_SYSSLOT_TYPE_PCIEGEN4X16, "PCI Express Gen 4 x16" }, +}; + +static const struct str_lookup_table slot_bus_width_strings[] = { + { SMBIOS_SYSSLOT_WIDTH_OTHER, "Other" }, + { SMBIOS_SYSSLOT_WIDTH_UNKNOWN, "Unknown" }, + { SMBIOS_SYSSLOT_WIDTH_8BIT, "8 bit" }, + { SMBIOS_SYSSLOT_WIDTH_16BIT, "16 bit" }, + { SMBIOS_SYSSLOT_WIDTH_32BIT, "32 bit" }, + { SMBIOS_SYSSLOT_WIDTH_64BIT, "64 bit" }, + { SMBIOS_SYSSLOT_WIDTH_128BIT, "128 bit " }, + { SMBIOS_SYSSLOT_WIDTH_1X, "1x or x1" }, + { SMBIOS_SYSSLOT_WIDTH_2X, "2x or x2" }, + { SMBIOS_SYSSLOT_WIDTH_4X, "4x or x4" }, + { SMBIOS_SYSSLOT_WIDTH_8X, "8x or x8" }, + { SMBIOS_SYSSLOT_WIDTH_12X, "12x or x12" }, + { SMBIOS_SYSSLOT_WIDTH_16X, "16x or x16" }, + { SMBIOS_SYSSLOT_WIDTH_32X, "32x or x32" }, +}; + +static const struct str_lookup_table slot_usage_strings[] = { + { SMBIOS_SYSSLOT_USAGE_OTHER, "Other" }, + { SMBIOS_SYSSLOT_USAGE_UNKNOWN, "Unknown" }, + { SMBIOS_SYSSLOT_USAGE_AVAILABLE, "Available" }, + { SMBIOS_SYSSLOT_USAGE_INUSE, "In use" }, + { SMBIOS_SYSSLOT_USAGE_NA, "Unavailable" }, +}; + +static const struct str_lookup_table slot_length_strings[] = { + { SMBIOS_SYSSLOT_LENG_OTHER, "Other" }, + { SMBIOS_SYSSLOT_LENG_UNKNOWN, "Unknown" }, + { SMBIOS_SYSSLOT_LENG_SHORT, "Short Length" }, + { SMBIOS_SYSSLOT_LENG_LONG, "Long Length" }, + { SMBIOS_SYSSLOT_LENG_2_5INDRV, "2.5 inch drive form factor" }, + { SMBIOS_SYSSLOT_LENG_3_5INDRV, "3.5 inch drive form factor" }, +}; + /** * smbios_get_string() - get SMBIOS string from table * @@ -403,6 +452,68 @@ static void smbios_print_type7(struct smbios_type7 *table) printf("\tInstalled Cache Size 2: 0x%08x\n", table->inst_size2.data); } +static void smbios_print_type9(struct smbios_type9 *table) +{ + int i; + u8 *addr = (u8 *)table + + offsetof(struct smbios_type9, slot_information); + + printf("System Slots:\n"); + smbios_print_str("Socket Designation", table, + table->socket_design); + smbios_print_lookup_str(slot_type_strings, + table->slot_type, + ARRAY_SIZE(slot_type_strings), + "Slot Type"); + smbios_print_lookup_str(slot_bus_width_strings, + table->slot_data_bus_width, + ARRAY_SIZE(slot_bus_width_strings), + "Slot Data Bus Width"); + smbios_print_lookup_str(slot_usage_strings, + table->current_usage, + ARRAY_SIZE(slot_usage_strings), + "Current Usage"); + smbios_print_lookup_str(slot_length_strings, + table->slot_length, + ARRAY_SIZE(slot_length_strings), + "Slot Length"); + printf("\tSlot ID: 0x%04x\n", table->slot_id); + printf("\tSlot Characteristics 1: 0x%04x\n", + table->slot_characteristics_1); + printf("\tSlot Characteristics 2: 0x%04x\n", + table->slot_characteristics_2); + printf("\tSegment Group Number (Base): 0x%04x\n", + table->segment_group_number); + printf("\tBus Number (Base): 0x%04x\n", table->bus_number); + printf("\tDevice/Function Number (Base): 0x%04x\n", + table->device_function_number.data); + printf("\tData Bus Width (Base): 0x%04x\n", + table->electrical_bus_width); + printf("\tPeer (S/B/D/F/Width) grouping count: 0x%04x\n", + table->peer_grouping_count); + printf("\tPeer (S/B/D/F/Width) groups:\n"); + for (i = 0; i < table->peer_grouping_count; i++) { + printf("\t\tPeer group[%03d]:\n", i); + if (CONFIG_IS_ENABLED(HEXDUMP)) + print_hex_dump("\t\t", DUMP_PREFIX_OFFSET, 16, 1, addr, + SMBIOS_TYPE9_PGROUP_SIZE, false); + addr += SMBIOS_TYPE9_PGROUP_SIZE; + } + printf("\n"); + + /* table->slot_information */ + printf("\tSlot Information: 0x%04x\n", *addr); + /* table->slot_physical_width */ + addr += sizeof(table->slot_information); + printf("\tSlot Physical Width: 0x%04x\n", *addr); + /* table->slot_pitch */ + addr += sizeof(table->slot_physical_width); + printf("\tSlot Pitch: 0x%04x\n", *(u16 *)addr); + /* table->slot_height */ + addr += sizeof(table->slot_pitch); + printf("\tSlot Height: 0x%04x\n", *addr); +} + static void smbios_print_type127(struct smbios_type127 *table) { printf("End Of Table\n"); @@ -482,6 +593,9 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc, case SMBIOS_CACHE_INFORMATION: smbios_print_type7((struct smbios_type7 *)pos); break; + case SMBIOS_SYSTEM_SLOTS: + smbios_print_type9((struct smbios_type9 *)pos); + break; case SMBIOS_END_OF_TABLE: smbios_print_type127((struct smbios_type127 *)pos); break; diff --git a/include/smbios.h b/include/smbios.h index b5fed57aba2..d885285ea41 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -264,6 +264,51 @@ struct __packed smbios_type7 { char eos[SMBIOS_STRUCT_EOS_BYTES]; }; +#define SMBIOS_TYPE9_PGROUP_SIZE 5 + +struct pci_attr_lookup_table { + const char *str; + u8 slot_type; + u8 data_bus_width; + u8 slot_length; + u8 chara1; + u8 chara2; +}; + +union dev_func_num { + struct { + u8 dev_num:5; + u8 func_num:3; + } fields; + u8 data; +}; + +struct __packed smbios_type9 { + struct smbios_header hdr; + u8 socket_design; + u8 slot_type; + u8 slot_data_bus_width; + u8 current_usage; + u8 slot_length; + u16 slot_id; + u8 slot_characteristics_1; + u8 slot_characteristics_2; + u16 segment_group_number; + u8 bus_number; + union dev_func_num device_function_number; + u8 electrical_bus_width; + u8 peer_grouping_count; + /* + * Dynamic bytes will be inserted here to store peer_groups. + * length is equal to 'peer_grouping_count' * 5 + */ + u8 slot_information; + u8 slot_physical_width; + u16 slot_pitch; + u8 slot_height; + char eos[SMBIOS_STRUCT_EOS_BYTES]; +}; + struct __packed smbios_type32 { u8 type; u8 length; diff --git a/include/smbios_def.h b/include/smbios_def.h index 81c5781217f..ef9cb02ed25 100644 --- a/include/smbios_def.h +++ b/include/smbios_def.h @@ -191,4 +191,93 @@ #define SMBIOS_CACHE_ASSOC_64WAY 13 #define SMBIOS_CACHE_ASSOC_20WAY 14 +/* + * System Slot + */ + +/* Slot Type */ +#define SMBIOS_SYSSLOT_TYPE_OTHER 1 +#define SMBIOS_SYSSLOT_TYPE_UNKNOWN 2 +#define SMBIOS_SYSSLOT_TYPE_ISA 3 /* ISA */ +#define SMBIOS_SYSSLOT_TYPE_PCI 6 /* PCI */ +#define SMBIOS_SYSSLOT_TYPE_PCMCIA 7 /* PCMCIA */ +#define SMBIOS_SYSSLOT_TYPE_PCIE 0xa5 /* PCI Express */ +#define SMBIOS_SYSSLOT_TYPE_PCIEX1 0xa6 /* PCI Express x1 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEX2 0xa7 /* PCI Express x2 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEX4 0xa8 /* PCI Express x4 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEX8 0xa9 /* PCI Express x8 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEX16 0xaa /* PCI Express x16 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2 0xab /* PCI Express Gen 2 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2X1 0xac /* PCI Express Gen 2 x1 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2X2 0xad /* PCI Express Gen 2 x2 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2X4 0xae /* PCI Express Gen 2 x4 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2X8 0xaf /* PCI Express Gen 2 x8 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN2X16 0xb0 /* PCI Express Gen 2 x16 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3 0xb1 /* PCI Express Gen 3 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3X1 0xb2 /* PCI Express Gen 3 x1 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3X2 0xb3 /* PCI Express Gen 3 x2 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3X4 0xb4 /* PCI Express Gen 3 x4 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3X8 0xb5 /* PCI Express Gen 3 x8 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN3X16 0xb6 /* PCI Express Gen 3 x16 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4 0xb8 /* PCI Express Gen 4 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4X1 0xb9 /* PCI Express Gen 4 x1 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4X2 0xba /* PCI Express Gen 4 x2 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4X4 0xbb /* PCI Express Gen 4 x4 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4X8 0xbc /* PCI Express Gen 4 x8 */ +#define SMBIOS_SYSSLOT_TYPE_PCIEGEN4X16 0xbd /* PCI Express Gen 4 x16 */ + +/* Slot Data Bus Width */ +#define SMBIOS_SYSSLOT_WIDTH_OTHER 1 +#define SMBIOS_SYSSLOT_WIDTH_UNKNOWN 2 +#define SMBIOS_SYSSLOT_WIDTH_8BIT 3 +#define SMBIOS_SYSSLOT_WIDTH_16BIT 4 +#define SMBIOS_SYSSLOT_WIDTH_32BIT 5 +#define SMBIOS_SYSSLOT_WIDTH_64BIT 6 +#define SMBIOS_SYSSLOT_WIDTH_128BIT 7 +#define SMBIOS_SYSSLOT_WIDTH_1X 8 +#define SMBIOS_SYSSLOT_WIDTH_2X 9 +#define SMBIOS_SYSSLOT_WIDTH_4X 10 +#define SMBIOS_SYSSLOT_WIDTH_8X 11 +#define SMBIOS_SYSSLOT_WIDTH_12X 12 +#define SMBIOS_SYSSLOT_WIDTH_16X 13 +#define SMBIOS_SYSSLOT_WIDTH_32X 14 + +/* Current Usage */ +#define SMBIOS_SYSSLOT_USAGE_OTHER 1 +#define SMBIOS_SYSSLOT_USAGE_UNKNOWN 2 +#define SMBIOS_SYSSLOT_USAGE_AVAILABLE 3 +#define SMBIOS_SYSSLOT_USAGE_INUSE 4 +#define SMBIOS_SYSSLOT_USAGE_NA 5 + +/* Slot Length */ +#define SMBIOS_SYSSLOT_LENG_OTHER 1 +#define SMBIOS_SYSSLOT_LENG_UNKNOWN 2 +#define SMBIOS_SYSSLOT_LENG_SHORT 3 +#define SMBIOS_SYSSLOT_LENG_LONG 4 +#define SMBIOS_SYSSLOT_LENG_2_5INDRV 5 +#define SMBIOS_SYSSLOT_LENG_3_5INDRV 6 + +/* Slot Characteristics 1 */ +#define SMBIOS_SYSSLOT_CHAR_UND 1 /* BIT(0) */ +#define SMBIOS_SYSSLOT_CHAR_5V 2 /* BIT(1) */ +#define SMBIOS_SYSSLOT_CHAR_3_3V 4 /* BIT(2) */ +#define SMBIOS_SYSSLOT_CHAR_SHARED 8 /* BIT(3) */ +#define SMBIOS_SYSSLOT_CHAR_PCCARD16 16 /* BIT(4) */ +#define SMBIOS_SYSSLOT_CHAR_PCCARDBUS 32 /* BIT(5) */ +#define SMBIOS_SYSSLOT_CHAR_PCCARDZV 64 /* BIT(6) */ +#define SMBIOS_SYSSLOT_CHAR_PCCARDMRR 0x80 /* BIT(7) */ + +/* Slot Characteristics 2 */ +#define SMBIOS_SYSSLOT_CHAR_PCIPME 1 /* BIT(0) */ +#define SMBIOS_SYSSLOT_CHAR_HOTPLUG 2 /* BIT(1) */ +#define SMBIOS_SYSSLOT_CHAR_PCISMB 4 /* BIT(2) */ +#define SMBIOS_SYSSLOT_CHAR_PCIBIF 8 /* BIT(3) */ +#define SMBIOS_SYSSLOT_CHAR_ASYNCRM 16 /* BIT(4) */ +#define SMBIOS_SYSSLOT_CHAR_FBCXL1 32 /* BIT(5) */ +#define SMBIOS_SYSSLOT_CHAR_FBCXL2 64 /* BIT(6) */ +#define SMBIOS_SYSSLOT_CHAR_FBCXL3 0x80 /* BIT(7) */ + +/* Slot segment group number */ +#define SMBIOS_SYSSLOT_SGGNUM_UND 0 + #endif /* _SMBIOS_DEF_H_ */ diff --git a/lib/smbios.c b/lib/smbios.c index 7c9701a57f9..55350d00067 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -66,11 +66,47 @@ struct map_sysinfo { static const struct map_sysinfo sysinfo_to_dt[] = { { .si_node = "system", .si_str = "product", .dt_str = "model", 2 }, - { .si_node = "system", .si_str = "manufacturer", .dt_str = "compatible", 1 }, - { .si_node = "baseboard", .si_str = "product", .dt_str = "model", 2 }, - { .si_node = "baseboard", .si_str = "manufacturer", .dt_str = "compatible", 1 }, + { .si_node = "system", .si_str = "manufacturer", + .dt_str = "compatible", 1 }, + { .si_node = "baseboard", .si_str = "product", + .dt_str = "model", 2 }, + { .si_node = "baseboard", .si_str = "manufacturer", + .dt_str = "compatible", 1 }, + { .si_node = "system-slot", .si_str = "slot-type", + .dt_str = "device_type", 0}, + { .si_node = "system-slot", .si_str = "segment-group-number", + .dt_str = "linux,pci-domain", 0}, }; +#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) +static const struct pci_attr_lookup_table pci_attr[] = { + { "pci-host-ecam-generic", SMBIOS_SYSSLOT_TYPE_PCIE, + SMBIOS_SYSSLOT_WIDTH_8X, SMBIOS_SYSSLOT_LENG_LONG, + SMBIOS_SYSSLOT_CHAR_3_3V, SMBIOS_SYSSLOT_CHAR_PCIPME }, + { "pci-host-cam-generic", SMBIOS_SYSSLOT_TYPE_PCI, + SMBIOS_SYSSLOT_WIDTH_32BIT, SMBIOS_SYSSLOT_LENG_SHORT, + SMBIOS_SYSSLOT_CHAR_5V | SMBIOS_SYSSLOT_CHAR_3_3V, + SMBIOS_SYSSLOT_CHAR_PCIPME }, + { "pci-host-thunder-ecam", SMBIOS_SYSSLOT_TYPE_PCIEGEN3, + SMBIOS_SYSSLOT_WIDTH_8X, SMBIOS_SYSSLOT_LENG_LONG, + SMBIOS_SYSSLOT_CHAR_3_3V, + SMBIOS_SYSSLOT_CHAR_PCIPME | SMBIOS_SYSSLOT_CHAR_HOTPLUG }, + { "pci-host-octeontx-ecam", SMBIOS_SYSSLOT_TYPE_PCIEGEN3X16, + SMBIOS_SYSSLOT_WIDTH_16X, SMBIOS_SYSSLOT_LENG_LONG, + SMBIOS_SYSSLOT_CHAR_3_3V, + SMBIOS_SYSSLOT_CHAR_PCIPME | SMBIOS_SYSSLOT_CHAR_HOTPLUG }, + { "pci-host-thunder-pem", SMBIOS_SYSSLOT_TYPE_PCIEGEN4X8, + SMBIOS_SYSSLOT_WIDTH_8X, SMBIOS_SYSSLOT_LENG_LONG, + SMBIOS_SYSSLOT_CHAR_3_3V, + SMBIOS_SYSSLOT_CHAR_PCIPME | SMBIOS_SYSSLOT_CHAR_HOTPLUG }, + { "pci-host-octeontx2-pem", SMBIOS_SYSSLOT_TYPE_PCIEGEN4X16, + SMBIOS_SYSSLOT_WIDTH_16X, SMBIOS_SYSSLOT_LENG_LONG, + SMBIOS_SYSSLOT_CHAR_3_3V, + SMBIOS_SYSSLOT_CHAR_PCIPME | SMBIOS_SYSSLOT_CHAR_HOTPLUG | + SMBIOS_SYSSLOT_CHAR_PCIBIF }, +}; +#endif + /** * struct smbios_ctx - context for writing SMBIOS tables * @@ -222,6 +258,7 @@ static int smbios_get_val_si(struct smbios_ctx * __maybe_unused ctx, { #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) int val; + const struct map_sysinfo *nprop; if (!ctx->dev) return val_def; @@ -240,6 +277,11 @@ static int smbios_get_val_si(struct smbios_ctx * __maybe_unused ctx, */ if (!ofnode_read_u32(ofnode_root(), prop, &val)) return val; + + /* If the node is still missing, try with the mapping values */ + nprop = convert_sysinfo_to_dt(ctx->subnode_name, prop); + if (!ofnode_read_u32(ofnode_root(), nprop->dt_str, &val)) + return val; #endif return val_def; } @@ -856,6 +898,222 @@ static int smbios_write_type7(ulong *current, int handle, return len; } +static void smbios_lookup_pci_attr(struct smbios_ctx *ctx, + struct smbios_type9 *t) +{ + const char *compatible; + u32 addr_cells, size_cells, total_cells; + const fdt32_t *reg; + int reglen; + int i; + + /* default attributes */ + t->slot_type = SMBIOS_SYSSLOT_TYPE_PCI; + t->slot_data_bus_width = SMBIOS_SYSSLOT_WIDTH_UNKNOWN; + t->slot_characteristics_1 = SMBIOS_SYSSLOT_CHAR_UND; + t->current_usage = SMBIOS_SYSSLOT_USAGE_UNKNOWN; + t->slot_length = SMBIOS_SYSSLOT_LENG_UNKNOWN; + t->segment_group_number = smbios_get_val_si(ctx, "segment-group-number", + SYSID_NONE, + SMBIOS_SYSSLOT_SGGNUM_UND); + + /* + * Get #address-cells and #size-cells dynamically + * Default 3 for #address-cells and 2 for #size-cells + */ + addr_cells = ofnode_read_u32_default(ctx->node, "#address-cells", 3); + size_cells = ofnode_read_u32_default(ctx->node, "#size-cells", 2); + total_cells = addr_cells + size_cells; + + /* Read property 'reg' from the node */ + reg = ofnode_read_prop(ctx->node, "reg", ®len); + if (reg && reglen > addr_cells * sizeof(*reg)) { + /* First address-cell: Bus Number */ + if (addr_cells >= 1) + t->bus_number = fdt32_to_cpu(reg[0]); + /* Second address-cell: Device/Function */ + if (addr_cells >= 2) + t->device_function_number.data = fdt32_to_cpu(reg[1]); + /* + * Third address-cell 'Register Offset' and the following + * size-cell bytes are not useful for SMBIOS type 9, just + * ignore them. + */ + /* + * As neither PCI IRQ Routing Table ($PIRQ) nor FDT + * property to represent a Slot ID, try to derive a + * Slot ID programmatically. + */ + t->slot_id = t->device_function_number.fields.dev_num | + (t->bus_number << 5); + } + + /* Read 'compatible' property */ + compatible = ofnode_read_string(ctx->node, "compatible"); + if (!compatible) + return; + + for (i = 0; i < ARRAY_SIZE(pci_attr); i++) { + if (strstr(compatible, pci_attr[i].str)) { + t->slot_type = pci_attr[i].slot_type; + t->slot_data_bus_width = pci_attr[i].data_bus_width; + t->slot_length = pci_attr[i].slot_length; + t->slot_characteristics_1 = pci_attr[i].chara1; + t->slot_characteristics_2 = pci_attr[i].chara2; + /* mark it as in-use arbitrarily */ + t->current_usage = SMBIOS_SYSSLOT_USAGE_INUSE; + return; + } + } +} + +static void smbios_write_type9_fields(struct smbios_ctx *ctx, + struct smbios_type9 *t) +{ + t->slot_type = smbios_get_val_si(ctx, "slot-type", SYSID_NONE, + SMBIOS_SYSSLOT_TYPE_UNKNOWN); + t->slot_data_bus_width = + smbios_get_val_si(ctx, "data-bus-width", + SYSID_NONE, SMBIOS_SYSSLOT_WIDTH_UNKNOWN); + t->current_usage = smbios_get_val_si(ctx, "current-usage", SYSID_NONE, + SMBIOS_SYSSLOT_USAGE_UNKNOWN); + t->slot_length = smbios_get_val_si(ctx, "slot-length", SYSID_NONE, + SMBIOS_SYSSLOT_LENG_UNKNOWN); + t->slot_id = smbios_get_val_si(ctx, "slot-id", SYSID_NONE, 0); + t->slot_characteristics_1 = + smbios_get_val_si(ctx, "slot-characteristics-1", SYSID_NONE, + SMBIOS_SYSSLOT_CHAR_UND); + t->slot_characteristics_2 = smbios_get_val_si(ctx, + "slot-characteristics-2", + SYSID_NONE, 0); + t->segment_group_number = smbios_get_val_si(ctx, "segment-group-number", + SYSID_NONE, 0); + t->bus_number = smbios_get_val_si(ctx, "bus-number", SYSID_NONE, 0); + t->device_function_number.data = + smbios_get_val_si(ctx, "device-function-number", SYSID_NONE, 0); +} + +static int smbios_write_type9_1slot(ulong *current, int handle, + struct smbios_ctx *ctx, u8 devtype) +{ + struct smbios_type9 *t; + int len = sizeof(*t); + u8 pgroups_cnt; + u8 *eos_addr; + size_t pgroups_size; + void *wp; + + pgroups_cnt = smbios_get_val_si(ctx, "peer-grouping-count", + SYSID_NONE, 0); + pgroups_size = pgroups_cnt * SMBIOS_TYPE9_PGROUP_SIZE; + + /* + * reserve the space for the dynamic bytes of peer_groups. + * TODO: + * peer_groups = <peer_grouping_count> * SMBIOS_TYPE9_PGROUP_SIZE + */ + len += pgroups_size; + + t = map_sysmem(*current, len); + memset(t, 0, len); + + fill_smbios_header(t, SMBIOS_SYSTEM_SLOTS, len, handle); + + /* eos is at the end of the structure */ + eos_addr = (u8 *)t + len - sizeof(t->eos); + smbios_set_eos(ctx, eos_addr); + + /* Write the general fields */ + t->peer_grouping_count = pgroups_cnt; + t->socket_design = smbios_add_prop_si(ctx, "socket-design", SYSID_NONE, + NULL); + t->electrical_bus_width = smbios_get_val_si(ctx, "data-bus-width", + SYSID_NONE, 0); + + /* skip the reserved peer groups and write the following fields from eos */ + /* t->slot_height */ + wp = eos_addr - sizeof(t->slot_height); + *((u8 *)wp) = smbios_get_val_si(ctx, "slot-height", SYSID_NONE, 0); + /* t->slot_pitch */ + wp -= sizeof(t->slot_pitch); + *((u16 *)wp) = smbios_get_val_si(ctx, "slot-pitch", SYSID_NONE, 0); + /* t->slot_physical_width */ + wp -= sizeof(t->slot_physical_width); + *((u8 *)wp) = smbios_get_val_si(ctx, "slot-physical-width", SYSID_NONE, 0); + /* t->slot_information */ + wp -= sizeof(t->slot_information); + *((u8 *)wp) = smbios_get_val_si(ctx, "slot-information", SYSID_NONE, 0); + + /* For PCI, some fields can be extracted from FDT node */ + if (devtype == SMBIOS_SYSSLOT_TYPE_PCI) + /* Populate PCI attributes from existing PCI properties */ + smbios_lookup_pci_attr(ctx, t); + else if (devtype == SMBIOS_SYSSLOT_TYPE_UNKNOWN) { + /* Properties that expected in smbios subnode 'system-slot' */ + smbios_write_type9_fields(ctx, t); + } + len = t->hdr.length + smbios_string_table_len(ctx); + *current += len; + unmap_sysmem(t); + + return len; +} + +static int smbios_write_type9(ulong *current, int handle, + struct smbios_ctx *ctx) +{ + int len = 0; + struct smbios_ctx ctx_bak; + ofnode child; + const struct map_sysinfo *prop; + + /* TODO: Get system slot information via pci subsystem */ + if (!IS_ENABLED(CONFIG_OF_CONTROL)) + return 0; /* Error, return 0-length */ + + memcpy(&ctx_bak, ctx, sizeof(ctx_bak)); + + /* write the properties if any subnode exists under 'system-slot' */ + for (child = ofnode_first_subnode(ctx->node); ofnode_valid(child); + child = ofnode_next_subnode(child)) { + ctx->node = child; + len += smbios_write_type9_1slot(current, handle++, ctx, + SMBIOS_SYSSLOT_TYPE_UNKNOWN); + memcpy(ctx, &ctx_bak, sizeof(*ctx)); + } + + if (len) + return len; + + /* if no subnode of 'system-slot', try scan the entire FDT */ + prop = convert_sysinfo_to_dt(ctx->subnode_name, "slot-type"); + for (child = ofnode_first_subnode(ofnode_root()); ofnode_valid(child); + child = ofnode_next_subnode(child)) { + const char *dev_type_str; + u8 dev_type = SMBIOS_SYSSLOT_TYPE_UNKNOWN; + + dev_type_str = ofnode_read_string(child, prop->dt_str); + if (!dev_type_str) + continue; + + if (!strcmp(dev_type_str, "pci")) + dev_type = SMBIOS_SYSSLOT_TYPE_PCI; + else if (!strcmp(dev_type_str, "isa")) + dev_type = SMBIOS_SYSSLOT_TYPE_ISA; + else if (!strcmp(dev_type_str, "pcmcia")) + dev_type = SMBIOS_SYSSLOT_TYPE_PCMCIA; + else + continue; + + ctx->node = child; + len += smbios_write_type9_1slot(current, handle++, ctx, + dev_type); + memcpy(ctx, &ctx_bak, sizeof(*ctx)); + } + + return len; +} + #endif /* #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) */ static int smbios_write_type32(ulong *current, int handle, @@ -902,6 +1160,9 @@ static struct smbios_write_method smbios_write_funcs[] = { { smbios_write_type7, "cache", }, #endif { smbios_write_type4, "processor"}, +#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) + { smbios_write_type9, "system-slot"}, +#endif { smbios_write_type32, }, { smbios_write_type127 }, }; -- 2.25.1