summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/smbios.c67
-rw-r--r--src/include/memory_info.h9
-rw-r--r--src/soc/intel/common/block/systemagent/systemagent.c87
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(&current,handle++));
- update_max(len, max_struct_size, smbios_write_type17(&current,
+
+ const int type16 = handle;
+ update_max(len, max_struct_size, smbios_write_type16(&current,
&handle));
+ update_max(len, max_struct_size, smbios_write_type17(&current,
+ &handle, type16));
update_max(len, max_struct_size, smbios_write_type19(&current,
&handle));
update_max(len, max_struct_size, smbios_write_type32(&current,
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[] = {