diff options
-rw-r--r-- | src/arch/x86/smbios.c | 67 | ||||
-rw-r--r-- | src/include/memory_info.h | 9 | ||||
-rw-r--r-- | src/soc/intel/common/block/systemagent/systemagent.c | 87 |
3 files changed, 106 insertions, 57 deletions
diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c index d7e87470db..47b54aa116 100644 --- a/src/arch/x86/smbios.c +++ b/src/arch/x86/smbios.c @@ -310,7 +310,8 @@ static void smbios_fill_dimm_serial_number(const struct dimm_info *dimm, } static int create_smbios_type17_for_dimm(struct dimm_info *dimm, - unsigned long *current, int *handle) + unsigned long *current, int *handle, + int type16_handle) { struct smbios_type17 *t = (struct smbios_type17 *)*current; @@ -365,6 +366,8 @@ static int create_smbios_type17_for_dimm(struct dimm_info *dimm, t->memory_error_information_handle = 0xFFFE; t->attributes = dimm->rank_per_dimm; t->handle = *handle; + t->phys_memory_array_handle = type16_handle; + *handle += 1; t->length = sizeof(struct smbios_type17) - 2; return t->length + smbios_string_table_len(t->eos); @@ -1063,7 +1066,53 @@ static int smbios_write_type11(unsigned long *current, int *handle) return len; } -static int smbios_write_type17(unsigned long *current, int *handle) +static int smbios_write_type16(unsigned long *current, int *handle) +{ + struct smbios_type16 *t = (struct smbios_type16 *)*current; + + int len; + int i; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + printk(BIOS_INFO, "Create SMBIOS type 16\n"); + + if (meminfo->max_capacity_mib == 0 || meminfo->number_of_devices == 0) { + /* Fill in defaults if not provided */ + meminfo->number_of_devices = 0; + meminfo->max_capacity_mib = 0; + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + meminfo->max_capacity_mib += meminfo->dimm[i].dimm_size; + meminfo->number_of_devices += !!meminfo->dimm[i].dimm_size; + } + } + + memset(t, 0, sizeof(*t)); + t->type = SMBIOS_PHYS_MEMORY_ARRAY; + t->handle = *handle; + t->length = len = sizeof(*t) - 2; + + t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; + t->use = MEMORY_ARRAY_USE_SYSTEM; + t->memory_error_correction = meminfo->ecc_capable ? + MEMORY_ARRAY_ECC_SINGLE_BIT : MEMORY_ARRAY_ECC_NONE; + + /* no error information handle available */ + t->memory_error_information_handle = 0xFFFE; + t->maximum_capacity = meminfo->max_capacity_mib * (MiB / KiB); + t->number_of_memory_devices = meminfo->number_of_devices; + + len += smbios_string_table_len(t->eos); + + *current += len; + (*handle)++; + return len; +} + +static int smbios_write_type17(unsigned long *current, int *handle, int type16) { int len = sizeof(struct smbios_type17); int totallen = 0; @@ -1079,7 +1128,13 @@ static int smbios_write_type17(unsigned long *current, int *handle) i++) { struct dimm_info *dimm; dimm = &meminfo->dimm[i]; - len = create_smbios_type17_for_dimm(dimm, current, handle); + /* + * Windows 10 GetPhysicallyInstalledSystemMemory functions reads SMBIOS tables + * type 16 and type 17. The type 17 tables need to point to a type 16 table. + * Otherwise, the physical installed memory size is guessed from the system + * memory map, which results in a slightly smaller value than the actual size. + */ + len = create_smbios_type17_for_dimm(dimm, current, handle, type16); *current += len; totallen += len; } @@ -1356,8 +1411,12 @@ unsigned long smbios_write_tables(unsigned long current) if (CONFIG(ELOG)) update_max(len, max_struct_size, elog_smbios_write_type15(¤t,handle++)); - update_max(len, max_struct_size, smbios_write_type17(¤t, + + const int type16 = handle; + update_max(len, max_struct_size, smbios_write_type16(¤t, &handle)); + update_max(len, max_struct_size, smbios_write_type17(¤t, + &handle, type16)); update_max(len, max_struct_size, smbios_write_type19(¤t, &handle)); update_max(len, max_struct_size, smbios_write_type32(¤t, diff --git a/src/include/memory_info.h b/src/include/memory_info.h index a9891189d2..f4a200995c 100644 --- a/src/include/memory_info.h +++ b/src/include/memory_info.h @@ -5,6 +5,7 @@ #define _MEMORY_INFO_H_ #include <stdint.h> +#include <stdbool.h> #define DIMM_INFO_SERIAL_SIZE 4 #define DIMM_INFO_PART_NUMBER_SIZE 33 @@ -81,6 +82,14 @@ struct dimm_info { } __packed; struct memory_info { + /* controller specific */ + bool ecc_capable; + /* Maximum capacity the DRAM controller/mainboard supports */ + uint32_t max_capacity_mib; + /* Maximum number of DIMMs the DRAM controller/mainboard supports */ + uint16_t number_of_devices; + + /* active DIMM configuration */ uint8_t dimm_cnt; struct dimm_info dimm[DIMM_INFO_TOTAL]; } __packed; diff --git a/src/soc/intel/common/block/systemagent/systemagent.c b/src/soc/intel/common/block/systemagent/systemagent.c index e12e07c376..5da28007ee 100644 --- a/src/soc/intel/common/block/systemagent/systemagent.c +++ b/src/soc/intel/common/block/systemagent/systemagent.c @@ -13,6 +13,7 @@ #include <soc/iomap.h> #include <soc/pci_devs.h> #include <soc/systemagent.h> +#include <types.h> #include "systemagent_def.h" /* SoC override function */ @@ -46,6 +47,38 @@ __weak uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) return 32768; /* 32 GiB per channel */ } +static bool sa_supports_ecc(const uint32_t capid0_a) +{ + return !(capid0_a & CAPID_ECCDIS); +} + +static size_t sa_slots_per_channel(const uint32_t capid0_a) +{ + return !(capid0_a & CAPID_DDPCD) + 1; +} + +static size_t sa_number_of_channels(const uint32_t capid0_a) +{ + return !(capid0_a & CAPID_PDCD) + 1; +} + +static void sa_soc_systemagent_init(struct device *dev) +{ + soc_systemagent_init(dev); + + struct memory_info *m = cbmem_find(CBMEM_ID_MEMINFO); + if (m == NULL) + return; + + const uint32_t capid0_a = pci_read_config32(dev, CAPID0_A); + + m->ecc_capable = sa_supports_ecc(capid0_a); + m->max_capacity_mib = soc_systemagent_max_chan_capacity_mib(CAPID_DDRSZ(capid0_a)) * + sa_number_of_channels(capid0_a); + m->number_of_devices = sa_slots_per_channel(capid0_a) * + sa_number_of_channels(capid0_a); +} + /* * Add all known fixed MMIO ranges that hang off the host bridge/memory * controller device. @@ -262,55 +295,6 @@ static void systemagent_read_resources(struct device *dev) sa_add_imr_resources(dev, &index); } -#if CONFIG(GENERATE_SMBIOS_TABLES) -static bool sa_supports_ecc(const uint32_t capida) -{ - return !(capida & CAPID_ECCDIS); -} - -static size_t sa_slots_per_channel(const uint32_t capida) -{ - return !(capida & CAPID_DDPCD) + 1; -} - -static size_t sa_number_of_channels(const uint32_t capida) -{ - return !(capida & CAPID_PDCD) + 1; -} - -static int sa_smbios_write_type_16(struct device *dev, int *handle, - unsigned long *current) -{ - struct smbios_type16 *t = (struct smbios_type16 *)*current; - int len = sizeof(struct smbios_type16); - const uint32_t capida = pci_read_config32(dev, CAPID0_A); - - struct memory_info *meminfo; - meminfo = cbmem_find(CBMEM_ID_MEMINFO); - if (meminfo == NULL) - return 0; /* can't find mem info in cbmem */ - - memset(t, 0, sizeof(struct smbios_type16)); - t->type = SMBIOS_PHYS_MEMORY_ARRAY; - t->handle = *handle; - t->length = len - 2; - t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; - t->use = MEMORY_ARRAY_USE_SYSTEM; - t->memory_error_correction = sa_supports_ecc(capida) ? MEMORY_ARRAY_ECC_SINGLE_BIT : - MEMORY_ARRAY_ECC_NONE; - /* no error information handle available */ - t->memory_error_information_handle = 0xFFFE; - t->maximum_capacity = soc_systemagent_max_chan_capacity_mib(CAPID_DDRSZ(capida)) * - sa_number_of_channels(capida) * (MiB / KiB); - t->number_of_memory_devices = sa_slots_per_channel(capida) * - sa_number_of_channels(capida); - - *current += len; - *handle += 1; - return len; -} -#endif - void enable_power_aware_intr(void) { uint8_t pair; @@ -326,14 +310,11 @@ static struct device_operations systemagent_ops = { .read_resources = systemagent_read_resources, .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, - .init = soc_systemagent_init, + .init = sa_soc_systemagent_init, .ops_pci = &pci_dev_ops_pci, #if CONFIG(HAVE_ACPI_TABLES) .write_acpi_tables = sa_write_acpi_tables, #endif -#if CONFIG(GENERATE_SMBIOS_TABLES) - .get_smbios_data = sa_smbios_write_type_16, -#endif }; static const unsigned short systemagent_ids[] = { |