summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-02-18 08:27:58 -0600
committerTom Rini <[email protected]>2026-02-18 08:27:58 -0600
commite8dd062642d91a00ddb596787ff35bd3641a6a21 (patch)
treeb1f660d3176f9b150375278f02974bcb12f84adb
parent9ddccb51443d4856e5ad2f06cc3552627b86b3d9 (diff)
parent4c816ddbadb1bd8bfe09a457538d4f518151fd6d (diff)
Merge patch series "Implement all missing SMBIOS types required by distro tooling"
Raymond Mao <[email protected]> says: From: Raymond Mao <[email protected]> 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. Link: https://lore.kernel.org/r/[email protected]
-rw-r--r--arch/arm/dts/smbios_generic.dtsi12
-rw-r--r--cmd/smbios.c365
-rw-r--r--drivers/sysinfo/smbios.c5
-rw-r--r--include/smbios.h151
-rw-r--r--include/smbios_def.h250
-rw-r--r--include/sysinfo.h4
-rw-r--r--lib/smbios.c1151
7 files changed, 1905 insertions, 33 deletions
diff --git a/arch/arm/dts/smbios_generic.dtsi b/arch/arm/dts/smbios_generic.dtsi
index fc168317c9e..fe16037fc20 100644
--- a/arch/arm/dts/smbios_generic.dtsi
+++ b/arch/arm/dts/smbios_generic.dtsi
@@ -77,6 +77,18 @@
SMBIOS_CACHE_OP_WB)>;
};
};
+
+ system-slot {
+ };
+
+ memory-array {
+ };
+
+ memory-device {
+ };
+
+ memory-array-mapped-address {
+ };
};
};
};
diff --git a/cmd/smbios.c b/cmd/smbios.c
index ed419f19028..3fafa46d0a5 100644
--- a/cmd/smbios.c
+++ b/cmd/smbios.c
@@ -119,6 +119,149 @@ 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" },
+};
+
+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" },
+};
+
+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
*
@@ -205,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",
@@ -217,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);
}
@@ -228,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)
@@ -358,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);
}
@@ -386,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,
@@ -399,10 +557,183 @@ 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);
}
+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);
+ 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);
+ 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_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,
+ 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);
+ 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",
+ 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);
+ 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");
+ 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);
+ 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);
+ 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_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);
+}
+
static void smbios_print_type127(struct smbios_type127 *table)
{
printf("End Of Table\n");
@@ -482,6 +813,18 @@ 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_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_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/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 f2f7483bce5..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;
@@ -264,6 +296,125 @@ 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];
+};
+
+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_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_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 81c5781217f..ae50e1a808e 100644
--- a/include/smbios_def.h
+++ b/include/smbios_def.h
@@ -191,4 +191,254 @@
#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
+
+/* 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
+
+/* 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
+
+/* Memory Array Mapped Address */
+
+/* Partition Width */
+#define SMBIOS_MAMA_PW_DEF 1 /* not partitioned */
+
#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 b8c2846277a..d5f18c8bd69 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,18 @@ struct smbios_ctx {
char *last_str;
};
+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
*
@@ -103,7 +151,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);
/**
@@ -222,6 +270,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,10 +289,58 @@ 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;
}
+#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
*
@@ -364,7 +461,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 +469,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 +520,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 +531,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 +568,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 +582,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 +616,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 +625,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 +645,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 +766,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 +776,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 +925,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 +948,1017 @@ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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,
+static int smbios_write_type32(ulong *current, int *handle,
struct smbios_ctx *ctx)
{
struct smbios_type32 *t;
@@ -866,7 +1966,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 +1975,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 +1983,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);
@@ -902,6 +2002,12 @@ 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"},
+ { smbios_write_type16, "memory-array"},
+ { smbios_write_type17, "memory-device"},
+ { smbios_write_type19, "memory-array-mapped-address"},
+#endif
{ smbios_write_type32, },
{ smbios_write_type127 },
};
@@ -954,7 +2060,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++;
}
/*