aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/boot/smbios.c115
-rw-r--r--src/include/cbmem.h4
-rw-r--r--src/include/memory_info.h46
-rw-r--r--src/include/smbios.h18
-rw-r--r--src/include/spd.h8
5 files changed, 190 insertions, 1 deletions
diff --git a/src/arch/x86/boot/smbios.c b/src/arch/x86/boot/smbios.c
index f2f998d7bc..16e25311a3 100644
--- a/src/arch/x86/boot/smbios.c
+++ b/src/arch/x86/boot/smbios.c
@@ -30,6 +30,9 @@
#include <cbfs_core.h>
#include <arch/byteorder.h>
#include <elog.h>
+#include <memory_info.h>
+#include <spd.h>
+#include <cbmem.h>
#if CONFIG_CHROMEOS
#include <vendorcode/google/chromeos/gnvs.h>
#endif
@@ -118,6 +121,97 @@ static int smbios_processor_name(char *start)
return smbios_add_string(start, tmp);
}
+/* this function will fill the corresponding manufacturer */
+static void fill_dimm_manufacturer(uint16_t mod_id, struct smbios_type17 *t)
+{
+ switch (mod_id) {
+ case 0xad80:
+ t->manufacturer = smbios_add_string(t->eos,
+ "Hynix/Hyundai");
+ break;
+ case 0xce80:
+ t->manufacturer = smbios_add_string(t->eos,
+ "Samsung");
+ break;
+ case 0xfe02:
+ t->manufacturer = smbios_add_string(t->eos,
+ "Elpida");
+ break;
+ default:
+ t->manufacturer = smbios_add_string(t->eos,
+ "Unknown");
+ break;
+ }
+}
+
+static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
+ unsigned long *current, int *handle)
+{
+ struct smbios_type17 *t = (struct smbios_type17 *)*current;
+ uint8_t length;
+ char locator[40];
+
+ memset(t, 0, sizeof(struct smbios_type17));
+ t->memory_type = dimm->ddr_type;
+ t->clock_speed = dimm->ddr_frequency;
+ t->speed = dimm->ddr_frequency;
+ t->type = SMBIOS_MEMORY_DEVICE;
+ t->size = dimm->dimm_size;
+ t->data_width = 8 * (1 << (dimm->bus_width & 0x7));
+ t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3);
+
+ switch (dimm->mod_type) {
+ case SPD_RDIMM:
+ case SPD_MINI_RDIMM:
+ t->form_factor = MEMORY_FORMFACTOR_RIMM;
+ break;
+ case SPD_UDIMM:
+ case SPD_MICRO_DIMM:
+ case SPD_MINI_UDIMM:
+ t->form_factor = MEMORY_FORMFACTOR_DIMM;
+ break;
+ case SPD_SODIMM:
+ t->form_factor = MEMORY_FORMFACTOR_SODIMM;
+ break;
+ default:
+ t->form_factor = MEMORY_FORMFACTOR_UNKNOWN;
+ break;
+ }
+
+ fill_dimm_manufacturer(dimm->mod_id, t);
+ /* put '\0' in the end of data */
+ length = sizeof(dimm->serial);
+ dimm->serial[length - 1] = '\0';
+ if (dimm->serial[0] == 0)
+ t->serial_number = smbios_add_string(t->eos, "None");
+ else
+ t->serial_number = smbios_add_string(t->eos,
+ (const char *)dimm->serial);
+
+ snprintf(locator, sizeof(locator), "Channel-%d-DIMM-%d",
+ dimm->channel_num, dimm->dimm_num);
+ t->device_locator = smbios_add_string(t->eos, locator);
+
+ snprintf(locator, sizeof(locator), "BANK %d", dimm->bank_locator);
+ t->bank_locator = smbios_add_string(t->eos, locator);
+
+ /* put '\0' in the end of data */
+ length = sizeof(dimm->module_part_number);
+ dimm->module_part_number[length - 1] = '\0';
+ t->part_number = smbios_add_string(t->eos,
+ (const char *)dimm->module_part_number);
+
+ /* Synchronous = 1 */
+ t->type_detail = 0x0080;
+ /* no handle for error information */
+ t->memory_error_information_handle = 0xFFFE;
+ t->attributes = dimm->rank_per_dimm;
+ t->handle = *handle;
+ *handle += 1;
+ t->length = sizeof(struct smbios_type17) - 2;
+ return t->length + smbios_string_table_len(t->eos);
+}
+
const char *__attribute__((weak)) smbios_mainboard_bios_version(void)
{
if (strlen(CONFIG_LOCALVERSION))
@@ -327,6 +421,26 @@ static int smbios_write_type11(unsigned long *current, int *handle)
return len;
}
+static int smbios_write_type17(unsigned long *current, int *handle)
+{
+ int len = sizeof(struct smbios_type17);
+ 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 17\n");
+ for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) {
+ struct dimm_info *dimm;
+ dimm = &meminfo->dimm[i];
+ len = create_smbios_type17_for_dimm(dimm, current, handle);
+ *current += len;
+ }
+ return meminfo->dimm_cnt * len;
+}
+
static int smbios_write_type32(unsigned long *current, int handle)
{
struct smbios_type32 *t = (struct smbios_type32 *)*current;
@@ -416,6 +530,7 @@ unsigned long smbios_write_tables(unsigned long current)
#if CONFIG_ELOG
len += elog_smbios_write_type15(&current, handle++);
#endif
+ len += smbios_write_type17(&current, &handle);
len += smbios_write_type32(&current, handle++);
len += smbios_walk_device_tree(all_devices, &handle, &current);
diff --git a/src/include/cbmem.h b/src/include/cbmem.h
index 2f86b85a1f..49eaf48414 100644
--- a/src/include/cbmem.h
+++ b/src/include/cbmem.h
@@ -72,6 +72,7 @@
#define CBMEM_ID_POWER_STATE 0x50535454
#define CBMEM_ID_SMM_SAVE_SPACE 0x07e9acee
#define CBMEM_ID_RAM_OOPS 0x05430095
+#define CBMEM_ID_MEMINFO 0x494D454D
#define CBMEM_ID_NONE 0x00000000
#define CBMEM_ID_AGESA_RUNTIME 0x41474553
#define CBMEM_ID_HOB_POINTER 0x484f4221
@@ -115,7 +116,8 @@ struct cbmem_id_to_name {
{ CBMEM_ID_SMM_SAVE_SPACE, "SMM BACKUP " }, \
{ CBMEM_ID_REFCODE_CACHE, "REFCODE $ " }, \
{ CBMEM_ID_POWER_STATE, "POWER STATE" }, \
- { CBMEM_ID_RAM_OOPS, "RAMOOPS " },
+ { CBMEM_ID_RAM_OOPS, "RAMOOPS " }, \
+ { CBMEM_ID_MEMINFO, "MEM INFO " },
struct cbmem_entry;
diff --git a/src/include/memory_info.h b/src/include/memory_info.h
new file mode 100644
index 0000000000..4613628dab
--- /dev/null
+++ b/src/include/memory_info.h
@@ -0,0 +1,46 @@
+/*
+ * Memory information
+ *
+ * Copyright (C) 2014, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEMORY_INFO_H_
+#define _MEMORY_INFO_H_
+
+/*
+ * If this table is filled and put in CBMEM,
+ * then these info in CBMEM will be used to generate smbios type 17 table
+ */
+struct dimm_info {
+ uint32_t dimm_size;
+ uint16_t ddr_type;
+ uint16_t ddr_frequency;
+ uint8_t rank_per_dimm;
+ uint8_t channel_num;
+ uint8_t dimm_num;
+ uint8_t bank_locator;
+ /* The 5th byte is '\0' for the end of string */
+ uint8_t serial[5];
+ /* The 19th byte is '\0' for the end of string */
+ uint8_t module_part_number[19];
+ uint16_t mod_id;
+ uint8_t mod_type;
+ uint8_t bus_width;
+} __attribute__((packed));
+
+struct memory_info {
+ uint8_t dimm_cnt;
+ /* Maximum num of dimm is 8 */
+ struct dimm_info dimm[8];
+} __attribute__((packed));
+
+#endif
diff --git a/src/include/smbios.h b/src/include/smbios.h
index 90609067b3..bd7bef57db 100644
--- a/src/include/smbios.h
+++ b/src/include/smbios.h
@@ -34,6 +34,24 @@ u8 smbios_mainboard_enclosure_type(void);
#define BIOS_EXT1_CHARACTERISTICS_ACPI (1 << 0)
#define BIOS_EXT2_CHARACTERISTICS_TARGET (1 << 2)
+typedef enum {
+ MEMORY_FORMFACTOR_OTHER = 0x01,
+ MEMORY_FORMFACTOR_UNKNOWN = 0x02,
+ MEMORY_FORMFACTOR_SIMM = 0x03,
+ MEMORY_FORMFACTOR_SIP = 0x04,
+ MEMORY_FORMFACTOR_CHIP = 0x05,
+ MEMORY_FORMFACTOR_DIP = 0x06,
+ MEMORY_FORMFACTOR_ZIP = 0x07,
+ MEMORY_FORMFACTOR_PROPRIETARY_CARD = 0x08,
+ MEMORY_FORMFACTOR_DIMM = 0x09,
+ MEMORY_FORMFACTOR_TSOP = 0x0a,
+ MEMORY_FORMFACTOR_ROC = 0x0b,
+ MEMORY_FORMFACTOR_RIMM = 0x0c,
+ MEMORY_FORMFACTOR_SODIMM = 0x0d,
+ MEMORY_FORMFACTOR_SRIMM = 0x0e,
+ MEMORY_FORMFACTOR_FBDIMM = 0x0f,
+} smbios_memory_form_factor;
+
#define SMBIOS_STATE_SAFE 3
typedef enum {
SMBIOS_BIOS_INFORMATION=0,
diff --git a/src/include/spd.h b/src/include/spd.h
index 2b07fb134b..ef0cf5a6a1 100644
--- a/src/include/spd.h
+++ b/src/include/spd.h
@@ -237,4 +237,12 @@ enum spd_memory_type {
#define RC62 62
#define RC63 63
+#define SPD_UNDEFINED 0
+#define SPD_RDIMM 1
+#define SPD_UDIMM 2
+#define SPD_SODIMM 3
+#define SPD_MICRO_DIMM 4
+#define SPD_MINI_RDIMM 5
+#define SPD_MINI_UDIMM 6
+
#endif