Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/32131
Change subject: arch/x86/smbios: Add type 7 ......................................................................
arch/x86/smbios: Add type 7
The SMBIOS spec requires type 7 to be present.
Add the type 7 fields and enums for SMBIOS 3.1+ and fill it with the "Deterministic Cache Parameters" as available on Intel and AMD.
As CPUID only provides partial information on caches, some fields are set to unknown. The following fields are supported: * Cache Level * Cache Size * Cache Type * Cache Ways of Associativity
Change-Id: I80ed25b8f2c7b425136b2f0c755324a8f5d1636d Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/arch/x86/smbios.c M src/include/smbios.h 2 files changed, 256 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/31/32131/1
diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c index 8cb59df..be024c16 100644 --- a/src/arch/x86/smbios.c +++ b/src/arch/x86/smbios.c @@ -34,6 +34,14 @@ #include <vendorcode/google/chromeos/gnvs.h> #endif
+#define update_max(len, max_len, stmt) \ + do { \ + int tmp = stmt; \ + \ + max_len = MAX(max_len, tmp); \ + len += tmp; \ + } while (0) + static u8 smbios_checksum(u8 *p, u32 length) { u8 ret = 0; @@ -580,6 +588,192 @@ return len; }
+/* + * Write SMBIOS type 7. + * Fill in some fields with constant values, as gathering the information + * from CPUID is impossible. + */ +static int +smbios_write_type7(unsigned long *current, + const int handle, + const u8 level, + const u8 sram_type, + const enum smbios_cache_associativity associativity, + const enum smbios_cache_type type, + const size_t max_cache_size, + const size_t cache_size) +{ + struct smbios_type7 *t = (struct smbios_type7 *)*current; + int len = sizeof(struct smbios_type7); + static size_t cnt = 0; + char buf[8]; + + memset(t, 0, sizeof(struct smbios_type7)); + t->type = SMBIOS_CACHE_INFORMATION; + t->handle = handle; + t->length = len - 2; + + snprintf(buf, sizeof(buf), "CACHE%x", cnt++); + t->socket_designation = smbios_add_string(t->eos, buf); + + /* Cache level, Internal, Enabled, Mode Varies with Memory Address */ + t->cache_configuration = ((level & 7) << 0) | (1 << 7) | (2 << 8); + + if (max_cache_size < (32 * KiB)) { + t->max_cache_size = max_cache_size; + t->max_cache_size2 = t->max_cache_size; + } else if (max_cache_size < (0x7fff * 64 * KiB)) { + t->max_cache_size = (max_cache_size / (64 * KiB)) | (1 << 15); + t->max_cache_size2 = (max_cache_size / (64 * KiB)) | (1 << 31); + } else { + t->max_cache_size = 0xffff; + t->max_cache_size2 = (max_cache_size / (64 * KiB)) | (1 << 31); + } + + if (cache_size < (32 * KiB)) { + t->installed_size = cache_size; + t->installed_size2 = t->installed_size; + } else if (cache_size < (0x7fff * 64 * KiB)) { + t->installed_size = (cache_size / (64 * KiB)) | (1 << 15); + t->installed_size2 = (cache_size / (64 * KiB)) | (1 << 31); + } else { + t->installed_size = 0xffff; + t->installed_size2 = (cache_size / (64 * KiB)) | (1 << 31); + } + + t->associativity = associativity; + t->supported_sram_type = sram_type; + t->cache_speed = 0; //Unknown + t->error_correction_type = SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN; + t->system_cache_type = type; + + len = t->length + smbios_string_table_len(t->eos); + *current += len; + return len; +} + +/* Convert the associativity as integer to the SMBIOS enum if available */ +static enum smbios_cache_associativity +smbios_cache_associativity(const u8 num) +{ + switch (num) { + case 1: + return SMBIOS_CACHE_ASSOCIATIVITY_DIRECT; + case 2: + return SMBIOS_CACHE_ASSOCIATIVITY_2WAY; + case 4: + return SMBIOS_CACHE_ASSOCIATIVITY_4WAY; + case 8: + return SMBIOS_CACHE_ASSOCIATIVITY_8WAY; + case 12: + return SMBIOS_CACHE_ASSOCIATIVITY_12WAY; + case 16: + return SMBIOS_CACHE_ASSOCIATIVITY_16WAY; + case 20: + return SMBIOS_CACHE_ASSOCIATIVITY_20WAY; + case 24: + return SMBIOS_CACHE_ASSOCIATIVITY_24WAY; + case 32: + return SMBIOS_CACHE_ASSOCIATIVITY_32WAY; + case 48: + return SMBIOS_CACHE_ASSOCIATIVITY_48WAY; + case 64: + return SMBIOS_CACHE_ASSOCIATIVITY_64WAY; + case 0xff: + return SMBIOS_CACHE_ASSOCIATIVITY_FULL; + default: + return SMBIOS_CACHE_ASSOCIATIVITY_UNKNOWN; + }; + +} + +/* + * Parse the "Deterministic Cache Parameters" as provided by Intel in + * leaf 4 or AMD in extended leaf 0x8000001d. + * + * @param current Pointer to memory address to write the tables to + * @param handle Pointer to the handle for the tables + * @param max_struct_size Pointer to maximum struct size + */ +static int smbios_write_type7_cache_parameters(unsigned long *current, + int *handle, + int *max_struct_size) +{ + struct cpuid_result res; + unsigned int cnt = 0; + int len = 0; + u32 leaf; + + if (!cpu_have_cpuid()) + return len; + + if (cpu_is_intel()) { + res = cpuid(0); + if (res.eax < 4) + return len; + leaf = 4; + } else if (cpu_is_amd()) { + res = cpuid(0x80000000); + if (res.eax < 0x80000001) + return len; + + res = cpuid(0x80000001); + if (!(res.ecx & (1 << 22))) + return len; + + leaf = 0x8000001d; + } else { + printk(BIOS_DEBUG, "SMBIOS: Unknown CPU\n"); + return len; + } + + while (1) { + enum smbios_cache_associativity associativity; + enum smbios_cache_type type; + + res = cpuid_ext(leaf, cnt++); + + const size_t cache_type = res.eax & 0x1f; + const size_t level = (res.eax >> 5) & 0x7; + const size_t assoc = ((res.ebx >> 22) & 0x3ff) + 1; + const size_t partitions = ((res.ebx >> 12) & 0x3ff) + 1; + const size_t cache_line_size = ((res.ebx >> 0) & 0xfff) + 1; + const size_t number_of_sets = res.ecx + 1; + const size_t cache_size = assoc * partitions * cache_line_size * + number_of_sets; + + if (!cache_type) + /* No more caches in the system */ + break; + + switch (cache_type) { + case 1: + type = SMBIOS_CACHE_TYPE_DATA; + break; + case 2: + type = SMBIOS_CACHE_TYPE_INSTRUCTION; + break; + case 3: + type = SMBIOS_CACHE_TYPE_UNIFIED; + break; + default: + type = SMBIOS_CACHE_TYPE_UNKNOWN; + break; + } + + if (res.eax & (1 << 9)) + associativity = SMBIOS_CACHE_ASSOCIATIVITY_FULL; + else + associativity = smbios_cache_associativity(assoc); + + update_max(len, *max_struct_size, smbios_write_type7(current, + *handle++, level, SMBIOS_CACHE_SRAM_TYPE_UNKNOWN, + associativity, type, cache_size, cache_size)); + }; + + return len; +} + static int smbios_write_type11(unsigned long *current, int *handle) { struct smbios_type11 *t = (struct smbios_type11 *)*current; @@ -726,14 +920,6 @@ return len; }
-#define update_max(len, max_len, stmt) \ - do { \ - int tmp = stmt; \ - \ - max_len = MAX(max_len, tmp); \ - len += tmp; \ - } while (0) - unsigned long smbios_write_tables(unsigned long current) { struct smbios_entry *se; @@ -761,6 +947,8 @@ handle++)); update_max(len, max_struct_size, smbios_write_type4(¤t, handle++)); + smbios_write_type7_cache_parameters(¤t, &handle, + &max_struct_size); update_max(len, max_struct_size, smbios_write_type11(¤t, &handle)); if (CONFIG(ELOG)) diff --git a/src/include/smbios.h b/src/include/smbios.h index af83bfe..c9deca5 100644 --- a/src/include/smbios.h +++ b/src/include/smbios.h @@ -393,6 +393,66 @@ u8 eos[2]; } __packed;
+#define SMBIOS_CACHE_SRAM_TYPE_OTHER (1 << 0) +#define SMBIOS_CACHE_SRAM_TYPE_UNKNOWN (1 << 1) +#define SMBIOS_CACHE_SRAM_TYPE_NON_BURST (1 << 2) +#define SMBIOS_CACHE_SRAM_TYPE_BURST (1 << 3) +#define SMBIOS_CACHE_SRAM_TYPE_PIPELINE_BURST (1 << 4) +#define SMBIOS_CACHE_SRAM_TYPE_SYNCHRONOUS (1 << 5) +#define SMBIOS_CACHE_SRAM_TYPE_ASYNCHRONOUS (1 << 6) + +enum smbios_cache_error_corr { + SMBIOS_CACHE_ERROR_CORRECTION_OTHER = 0, + SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN, + SMBIOS_CACHE_ERROR_CORRECTION_NONE, + SMBIOS_CACHE_ERROR_CORRECTION_PARITY, + SMBIOS_CACHE_ERROR_CORRECTION_SINGLE_BIT, + SMBIOS_CACHE_ERROR_CORRECTION_MULTI_BIT, +}; + +enum smbios_cache_type { + SMBIOS_CACHE_TYPE_OTHER = 0, + SMBIOS_CACHE_TYPE_UNKNOWN, + SMBIOS_CACHE_TYPE_INSTRUCTION, + SMBIOS_CACHE_TYPE_DATA, + SMBIOS_CACHE_TYPE_UNIFIED, +}; + +enum smbios_cache_associativity { + SMBIOS_CACHE_ASSOCIATIVITY_OTHER = 0, + SMBIOS_CACHE_ASSOCIATIVITY_UNKNOWN, + SMBIOS_CACHE_ASSOCIATIVITY_DIRECT, + SMBIOS_CACHE_ASSOCIATIVITY_2WAY, + SMBIOS_CACHE_ASSOCIATIVITY_4WAY, + SMBIOS_CACHE_ASSOCIATIVITY_FULL, + SMBIOS_CACHE_ASSOCIATIVITY_8WAY, + SMBIOS_CACHE_ASSOCIATIVITY_16WAY, + SMBIOS_CACHE_ASSOCIATIVITY_12WAY, + SMBIOS_CACHE_ASSOCIATIVITY_24WAY, + SMBIOS_CACHE_ASSOCIATIVITY_32WAY, + SMBIOS_CACHE_ASSOCIATIVITY_48WAY, + SMBIOS_CACHE_ASSOCIATIVITY_64WAY, + SMBIOS_CACHE_ASSOCIATIVITY_20WAY, +}; + +struct smbios_type7 { + u8 type; + u8 length; + u16 handle; + u8 socket_designation; + u16 cache_configuration; + u16 max_cache_size; + u16 installed_size; + u16 supported_sram_type; + u8 cache_speed; + u8 error_correction_type; + u8 system_cache_type; + u8 associativity; + u32 max_cache_size2; + u32 installed_size2; + u8 eos[2]; +} __packed; + struct smbios_type11 { u8 type; u8 length;