smbios: add support for dynamic generation of Type 9 system slot tables

This commit introduces support for generating SMBIOS Type 9 (System Slot)
tables using a hybrid approach:

1. Explicit Device Tree definitions:
   Child node under '/smbios/smbios/system-slot' 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 child node under '/smbios/smbios/system-slot' does not exist, the
   implementation will scan the entire device tree for nodes 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 to 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.

Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
Raymond Mao
2026-02-13 17:52:47 -05:00
committed by Tom Rini
parent 87f8a143da
commit 83b28b55d7
5 changed files with 549 additions and 3 deletions

View File

@@ -77,6 +77,9 @@
SMBIOS_CACHE_OP_WB)>;
};
};
system-slot {
};
};
};
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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_ */

View File

@@ -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 },
};