[PATCH v3 2/2] smbios: add support for dynamic generation of Type 9 system slot tables

Ilias Apalodimas ilias.apalodimas at linaro.org
Tue Sep 23 08:48:34 CEST 2025


On Fri, 19 Sept 2025 at 23:56, Raymond Mao <raymond.mao at linaro.org> wrote:
>
> This commit introduces support for generating SMBIOS Type 9 (System Slot)
> tables using a hybrid approach:
>
> 1. Explicit Device Tree definitions:
>    If the 'smbios' node contains a 'system-slot' subnode, its child nodes
>    will be interpreted as individual slot definitions.
>    - Each child represents a slot (e.g., isa, pcmcia, etc.).
>    - Properties follow the SMBIOS specification using lowercase
>      hyphen-separated names such as 'slot-type', 'slot-id',
>      'segment-group-number', 'bus-number', 'slot-information', etc.
>    - This approach allows full customization of each system slot and is
>      especially suitable for platforms with well-defined slot topology.
>
> 2. Automatic detection fallback:
>    If no 'system-slot' subnode is found under the 'smbios' node, the code
>    will scan the entire device tree for any node whose 'device_type'
>    matches known slot-related types ("pci", "isa", "pcmcia", etc.).
>    - When a match is found, default values or heuristics are applied to
>      populate the System Slot table.
>    - This mode is useful for platforms that lack explicit SMBIOS nodes
>      but still expose slot topology via standard DT conventions.
>
> Together, two approaches ensure that SMBIOS Type 9 entries are available
> whether explicitly described or automatically derived.

This overall looks reasonable to me to enable more types in SMBIOS. It
also follows the logic we have on looking for a system-slot first and
then have the DT as a fallbacl.

Can anyone that's more familiar with the DT probing libraries, take a
look at that part?

Thanks
/Ilias
>
> Signed-off-by: Raymond Mao <raymond.mao at linaro.org>
> ---
> Changes in v2:
> - Reuse sysinfo_to_dt and convert_sysinfo_to_dt() for mapping SMBIOS properties to DT.
> Changes in v3:
> - Update subject and commit message.
> - Abstract helper functions and add callback for writing subnodes.
>
>  arch/arm/dts/smbios_generic.dtsi |   3 +
>  cmd/smbios.c                     | 114 ++++++++++++
>  include/smbios.h                 |  45 +++++
>  include/smbios_def.h             |  89 +++++++++
>  lib/smbios.c                     | 301 ++++++++++++++++++++++++++++++-
>  5 files changed, 549 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 ed419f19028..f9b62e66229 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 85508c06547..caeb309294d 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
>   *
> @@ -95,6 +131,10 @@ struct smbios_ctx {
>         char *last_str;
>  };
>
> +typedef int (*smbios_write_subnode)(ulong *current, int handle,
> +                                  struct smbios_ctx *ctx, int idx,
> +                                  int type);
> +
>  /**
>   * Function prototype to write a specific type of SMBIOS structure
>   *
> @@ -222,6 +262,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 +281,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;
>  }
> @@ -859,6 +905,252 @@ static int smbios_write_type7(ulong *current, int *handle,
>         return len;
>  }
>
> +static int smbios_scan_subnodes(ulong *current, struct smbios_ctx *ctx,
> +                               int *handle, smbios_write_subnode cb, int type)
> +{
> +       ofnode child;
> +       int i;
> +       int hdl_base = *handle;
> +       int len = 0;
> +       struct smbios_ctx ctx_bak;
> +
> +       memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
> +
> +       for (i = 0, child = ofnode_first_subnode(ctx->node);
> +            ofnode_valid(child); child = ofnode_next_subnode(child), i++) {
> +               ctx->node = child;
> +               *handle = hdl_base + i;
> +               len += cb(current, *handle, ctx, i, type);
> +               memcpy(ctx, &ctx_bak, sizeof(*ctx));
> +       }
> +
> +       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", &reglen);
> +       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,
> +                                   int __maybe_unused idx, int 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_scan_slot_type(ulong *current, int *handle,
> +                                struct smbios_ctx *ctx)
> +{
> +       int i = 0;
> +       struct smbios_ctx ctx_bak;
> +       ofnode child;
> +       const struct map_sysinfo *prop;
> +       int hdl_base = *handle;
> +       int len = 0;
> +
> +       memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
> +       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;
> +
> +               *handle = hdl_base + i;
> +               ctx->node = child;
> +               len += smbios_write_type9_1slot(current, *handle, ctx, 0,
> +                                               dev_type);
> +               memcpy(ctx, &ctx_bak, sizeof(*ctx));
> +               i++;
> +       }
> +
> +       return len;
> +}
> +
> +static int smbios_write_type9(ulong *current, int *handle,
> +                             struct smbios_ctx *ctx)
> +{
> +       int len;
> +
> +       /* TODO: Get system slot information via pci subsystem */
> +       if (!IS_ENABLED(CONFIG_OF_CONTROL))
> +               return 0;       /* Error, return 0-length */
> +
> +       len = smbios_scan_subnodes(current, ctx, handle,
> +                                  smbios_write_type9_1slot,
> +                                  SMBIOS_SYSSLOT_TYPE_UNKNOWN);
> +       if (len)
> +               return len;
> +
> +       /* if no subnode under 'system-slot', try scan the entire FDT */
> +       len = smbios_scan_slot_type(current, handle, ctx);
> +
> +       return len;
> +}
> +
>  #endif /* #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) */
>
>  static int smbios_write_type32(ulong *current, int *handle,
> @@ -905,6 +1197,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
>


More information about the U-Boot mailing list