[coreboot] [RFC] (ab)using the devicetree/device drivers for automatic SMBIOS table generation

Sven Schnelle svens at stackframe.org
Mon Oct 24 14:44:30 CEST 2011


Hi List,

with commit 164bcfdd1b0b2cc789203eeb9e3ff842df215a7c ("Add automatic
SMBIOS table generation") i've introduced a new member
'(*get_smbios_data) in struct device_operations / struct chip_operations.

We might use that now to generate SMBIOS tables based on device drivers.
I've just implement a quick'n'dirty pseudo driver, which reads the SPD
EEPROM of memory devices, and automatically generates the SMBIOS
type16/type17 tables.

All what's needed in the devicetree.cb are the following lines:

-----------------------8<-----------------------
device pci 1f.3 on # SMBUS controller the SPD EEPROMs are behind
       chip drivers/i2c/dramspd
       register "memtype" = "SMBIOS_MEMORY_FORM_FACTOR_SODIMM"
		device i2c 50 on end # All possible SPD addresses
		device i2c 51 on end # listed here
end
-----------------------8<-----------------------
The generated output looks like this on my Thinkpad T60:
(Handle 0005,0006,0007 are the new ones)

$ sudo dmidecode
# dmidecode 2.11
SMBIOS 2.7 present.
9 structures occupying 389 bytes.
Table at 0xCFEFD820.

Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
        Vendor: coreboot
        Version: 4.0-1784-gbd6d870-dirty
        Release Date: 10/24/2011
        ROM Size: 2048 kB
        Characteristics:
                PCI is supported
                PC Card (PCMCIA) is supported
                BIOS is upgradeable
                Selectable boot is supported
                ACPI is supported
                Targeted content distribution is supported
        BIOS Revision: 4.0
        Firmware Revision: 0.0

Handle 0x0001, DMI type 1, 27 bytes
System Information
        Manufacturer: Lenovo
        Product Name: ThinkPad T60 / T60p
        Version: Not Specified
        Serial Number: Not Specified
        UUID: Not Settable
        Wake-up Type: Reserved
        SKU Number: Not Specified
        Family: Not Specified

Handle 0x0002, DMI type 3, 21 bytes
Chassis Information
        Manufacturer: Lenovo
        Type: Desktop
        Lock: Not Present
        Version: Not Specified
        Serial Number: Not Specified
        Asset Tag: Not Specified
        Boot-up State: Safe
        Power Supply State: Safe
        Thermal State: Safe
        Security Status: None
        OEM Information: 0x00000000
        Height: Unspecified
        Number Of Power Cords: Unspecified
        Contained Elements: 0

Handle 0x0003, DMI type 4, 42 bytes
Processor Information
        Socket Designation: Not Specified
        Type: Central Processor
        Family: Pentium Pro
        Manufacturer: GenuineIntel
        ID: F6 06 00 00 FF FB EB BF
        Signature: Type 0, Family 6, Model 15, Stepping 6
        Flags:
                FPU (Floating-point unit on-chip)
                VME (Virtual mode extension)
                DE (Debugging extension)
                PSE (Page size extension)
                TSC (Time stamp counter)
                MSR (Model specific registers)
                PAE (Physical address extension)
                MCE (Machine check exception)
                CX8 (CMPXCHG8 instruction supported)
                APIC (On-chip APIC hardware supported)
                SEP (Fast system call)
                MTRR (Memory type range registers)
                PGE (Page global enable)
                MCA (Machine check architecture)
                CMOV (Conditional move instruction supported)
                PAT (Page attribute table)
                PSE-36 (36-bit page size extension)
                CLFSH (CLFLUSH instruction supported)
                DS (Debug store)
                ACPI (ACPI supported)
                MMX (MMX technology supported)
                FXSR (FXSAVE and FXSTOR instructions supported)
                SSE (Streaming SIMD extensions)
                SSE2 (Streaming SIMD extensions 2)
                SS (Self-snoop)
                HTT (Multi-threading)
                TM (Thermal monitor supported)
                PBE (Pending break enabled)
        Version: Intel(R) Core(TM)2 CPU         T7200  @ 2.00GHz
        Voltage: Unknown
        External Clock: Unknown
        Max Speed: Unknown
        Current Speed: Unknown
        Status: Unpopulated
        Upgrade: Other
        L1 Cache Handle: Not Provided
        L2 Cache Handle: Not Provided
        L3 Cache Handle: Not Provided
        Serial Number: Not Specified
        Asset Tag: Not Specified
        Part Number: Not Specified
        Core Count: 2
        Characteristics: None

Handle 0x0004, DMI type 32, 11 bytes
System Boot Information
        Status: No errors detected

Handle 0x0005, DMI type 16, 23 bytes
Physical Memory Array
        Location: System Board Or Motherboard
        Use: System Memory
        Error Correction Type: Unknown
        Maximum Capacity: 4 GB
        Error Information Handle: Not Provided
        Number Of Devices: 2

Handle 0x0006, DMI type 17, 32 bytes
Memory Device
        Array Handle: 0x0005
        Error Information Handle: Not Provided
        Total Width: 64 bits
        Data Width: 64 bits
        Size: 2048 MB
        Form Factor: SODIMM
        Set: None
        Locator: I2C: 01:50
        Bank Locator: Not Specified
        Type: DDR2
        Type Detail: Unbuffered (Unregistered)
        Speed: Unknown
        Manufacturer: Not Specified
        Serial Number: Not Specified
        Asset Tag: Not Specified
        Part Number: Not Specified
        Rank: Unknown

Handle 0x0007, DMI type 17, 32 bytes
Memory Device
        Array Handle: 0x0005
        Error Information Handle: Not Provided
        Total Width: 64 bits
        Data Width: 64 bits
        Size: 2048 MB
        Form Factor: SODIMM
        Set: None
        Locator: I2C: 01:51
        Bank Locator: Not Specified
        Type: DDR2
        Type Detail: Unbuffered (Unregistered)
        Speed: Unknown
        Manufacturer: Not Specified
        Serial Number: Not Specified
        Asset Tag: Not Specified
        Part Number: Not Specified
        Rank: Unknown

Handle 0x0008, DMI type 127, 4 bytes
End Of Table

There are a few fields missing in the output, which i have to add to the
driver. I'll need to clea nup the patch a bit, and finish it.
I just want to know your opinions on that topic before submitting it.

And here's the Ha^H^Hpatch:

diff --git a/src/drivers/i2c/Kconfig b/src/drivers/i2c/Kconfig
index 91ad025..4aefc96 100644
--- a/src/drivers/i2c/Kconfig
+++ b/src/drivers/i2c/Kconfig
@@ -4,3 +4,4 @@ source src/drivers/i2c/adt7463/Kconfig
 source src/drivers/i2c/i2cmux/Kconfig
 source src/drivers/i2c/i2cmux2/Kconfig
 source src/drivers/i2c/lm63/Kconfig
+source src/drivers/i2c/dramspd/Kconfig
diff --git a/src/drivers/i2c/Makefile.inc b/src/drivers/i2c/Makefile.inc
index d462b69..f2a53fa 100644
--- a/src/drivers/i2c/Makefile.inc
+++ b/src/drivers/i2c/Makefile.inc
@@ -4,3 +4,4 @@ subdirs-y += adt7463
 subdirs-y += i2cmux
 subdirs-y += i2cmux2
 subdirs-y += lm63
+subdirs-y += dramspd
diff --git a/src/drivers/i2c/dramspd/Kconfig
b/src/drivers/i2c/dramspd/Kconfig
new file mode 100644
index 0000000..2f76a85
--- /dev/null
+++ b/src/drivers/i2c/dramspd/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_I2C_DRAMSPD
+       bool
diff --git a/src/drivers/i2c/dramspd/Makefile.inc
b/src/drivers/i2c/dramspd/Makefile.inc
new file mode 100644
index 0000000..29fd0ee
--- /dev/null
+++ b/src/drivers/i2c/dramspd/Makefile.inc
@@ -0,0 +1 @@
+driver-$(CONFIG_DRIVERS_I2C_DRAMSPD) += dramspd.c
diff --git a/src/drivers/i2c/dramspd/chip.h b/src/drivers/i2c/dramspd/chip.h
new file mode 100644
index 0000000..25f4a0f
--- /dev/null
+++ b/src/drivers/i2c/dramspd/chip.h
@@ -0,0 +1,7 @@
+extern struct chip_operations drivers_i2c_dramspd_ops;
+
+#include <smbios.h>
+
+struct drivers_i2c_dramspd_config {
+       smbios_memory_form_factor_t memtype;
+};
diff --git a/src/drivers/i2c/dramspd/dramspd.c
b/src/drivers/i2c/dramspd/dramspd.c
new file mode 100644
index 0000000..6a8a06a
--- /dev/null
+++ b/src/drivers/i2c/dramspd/dramspd.c
@@ -0,0 +1,115 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/smbus.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <smbios.h>
+#include <string.h>
+#include <spd.h>
+#include "chip.h"
+
+static struct smbios_type16 *global_smbios_type16;
+
+static int dramspd_fill_type16(device_t dev, int *handle, unsigned long
*current)
+{
+       struct smbios_type16 *t;
+       int len;
+
+       if (global_smbios_type16)
+               return 0;
+
+       t = (struct smbios_type16 *)*current;
+       global_smbios_type16 = t;
+
+       len = sizeof(struct smbios_type16);
+       memset(t, 0, len);
+       t->type = SMBIOS_PHYS_MEMORY_ARRAY;
+       t->length = len - 2;
+       t->handle = (*handle)++;
+       t->location = 3; // System Board
+       t->use = 3; // System Memory
+       t->memory_error_correction = 2;
+       t->memory_error_information_handle = 0xfffe;
+       *current += len;
+       return len;
+}
+
+static int dramspd_get_smbios_data(device_t dev, int *handle, unsigned
long *current)
+{
+       struct smbios_type17 *t;
+       struct drivers_i2c_dramspd_config *config = dev->chip_info;
+       int len, features, eccwidth, type16len;
+       u64 size;
+       int rows, columns, banks, numdimmbanks;
+
+       type16len = dramspd_fill_type16(dev, handle, current);
+
+       t = (struct smbios_type17 *)*current;
+       len = sizeof(struct smbios_type17);
+       memset(t, 0, len);
+       t->type = SMBIOS_MEMORY_DEVICE;
+       t->length = len - 2;
+
+       switch(smbus_read_byte(dev, SPD_MEMORY_TYPE)) {
+       case SPD_MEMORY_TYPE_FPM_DRAM:
+               t->memory_type = SMBIOS_MEMORY_TYPE_DRAM;
+               t->type_detail |= (1 << 3); // FAST PAGED
+               break;
+       case SPD_MEMORY_TYPE_EDO:
+               t->memory_type = SMBIOS_MEMORY_TYPE_EDRAM;
+               t->type_detail |= (1 << 9); // EDO
+               break;
+       case SPD_MEMORY_TYPE_SDRAM:
+               t->memory_type = SMBIOS_MEMORY_TYPE_SDRAM;
+               t->type_detail |= (1 << 7); // SYNC
+               break;
+       case SPD_MEMORY_TYPE_SDRAM_DDR2:
+               t->memory_type = SMBIOS_MEMORY_TYPE_DDR2;
+               t->type_detail |= (1 << 7); // SYNC
+               break;
+       case SPD_MEMORY_TYPE_SDRAM_DDR3:
+               t->memory_type = SMBIOS_MEMORY_TYPE_DDR3;
+               t->type_detail |= (1 << 7); // SYNC
+       default:
+               return 0;
+       }
+
+       t->device_locator = smbios_add_string(t->eos, dev_path(dev));
+       t->data_width = smbus_read_byte(dev, SPD_MODULE_DATA_WIDTH_LSB);
+       t->data_width |= (smbus_read_byte(dev,
SPD_MODULE_DATA_WIDTH_MSB) << 8);
+       eccwidth = smbus_read_byte(dev, SPD_ERROR_CHECKING_SDRAM_WIDTH);
+
+       rows = smbus_read_byte(dev, SPD_NUM_ROWS) & 0xf;
+       columns = smbus_read_byte(dev, SPD_NUM_COLUMNS) & 0xf;
+       banks = smbus_read_byte(dev, SPD_NUM_BANKS_PER_SDRAM);
+       numdimmbanks = (smbus_read_byte(dev, SPD_NUM_DIMM_BANKS) & 0x7) + 1;
+
+       if (!(rows && columns && banks && t->data_width))
+               return 0;
+
+       size = 1ULL << (rows + columns);
+       size *= (u64)((t->data_width / 8) * banks * numdimmbanks);
+
+       printk(BIOS_ERR, "%d rows, %d columns, %d banks, t->data_width
%d %lld\n",
+              rows, columns, banks, t->data_width, size);
+
+       t->total_width = eccwidth ? eccwidth : t->data_width;
+       t->form_factor = config->memtype;
+       t->memory_error_information_handle = 0xfffe;
+       features = smbus_read_byte(dev, SPD_MODULE_ATTRIBUTES);
+       t->type_detail = (features & 9) ? (1 << 13) : (1 << 14);
+       t->handle = (*handle)++;
+       t->phys_memory_array_handle = global_smbios_type16->handle;
+       t->size = (u16)(size/1048576);
+       global_smbios_type16->maximum_capacity += (u32)size/1024;
+       global_smbios_type16->number_of_memory_devices++;
+       len = t->length + smbios_string_table_len(t->eos);
+       *current += len;
+       return len + type16len;
+}
+
+struct chip_operations drivers_i2c_dramspd_ops = {
+       CHIP_NAME("Generic DRAM SPD")
+       .get_smbios_data = dramspd_get_smbios_data,
+};
diff --git a/src/include/smbios.h b/src/include/smbios.h
index f13d621..6ac8628 100644
--- a/src/include/smbios.h
+++ b/src/include/smbios.h
@@ -20,7 +20,35 @@ int smbios_string_table_len(char *start);
 #define BIOS_EXT1_CHARACTERISTICS_ACPI    (1 << 0)
 #define BIOS_EXT2_CHARACTERISTICS_TARGET  (1 << 2)

+#define SMBIOS_MEMORY_TYPE_DRAM 0x03
+#define SMBIOS_MEMORY_TYPE_EDRAM 0x04
+#define SMBIOS_MEMORY_TYPE_VRAM 0x05
+#define SMBIOS_MEMORY_TYPE_SRAM 0x06
+#define SMBIOS_MEMORY_TYPE_RAM 0x07
+#define SMBIOS_MEMORY_TYPE_ROM 0x08
+#define SMBIOS_MEMORY_TYPE_FLASH 0x09
+#define SMBIOS_MEMORY_TYPE_EEPROM 0x0a
+#define SMBIOS_MEMORY_TYPE_FEPROM 0x0b
+#define SMBIOS_MEMORY_TYPE_EPROM 0x0c
+#define SMBIOS_MEMORY_TYPE_CDRAM 0x0d
+#define SMBIOS_MEMORY_TYPE_3DRAM 0x0e
+#define SMBIOS_MEMORY_TYPE_SDRAM 0x0f
+#define SMBIOS_MEMORY_TYPE_SGRAM 0x10
+#define SMBIOS_MEMORY_TYPE_RDRAM 0x11
+#define SMBIOS_MEMORY_TYPE_DDR 0x12
+#define SMBIOS_MEMORY_TYPE_DDR2 0x13
+#define SMBIOS_MEMORY_TYPE_DDR2_FBDIMM 0x14
+#define SMBIOS_MEMORY_TYPE_DDR3 0x18
+#define SMBIOS_MEMORY_TYPE_FBD2
+
+
 #define SMBIOS_STATE_SAFE 3
+
+typedef enum {
+       SMBIOS_MEMORY_FORM_FACTOR_DIMM=9,
+       SMBIOS_MEMORY_FORM_FACTOR_SODIMM=0x0d,
+       SMBIOS_MEMORY_FORM_FACTOR_FBDIMM=0x0f,
+} smbios_memory_form_factor_t;
+
 typedef enum {
        SMBIOS_BIOS_INFORMATION=0,
        SMBIOS_SYSTEM_INFORMATION=1,
diff --git a/src/mainboard/lenovo/t60/Kconfig
b/src/mainboard/lenovo/t60/Kconfig
index 9deb5a3..864fbf1 100644
--- a/src/mainboard/lenovo/t60/Kconfig
+++ b/src/mainboard/lenovo/t60/Kconfig
@@ -13,6 +13,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
        select EC_LENOVO_PMH7
        select EC_LENOVO_H8
        select DRIVERS_ICS_954309
+       select DRIVERS_I2C_DRAMSPD
        select BOARD_HAS_FADT
        select HAVE_OPTION_TABLE
        select HAVE_PIRQ_TABLE
diff --git a/src/mainboard/lenovo/t60/devicetree.cb
b/src/mainboard/lenovo/t60/devicetree.cb
index dba3fdd..92852c3 100644
--- a/src/mainboard/lenovo/t60/devicetree.cb
+++ b/src/mainboard/lenovo/t60/devicetree.cb
@@ -214,6 +214,11 @@ chip northbridge/intel/i945
                                        register "reg11" = "0x07"
                                        device i2c 69 on end
                                end
+                               chip drivers/i2c/dramspd
+                                       register "memtype" =
"SMBIOS_MEMORY_FORM_FACTOR_SODIMM"
+                                       device i2c 50 on end
+                                       device i2c 51 on end
+                               end
                        end
                end
        end


Cheers,

Sven




More information about the coreboot mailing list