diff options
| author | Tom Rini <[email protected]> | 2025-01-14 14:29:49 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-01-14 14:29:49 -0600 |
| commit | 079214e4beea2deac88f3ceaeda56b6914190aec (patch) | |
| tree | e668614c5186bea838fd4dea79d9d4744effc14f /drivers | |
| parent | e17be5a07ad6947c13c39936be812a65e694ecee (diff) | |
| parent | 0af16b35561f09e529f3ced1b1f738858ec462fb (diff) | |
Merge patch series "SMBIOS improvements"
Raymond Mao <[email protected]> says:
Motivations for changes:
Current SMBIOS library and command-line tool is not fully matching with
the requirements:
1. Missing support for other mandatory types (#7, #9, #16, #17, #19).
2. Only a few platforms support SMBIOS node from the device tree.
3. Values of some fields are hardcoded in the library other than fetching
from the device hardware.
4. Embedded data with dynamic length is not supported (E.g. Contained
Object Handles in Type #2 and Contained Elements in Type #3)
Changes:
1. Refactor the SMBIOS library and command-line tool to better align with
the SMBIOS spec.
2. Create an arch-specific driver for all aarch64-based platforms to fetch
SMBIOS private data from the device hardware (processor and cache).
3. Create a sysinfo driver to poppulate platform SMBIOS private data.
4. Add generic SMBIOS DTS file for arm64 platforms for those common strings
and values which cannot be retrieved from the system registers.
Vendors can create their own SMBIOS node using this as an example.
For those boards without SMBIOS nodes, this DTS file can be included to
have a generic SMBIOS information of the system.
5. Add support for Type #7 (Cache Information) and link its handles to
Type #4.
6. To minimize size-growth for those platforms which have not sufficient
ROM spaces or the platforms which don't need detailed SMBIOS
information, new added fields are only being built when kconfig
GENERATE_SMBIOS_TABLE_VERBOSE is selected.
Once this patch is acceptted, subsequent patch sets will add other missing
types (#9, #16, #17, #19).
Tests:
To test this with QEMU arm64, please follow the guide on dt_qemu.rst to
get a merged DT to run with.
```
qemu-system-aarch64 -machine virt -machine dumpdtb=qemu.dtb
cat <(dtc -I dtb qemu.dtb) <(dtc -I dtb ./dts/dt.dtb | grep -v /dts-v1/) \
| dtc - -o merged.dtb
qemu-system-aarch64 -machine virt -nographic -bios u-boot.bin \
-dtb merged.dtb
```
Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/misc/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/sysinfo/sandbox.c | 19 | ||||
| -rw-r--r-- | drivers/sysinfo/sandbox.h | 1 | ||||
| -rw-r--r-- | drivers/sysinfo/smbios.c | 228 | ||||
| -rw-r--r-- | drivers/sysinfo/sysinfo-uclass.c | 20 |
5 files changed, 269 insertions, 1 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..da84b35e804 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -568,7 +568,7 @@ config QFW_MMIO config QFW_SMBIOS bool default y - depends on QFW && SMBIOS && !SANDBOX + depends on QFW && SMBIOS && !SANDBOX && !SYSINFO_SMBIOS help Hidden option to read SMBIOS tables from QEMU. diff --git a/drivers/sysinfo/sandbox.c b/drivers/sysinfo/sandbox.c index d39720958f0..af54fe87596 100644 --- a/drivers/sysinfo/sandbox.c +++ b/drivers/sysinfo/sandbox.c @@ -13,6 +13,7 @@ struct sysinfo_sandbox_priv { bool called_detect; int test_i1; int test_i2; + u32 test_data[2]; }; char vacation_spots[][64] = {"R'lyeh", "Dreamlands", "Plateau of Leng", @@ -24,6 +25,8 @@ int sysinfo_sandbox_detect(struct udevice *dev) priv->called_detect = true; priv->test_i2 = 100; + priv->test_data[0] = 0xabcdabcd; + priv->test_data[1] = 0xdeadbeef; return 0; } @@ -79,6 +82,21 @@ int sysinfo_sandbox_get_str(struct udevice *dev, int id, size_t size, char *val) return -ENOENT; } +int sysinfo_sandbox_get_data(struct udevice *dev, int id, void **buf, + size_t *size) +{ + struct sysinfo_sandbox_priv *priv = dev_get_priv(dev); + + switch (id) { + case DATA_TEST: + *buf = priv->test_data; + *size = sizeof(priv->test_data); + return 0; + } + + return -ENOENT; +} + static const struct udevice_id sysinfo_sandbox_ids[] = { { .compatible = "sandbox,sysinfo-sandbox" }, { /* sentinel */ } @@ -89,6 +107,7 @@ static const struct sysinfo_ops sysinfo_sandbox_ops = { .get_bool = sysinfo_sandbox_get_bool, .get_int = sysinfo_sandbox_get_int, .get_str = sysinfo_sandbox_get_str, + .get_data = sysinfo_sandbox_get_data, }; int sysinfo_sandbox_probe(struct udevice *dev) diff --git a/drivers/sysinfo/sandbox.h b/drivers/sysinfo/sandbox.h index a7cbac0ce18..47b7f5ef9fe 100644 --- a/drivers/sysinfo/sandbox.h +++ b/drivers/sysinfo/sandbox.h @@ -9,4 +9,5 @@ enum { INT_TEST1, INT_TEST2, STR_VACATIONSPOT, + DATA_TEST, }; diff --git a/drivers/sysinfo/smbios.c b/drivers/sysinfo/smbios.c index a7ac8e3f072..99104274f72 100644 --- a/drivers/sysinfo/smbios.c +++ b/drivers/sysinfo/smbios.c @@ -5,14 +5,240 @@ */ #include <dm.h> +#include <smbios_plat.h> #include <sysinfo.h> +/* platform information storage */ +struct processor_info processor_info; +struct cache_info cache_info[SYSINFO_CACHE_LVL_MAX]; +struct sysinfo_plat sysinfo_smbios_p = { + /* Processor Information */ + .processor = &processor_info, + /* Cache Information */ + .cache = &cache_info[0], +}; + +/* structure for smbios private data storage */ +struct sysinfo_plat_priv { + struct processor_info *t4; + struct smbios_type7 t7[SYSINFO_CACHE_LVL_MAX]; + u16 cache_handles[SYSINFO_CACHE_LVL_MAX]; + u8 cache_level; +}; + +static void smbios_cache_info_dump(struct smbios_type7 *cache_info) +{ + log_debug("SMBIOS Type 7 (Cache Information):\n"); + log_debug("Cache Configuration: 0x%04x\n", cache_info->config.data); + log_debug("Maximum Cache Size: %u KB\n", cache_info->max_size.data); + log_debug("Installed Size: %u KB\n", cache_info->inst_size.data); + log_debug("Supported SRAM Type: 0x%04x\n", + cache_info->supp_sram_type.data); + log_debug("Current SRAM Type: 0x%04x\n", + cache_info->curr_sram_type.data); + log_debug("Cache Speed: %u\n", cache_info->speed); + log_debug("Error Correction Type: %u\n", cache_info->err_corr_type); + log_debug("System Cache Type: %u\n", cache_info->sys_cache_type); + log_debug("Associativity: %u\n", cache_info->associativity); + log_debug("Maximum Cache Size 2: %u KB\n", cache_info->max_size2.data); + log_debug("Installed Cache Size 2: %u KB\n", + cache_info->inst_size2.data); +} + +/* weak function for the platforms not yet supported */ +__weak int sysinfo_get_cache_info(u8 level, struct cache_info *cache_info) +{ + return -ENOSYS; +} + +__weak int sysinfo_get_processor_info(struct processor_info *pinfo) +{ + return -ENOSYS; +} + +void sysinfo_cache_info_default(struct cache_info *ci) +{ + memset(ci, 0, sizeof(*ci)); + ci->config.data = SMBIOS_CACHE_LOCATE_UNKNOWN | SMBIOS_CACHE_OP_UND; + ci->supp_sram_type.fields.unknown = 1; + ci->curr_sram_type.fields.unknown = 1; + ci->speed = SMBIOS_CACHE_SPEED_UNKNOWN; + ci->err_corr_type = SMBIOS_CACHE_ERRCORR_UNKNOWN; + ci->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_UNKNOWN; +} + +static int sysinfo_plat_detect(struct udevice *dev) +{ + return 0; +} + +static int sysinfo_plat_get_str(struct udevice *dev, int id, + size_t size, char *val) +{ + struct sysinfo_plat_priv *priv = dev_get_priv(dev); + const char *str = NULL; + + switch (id) { + case SYSID_SM_PROCESSOR_MANUFACT: + str = priv->t4->manufacturer; + break; + default: + break; + } + + if (!str) + return -ENOSYS; + + strlcpy(val, str, size); + + return 0; +} + +static int sysinfo_plat_get_int(struct udevice *dev, int id, int *val) +{ + struct sysinfo_plat_priv *priv = dev_get_priv(dev); + u8 i; + + if (id >= SYSID_SM_CACHE_INFO_START && + id <= SYSID_SM_CACHE_INFO_END) { + /* For smbios type 7 */ + for (i = 0; i < priv->cache_level; i++) { + switch (id - i) { + case SYSID_SM_CACHE_MAX_SIZE: + *val = priv->t7[i].max_size.data; + return 0; + case SYSID_SM_CACHE_INST_SIZE: + *val = priv->t7[i].inst_size.data; + return 0; + case SYSID_SM_CACHE_SCACHE_TYPE: + *val = priv->t7[i].sys_cache_type; + return 0; + case SYSID_SM_CACHE_ASSOC: + *val = priv->t7[i].associativity; + return 0; + case SYSID_SM_CACHE_MAX_SIZE2: + *val = priv->t7[i].max_size2.data; + return 0; + case SYSID_SM_CACHE_INST_SIZE2: + *val = priv->t7[i].inst_size2.data; + return 0; + default: + break; + } + } + return -ENOSYS; + } + + switch (id) { + case SYSID_SM_PROCESSOR_CORE_CNT: + *val = priv->t4->core_count; + break; + case SYSID_SM_PROCESSOR_CORE_EN: + *val = priv->t4->core_enabled; + break; + case SYSID_SM_PROCESSOR_CHARA: + *val = priv->t4->characteristics; + break; + case SYSID_SM_CACHE_LEVEL: + if (!priv->cache_level) /* No cache detected */ + return -ENOSYS; + *val = priv->cache_level - 1; + break; + default: + return -ENOSYS; + } + + return 0; +} + +static int sysinfo_plat_get_data(struct udevice *dev, int id, void **buf, + size_t *size) +{ + struct sysinfo_plat_priv *priv = dev_get_priv(dev); + + switch (id) { + case SYSID_SM_PROCESSOR_ID: + *buf = priv->t4->id; + *size = sizeof(priv->t4->id); + break; + case SYSID_SM_CACHE_HANDLE: + *buf = &priv->cache_handles[0]; + *size = sizeof(priv->cache_handles); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int sysinfo_plat_probe(struct udevice *dev) +{ + struct sysinfo_plat_priv *priv = dev_get_priv(dev); + struct sysinfo_plat *plat = &sysinfo_smbios_p; + u8 level; + + if (!sysinfo_get_processor_info(plat->processor)) + priv->t4 = plat->processor; + + for (level = 0; level < SYSINFO_CACHE_LVL_MAX; level++) { + struct cache_info *pcache = plat->cache + level; + + if (sysinfo_get_cache_info(level, pcache)) + break; /* no more levels */ + + /* + * Fill in the SMBIOS type 7 structure, + * skip the header members (type, length, handle), + * and the ones in DT smbios node. + */ + priv->t7[level].sys_cache_type = pcache->cache_type; + priv->t7[level].associativity = pcache->associativity; + + if (pcache->max_size > SMBIOS_CACHE_SIZE_EXT_KB) { + priv->t7[level].max_size.data = 0xFFFF; + priv->t7[level].max_size2.fields.size = + pcache->max_size / 64; + priv->t7[level].max_size2.fields.granu = + SMBIOS_CACHE_GRANU_64K; + } else { + priv->t7[level].max_size.fields.size = pcache->max_size; + priv->t7[level].max_size.fields.granu = + SMBIOS_CACHE_GRANU_1K; + priv->t7[level].max_size2.data = 0; + } + if (pcache->inst_size > SMBIOS_CACHE_SIZE_EXT_KB) { + priv->t7[level].inst_size.data = 0xFFFF; + priv->t7[level].inst_size2.fields.size = + pcache->inst_size / 64; + priv->t7[level].inst_size2.fields.granu = + SMBIOS_CACHE_GRANU_64K; + } else { + priv->t7[level].inst_size.fields.size = + pcache->inst_size; + priv->t7[level].inst_size.fields.granu = + SMBIOS_CACHE_GRANU_1K; + priv->t7[level].inst_size2.data = 0; + } + smbios_cache_info_dump(&priv->t7[level]); + } + if (!level) /* no cache detected */ + return -ENOSYS; + + priv->cache_level = level; + + return 0; +} + static const struct udevice_id sysinfo_smbios_ids[] = { { .compatible = "u-boot,sysinfo-smbios" }, { /* sentinel */ } }; static const struct sysinfo_ops sysinfo_smbios_ops = { + .detect = sysinfo_plat_detect, + .get_str = sysinfo_plat_get_str, + .get_int = sysinfo_plat_get_int, + .get_data = sysinfo_plat_get_data, }; U_BOOT_DRIVER(sysinfo_smbios) = { @@ -20,4 +246,6 @@ U_BOOT_DRIVER(sysinfo_smbios) = { .id = UCLASS_SYSINFO, .of_match = sysinfo_smbios_ids, .ops = &sysinfo_smbios_ops, + .priv_auto = sizeof(struct sysinfo_plat_priv), + .probe = sysinfo_plat_probe, }; diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index d77d1e3ee44..3c0cd51273e 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -99,6 +99,26 @@ int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val) return ops->get_str(dev, id, size, val); } +int sysinfo_get_data(struct udevice *dev, int id, void **data, size_t *size) +{ + struct sysinfo_priv *priv; + struct sysinfo_ops *ops; + + if (!dev) + return -ENOSYS; + + priv = dev_get_uclass_priv(dev); + ops = sysinfo_get_ops(dev); + + if (!priv->detected) + return -EPERM; + + if (!ops->get_data) + return -ENOSYS; + + return ops->get_data(dev, id, data, size); +} + UCLASS_DRIVER(sysinfo) = { .id = UCLASS_SYSINFO, .name = "sysinfo", |
