public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling
@ 2026-02-13 22:52 Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 1/6] smbios: Fix duplicated smbios handles Raymond Mao
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Raymond Mao, Tom Rini, Mark Kettenis,
	Heinrich Schuchardt, Ilias Apalodimas, Baocheng Su, Li Hua Qian,
	Jan Kiszka, Samuel Holland

From: Raymond Mao <raymond.mao@riscstar.com>

This series finish the last missing puzzle of required SMBIOS types by:
1) Fixing duplicated handles when multiple instances exist in one type;
2) Implementing the rest of required types 9/16/17/19;
3) Adding version control when printing properties for all types.

Type 9/16/17/19 are generally DT-based, the idea is to write these tables
using a hybrid approach:
Explicit DT definitions under existing '/smbios/smbios' take precedence,
with fallback to scan and interpret values from the entire DT.

Moreover, all below APIs:
smbios_get_val_si()
smbios_get_u64_si()
smbios_add_prop_si()
are on top of sysinfo, thus allow vendors to get values from other
subsystems by implementing their own sysinfo driver if needed.

Raymond Mao (6):
  smbios: Fix duplicated smbios handles
  smbios: add support for dynamic generation of Type 9 system slot
    tables
  smbios: add support for dynamic generation of Type 16 table
  smbios: add support for dynamic generation of Type 17 table
  smbios: add support for dynamic generation of Type 19 table
  smbios: print the properties only when they exist in a specified
    version of spec

 arch/arm/dts/smbios_generic.dtsi |   12 +
 cmd/smbios.c                     |  365 +++++++++-
 drivers/sysinfo/smbios.c         |    5 +
 include/smbios.h                 |  151 ++++
 include/smbios_def.h             |  250 +++++++
 include/sysinfo.h                |    4 +
 lib/smbios.c                     | 1151 +++++++++++++++++++++++++++++-
 7 files changed, 1905 insertions(+), 33 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v6 1/6] smbios: Fix duplicated smbios handles
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 2/6] smbios: add support for dynamic generation of Type 9 system slot tables Raymond Mao
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Ilias Apalodimas, Tom Rini, Heinrich Schuchardt,
	Mark Kettenis, Baocheng Su, Jan Kiszka, Li Hua Qian,
	Samuel Holland

Some smbios types can have multiple instances (e.g. Type 7, 9, 16, 17,
19), thus the 'handle' argument should be a pointer so that the value
can be accumulated when writing all the instances.
This also fix the observed duplicated Type 7 handles.

Fixes: bcf456dd369e ("smbios: add detailed smbios information")
Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes in v3:
- Initial patch.
Changes in v4:
- None.
Changes in v5:
- None.
Changes in v6:
- None.

 lib/smbios.c | 42 +++++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/lib/smbios.c b/lib/smbios.c
index b8c2846277a..85508c06547 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -103,7 +103,7 @@ struct smbios_ctx {
  * @ctx:	context for writing the tables
  * Return:	size of the structure
  */
-typedef int (*smbios_write_type)(ulong *addr, int handle,
+typedef int (*smbios_write_type)(ulong *addr, int *handle,
 				 struct smbios_ctx *ctx);
 
 /**
@@ -364,7 +364,7 @@ static int smbios_string_table_len(const struct smbios_ctx *ctx)
 	return (ctx->next_ptr + 1) - ctx->eos;
 }
 
-static int smbios_write_type0(ulong *current, int handle,
+static int smbios_write_type0(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	struct smbios_type0 *t;
@@ -372,7 +372,7 @@ static int smbios_write_type0(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle);
+	fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, *handle);
 	smbios_set_eos(ctx, t->eos);
 	t->vendor = smbios_add_prop_si(ctx, NULL, SYSID_SM_BIOS_VENDOR,
 				       "U-Boot");
@@ -423,7 +423,7 @@ static int smbios_write_type0(ulong *current, int handle,
 	return len;
 }
 
-static int smbios_write_type1(ulong *current, int handle,
+static int smbios_write_type1(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	struct smbios_type1 *t;
@@ -434,7 +434,7 @@ static int smbios_write_type1(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
+	fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, *handle);
 	smbios_set_eos(ctx, t->eos);
 
 	t->manufacturer = smbios_add_prop_si(ctx, "manufacturer",
@@ -471,7 +471,7 @@ static int smbios_write_type1(ulong *current, int handle,
 	return len;
 }
 
-static int smbios_write_type2(ulong *current, int handle,
+static int smbios_write_type2(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	struct smbios_type2 *t;
@@ -485,7 +485,7 @@ static int smbios_write_type2(ulong *current, int handle,
 	 */
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
+	fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, *handle);
 
 	/* eos is at the end of the structure */
 	eos_addr = (u8 *)t + len - sizeof(t->eos);
@@ -519,7 +519,7 @@ static int smbios_write_type2(ulong *current, int handle,
 	 * t->number_contained_objects = <obj_handle_num>;
 	 */
 
-	t->chassis_handle = handle + 1;
+	t->chassis_handle = *handle + 1;
 
 	len = t->hdr.length + smbios_string_table_len(ctx);
 	*current += len;
@@ -528,7 +528,7 @@ static int smbios_write_type2(ulong *current, int handle,
 	return len;
 }
 
-static int smbios_write_type3(ulong *current, int handle,
+static int smbios_write_type3(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	struct smbios_type3 *t;
@@ -548,7 +548,7 @@ static int smbios_write_type3(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle);
+	fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, *handle);
 #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE)
 	elem_addr = (u8 *)t + offsetof(struct smbios_type3, sku_number);
 	sku_num_addr = elem_addr + elem_size;
@@ -669,7 +669,7 @@ static void smbios_write_type4_dm(struct smbios_type4 *t,
 #endif
 }
 
-static int smbios_write_type4(ulong *current, int handle,
+static int smbios_write_type4(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	struct smbios_type4 *t;
@@ -679,7 +679,7 @@ static int smbios_write_type4(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle);
+	fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, *handle);
 	smbios_set_eos(ctx, t->eos);
 	t->socket_design = smbios_add_prop_si(ctx, "socket-design",
 					      SYSID_SM_PROCESSOR_SOCKET, NULL);
@@ -828,13 +828,14 @@ static int smbios_write_type7_1level(ulong *current, int handle,
 	return len;
 }
 
-static int smbios_write_type7(ulong *current, int handle,
+static int smbios_write_type7(ulong *current, int *handle,
 			      struct smbios_ctx *ctx)
 {
 	int len = 0;
 	int i, level;
 	ofnode parent = ctx->node;
 	struct smbios_ctx ctx_bak;
+	int hdl_base = *handle;
 
 	memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
 
@@ -850,15 +851,17 @@ static int smbios_write_type7(ulong *current, int handle,
 			return 0;
 		ctx->subnode_name = buf;
 		ctx->node = ofnode_find_subnode(parent, ctx->subnode_name);
-		len += smbios_write_type7_1level(current, handle++, ctx, i);
+		*handle = hdl_base + i;
+		len += smbios_write_type7_1level(current, *handle, ctx, i);
 		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,
+static int smbios_write_type32(ulong *current, int *handle,
 			       struct smbios_ctx *ctx)
 {
 	struct smbios_type32 *t;
@@ -866,7 +869,7 @@ static int smbios_write_type32(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle);
+	fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, *handle);
 	smbios_set_eos(ctx, t->eos);
 
 	*current += len;
@@ -875,7 +878,7 @@ static int smbios_write_type32(ulong *current, int handle,
 	return len;
 }
 
-static int smbios_write_type127(ulong *current, int handle,
+static int smbios_write_type127(ulong *current, int *handle,
 				struct smbios_ctx *ctx)
 {
 	struct smbios_type127 *t;
@@ -883,7 +886,7 @@ static int smbios_write_type127(ulong *current, int handle,
 
 	t = map_sysmem(*current, len);
 	memset(t, 0, len);
-	fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle);
+	fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, *handle);
 
 	*current += len;
 	unmap_sysmem(t);
@@ -954,7 +957,8 @@ ulong write_smbios_table(ulong addr)
 				ctx.node = ofnode_find_subnode(parent_node,
 							       method->subnode_name);
 		}
-		len += method->write((ulong *)&addr, handle++, &ctx);
+		len += method->write((ulong *)&addr, &handle, &ctx);
+		handle++;
 	}
 
 	/*
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v6 2/6] smbios: add support for dynamic generation of Type 9 system slot tables
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 1/6] smbios: Fix duplicated smbios handles Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 3/6] smbios: add support for dynamic generation of Type 16 table Raymond Mao
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Tom Rini, Mark Kettenis, Heinrich Schuchardt,
	Ilias Apalodimas, Baocheng Su, Jan Kiszka, Li Hua Qian,
	Samuel Holland

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>
---
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.
Changes in v4:
- Refine the commit message.
Changes in v5:
- None.
Changes in v6:
- None.

 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 f2f7483bce5..752a25250d3 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


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v6 3/6] smbios: add support for dynamic generation of Type 16 table
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 1/6] smbios: Fix duplicated smbios handles Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 2/6] smbios: add support for dynamic generation of Type 9 system slot tables Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 4/6] smbios: add support for dynamic generation of Type 17 table Raymond Mao
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Tom Rini, Heinrich Schuchardt, Mark Kettenis,
	Ilias Apalodimas, Baocheng Su, Li Hua Qian, Jan Kiszka,
	Samuel Holland

This commit implements SMBIOS Type 16 (Physical Memory Array)
generation with a hybrid approach supporting both:

1. Explicit definition via Device Tree 'smbios' node:
   Child node under '/smbios/smbios/memory-array' will be used to
   populate as individual Type 16 structure directly.
   - Properties follow SMBIOS field names with lowercase letters and
     hyphen-separated words (e.g., 'memory-error-correction',
     'maximum-capacity', 'extended-maximum-capacity', etc.).
   - This method supports precise platform-defined overrides and system
     descriptions.

2. Fallback to automatic DT-based discovery:
   If child node under '/smbios/smbios/memory-array' does not exist,
   the implementation will:
   - Scan all top-level 'memory@' nodes to populate Type 16 structure with
     inferred size and location data.
   - Scan nodes named or marked as 'memory-controller' and parse
     associated 'dimm@' subnodes (if present) to extract DIMM sizes and
     map them accordingly.

This dual-mode support enables flexible firmware SMBIOS reporting while
aligning with spec-compliant naming and runtime-detected memory topology.

Type 16 support is under GENERATE_SMBIOS_TABLE_VERBOSE to avoid
increasing rom size for those platforms which only require basic SMBIOS
support.

Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
---
Changes in v4:
- Initial patch.
Changes in v5:
- None.
Changes in v6:
- None.

 arch/arm/dts/smbios_generic.dtsi |   3 +
 cmd/smbios.c                     |  46 +++++
 drivers/sysinfo/smbios.c         |   5 +
 include/smbios.h                 |  18 ++
 include/smbios_def.h             |  29 ++++
 include/sysinfo.h                |   4 +
 lib/smbios.c                     | 282 +++++++++++++++++++++++++++++++
 7 files changed, 387 insertions(+)

diff --git a/arch/arm/dts/smbios_generic.dtsi b/arch/arm/dts/smbios_generic.dtsi
index 4463dade217..1a9adfaa409 100644
--- a/arch/arm/dts/smbios_generic.dtsi
+++ b/arch/arm/dts/smbios_generic.dtsi
@@ -80,6 +80,9 @@
 
 			system-slot {
 			};
+
+			memory-array {
+			};
 		};
 	};
 };
diff --git a/cmd/smbios.c b/cmd/smbios.c
index f9b62e66229..3f7dd21f92e 100644
--- a/cmd/smbios.c
+++ b/cmd/smbios.c
@@ -168,6 +168,32 @@ static const struct str_lookup_table slot_length_strings[] = {
 	{ SMBIOS_SYSSLOT_LENG_3_5INDRV,	"3.5 inch drive form factor" },
 };
 
+static const struct str_lookup_table ma_location_strings[] = {
+	{ SMBIOS_MA_LOCATION_OTHER,		"Other" },
+	{ SMBIOS_MA_LOCATION_UNKNOWN,		"Unknown" },
+	{ SMBIOS_MA_LOCATION_MOTHERBOARD,	"System board or motherboard" },
+};
+
+static const struct str_lookup_table ma_use_strings[] = {
+	{ SMBIOS_MA_USE_OTHER,		"Other" },
+	{ SMBIOS_MA_USE_UNKNOWN,	"Unknown" },
+	{ SMBIOS_MA_USE_SYSTEM,		"System memory" },
+	{ SMBIOS_MA_USE_VIDEO,		"Video memory" },
+	{ SMBIOS_MA_USE_FLASH,		"Flash memory" },
+	{ SMBIOS_MA_USE_NVRAM,		"Non-volatile RAM" },
+	{ SMBIOS_MA_USE_CACHE,		"Cache memory" },
+};
+
+static const struct str_lookup_table ma_err_corr_strings[] = {
+	{ SMBIOS_MA_ERRCORR_OTHER,	"Other" },
+	{ SMBIOS_MA_ERRCORR_UNKNOWN,	"Unknown" },
+	{ SMBIOS_MA_ERRCORR_NONE,	"None" },
+	{ SMBIOS_MA_ERRCORR_PARITY,	"Parity" },
+	{ SMBIOS_MA_ERRCORR_SBITECC,	"Single-bit ECC" },
+	{ SMBIOS_MA_ERRCORR_MBITECC,	"Multi-bit ECC" },
+	{ SMBIOS_MA_ERRCORR_CRC,	"CRC" },
+};
+
 /**
  * smbios_get_string() - get SMBIOS string from table
  *
@@ -514,6 +540,23 @@ static void smbios_print_type9(struct smbios_type9 *table)
 	printf("\tSlot Height: 0x%04x\n", *addr);
 }
 
+static void smbios_print_type16(struct smbios_type16 *table)
+{
+	printf("Physical Memory Array:\n");
+	smbios_print_lookup_str(ma_location_strings, table->location,
+				ARRAY_SIZE(ma_location_strings), "Location");
+	smbios_print_lookup_str(ma_use_strings, table->use,
+				ARRAY_SIZE(ma_use_strings), "Use");
+	smbios_print_lookup_str(ma_err_corr_strings, table->mem_err_corr,
+				ARRAY_SIZE(ma_err_corr_strings),
+				"Memory Error Correction");
+	printf("\tMaximum Capacity: 0x%08x\n", table->max_cap);
+	printf("\tMemory Error Information Handle: 0x%04x\n",
+	       table->mem_err_info_hdl);
+	printf("\tNumber of Memory Devices: 0x%04x\n", table->num_of_mem_dev);
+	printf("\tExtended Maximum Capacity: 0x%016llx\n", table->ext_max_cap);
+}
+
 static void smbios_print_type127(struct smbios_type127 *table)
 {
 	printf("End Of Table\n");
@@ -596,6 +639,9 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc,
 		case SMBIOS_SYSTEM_SLOTS:
 			smbios_print_type9((struct smbios_type9 *)pos);
 			break;
+		case SMBIOS_PHYS_MEMORY_ARRAY:
+			smbios_print_type16((struct smbios_type16 *)pos);
+			break;
 		case SMBIOS_END_OF_TABLE:
 			smbios_print_type127((struct smbios_type127 *)pos);
 			break;
diff --git a/drivers/sysinfo/smbios.c b/drivers/sysinfo/smbios.c
index 99104274f72..ff5873c940e 100644
--- a/drivers/sysinfo/smbios.c
+++ b/drivers/sysinfo/smbios.c
@@ -24,6 +24,7 @@ struct sysinfo_plat_priv {
 	struct smbios_type7 t7[SYSINFO_CACHE_LVL_MAX];
 	u16 cache_handles[SYSINFO_CACHE_LVL_MAX];
 	u8 cache_level;
+	u16 marray_handles[SYSINFO_MEM_HANDLE_MAX];
 };
 
 static void smbios_cache_info_dump(struct smbios_type7 *cache_info)
@@ -165,6 +166,10 @@ static int sysinfo_plat_get_data(struct udevice *dev, int id, void **buf,
 		*buf = &priv->cache_handles[0];
 		*size = sizeof(priv->cache_handles);
 		break;
+	case SYSID_SM_MEMARRAY_HANDLE:
+		*buf = &priv->marray_handles[0];
+		*size = sizeof(priv->marray_handles);
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/include/smbios.h b/include/smbios.h
index 752a25250d3..293d6795cf3 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -309,6 +309,24 @@ struct __packed smbios_type9 {
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
 
+enum {
+	SMBIOS_MEM_NONE = 0,
+	SMBIOS_MEM_CUSTOM = 1,
+	SMBIOS_MEM_FDT_MEM_NODE = 2,
+	SMBIOS_MEM_FDT_MEMCON_NODE = 3
+};
+
+struct __packed smbios_type16 {
+	struct smbios_header hdr;
+	u8 location;
+	u8 use;
+	u8 mem_err_corr;
+	u32 max_cap;
+	u16 mem_err_info_hdl;
+	u16 num_of_mem_dev;
+	u64 ext_max_cap;
+	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 ef9cb02ed25..c6850a5d6f5 100644
--- a/include/smbios_def.h
+++ b/include/smbios_def.h
@@ -280,4 +280,33 @@
 /* Slot segment group number */
 #define SMBIOS_SYSSLOT_SGGNUM_UND	0
 
+/* Physical Memory Array */
+
+/* Location */
+#define SMBIOS_MA_LOCATION_OTHER	1
+#define SMBIOS_MA_LOCATION_UNKNOWN	2
+#define SMBIOS_MA_LOCATION_MOTHERBOARD	3
+
+/* Use */
+#define SMBIOS_MA_USE_OTHER		1
+#define SMBIOS_MA_USE_UNKNOWN		2
+#define SMBIOS_MA_USE_SYSTEM		3
+#define SMBIOS_MA_USE_VIDEO		4
+#define SMBIOS_MA_USE_FLASH		5
+#define SMBIOS_MA_USE_NVRAM		6
+#define SMBIOS_MA_USE_CACHE		7
+
+/* Error Correction Type */
+#define SMBIOS_MA_ERRCORR_OTHER		1
+#define SMBIOS_MA_ERRCORR_UNKNOWN	2
+#define SMBIOS_MA_ERRCORR_NONE		3
+#define SMBIOS_MA_ERRCORR_PARITY	4
+#define SMBIOS_MA_ERRCORR_SBITECC	5
+#define SMBIOS_MA_ERRCORR_MBITECC	6
+#define SMBIOS_MA_ERRCORR_CRC		7
+
+/* Error Information Handle */
+#define SMBIOS_MA_ERRINFO_NONE		0xFFFE
+#define SMBIOS_MA_ERRINFO_NOERR		0xFFFF
+
 #endif /* _SMBIOS_DEF_H_ */
diff --git a/include/sysinfo.h b/include/sysinfo.h
index e87cf969fcd..54eb64a204a 100644
--- a/include/sysinfo.h
+++ b/include/sysinfo.h
@@ -12,6 +12,7 @@
 struct udevice;
 
 #define SYSINFO_CACHE_LVL_MAX 3
+#define SYSINFO_MEM_HANDLE_MAX 8
 
 /*
  * This uclass encapsulates hardware methods to gather information about a
@@ -149,6 +150,9 @@ enum sysinfo_id {
 	SYSID_SM_CACHE_INFO_END =
 		SYSID_SM_CACHE_INST_SIZE2 + SYSINFO_CACHE_LVL_MAX - 1,
 
+	/* Memory Array (Type 16) */
+	SYSID_SM_MEMARRAY_HANDLE,
+
 	/* For show_board_info() */
 	SYSID_BOARD_MODEL,
 	SYSID_BOARD_MANUFACTURER,
diff --git a/lib/smbios.c b/lib/smbios.c
index caeb309294d..27c9c975cf2 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -290,6 +290,49 @@ static int smbios_get_val_si(struct smbios_ctx * __maybe_unused ctx,
 	return val_def;
 }
 
+#if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE)
+static u64 smbios_get_u64_si(struct smbios_ctx * __maybe_unused ctx,
+			     const char * __maybe_unused prop,
+			     int __maybe_unused sysinfo_id, u64 val_def)
+{
+	size_t len;
+	void *data;
+	const fdt32_t *prop_val;
+	int prop_len;
+	u64 val = 0;
+
+	if (!ctx->dev)
+		return val_def;
+
+	if (!sysinfo_get_data(ctx->dev, sysinfo_id, &data, &len))
+		return *((u64 *)data);
+
+	if (!IS_ENABLED(CONFIG_OF_CONTROL) || !prop || !ofnode_valid(ctx->node))
+		return val_def;
+
+	prop_val = ofnode_read_prop(ctx->node, prop, &prop_len);
+	if (!prop_val || prop_len < sizeof(fdt32_t) ||
+	    prop_len % sizeof(fdt32_t)) {
+		/*
+		 * If the node or property is not valid fallback and try the root
+		 */
+		prop_val = ofnode_read_prop(ofnode_root(), prop, &prop_len);
+		if (!prop_val || prop_len < sizeof(fdt32_t) ||
+		    prop_len % sizeof(fdt32_t))
+			return val_def;
+	}
+
+	/* 64-bit: <hi lo> or 32-bit */
+	if (prop_len >= sizeof(fdt32_t) * 2) {
+		val = ((u64)fdt32_to_cpu(prop_val[0]) << 32) |
+		     fdt32_to_cpu(prop_val[1]);
+	} else {
+		val = fdt32_to_cpu(prop_val[0]);
+	}
+	return val;
+}
+#endif
+
 /**
  * smbios_add_prop_si() - Add a property from the devicetree or sysinfo
  *
@@ -1151,6 +1194,244 @@ static int smbios_write_type9(ulong *current, int *handle,
 	return len;
 }
 
+static u64 smbios_pop_size_from_memory_node(ofnode node)
+{
+	const fdt32_t *reg;
+	int len;
+	u64 size_bytes;
+
+	/* Read property 'reg' from the node */
+	reg = ofnode_read_prop(node, "reg", &len);
+	if (!reg || len < sizeof(fdt32_t) * 4 || len % sizeof(fdt32_t))
+		return 0;
+
+	/* Combine hi/lo for size (typically 64-bit) */
+	size_bytes = ((u64)fdt32_to_cpu(reg[2]) << 32) | fdt32_to_cpu(reg[3]);
+
+	return size_bytes;
+}
+
+static int
+smbios_write_type16_sum_memory_nodes(ulong *current, int handle,
+				     struct smbios_ctx *ctx, u16 cnt, u64 size)
+{
+	struct smbios_type16 *t;
+	int len = sizeof(*t);
+	u8 *eos_addr;
+	void *hdl;
+	size_t hdl_size;
+
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_PHYS_MEMORY_ARRAY, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	/* default attributes */
+	t->location = SMBIOS_MA_LOCATION_MOTHERBOARD;
+	t->use = SMBIOS_MA_USE_SYSTEM;
+	t->mem_err_corr = SMBIOS_MA_ERRCORR_UNKNOWN;
+	t->mem_err_info_hdl = SMBIOS_MA_ERRINFO_NONE;
+	t->num_of_mem_dev = cnt;
+
+	/* Use extended field */
+	t->max_cap = cpu_to_le32(0x80000000);
+	t->ext_max_cap = cpu_to_le64(size >> 10); /* In KB */
+
+	/* Save the memory array handles */
+	if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+			      &hdl_size) &&
+	    hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+		*((u16 *)hdl) = handle;
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static void
+smbios_pop_type16_from_memcontroller_node(ofnode node, struct smbios_type16 *t)
+{
+	ofnode child;
+	int count = 0;
+	u64 total = 0;
+
+	/* default attributes */
+	t->location = SMBIOS_MA_LOCATION_MOTHERBOARD;
+	t->use = SMBIOS_MA_USE_SYSTEM;
+	t->mem_err_info_hdl = SMBIOS_MA_ERRINFO_NONE;
+
+	/* Check custom property 'ecc-enabled' */
+	if (ofnode_read_bool(node, "ecc-enabled"))
+		t->mem_err_corr = SMBIOS_MA_ERRCORR_SBITECC;
+	else
+		t->mem_err_corr = SMBIOS_MA_ERRCORR_UNKNOWN;
+
+	/* Read subnodes with 'size' property */
+	for (child = ofnode_first_subnode(node); ofnode_valid(child);
+	     child = ofnode_next_subnode(child)) {
+		u64 sz = 0;
+		const fdt32_t *size;
+		int len;
+
+		size = ofnode_read_prop(child, "size", &len);
+		if (!size || len < sizeof(fdt32_t) || len % sizeof(fdt32_t))
+			continue;
+
+		/* 64-bit size: <hi lo> or 32-bit size */
+		if (len >= sizeof(fdt32_t) * 2)
+			sz = ((u64)fdt32_to_cpu(size[0]) << 32) |
+			     fdt32_to_cpu(size[1]);
+		else
+			sz = fdt32_to_cpu(size[0]);
+
+		count++;
+		total += sz;
+	}
+
+	/*
+	 * Number of memory devices associated with this array
+	 * (i.e., how many Type17 entries link to this Type16 array)
+	 */
+	t->num_of_mem_dev = count;
+
+	/* Use extended field */
+	t->max_cap = cpu_to_le32(0x80000000);
+	t->ext_max_cap = cpu_to_le64(total >> 10); /* In KB */
+}
+
+static void smbios_pop_type16_si(struct smbios_ctx *ctx,
+				 struct smbios_type16 *t)
+{
+	t->location = smbios_get_val_si(ctx, "location", SYSID_NONE,
+					SMBIOS_MA_LOCATION_UNKNOWN);
+	t->use = smbios_get_val_si(ctx, "use", SYSID_NONE,
+				   SMBIOS_MA_USE_UNKNOWN);
+	t->mem_err_corr = smbios_get_val_si(ctx, "memory-error-correction", SYSID_NONE,
+					    SMBIOS_MA_ERRCORR_UNKNOWN);
+	t->max_cap = smbios_get_val_si(ctx, "maximum-capacity", SYSID_NONE, 0);
+	t->mem_err_info_hdl = smbios_get_val_si(ctx, "memory-error-information-handle",
+						SYSID_NONE, SMBIOS_MA_ERRINFO_NONE);
+	t->num_of_mem_dev = smbios_get_val_si(ctx, "number-of-memory-devices", SYSID_NONE, 1);
+	t->ext_max_cap = smbios_get_u64_si(ctx, "extended-maximum-capacity", SYSID_NONE, 0);
+}
+
+static int smbios_write_type16_1array(ulong *current, int handle,
+				      struct smbios_ctx *ctx, int idx,
+				      int type)
+{
+	struct smbios_type16 *t;
+	int len = sizeof(*t);
+	u8 *eos_addr;
+	void *hdl;
+	size_t hdl_size;
+
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_PHYS_MEMORY_ARRAY, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	if (type == SMBIOS_MEM_CUSTOM)
+		smbios_pop_type16_si(ctx, t);
+	else if (type == SMBIOS_MEM_FDT_MEMCON_NODE)
+		smbios_pop_type16_from_memcontroller_node(ctx->node, t);
+
+	/* Save the memory array handles */
+	if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+			      &hdl_size) &&
+	    hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+		*((u16 *)hdl + idx) = handle;
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static int smbios_write_type16(ulong *current, int *handle,
+			       struct smbios_ctx *ctx)
+{
+	int len;
+	struct smbios_ctx ctx_bak;
+	ofnode child;
+	int idx;
+	u64 total = 0;
+	int count = 0;
+	int hdl_base = *handle;
+
+	if (!IS_ENABLED(CONFIG_OF_CONTROL))
+		return 0;	/* Error, return 0-length */
+
+	/* Step 1: Scan any subnode exists under 'memory-array' */
+	len = smbios_scan_subnodes(current, ctx, handle,
+				   smbios_write_type16_1array,
+				   SMBIOS_MEM_CUSTOM);
+	if (len)
+		return len;
+
+	/* Step 2: Scan 'memory' node from the entire FDT */
+	for (child = ofnode_first_subnode(ofnode_root());
+	     ofnode_valid(child); child = ofnode_next_subnode(child)) {
+		const char *str;
+
+		/* Look up for 'device_type = "memory"' */
+		str = ofnode_read_string(child, "device_type");
+		if (str && !strcmp(str, "memory")) {
+			count++;
+			total += smbios_pop_size_from_memory_node(child);
+		}
+	}
+	/*
+	 * Generate one type16 instance for all 'memory' nodes,
+	 * use idx=0 implicitly
+	 */
+	if (count)
+		len += smbios_write_type16_sum_memory_nodes(current, *handle,
+							    ctx, count, total);
+
+	/* Step 3: Scan 'memory-controller' node from the entire FDT */
+	/* idx starts from 1 */
+	memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
+	for (idx = 1, child = ofnode_first_subnode(ofnode_root());
+	     ofnode_valid(child); child = ofnode_next_subnode(child)) {
+		const char *compat;
+		const char *name;
+
+		/*
+		 * Look up for node with name or property 'compatible'
+		 * containing 'memory-controller'.
+		 */
+		name = ofnode_get_name(child);
+		compat = ofnode_read_string(child, "compatible");
+		if ((!compat || !strstr(compat, "memory-controller")) &&
+		    (!name || !strstr(name, "memory-controller")))
+			continue;
+
+		*handle = hdl_base + idx;
+		ctx->node = child;
+		/*
+		 * Generate one type16 instance for each 'memory-controller'
+		 * node, sum the 'size' of all subnodes.
+		 */
+		len += smbios_write_type16_1array(current, *handle, ctx, idx,
+						  SMBIOS_MEM_FDT_MEMCON_NODE);
+		idx++;
+		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,
@@ -1199,6 +1480,7 @@ static struct smbios_write_method smbios_write_funcs[] = {
 	{ smbios_write_type4, "processor"},
 #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE)
 	{ smbios_write_type9, "system-slot"},
+	{ smbios_write_type16, "memory-array"},
 #endif
 	{ smbios_write_type32, },
 	{ smbios_write_type127 },
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v6 4/6] smbios: add support for dynamic generation of Type 17 table
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
                   ` (2 preceding siblings ...)
  2026-02-13 22:52 ` [PATCH v6 3/6] smbios: add support for dynamic generation of Type 16 table Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 5/6] smbios: add support for dynamic generation of Type 19 table Raymond Mao
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Tom Rini, Heinrich Schuchardt, Mark Kettenis,
	Ilias Apalodimas, Baocheng Su, Li Hua Qian, Jan Kiszka,
	Samuel Holland

This commit implements SMBIOS Type 17 (Memory Device) generation with a
hybrid approach supporting both:

1. Explicit definition via Device Tree 'smbios' node:
   Child node under '/smbios/smbios/memory-device' will be used to
   populate as individual Type 17 structure directly.
   - Properties follow SMBIOS field names with lowercase letters and
     hyphen-separated words (e.g., 'physical-memory-array-handle',
     ' memory-error-information-handle', 'configured-memory-speed', etc.).
   - This method supports precise platform-defined overrides and system
     descriptions.

2. Fallback to automatic DT-based discovery:
   If child node under '/smbios/smbios/memory-device' does not exist,
   the implementation will:
   - Scan all top-level 'memory@' nodes to populate Type 17 structure with
     inferred size and location data.
   - Scan nodes named or marked as 'memory-controller' and parse
     associated 'dimm@' subnodes (if present) to extract DIMM sizes and
     map them accordingly.

This dual-mode support enables flexible firmware SMBIOS reporting while
aligning with spec-compliant naming and runtime-detected memory topology.

Type 17 support is under GENERATE_SMBIOS_TABLE_VERBOSE to avoid
increasing rom size for those platforms which only require basic SMBIOS
support.

Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
---
Changes in v4:
- Initial patch.
Changes in v5:
- None.
Changes in v6:
- Fixed mis-aligned type17 structure.
- Remove a duplicated line of setting type17 data width.

 arch/arm/dts/smbios_generic.dtsi |   3 +
 cmd/smbios.c                     | 126 +++++++++++
 include/smbios.h                 |  45 ++++
 include/smbios_def.h             | 127 +++++++++++
 lib/smbios.c                     | 376 +++++++++++++++++++++++++++++++
 5 files changed, 677 insertions(+)

diff --git a/arch/arm/dts/smbios_generic.dtsi b/arch/arm/dts/smbios_generic.dtsi
index 1a9adfaa409..fd2df8d02e0 100644
--- a/arch/arm/dts/smbios_generic.dtsi
+++ b/arch/arm/dts/smbios_generic.dtsi
@@ -83,6 +83,9 @@
 
 			memory-array {
 			};
+
+			memory-device {
+			};
 		};
 	};
 };
diff --git a/cmd/smbios.c b/cmd/smbios.c
index 3f7dd21f92e..39c9c44a28e 100644
--- a/cmd/smbios.c
+++ b/cmd/smbios.c
@@ -194,6 +194,74 @@ static const struct str_lookup_table ma_err_corr_strings[] = {
 	{ SMBIOS_MA_ERRCORR_CRC,	"CRC" },
 };
 
+static const struct str_lookup_table md_form_factor_strings[] = {
+	{ SMBIOS_MD_FF_OTHER,		"Other" },
+	{ SMBIOS_MD_FF_UNKNOWN,		"Unknown" },
+	{ SMBIOS_MD_FF_SIMM,		"SIMM" },
+	{ SMBIOS_MD_FF_SIP,		"SIP" },
+	{ SMBIOS_MD_FF_CHIP,		"Chip" },
+	{ SMBIOS_MD_FF_DIP,		"DIP" },
+	{ SMBIOS_MD_FF_ZIP,		"ZIP" },
+	{ SMBIOS_MD_FF_PROPCARD,	"Proprietary Card" },
+	{ SMBIOS_MD_FF_DIMM,		"DIMM" },
+	{ SMBIOS_MD_FF_TSOP,		"TSOP" },
+	{ SMBIOS_MD_FF_ROC,		"Row of chips" },
+	{ SMBIOS_MD_FF_RIMM,		"RIMM" },
+	{ SMBIOS_MD_FF_SODIMM,		"SODIMM" },
+	{ SMBIOS_MD_FF_SRIMM,		"SRIMM" },
+	{ SMBIOS_MD_FF_FBDIMM,		"FB-DIMM" },
+	{ SMBIOS_MD_FF_DIE,		"Die" },
+};
+
+static const struct str_lookup_table md_type_strings[] = {
+	{ SMBIOS_MD_TYPE_OTHER,		"Other" },
+	{ SMBIOS_MD_TYPE_UNKNOWN,	"Unknown" },
+	{ SMBIOS_MD_TYPE_DRAM,		"DRAM" },
+	{ SMBIOS_MD_TYPE_EDRAM,		"EDRAM" },
+	{ SMBIOS_MD_TYPE_VRAM,		"VRAM" },
+	{ SMBIOS_MD_TYPE_SRAM,		"SRAM" },
+	{ SMBIOS_MD_TYPE_RAM,		"RAM" },
+	{ SMBIOS_MD_TYPE_ROM,		"ROM" },
+	{ SMBIOS_MD_TYPE_FLASH,		"FLASH" },
+	{ SMBIOS_MD_TYPE_EEPROM,	"EEPROM" },
+	{ SMBIOS_MD_TYPE_FEPROM,	"FEPROM" },
+	{ SMBIOS_MD_TYPE_EPROM,		"EPROM" },
+	{ SMBIOS_MD_TYPE_CDRAM,		"CDRAM" },
+	{ SMBIOS_MD_TYPE_3DRAM,		"3DRAM" },
+	{ SMBIOS_MD_TYPE_SDRAM,		"SDRAM" },
+	{ SMBIOS_MD_TYPE_SGRAM,		"SGRAM" },
+	{ SMBIOS_MD_TYPE_RDRAM,		"RDRAM" },
+	{ SMBIOS_MD_TYPE_DDR,		"DDR" },
+	{ SMBIOS_MD_TYPE_DDR2,		"DDR2" },
+	{ SMBIOS_MD_TYPE_DDR2FBD,	"DDR2 FB-DIMM" },
+	{ SMBIOS_MD_TYPE_RSVD1,		"Reserved" },
+	{ SMBIOS_MD_TYPE_RSVD2,		"Reserved" },
+	{ SMBIOS_MD_TYPE_DSVD3,		"Reserved" },
+	{ SMBIOS_MD_TYPE_DDR3,		"DDR3" },
+	{ SMBIOS_MD_TYPE_FBD2,		"FBD2" },
+	{ SMBIOS_MD_TYPE_DDR4,		"DDR4" },
+	{ SMBIOS_MD_TYPE_LPDDR,		"LPDDR" },
+	{ SMBIOS_MD_TYPE_LPDDR2,	"LPDDR2" },
+	{ SMBIOS_MD_TYPE_LPDDR3,	"LPDDR3" },
+	{ SMBIOS_MD_TYPE_LPDDR4,	"LPDDR4" },
+	{ SMBIOS_MD_TYPE_LNVD,		"Logical non-volatile device" },
+	{ SMBIOS_MD_TYPE_HBM,		"HBM" },
+	{ SMBIOS_MD_TYPE_HBM2,		"HBM2" },
+	{ SMBIOS_MD_TYPE_DDR5,		"DDR5" },
+	{ SMBIOS_MD_TYPE_LPDDR5,	"LPDDR5" },
+	{ SMBIOS_MD_TYPE_HBM3,		"HBM3" },
+};
+
+static const struct str_lookup_table md_tech_strings[] = {
+	{ SMBIOS_MD_TECH_OTHER,		"Other" },
+	{ SMBIOS_MD_TECH_UNKNOWN,	"Unknown" },
+	{ SMBIOS_MD_TECH_DRAM,		"DRAM" },
+	{ SMBIOS_MD_TECH_NVDIMMN,	"NVDIMM-N" },
+	{ SMBIOS_MD_TECH_NVDIMMF,	"NVDIMM-F" },
+	{ SMBIOS_MD_TECH_NVDIMMP,	"NVDIMM-P" },
+	{ SMBIOS_MD_TECH_OPTANE,	"Intel Optane persistent memory" },
+};
+
 /**
  * smbios_get_string() - get SMBIOS string from table
  *
@@ -557,6 +625,61 @@ static void smbios_print_type16(struct smbios_type16 *table)
 	printf("\tExtended Maximum Capacity: 0x%016llx\n", table->ext_max_cap);
 }
 
+static void smbios_print_type17(struct smbios_type17 *table)
+{
+	printf("Memory Device:\n");
+	printf("\tPhysical Memory Array Handle: 0x%04x\n",
+	       table->phy_mem_array_hdl);
+	printf("\tMemory Error Information Handle: 0x%04x\n",
+	       table->mem_err_info_hdl);
+	printf("\tTotal Width: 0x%04x\n", table->total_width);
+	printf("\tData Width: 0x%04x\n", table->data_width);
+	printf("\tSize: 0x%04x\n", table->size);
+	smbios_print_lookup_str(md_form_factor_strings, table->form_factor,
+				ARRAY_SIZE(md_form_factor_strings),
+				"Form Factor");
+	printf("\tDevice Set: 0x%04x\n", table->dev_set);
+	smbios_print_str("Device Locator", table, table->dev_locator);
+	smbios_print_str("Bank Locator", table, table->bank_locator);
+	smbios_print_lookup_str(md_type_strings, table->mem_type,
+				ARRAY_SIZE(md_type_strings), "Memory Type");
+	printf("\tType Detail: 0x%04x\n", table->type_detail);
+	printf("\tSpeed: 0x%04x\n", table->speed);
+	smbios_print_str("Manufacturer", table, table->manufacturer);
+	smbios_print_str("Serial Number", table, table->serial_number);
+	smbios_print_str("Asset Tag", table, table->asset_tag);
+	smbios_print_str("Part Number", table, table->part_number);
+	printf("\tAttributes: 0x%04x\n", table->attributes);
+	printf("\tExtended Size: 0x%08x\n", table->ext_size);
+	printf("\tConfigured Memory Speed: 0x%04x\n", table->config_mem_speed);
+	printf("\tMinimum voltage: 0x%04x\n", table->min_voltage);
+	printf("\tMaximum voltage: 0x%04x\n", table->max_voltage);
+	printf("\tConfigured voltage: 0x%04x\n", table->config_voltage);
+	smbios_print_lookup_str(md_tech_strings, table->mem_tech,
+				ARRAY_SIZE(md_tech_strings),
+				"Memory Technology");
+	printf("\tMemory Operating Mode Capability: 0x%04x\n",
+	       table->mem_op_mode_cap);
+	smbios_print_str("Firmware Version", table, table->fw_ver);
+	printf("\tModule Manufacturer ID: 0x%04x\n", table->module_man_id);
+	printf("\tModule Product ID: 0x%04x\n", table->module_prod_id);
+	printf("\tMemory Subsystem Controller Manufacturer ID: 0x%04x\n",
+	       table->mem_subsys_con_man_id);
+	printf("\tMemory Subsystem Controller Product ID: 0x%04x\n",
+	       table->mem_subsys_con_prod_id);
+	printf("\tNon-volatile Size: 0x%016llx\n", table->nonvolatile_size);
+	printf("\tVolatile Size: 0x%016llx\n", table->volatile_size);
+	printf("\tCache Size: 0x%016llx\n", table->cache_size);
+	printf("\tLogical Size: 0x%016llx\n", table->logical_size);
+	printf("\tExtended Speed: 0x%04x\n", table->ext_speed);
+	printf("\tExtended Configured Memory Speed: 0x%04x\n",
+	       table->ext_config_mem_speed);
+	printf("\tPMIC0 Manufacturer ID: 0x%04x\n", table->pmic0_man_id);
+	printf("\tPMIC0 Revision Number: 0x%04x\n", table->pmic0_rev_num);
+	printf("\tRCD Manufacturer ID: 0x%04x\n", table->rcd_man_id);
+	printf("\tRCD Revision Number: 0x%04x\n", table->rcd_rev_num);
+}
+
 static void smbios_print_type127(struct smbios_type127 *table)
 {
 	printf("End Of Table\n");
@@ -642,6 +765,9 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc,
 		case SMBIOS_PHYS_MEMORY_ARRAY:
 			smbios_print_type16((struct smbios_type16 *)pos);
 			break;
+		case SMBIOS_MEMORY_DEVICE:
+			smbios_print_type17((struct smbios_type17 *)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 293d6795cf3..2deafea9aa1 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -327,6 +327,51 @@ struct __packed smbios_type16 {
 	u64 ext_max_cap;
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
+
+struct __packed smbios_type17 {
+	struct smbios_header hdr;
+	u16 phy_mem_array_hdl;
+	u16 mem_err_info_hdl;
+	u16 total_width;
+	u16 data_width;
+	u16 size;
+	u8 form_factor;
+	u8 dev_set;
+	u8 dev_locator;
+	u8 bank_locator;
+	u8 mem_type;
+	u16 type_detail;
+	u16 speed;
+	u8 manufacturer;
+	u8 serial_number;
+	u8 asset_tag;
+	u8 part_number;
+	u8 attributes;
+	u32 ext_size;
+	u16 config_mem_speed;
+	u16 min_voltage;
+	u16 max_voltage;
+	u16 config_voltage;
+	u8 mem_tech;
+	u16 mem_op_mode_cap;
+	u8 fw_ver;
+	u16 module_man_id;
+	u16 module_prod_id;
+	u16 mem_subsys_con_man_id;
+	u16 mem_subsys_con_prod_id;
+	u64 nonvolatile_size;
+	u64 volatile_size;
+	u64 cache_size;
+	u64 logical_size;
+	u32 ext_speed;
+	u32 ext_config_mem_speed;
+	u16 pmic0_man_id;
+	u16 pmic0_rev_num;
+	u16 rcd_man_id;
+	u16 rcd_rev_num;
+	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 c6850a5d6f5..ce913f2f32a 100644
--- a/include/smbios_def.h
+++ b/include/smbios_def.h
@@ -309,4 +309,131 @@
 #define SMBIOS_MA_ERRINFO_NONE		0xFFFE
 #define SMBIOS_MA_ERRINFO_NOERR		0xFFFF
 
+/* Memory Device */
+
+/* Size */
+
+#define SMBIOS_MD_SIZE_UNKNOWN	0xFFFF
+#define SMBIOS_MD_SIZE_EXT	0x7FFF
+
+/* Form Factor */
+#define SMBIOS_MD_FF_OTHER	1
+#define SMBIOS_MD_FF_UNKNOWN	2
+#define SMBIOS_MD_FF_SIMM	3
+#define SMBIOS_MD_FF_SIP	4
+#define SMBIOS_MD_FF_CHIP	5
+#define SMBIOS_MD_FF_DIP	6
+#define SMBIOS_MD_FF_ZIP	7
+#define SMBIOS_MD_FF_PROPCARD	8
+#define SMBIOS_MD_FF_DIMM	9
+#define SMBIOS_MD_FF_TSOP	10
+#define SMBIOS_MD_FF_ROC	11
+#define SMBIOS_MD_FF_RIMM	12
+#define SMBIOS_MD_FF_SODIMM	13
+#define SMBIOS_MD_FF_SRIMM	14
+#define SMBIOS_MD_FF_FBDIMM	15
+#define SMBIOS_MD_FF_DIE	16
+
+/* Device set */
+#define SMBIOS_MD_DEVSET_NONE		0
+#define SMBIOS_MD_DEVSET_UNKNOWN	0xFF
+
+/* Speed */
+#define SMBIOS_MD_SPEED_UNKNOWN	0
+#define SMBIOS_MD_SPEED_EXT	0xFFFF
+
+/* Attributes */
+#define SMBIOS_MD_ATTR_RANK_UNKNOWN	0
+
+/* Configured Memory Speed */
+#define SMBIOS_MD_CONFSPEED_UNKNOWN	0
+#define SMBIOS_MD_CONFSPEED_EXT		0xFFFF
+
+/* Voltage */
+#define SMBIOS_MD_VOLTAGE_UNKNOWN	0
+
+/* Type */
+#define SMBIOS_MD_TYPE_OTHER	1
+#define SMBIOS_MD_TYPE_UNKNOWN	2
+#define SMBIOS_MD_TYPE_DRAM	3
+#define SMBIOS_MD_TYPE_EDRAM	4
+#define SMBIOS_MD_TYPE_VRAM	5
+#define SMBIOS_MD_TYPE_SRAM	6
+#define SMBIOS_MD_TYPE_RAM	7
+#define SMBIOS_MD_TYPE_ROM	8
+#define SMBIOS_MD_TYPE_FLASH	9
+#define SMBIOS_MD_TYPE_EEPROM	10
+#define SMBIOS_MD_TYPE_FEPROM	11
+#define SMBIOS_MD_TYPE_EPROM	12
+#define SMBIOS_MD_TYPE_CDRAM	13
+#define SMBIOS_MD_TYPE_3DRAM	14
+#define SMBIOS_MD_TYPE_SDRAM	15
+#define SMBIOS_MD_TYPE_SGRAM	16
+#define SMBIOS_MD_TYPE_RDRAM	17
+#define SMBIOS_MD_TYPE_DDR	18
+#define SMBIOS_MD_TYPE_DDR2	19
+#define SMBIOS_MD_TYPE_DDR2FBD	20
+#define SMBIOS_MD_TYPE_RSVD1	21
+#define SMBIOS_MD_TYPE_RSVD2	22
+#define SMBIOS_MD_TYPE_DSVD3	23
+#define SMBIOS_MD_TYPE_DDR3	24
+#define SMBIOS_MD_TYPE_FBD2	25
+#define SMBIOS_MD_TYPE_DDR4	26
+#define SMBIOS_MD_TYPE_LPDDR	27
+#define SMBIOS_MD_TYPE_LPDDR2	28
+#define SMBIOS_MD_TYPE_LPDDR3	29
+#define SMBIOS_MD_TYPE_LPDDR4	30
+#define SMBIOS_MD_TYPE_LNVD	31
+#define SMBIOS_MD_TYPE_HBM	32
+#define SMBIOS_MD_TYPE_HBM2	33
+#define SMBIOS_MD_TYPE_DDR5	34
+#define SMBIOS_MD_TYPE_LPDDR5	35
+#define SMBIOS_MD_TYPE_HBM3	36
+
+/* Type Detail */
+#define SMBIOS_MD_TD_RSVD	1 /* BIT(0), set to 0 */
+#define SMBIOS_MD_TD_OTHER	2 /* BIT(1) */
+#define SMBIOS_MD_TD_UNKNOWN	4 /* BIT(2) */
+#define SMBIOS_MD_TD_FP		8 /* BIT(3) */
+#define SMBIOS_MD_TD_SC		0x10 /* BIT(4) */
+#define SMBIOS_MD_TD_PS		0x20 /* BIT(5) */
+#define SMBIOS_MD_TD_RAMBUS	0x40 /* BIT(6) */
+#define SMBIOS_MD_TD_SYNC	0x80 /* BIT(7) */
+#define SMBIOS_MD_TD_CMOS	0x100 /* BIT(8) */
+#define SMBIOS_MD_TD_EDO	0x200 /* BIT(9) */
+#define SMBIOS_MD_TD_WINDRAM	0x400 /* BIT(10) */
+#define SMBIOS_MD_TD_CACHEDRAM	0x800 /* BIT(11) */
+#define SMBIOS_MD_TD_NV		0x1000 /* BIT(12) */
+#define SMBIOS_MD_TD_RGSTD	0x2000 /* BIT(13) */
+#define SMBIOS_MD_TD_UNRGSTD	0x4000 /* BIT(14) */
+#define SMBIOS_MD_TD_LRDIMM	0x8000 /* BIT(15) */
+
+/* Technology */
+#define SMBIOS_MD_TECH_OTHER	1
+#define SMBIOS_MD_TECH_UNKNOWN	2
+#define SMBIOS_MD_TECH_DRAM	3
+#define SMBIOS_MD_TECH_NVDIMMN	4
+#define SMBIOS_MD_TECH_NVDIMMF	5
+#define SMBIOS_MD_TECH_NVDIMMP	6
+#define SMBIOS_MD_TECH_OPTANE	7
+
+/* Operating Mode Capability */
+#define SMBIOS_MD_OPMC_RSVD	1 /* BIT(0), set to 0 */
+#define SMBIOS_MD_OPMC_OTHER	2 /* BIT(1) */
+#define SMBIOS_MD_OPMC_UNKNOWN	4 /* BIT(2) */
+#define SMBIOS_MD_OPMC_VM	8 /* BIT(3) */
+#define SMBIOS_MD_OPMC_BYTEAPM	0x10 /* BIT(4) */
+#define SMBIOS_MD_OPMC_BLKAPM	0x20 /* BIT(5) */
+/* Bit 6:15 Reserved, set to 0 */
+
+/* Non-volatile / Volatile / Cache / Logical portion Size */
+#define SMBIOS_MD_PORT_SIZE_NONE	0
+#define SMBIOS_MD_PORT_SIZE_UNKNOWN_HI	0xFFFFFFFF
+#define SMBIOS_MD_PORT_SIZE_UNKNOWN_LO	0xFFFFFFFF
+#define SMBIOS_MS_PORT_SIZE_UNKNOWN	0xFFFFFFFFFFFFFFFF
+
+/* Error Information Handle */
+#define SMBIOS_MD_ERRINFO_NONE		0xFFFE
+#define SMBIOS_MD_ERRINFO_NOERR		0xFFFF
+
 #endif /* _SMBIOS_DEF_H_ */
diff --git a/lib/smbios.c b/lib/smbios.c
index 27c9c975cf2..7c6ad63b1c7 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -135,6 +135,14 @@ typedef int (*smbios_write_subnode)(ulong *current, int handle,
 				   struct smbios_ctx *ctx, int idx,
 				   int type);
 
+typedef int (*smbios_write_memnode)(ulong *current, int handle,
+				    struct smbios_ctx *ctx, int idx,
+				    int type);
+
+typedef int (*smbios_write_memctrlnode)(ulong *current, int handle,
+				      struct smbios_ctx *ctx, int idx,
+				      u64 base, u64 sz);
+
 /**
  * Function prototype to write a specific type of SMBIOS structure
  *
@@ -1432,6 +1440,373 @@ static int smbios_write_type16(ulong *current, int *handle,
 	return len;
 }
 
+static void smbios_pop_type17_general_si(struct smbios_ctx *ctx,
+					 struct smbios_type17 *t)
+{
+	t->mem_err_info_hdl =
+		smbios_get_val_si(ctx, "memory-error-information-handle",
+				  SYSID_NONE, SMBIOS_MD_ERRINFO_NONE);
+	t->total_width = smbios_get_val_si(ctx, "total-width", SYSID_NONE, 0);
+	t->data_width = smbios_get_val_si(ctx, "data-width", SYSID_NONE, 0);
+	t->form_factor = smbios_get_val_si(ctx, "form-factor",
+					   SYSID_NONE, SMBIOS_MD_FF_UNKNOWN);
+	t->dev_set = smbios_get_val_si(ctx, "device-set", SYSID_NONE,
+				       SMBIOS_MD_DEVSET_UNKNOWN);
+	t->dev_locator = smbios_add_prop_si(ctx, "device-locator", SYSID_NONE,
+					    NULL);
+	t->bank_locator = smbios_add_prop_si(ctx, "bank-locator", SYSID_NONE,
+					     NULL);
+	t->mem_type = smbios_get_val_si(ctx, "memory-type",
+					SYSID_NONE, SMBIOS_MD_TYPE_UNKNOWN);
+	t->type_detail = smbios_get_val_si(ctx, "type-detail",
+					   SYSID_NONE, SMBIOS_MD_TD_UNKNOWN);
+	t->speed = smbios_get_val_si(ctx, "speed", SYSID_NONE,
+				     SMBIOS_MD_SPEED_UNKNOWN);
+	t->manufacturer = smbios_add_prop_si(ctx, "manufacturer", SYSID_NONE,
+					     NULL);
+	t->serial_number = smbios_add_prop_si(ctx, "serial-number", SYSID_NONE,
+					      NULL);
+	t->asset_tag = smbios_add_prop_si(ctx, "asset-tag", SYSID_NONE, NULL);
+	t->part_number = smbios_add_prop_si(ctx, "part-number", SYSID_NONE,
+					    NULL);
+	t->attributes = smbios_get_val_si(ctx, "attributes", SYSID_NONE,
+					  SMBIOS_MD_ATTR_RANK_UNKNOWN);
+	t->config_mem_speed = smbios_get_val_si(ctx, "configured-memory-speed",
+						SYSID_NONE,
+						SMBIOS_MD_CONFSPEED_UNKNOWN);
+	t->min_voltage = smbios_get_val_si(ctx, "minimum-voltage", SYSID_NONE,
+					   SMBIOS_MD_VOLTAGE_UNKNOWN);
+	t->max_voltage = smbios_get_val_si(ctx, "maximum-voltage", SYSID_NONE,
+					   SMBIOS_MD_VOLTAGE_UNKNOWN);
+	t->config_voltage = smbios_get_val_si(ctx, "configured-voltage",
+					      SYSID_NONE,
+					      SMBIOS_MD_VOLTAGE_UNKNOWN);
+	t->mem_tech = smbios_get_val_si(ctx, "memory-technology",
+					SYSID_NONE, SMBIOS_MD_TECH_UNKNOWN);
+	t->mem_op_mode_cap =
+		smbios_get_val_si(ctx, "memory-operating-mode-capability",
+				  SYSID_NONE, SMBIOS_MD_OPMC_UNKNOWN);
+	t->fw_ver = smbios_add_prop_si(ctx, "firmware-version", SYSID_NONE,
+				       NULL);
+	t->module_man_id = smbios_get_val_si(ctx, "module-manufacturer-id",
+					     SYSID_NONE, 0);
+	t->module_prod_id = smbios_get_val_si(ctx, "module-product-id",
+					      SYSID_NONE, 0);
+	t->mem_subsys_con_man_id =
+		smbios_get_val_si(ctx,
+				  "memory-subsystem-controller-manufacturer-id",
+				  SYSID_NONE, 0);
+	t->mem_subsys_con_prod_id =
+		smbios_get_val_si(ctx,
+				  "memory-subsystem-controller-product-id",
+				  SYSID_NONE, 0);
+	t->nonvolatile_size = smbios_get_u64_si(ctx, "non-volatile-size",
+						SYSID_NONE,
+						SMBIOS_MS_PORT_SIZE_UNKNOWN);
+	t->volatile_size = smbios_get_u64_si(ctx, "volatile-size",
+					     SYSID_NONE,
+					     SMBIOS_MS_PORT_SIZE_UNKNOWN);
+	t->cache_size = smbios_get_u64_si(ctx, "cache-size",
+					  SYSID_NONE,
+					  SMBIOS_MS_PORT_SIZE_UNKNOWN);
+	t->logical_size = smbios_get_u64_si(ctx, "logical-size",
+					    SYSID_NONE,
+					    SMBIOS_MS_PORT_SIZE_UNKNOWN);
+	t->ext_speed = smbios_get_val_si(ctx, "extended-speed", SYSID_NONE, 0);
+	t->ext_config_mem_speed =
+		smbios_get_val_si(ctx, "extended-configured-memory-speed",
+				  SYSID_NONE, 0);
+	t->pmic0_man_id = smbios_get_val_si(ctx, "pmic0-manufacturer-id",
+					    SYSID_NONE, 0);
+	t->pmic0_rev_num = smbios_get_val_si(ctx, "pmic0-revision-number",
+					     SYSID_NONE, 0);
+	t->rcd_man_id = smbios_get_val_si(ctx, "rcd-manufacturer-id",
+					  SYSID_NONE, 0);
+	t->rcd_rev_num = smbios_get_val_si(ctx, "rcd-revision-number",
+					   SYSID_NONE, 0);
+}
+
+static void
+smbios_pop_type17_size_from_memory_node(ofnode node, struct smbios_type17 *t)
+{
+	const fdt32_t *reg;
+	int len;
+	u64 sz;
+	u32 size_mb;
+
+	/* Read property 'reg' from the node */
+	reg = ofnode_read_prop(node, "reg", &len);
+	if (!reg || len < sizeof(fdt32_t) * 4 || len % sizeof(fdt32_t))
+		return;
+
+	/* Combine hi/lo for size (typically 64-bit) */
+	sz = ((u64)fdt32_to_cpu(reg[2]) << 32) | fdt32_to_cpu(reg[3]);
+
+	/* Convert size to MB */
+	size_mb = (u32)(sz >> 20); /* 1 MB = 2^20 */
+	if (size_mb < SMBIOS_MD_SIZE_EXT) {
+		t->size = cpu_to_le16(size_mb);
+		t->ext_size = 0;
+		return;
+	}
+
+	t->size = cpu_to_le16(SMBIOS_MD_SIZE_EXT); /* Signal extended used */
+	t->ext_size = cpu_to_le32((u32)(sz >> 10)); /* In KB */
+}
+
+static void smbios_pop_type17_size_si(struct smbios_ctx *ctx,
+				      struct smbios_type17 *t)
+{
+	t->size = smbios_get_val_si(ctx, "size", SYSID_NONE,
+				    SMBIOS_MD_SIZE_UNKNOWN);
+	t->ext_size = smbios_get_val_si(ctx, "extended-size", SYSID_NONE, 0);
+}
+
+static int
+smbios_scan_memctrl_subnode(ulong *current, int *handle, struct smbios_ctx *ctx,
+			    int idx, smbios_write_memctrlnode cb)
+{
+	int total_len = 0;
+	ofnode child;
+	int i = 0;
+	int hdl_base = *handle;
+	u64 base = 0;
+
+	/*
+	 * Enumerate all subnodes of 'memory-controller' that contain 'size'
+	 * property and generate one instance for each.
+	 */
+	for (child = ofnode_first_subnode(ctx->node); ofnode_valid(child);
+	     child = ofnode_next_subnode(child)) {
+		u64 sz = 0;
+		const fdt32_t *size;
+		int proplen;
+
+		size = ofnode_read_prop(child, "size", &proplen);
+		if (!size || proplen < sizeof(fdt32_t) ||
+		    proplen % sizeof(fdt32_t))
+			continue;
+
+		/* 64-bit size: <hi lo> or 32-bit size */
+		if (proplen >= sizeof(fdt32_t) * 2)
+			sz = ((u64)fdt32_to_cpu(size[0]) << 32) |
+			     fdt32_to_cpu(size[1]);
+		else
+			sz = fdt32_to_cpu(size[0]);
+
+		*handle = hdl_base + i;
+		total_len += cb(current, *handle, ctx, idx, base, sz);
+		base += sz;
+		i++;
+	}
+
+	return total_len;
+}
+
+static int
+smbios_write_type17_from_memctrl_node(ulong *current, int handle,
+				      struct smbios_ctx *ctx, int idx,
+				      u64 __maybe_unused base, u64 sz)
+{
+	struct smbios_type17 *t;
+	int len;
+	u8 *eos_addr;
+	u32 size_mb;
+	void *hdl;
+	size_t hdl_size;
+
+	len = sizeof(*t);
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_MEMORY_DEVICE, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	/* Read the memory array handles */
+	if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+			      &hdl_size) &&
+		hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+		t->phy_mem_array_hdl = *((u16 *)hdl + idx);
+
+	/* Convert to MB */
+	size_mb = (u32)(sz >> 20);
+	if (size_mb < SMBIOS_MD_SIZE_EXT) {
+		/* Use 16-bit size field */
+		t->size = cpu_to_le16(size_mb);  /* In MB */
+		t->ext_size = cpu_to_le32(0);
+	} else {
+		/* Signal use of extended size field */
+		t->size = cpu_to_le16(SMBIOS_MD_SIZE_EXT);
+		t->ext_size = cpu_to_le32((u32)(sz >> 10)); /* In KB */
+	}
+
+	/* Write other general fields */
+	smbios_pop_type17_general_si(ctx, t);
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static int smbios_write_type17_mem(ulong *current, int handle,
+				   struct smbios_ctx *ctx, int idx,
+				   int type)
+{
+	struct smbios_type17 *t;
+	int len;
+	u8 *eos_addr;
+	void *hdl;
+	size_t hdl_size;
+
+	len = sizeof(*t);
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_MEMORY_DEVICE, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	if (type == SMBIOS_MEM_CUSTOM) {
+		smbios_pop_type17_size_si(ctx, t);
+
+		t->phy_mem_array_hdl =
+			smbios_get_val_si(ctx, "physical-memory-array-handle",
+					  SYSID_NONE, 0);
+	} else if (type == SMBIOS_MEM_FDT_MEM_NODE) {
+		smbios_pop_type17_size_from_memory_node(ctx->node, t);
+
+		/* Read the memory array handles */
+		if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+				      &hdl_size) &&
+		    hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+			t->phy_mem_array_hdl = *((u16 *)hdl + idx);
+	}
+
+	/* Write other general fields */
+	smbios_pop_type17_general_si(ctx, t);
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static int smbios_scan_mem_nodes(ulong *current, int *handle,
+				 struct smbios_ctx *ctx,
+				 smbios_write_memnode mem_cb,
+				 int *idx)
+{
+	int len = 0;
+	struct smbios_ctx ctx_bak;
+	ofnode child;
+	int hdl_base = *handle;
+
+	memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
+
+	for (child = ofnode_first_subnode(ofnode_root());
+	     ofnode_valid(child); child = ofnode_next_subnode(child)) {
+		const char *str;
+
+		/* Look up for 'device_type = "memory"' */
+		str = ofnode_read_string(child, "device_type");
+		if (!str || strcmp(str, "memory"))
+			continue;
+
+		ctx->node = child;
+		*handle = hdl_base + *idx;
+		/* Generate one instance for each 'memory' node */
+		len += mem_cb(current, *handle, ctx, *idx,
+			      SMBIOS_MEM_FDT_MEM_NODE);
+		memcpy(ctx, &ctx_bak, sizeof(*ctx));
+		(*idx)++;
+	}
+
+	return len;
+}
+
+static int smbios_scan_mctrl_subnodes(ulong *current, int *handle,
+				      struct smbios_ctx *ctx,
+				      smbios_write_memctrlnode mctrl_wcb,
+				      int *idx)
+{
+	int len = 0;
+	struct smbios_ctx ctx_bak;
+	ofnode child;
+
+	memcpy(&ctx_bak, ctx, sizeof(ctx_bak));
+
+	for (child = ofnode_first_subnode(ofnode_root());
+	     ofnode_valid(child); child = ofnode_next_subnode(child)) {
+		const char *compat;
+		const char *name;
+
+		/*
+		 * Look up for node with name or property 'compatible'
+		 * containing 'memory-controller'.
+		 */
+		name = ofnode_get_name(child);
+		compat = ofnode_read_string(child, "compatible");
+		if ((!compat || !strstr(compat, "memory-controller")) &&
+		    (!name || !strstr(name, "memory-controller")))
+			continue;
+
+		(*handle)++;
+		ctx->node = child;
+		/*
+		 * Generate one instance for each subnode of
+		 * 'memory-controller' which contains property 'size'.
+		 */
+		len += smbios_scan_memctrl_subnode(current, handle, ctx,
+						   *idx, mctrl_wcb);
+		memcpy(ctx, &ctx_bak, sizeof(*ctx));
+		(*idx)++;
+	}
+	return len;
+}
+
+static int smbios_write_type1719(ulong *current, int *handle,
+				 struct smbios_ctx *ctx,
+				 smbios_write_memnode mem_cb,
+				 smbios_write_memctrlnode mctrl_wcb)
+{
+	int len = 0;
+	int idx;
+
+	if (!IS_ENABLED(CONFIG_OF_CONTROL))
+		return 0;	/* Error, return 0-length */
+
+	/* Step 1: Scan any subnode exists */
+	len = smbios_scan_subnodes(current, ctx, handle, mem_cb,
+				   SMBIOS_MEM_CUSTOM);
+	if (len)
+		return len;
+
+	/* Step 2: Scan 'memory' node from the entire FDT */
+	idx = 0;
+	len += smbios_scan_mem_nodes(current, handle, ctx, mem_cb, &idx);
+
+	/* Step 3: Scan 'memory-controller' node from the entire FDT */
+	len += smbios_scan_mctrl_subnodes(current, handle, ctx, mctrl_wcb, &idx);
+
+	return len;
+}
+
+static int smbios_write_type17(ulong *current, int *handle,
+			       struct smbios_ctx *ctx)
+{
+	return smbios_write_type1719(current, handle, ctx,
+				     smbios_write_type17_mem,
+				     smbios_write_type17_from_memctrl_node);
+}
+
 #endif /* #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) */
 
 static int smbios_write_type32(ulong *current, int *handle,
@@ -1481,6 +1856,7 @@ static struct smbios_write_method smbios_write_funcs[] = {
 #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE)
 	{ smbios_write_type9, "system-slot"},
 	{ smbios_write_type16, "memory-array"},
+	{ smbios_write_type17, "memory-device"},
 #endif
 	{ smbios_write_type32, },
 	{ smbios_write_type127 },
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v6 5/6] smbios: add support for dynamic generation of Type 19 table
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
                   ` (3 preceding siblings ...)
  2026-02-13 22:52 ` [PATCH v6 4/6] smbios: add support for dynamic generation of Type 17 table Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-13 22:52 ` [PATCH v6 6/6] smbios: print the properties only when they exist in a specified version of spec Raymond Mao
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Tom Rini, Mark Kettenis, Heinrich Schuchardt,
	Ilias Apalodimas, Baocheng Su, Jan Kiszka, Li Hua Qian,
	Samuel Holland

This commit implements SMBIOS Type 19 (Memory Array Mapped Address)
generation with a hybrid approach supporting both:

1. Explicit definition via Device Tree 'smbios' node:
   Child node under '/smbios/smbios/memory-array-mapped-address' will be
   used to populate as individual Type 19 structure directly.
   - Properties follow SMBIOS field names with lowercase letters and
     hyphen-separated words (e.g., 'starting-address', 'ending-address',
     'partition-width', etc.).
   - This method supports precise platform-defined overrides and system
     descriptions.

2. Fallback to automatic DT-based discovery:
   If child node under '/smbios/smbios/memory-array-mapped-address' does
   not exist, the implementation will:
   - Scan all top-level 'memory@' nodes to populate Type 19 structure with
     inferred size and location data.
   - Scan nodes named or marked as 'memory-controller' and parse
     associated 'dimm@' subnodes (if present) to extract DIMM sizes and
     map them accordingly.

This dual-mode support enables flexible firmware SMBIOS reporting while
aligning with spec-compliant naming and runtime-detected memory topology.

Type 19 support is under GENERATE_SMBIOS_TABLE_VERBOSE to avoid
increasing rom size for those platforms which only require basic SMBIOS
support.

Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
---
Changes in v4:
- Initial patch.
Changes in v5:
- None.
Changes in v6:
- None.

 arch/arm/dts/smbios_generic.dtsi |   3 +
 cmd/smbios.c                     |  14 +++
 include/smbios.h                 |  11 +++
 include/smbios_def.h             |   5 ++
 lib/smbios.c                     | 150 +++++++++++++++++++++++++++++++
 5 files changed, 183 insertions(+)

diff --git a/arch/arm/dts/smbios_generic.dtsi b/arch/arm/dts/smbios_generic.dtsi
index fd2df8d02e0..fe16037fc20 100644
--- a/arch/arm/dts/smbios_generic.dtsi
+++ b/arch/arm/dts/smbios_generic.dtsi
@@ -86,6 +86,9 @@
 
 			memory-device {
 			};
+
+			memory-array-mapped-address {
+			};
 		};
 	};
 };
diff --git a/cmd/smbios.c b/cmd/smbios.c
index 39c9c44a28e..671c14e05b5 100644
--- a/cmd/smbios.c
+++ b/cmd/smbios.c
@@ -680,6 +680,17 @@ static void smbios_print_type17(struct smbios_type17 *table)
 	printf("\tRCD Revision Number: 0x%04x\n", table->rcd_rev_num);
 }
 
+static void smbios_print_type19(struct smbios_type19 *table)
+{
+	printf("Memory Array Mapped Address:\n");
+	printf("\tStarting Address: 0x%08x\n", table->start_addr);
+	printf("\tEnding Address: 0x%08x\n", table->end_addr);
+	printf("\tMemory Array Handle: 0x%04x\n", table->mem_array_hdl);
+	printf("\tPartition Width: 0x%04x\n", table->partition_wid);
+	printf("\tExtended Starting Address: 0x%016llx\n", table->ext_start_addr);
+	printf("\tExtended Ending Address: 0x%016llx\n", table->ext_end_addr);
+}
+
 static void smbios_print_type127(struct smbios_type127 *table)
 {
 	printf("End Of Table\n");
@@ -768,6 +779,9 @@ static int do_smbios(struct cmd_tbl *cmdtp, int flag, int argc,
 		case SMBIOS_MEMORY_DEVICE:
 			smbios_print_type17((struct smbios_type17 *)pos);
 			break;
+		case SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS:
+			smbios_print_type19((struct smbios_type19 *)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 2deafea9aa1..e4b5ff314d9 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -372,6 +372,17 @@ struct __packed smbios_type17 {
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
 
+struct __packed smbios_type19 {
+	struct smbios_header hdr;
+	u32 start_addr;
+	u32 end_addr;
+	u16 mem_array_hdl;
+	u8 partition_wid;
+	u64 ext_start_addr;
+	u64 ext_end_addr;
+	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 ce913f2f32a..ae50e1a808e 100644
--- a/include/smbios_def.h
+++ b/include/smbios_def.h
@@ -436,4 +436,9 @@
 #define SMBIOS_MD_ERRINFO_NONE		0xFFFE
 #define SMBIOS_MD_ERRINFO_NOERR		0xFFFF
 
+/* Memory Array Mapped Address */
+
+/* Partition Width */
+#define SMBIOS_MAMA_PW_DEF	1 /* not partitioned */
+
 #endif /* _SMBIOS_DEF_H_ */
diff --git a/lib/smbios.c b/lib/smbios.c
index 7c6ad63b1c7..d5f18c8bd69 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -1807,6 +1807,155 @@ static int smbios_write_type17(ulong *current, int *handle,
 				     smbios_write_type17_from_memctrl_node);
 }
 
+static void smbios_pop_type19_general_si(struct smbios_ctx *ctx,
+					 struct smbios_type19 *t)
+{
+	t->partition_wid =
+		smbios_get_val_si(ctx, "partition-width ",
+				  SYSID_NONE, SMBIOS_MAMA_PW_DEF);
+}
+
+static void smbios_pop_type19_addr_si(struct smbios_ctx *ctx,
+				      struct smbios_type19 *t)
+{
+	t->start_addr = smbios_get_val_si(ctx, "starting-address", SYSID_NONE,
+					  0);
+	t->end_addr = smbios_get_val_si(ctx, "ending-address", SYSID_NONE, 0);
+	t->ext_start_addr = smbios_get_u64_si(ctx, "extended-starting-address",
+					      SYSID_NONE, 0);
+	t->ext_end_addr = smbios_get_u64_si(ctx, "extended-ending-address",
+					    SYSID_NONE, 0);
+}
+
+static void
+smbios_pop_type19_addr_from_memory_node(ofnode node, struct smbios_type19 *t)
+{
+	const fdt32_t *reg;
+	int len;
+	u64 sz;
+	u64 addr;
+
+	/* Read property 'reg' from the node */
+	reg = ofnode_read_prop(node, "reg", &len);
+	if (!reg || len < sizeof(fdt32_t) * 4 || len % sizeof(fdt32_t))
+		return;
+
+	/* Combine hi/lo for size and address (typically 64-bit) */
+	sz = ((u64)fdt32_to_cpu(reg[2]) << 32) | fdt32_to_cpu(reg[3]);
+	addr = ((u64)fdt32_to_cpu(reg[0]) << 32) | fdt32_to_cpu(reg[1]);
+
+	t->ext_start_addr = cpu_to_le64(addr);
+	t->ext_end_addr = cpu_to_le64(addr + sz - 1);
+
+	/* If address range fits in 32-bit, populate legacy fields */
+	if ((addr + sz - 1) <= 0xFFFFFFFFULL) {
+		t->start_addr = cpu_to_le32((u32)addr);
+		t->end_addr   = cpu_to_le32((u32)(addr + sz - 1));
+	} else {
+		t->start_addr = cpu_to_le32(0xFFFFFFFF);
+		t->end_addr   = cpu_to_le32(0xFFFFFFFF);
+	}
+}
+
+static int
+smbios_write_type19_from_memctrl_node(ulong *current, int handle,
+				      struct smbios_ctx *ctx, int idx,
+				      u64 base, u64 sz)
+{
+	struct smbios_type19 *t;
+	int len;
+	u8 *eos_addr;
+	void *hdl;
+	size_t hdl_size;
+
+	len = sizeof(*t);
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	/* Read the memory array handles */
+	if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+			      &hdl_size) &&
+	    hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+		t->mem_array_hdl = *((u16 *)hdl + idx);
+
+	t->ext_start_addr = cpu_to_le64(base);
+	t->ext_end_addr = cpu_to_le64(base + sz - 1);
+
+	if ((base + sz - 1) <= 0xFFFFFFFFULL) {
+		t->start_addr = cpu_to_le32((u32)base);
+		t->end_addr   = cpu_to_le32((u32)(base + sz - 1));
+	} else {
+		t->start_addr = cpu_to_le32(0xFFFFFFFF);
+		t->end_addr   = cpu_to_le32(0xFFFFFFFF);
+	}
+
+	/* Write other general fields */
+	smbios_pop_type19_general_si(ctx, t);
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static int smbios_write_type19_mem(ulong *current, int handle,
+				   struct smbios_ctx *ctx, int idx,
+				   int type)
+{
+	struct smbios_type19 *t;
+	int len;
+	u8 *eos_addr;
+	void *hdl;
+	size_t hdl_size;
+
+	len = sizeof(*t);
+	t = map_sysmem(*current, len);
+	memset(t, 0, len);
+
+	fill_smbios_header(t, SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS, len, handle);
+
+	/* eos is at the end of the structure */
+	eos_addr = (u8 *)t + len - sizeof(t->eos);
+	smbios_set_eos(ctx, eos_addr);
+
+	if (type == SMBIOS_MEM_CUSTOM) {
+		smbios_pop_type19_addr_si(ctx, t);
+		t->mem_array_hdl = smbios_get_val_si(ctx, "memory-array-handle",
+						     SYSID_NONE, 0);
+	} else if (type == SMBIOS_MEM_FDT_MEM_NODE) {
+		smbios_pop_type19_addr_from_memory_node(ctx->node, t);
+		/* Read the memory array handles */
+		if (!sysinfo_get_data(ctx->dev, SYSID_SM_MEMARRAY_HANDLE, &hdl,
+				      &hdl_size) &&
+		    hdl_size == SYSINFO_MEM_HANDLE_MAX * sizeof(u16))
+			t->mem_array_hdl = *((u16 *)hdl + idx);
+	}
+
+	/* Write other general fields */
+	smbios_pop_type19_general_si(ctx, t);
+
+	len = t->hdr.length + smbios_string_table_len(ctx);
+	*current += len;
+	unmap_sysmem(t);
+
+	return len;
+}
+
+static int smbios_write_type19(ulong *current, int *handle,
+			       struct smbios_ctx *ctx)
+{
+	return smbios_write_type1719(current, handle, ctx,
+				     smbios_write_type19_mem,
+				     smbios_write_type19_from_memctrl_node);
+}
+
 #endif /* #if IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE) */
 
 static int smbios_write_type32(ulong *current, int *handle,
@@ -1857,6 +2006,7 @@ static struct smbios_write_method smbios_write_funcs[] = {
 	{ smbios_write_type9, "system-slot"},
 	{ smbios_write_type16, "memory-array"},
 	{ smbios_write_type17, "memory-device"},
+	{ smbios_write_type19, "memory-array-mapped-address"},
 #endif
 	{ smbios_write_type32, },
 	{ smbios_write_type127 },
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v6 6/6] smbios: print the properties only when they exist in a specified version of spec
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
                   ` (4 preceding siblings ...)
  2026-02-13 22:52 ` [PATCH v6 5/6] smbios: add support for dynamic generation of Type 19 table Raymond Mao
@ 2026-02-13 22:52 ` Raymond Mao
  2026-02-17  7:14 ` [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Ilias Apalodimas
  2026-02-18 16:00 ` Tom Rini
  7 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-13 22:52 UTC (permalink / raw)
  To: u-boot
  Cc: Raymond Mao, Tom Rini, Heinrich Schuchardt, Mark Kettenis,
	Ilias Apalodimas, Baocheng Su, Jan Kiszka, Li Hua Qian,
	Samuel Holland

By checking the payload length, we can know the version of the spec and
skip the ones which are not expected to exist.

Signed-off-by: Raymond Mao <raymondmaoca@gmail.com>
---
Changes in v5:
- Initial patch.
Changes in v6:
- None.

 cmd/smbios.c     | 65 ++++++++++++++++++++++++++++++++++++++++--------
 include/smbios.h | 32 ++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/cmd/smbios.c b/cmd/smbios.c
index 671c14e05b5..3fafa46d0a5 100644
--- a/cmd/smbios.c
+++ b/cmd/smbios.c
@@ -348,6 +348,8 @@ static void smbios_print_type0(struct smbios_type0 *table)
 	printf("\tBIOS ROM Size: 0x%02x\n", table->bios_rom_size);
 	printf("\tBIOS Characteristics: 0x%016llx\n",
 	       table->bios_characteristics);
+	if (table->hdr.length < SMBIOS_TYPE0_LENGTH_V24)
+		return;
 	printf("\tBIOS Characteristics Extension Byte 1: 0x%02x\n",
 	       table->bios_characteristics_ext1);
 	printf("\tBIOS Characteristics Extension Byte 2: 0x%02x\n",
@@ -360,6 +362,8 @@ static void smbios_print_type0(struct smbios_type0 *table)
 	       table->ec_major_release);
 	printf("\tEmbedded Controller Firmware Minor Release: 0x%02x\n",
 	       table->ec_minor_release);
+	if (table->hdr.length < SMBIOS_TYPE0_LENGTH_V31)
+		return;
 	printf("\tExtended BIOS ROM Size: 0x%04x\n",
 	       table->extended_bios_rom_size);
 }
@@ -371,17 +375,16 @@ static void smbios_print_type1(struct smbios_type1 *table)
 	smbios_print_str("Product Name", table, table->product_name);
 	smbios_print_str("Version", table, table->version);
 	smbios_print_str("Serial Number", table, table->serial_number);
-	if (table->hdr.length >= SMBIOS_TYPE1_LENGTH_V21) {
-		printf("\tUUID: %pUl\n", table->uuid);
-		smbios_print_lookup_str(wakeup_type_strings,
-					table->wakeup_type,
-					ARRAY_SIZE(wakeup_type_strings),
-					"Wake-up Type");
-	}
-	if (table->hdr.length >= SMBIOS_TYPE1_LENGTH_V24) {
-		smbios_print_str("SKU Number", table, table->sku_number);
-		smbios_print_str("Family", table, table->family);
-	}
+	if (table->hdr.length < SMBIOS_TYPE1_LENGTH_V21)
+		return;
+	printf("\tUUID: %pUl\n", table->uuid);
+	smbios_print_lookup_str(wakeup_type_strings, table->wakeup_type,
+				ARRAY_SIZE(wakeup_type_strings),
+				"Wake-up Type");
+	if (table->hdr.length < SMBIOS_TYPE1_LENGTH_V24)
+		return;
+	smbios_print_str("SKU Number", table, table->sku_number);
+	smbios_print_str("Family", table, table->family);
 }
 
 static void smbios_print_type2(struct smbios_type2 *table)
@@ -501,21 +504,31 @@ static void smbios_print_type4(struct smbios_type4 *table)
 	printf("\tL1 Cache Handle: 0x%04x\n", table->l1_cache_handle);
 	printf("\tL2 Cache Handle: 0x%04x\n", table->l2_cache_handle);
 	printf("\tL3 Cache Handle: 0x%04x\n", table->l3_cache_handle);
+	if (table->hdr.length < SMBIOS_TYPE4_LENGTH_V23)
+		return;
 	smbios_print_str("Serial Number", table, table->serial_number);
 	smbios_print_str("Asset Tag", table, table->asset_tag);
 	smbios_print_str("Part Number", table, table->part_number);
+	if (table->hdr.length < SMBIOS_TYPE4_LENGTH_V25)
+		return;
 	printf("\tCore Count: 0x%02x\n", table->core_count);
 	printf("\tCore Enabled: 0x%02x\n", table->core_enabled);
 	printf("\tThread Count: 0x%02x\n", table->thread_count);
 	printf("\tProcessor Characteristics: 0x%04x\n",
 	       table->processor_characteristics);
+	if (table->hdr.length < SMBIOS_TYPE4_LENGTH_V26)
+		return;
 	smbios_print_lookup_str(processor_family_strings,
 				table->processor_family2,
 				ARRAY_SIZE(processor_family_strings),
 				"Processor Family 2");
+	if (table->hdr.length < SMBIOS_TYPE4_LENGTH_V30)
+		return;
 	printf("\tCore Count 2: 0x%04x\n", table->core_count2);
 	printf("\tCore Enabled 2: 0x%04x\n", table->core_enabled2);
 	printf("\tThread Count 2: 0x%04x\n", table->thread_count2);
+	if (table->hdr.length < SMBIOS_TYPE4_LENGTH_V36)
+		return;
 	printf("\tThread Enabled: 0x%04x\n", table->thread_enabled);
 }
 
@@ -529,6 +542,8 @@ static void smbios_print_type7(struct smbios_type7 *table)
 	printf("\tInstalled Size: 0x%04x\n", table->inst_size.data);
 	printf("\tSupported SRAM Type: 0x%04x\n", table->supp_sram_type.data);
 	printf("\tCurrent SRAM Type: 0x%04x\n", table->curr_sram_type.data);
+	if (table->hdr.length < SMBIOS_TYPE7_LENGTH_V21)
+		return;
 	printf("\tCache Speed: 0x%02x\n", table->speed);
 	smbios_print_lookup_str(err_corr_type_strings,
 				table->err_corr_type,
@@ -542,6 +557,8 @@ static void smbios_print_type7(struct smbios_type7 *table)
 				table->associativity,
 				ARRAY_SIZE(associativity_strings),
 				"Associativity");
+	if (table->hdr.length < SMBIOS_TYPE7_LENGTH_V31)
+		return;
 	printf("\tMaximum Cache Size 2: 0x%08x\n", table->max_size2.data);
 	printf("\tInstalled Cache Size 2: 0x%08x\n", table->inst_size2.data);
 }
@@ -574,8 +591,12 @@ static void smbios_print_type9(struct smbios_type9 *table)
 	printf("\tSlot ID: 0x%04x\n", table->slot_id);
 	printf("\tSlot Characteristics 1: 0x%04x\n",
 	       table->slot_characteristics_1);
+	if (table->hdr.length < SMBIOS_TYPE9_LENGTH_V21)
+		return;
 	printf("\tSlot Characteristics 2: 0x%04x\n",
 	       table->slot_characteristics_2);
+	if (table->hdr.length < SMBIOS_TYPE9_LENGTH_V26)
+		return;
 	printf("\tSegment Group Number (Base): 0x%04x\n",
 	       table->segment_group_number);
 	printf("\tBus Number (Base): 0x%04x\n", table->bus_number);
@@ -611,6 +632,8 @@ static void smbios_print_type9(struct smbios_type9 *table)
 static void smbios_print_type16(struct smbios_type16 *table)
 {
 	printf("Physical Memory Array:\n");
+	if (table->hdr.length < SMBIOS_TYPE16_LENGTH_V21)
+		return;
 	smbios_print_lookup_str(ma_location_strings, table->location,
 				ARRAY_SIZE(ma_location_strings), "Location");
 	smbios_print_lookup_str(ma_use_strings, table->use,
@@ -622,12 +645,16 @@ static void smbios_print_type16(struct smbios_type16 *table)
 	printf("\tMemory Error Information Handle: 0x%04x\n",
 	       table->mem_err_info_hdl);
 	printf("\tNumber of Memory Devices: 0x%04x\n", table->num_of_mem_dev);
+	if (table->hdr.length < SMBIOS_TYPE16_LENGTH_V27)
+		return;
 	printf("\tExtended Maximum Capacity: 0x%016llx\n", table->ext_max_cap);
 }
 
 static void smbios_print_type17(struct smbios_type17 *table)
 {
 	printf("Memory Device:\n");
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V21)
+		return;
 	printf("\tPhysical Memory Array Handle: 0x%04x\n",
 	       table->phy_mem_array_hdl);
 	printf("\tMemory Error Information Handle: 0x%04x\n",
@@ -644,17 +671,27 @@ static void smbios_print_type17(struct smbios_type17 *table)
 	smbios_print_lookup_str(md_type_strings, table->mem_type,
 				ARRAY_SIZE(md_type_strings), "Memory Type");
 	printf("\tType Detail: 0x%04x\n", table->type_detail);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V23)
+		return;
 	printf("\tSpeed: 0x%04x\n", table->speed);
 	smbios_print_str("Manufacturer", table, table->manufacturer);
 	smbios_print_str("Serial Number", table, table->serial_number);
 	smbios_print_str("Asset Tag", table, table->asset_tag);
 	smbios_print_str("Part Number", table, table->part_number);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V26)
+		return;
 	printf("\tAttributes: 0x%04x\n", table->attributes);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V27)
+		return;
 	printf("\tExtended Size: 0x%08x\n", table->ext_size);
 	printf("\tConfigured Memory Speed: 0x%04x\n", table->config_mem_speed);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V28)
+		return;
 	printf("\tMinimum voltage: 0x%04x\n", table->min_voltage);
 	printf("\tMaximum voltage: 0x%04x\n", table->max_voltage);
 	printf("\tConfigured voltage: 0x%04x\n", table->config_voltage);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V32)
+		return;
 	smbios_print_lookup_str(md_tech_strings, table->mem_tech,
 				ARRAY_SIZE(md_tech_strings),
 				"Memory Technology");
@@ -671,6 +708,8 @@ static void smbios_print_type17(struct smbios_type17 *table)
 	printf("\tVolatile Size: 0x%016llx\n", table->volatile_size);
 	printf("\tCache Size: 0x%016llx\n", table->cache_size);
 	printf("\tLogical Size: 0x%016llx\n", table->logical_size);
+	if (table->hdr.length < SMBIOS_TYPE17_LENGTH_V33)
+		return;
 	printf("\tExtended Speed: 0x%04x\n", table->ext_speed);
 	printf("\tExtended Configured Memory Speed: 0x%04x\n",
 	       table->ext_config_mem_speed);
@@ -683,10 +722,14 @@ static void smbios_print_type17(struct smbios_type17 *table)
 static void smbios_print_type19(struct smbios_type19 *table)
 {
 	printf("Memory Array Mapped Address:\n");
+	if (table->hdr.length < SMBIOS_TYPE19_LENGTH_V21)
+		return;
 	printf("\tStarting Address: 0x%08x\n", table->start_addr);
 	printf("\tEnding Address: 0x%08x\n", table->end_addr);
 	printf("\tMemory Array Handle: 0x%04x\n", table->mem_array_hdl);
 	printf("\tPartition Width: 0x%04x\n", table->partition_wid);
+	if (table->hdr.length < SMBIOS_TYPE19_LENGTH_V27)
+		return;
 	printf("\tExtended Starting Address: 0x%016llx\n", table->ext_start_addr);
 	printf("\tExtended Ending Address: 0x%016llx\n", table->ext_end_addr);
 }
diff --git a/include/smbios.h b/include/smbios.h
index e4b5ff314d9..39090d3ba18 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -110,10 +110,42 @@ struct __packed smbios_type0 {
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
 
+#define SMBIOS_TYPE0_LENGTH_V24		0x18
+#define SMBIOS_TYPE0_LENGTH_V31		0x1a
+
 #define SMBIOS_TYPE1_LENGTH_V20		0x08
 #define SMBIOS_TYPE1_LENGTH_V21		0x19
 #define SMBIOS_TYPE1_LENGTH_V24		0x1b
 
+#define SMBIOS_TYPE4_LENGTH_V20		0x1a
+#define SMBIOS_TYPE4_LENGTH_V23		0x23
+#define SMBIOS_TYPE4_LENGTH_V25		0x28
+#define SMBIOS_TYPE4_LENGTH_V26		0x2a
+#define SMBIOS_TYPE4_LENGTH_V30		0x30
+#define SMBIOS_TYPE4_LENGTH_V36		0x32
+
+#define SMBIOS_TYPE7_LENGTH_V20		0x0f
+#define SMBIOS_TYPE7_LENGTH_V21		0x13
+#define SMBIOS_TYPE7_LENGTH_V31		0x1b
+
+#define SMBIOS_TYPE9_LENGTH_V20		0x0c
+#define SMBIOS_TYPE9_LENGTH_V21		0x0d
+#define SMBIOS_TYPE9_LENGTH_V26		0x11
+
+#define SMBIOS_TYPE16_LENGTH_V21	0x0f
+#define SMBIOS_TYPE16_LENGTH_V27	0x17
+
+#define SMBIOS_TYPE17_LENGTH_V21	0x15
+#define SMBIOS_TYPE17_LENGTH_V23	0x1b
+#define SMBIOS_TYPE17_LENGTH_V26	0x1c
+#define SMBIOS_TYPE17_LENGTH_V27	0x22
+#define SMBIOS_TYPE17_LENGTH_V28	0x28
+#define SMBIOS_TYPE17_LENGTH_V32	0x54
+#define SMBIOS_TYPE17_LENGTH_V33	0x5c
+
+#define SMBIOS_TYPE19_LENGTH_V21	0x0f
+#define SMBIOS_TYPE19_LENGTH_V27	0x1f
+
 struct __packed smbios_type1 {
 	struct smbios_header hdr;
 	u8 manufacturer;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
                   ` (5 preceding siblings ...)
  2026-02-13 22:52 ` [PATCH v6 6/6] smbios: print the properties only when they exist in a specified version of spec Raymond Mao
@ 2026-02-17  7:14 ` Ilias Apalodimas
  2026-02-17 14:01   ` Raymond Mao
  2026-02-18 16:00 ` Tom Rini
  7 siblings, 1 reply; 10+ messages in thread
From: Ilias Apalodimas @ 2026-02-17  7:14 UTC (permalink / raw)
  To: Raymond Mao, Tom Rini
  Cc: u-boot, Raymond Mao, Mark Kettenis, Heinrich Schuchardt,
	Baocheng Su, Li Hua Qian, Jan Kiszka, Samuel Holland

Tom, Raymond

I tested the patches and they now work properly in linux.
Unfortunately I don't have time to review them depth, but I think we
can pull them in since they improve the SMBIOS reporting overall


For the series
Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

On Sat, 14 Feb 2026 at 00:53, Raymond Mao <raymondmaoca@gmail.com> wrote:
>
> From: Raymond Mao <raymond.mao@riscstar.com>
>
> This series finish the last missing puzzle of required SMBIOS types by:
> 1) Fixing duplicated handles when multiple instances exist in one type;
> 2) Implementing the rest of required types 9/16/17/19;
> 3) Adding version control when printing properties for all types.
>
> Type 9/16/17/19 are generally DT-based, the idea is to write these tables
> using a hybrid approach:
> Explicit DT definitions under existing '/smbios/smbios' take precedence,
> with fallback to scan and interpret values from the entire DT.
>
> Moreover, all below APIs:
> smbios_get_val_si()
> smbios_get_u64_si()
> smbios_add_prop_si()
> are on top of sysinfo, thus allow vendors to get values from other
> subsystems by implementing their own sysinfo driver if needed.
>
> Raymond Mao (6):
>   smbios: Fix duplicated smbios handles
>   smbios: add support for dynamic generation of Type 9 system slot
>     tables
>   smbios: add support for dynamic generation of Type 16 table
>   smbios: add support for dynamic generation of Type 17 table
>   smbios: add support for dynamic generation of Type 19 table
>   smbios: print the properties only when they exist in a specified
>     version of spec
>
>  arch/arm/dts/smbios_generic.dtsi |   12 +
>  cmd/smbios.c                     |  365 +++++++++-
>  drivers/sysinfo/smbios.c         |    5 +
>  include/smbios.h                 |  151 ++++
>  include/smbios_def.h             |  250 +++++++
>  include/sysinfo.h                |    4 +
>  lib/smbios.c                     | 1151 +++++++++++++++++++++++++++++-
>  7 files changed, 1905 insertions(+), 33 deletions(-)
>
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling
  2026-02-17  7:14 ` [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Ilias Apalodimas
@ 2026-02-17 14:01   ` Raymond Mao
  0 siblings, 0 replies; 10+ messages in thread
From: Raymond Mao @ 2026-02-17 14:01 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Tom Rini, u-boot, Raymond Mao, Mark Kettenis, Heinrich Schuchardt,
	Baocheng Su, Li Hua Qian, Jan Kiszka, Samuel Holland

Hi Ilias,

On Tue, Feb 17, 2026 at 2:15 AM Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Tom, Raymond
>
> I tested the patches and they now work properly in linux.
> Unfortunately I don't have time to review them depth, but I think we
> can pull them in since they improve the SMBIOS reporting overall
>
>
> For the series
> Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
>

Thank you so much for spending the time to test.

Regards
Raymons

> On Sat, 14 Feb 2026 at 00:53, Raymond Mao <raymondmaoca@gmail.com> wrote:
> >
> > From: Raymond Mao <raymond.mao@riscstar.com>
> >
> > This series finish the last missing puzzle of required SMBIOS types by:
> > 1) Fixing duplicated handles when multiple instances exist in one type;
> > 2) Implementing the rest of required types 9/16/17/19;
> > 3) Adding version control when printing properties for all types.
> >
> > Type 9/16/17/19 are generally DT-based, the idea is to write these tables
> > using a hybrid approach:
> > Explicit DT definitions under existing '/smbios/smbios' take precedence,
> > with fallback to scan and interpret values from the entire DT.
> >
> > Moreover, all below APIs:
> > smbios_get_val_si()
> > smbios_get_u64_si()
> > smbios_add_prop_si()
> > are on top of sysinfo, thus allow vendors to get values from other
> > subsystems by implementing their own sysinfo driver if needed.
> >
> > Raymond Mao (6):
> >   smbios: Fix duplicated smbios handles
> >   smbios: add support for dynamic generation of Type 9 system slot
> >     tables
> >   smbios: add support for dynamic generation of Type 16 table
> >   smbios: add support for dynamic generation of Type 17 table
> >   smbios: add support for dynamic generation of Type 19 table
> >   smbios: print the properties only when they exist in a specified
> >     version of spec
> >
> >  arch/arm/dts/smbios_generic.dtsi |   12 +
> >  cmd/smbios.c                     |  365 +++++++++-
> >  drivers/sysinfo/smbios.c         |    5 +
> >  include/smbios.h                 |  151 ++++
> >  include/smbios_def.h             |  250 +++++++
> >  include/sysinfo.h                |    4 +
> >  lib/smbios.c                     | 1151 +++++++++++++++++++++++++++++-
> >  7 files changed, 1905 insertions(+), 33 deletions(-)
> >
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling
  2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
                   ` (6 preceding siblings ...)
  2026-02-17  7:14 ` [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Ilias Apalodimas
@ 2026-02-18 16:00 ` Tom Rini
  7 siblings, 0 replies; 10+ messages in thread
From: Tom Rini @ 2026-02-18 16:00 UTC (permalink / raw)
  To: u-boot, Raymond Mao
  Cc: Raymond Mao, Mark Kettenis, Heinrich Schuchardt, Ilias Apalodimas,
	Baocheng Su, Li Hua Qian, Jan Kiszka, Samuel Holland

On Fri, 13 Feb 2026 17:52:45 -0500, Raymond Mao wrote:

> From: Raymond Mao <raymond.mao@riscstar.com>
> 
> This series finish the last missing puzzle of required SMBIOS types by:
> 1) Fixing duplicated handles when multiple instances exist in one type;
> 2) Implementing the rest of required types 9/16/17/19;
> 3) Adding version control when printing properties for all types.
> 
> [...]

Applied to u-boot/next, thanks!

[1/6] smbios: Fix duplicated smbios handles
      commit: 87f8a143da550a2de39dd5b30d3547bc8dfd7174
[2/6] smbios: add support for dynamic generation of Type 9 system slot tables
      commit: 83b28b55d74f884a30c47238dc8bdf9fbe6e495c
[3/6] smbios: add support for dynamic generation of Type 16 table
      commit: 374896158b435843d8ecf2c04c9985b0321295e0
[4/6] smbios: add support for dynamic generation of Type 17 table
      commit: 23674dee60240393dd17836c05df5b4f4aa01e5c
[5/6] smbios: add support for dynamic generation of Type 19 table
      commit: 41b7a09d24d878f748eba87ae85575043224148b
[6/6] smbios: print the properties only when they exist in a specified version of spec
      commit: 4c816ddbadb1bd8bfe09a457538d4f518151fd6d
-- 
Tom



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-02-18 16:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-13 22:52 [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Raymond Mao
2026-02-13 22:52 ` [PATCH v6 1/6] smbios: Fix duplicated smbios handles Raymond Mao
2026-02-13 22:52 ` [PATCH v6 2/6] smbios: add support for dynamic generation of Type 9 system slot tables Raymond Mao
2026-02-13 22:52 ` [PATCH v6 3/6] smbios: add support for dynamic generation of Type 16 table Raymond Mao
2026-02-13 22:52 ` [PATCH v6 4/6] smbios: add support for dynamic generation of Type 17 table Raymond Mao
2026-02-13 22:52 ` [PATCH v6 5/6] smbios: add support for dynamic generation of Type 19 table Raymond Mao
2026-02-13 22:52 ` [PATCH v6 6/6] smbios: print the properties only when they exist in a specified version of spec Raymond Mao
2026-02-17  7:14 ` [PATCH v6 0/6] Implement all missing SMBIOS types required by distro tooling Ilias Apalodimas
2026-02-17 14:01   ` Raymond Mao
2026-02-18 16:00 ` Tom Rini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox