diff options
Diffstat (limited to 'lib/dimm_spd.c')
-rw-r--r-- | lib/dimm_spd.c | 171 |
1 files changed, 166 insertions, 5 deletions
diff --git a/lib/dimm_spd.c b/lib/dimm_spd.c index 1f27de2..91ae117 100644 --- a/lib/dimm_spd.c +++ b/lib/dimm_spd.c @@ -63,10 +63,11 @@ const struct valstr spd_memtype_vals[] = { { 0x09, "DDR2 SDRAM FB-DIMM" }, { 0x0A, "DDR2 SDRAM FB-DIMM Probe" }, { 0x0B, "DDR3 SDRAM" }, + { 0x0C, "DDR4 SDRAM" }, { 0x00, NULL }, }; -const struct valstr ddr3_density_vals[] = +const struct valstr ddr3_density_vals[] = { { 0, "256 Mb" }, { 1, "512 Mb" }, @@ -87,6 +88,8 @@ const struct valstr ddr3_banks_vals[] = { 0x00, NULL }, }; + +#define ddr4_ecc_vals ddr3_ecc_vals const struct valstr ddr3_ecc_vals[] = { { 0, "0 bits" }, @@ -94,6 +97,62 @@ const struct valstr ddr3_ecc_vals[] = { 0x00, NULL }, }; +const struct valstr ddr4_density_vals[] = +{ + { 0, "256 Mb" }, + { 1, "512 Mb" }, + { 2, "1 Gb" }, + { 3, "2 Gb" }, + { 4, "4 Gb" }, + { 5, "8 Gb" }, + { 6, "16 Gb" }, + { 7, "32 Gb" }, + { 0x00, NULL }, +}; + +const struct valstr ddr4_banks_vals[] = +{ + { 0, "2 (4 Banks)" }, + { 1, "3 (8 Banks)" }, + { 0x00, NULL }, +}; + +const struct valstr ddr4_bank_groups[] = +{ + { 0, "0 (no Bank Groups)" }, + { 1, "1 (2 Bank Groups)" }, + { 2, "2 (4 Bank Groups)" }, + { 0x00, NULL }, +}; + +const struct valstr ddr4_package_type[] = +{ + { 0, "Monolithic DRAM Device" }, + { 1, "Non-Monolithic Device" }, + { 0x00, NULL }, +}; + +const struct valstr ddr4_technology_type[] = +{ + { 0, "Extended module type, see byte 15" }, + { 1, "RDIMM" }, + { 2, "UDIMM" }, + { 3, "SO-DIMM" }, + { 4, "LRDIMM" }, + { 5, "Mini-RDIMM" }, + { 6, "Mini-UDIMM" }, + { 7, "7 - Reserved" }, + { 8, "72b-SO-RDIMM" }, + { 9, "72b-SO-UDIMM" }, + { 10, "10 - Reserved" }, + { 11, "11 - Reserved" }, + { 12, "16b-SO-DIMM" }, + { 13, "32b-SO-DIMM" }, + { 14, "14 - Reserved" }, + { 15, "No base memory present" }, + { 0x00, NULL }, +}; + const struct valstr spd_config_vals[] = { { 0x00, "None" }, { 0x01, "Parity" }, @@ -800,6 +859,92 @@ ipmi_spd_print(uint8_t *spd_data, int len) printf( "%c", *pchPN++ ); } printf("\n"); + } else if (spd_data[2] == 0x0C) /* DDR4 SDRAM */ + { + int i; + int sdram_cap = 0; + int pri_bus_width = 0; + int sdram_width = 0; + int mem_size = 0; + int lrank_dimm; + + if (len < 148) + return -1; /* we need first 91 bytes to do our thing */ + + /* "Logical rank" referes to the individually addressable die + * in a 3DS stack and has no meaning for monolithic or + * multi-load stacked SDRAMs; however, for the purposes of + * calculating the capacity of the module, one should treat + * monolithic and multi-load stack SDRAMs as having one logical + * rank per package rank. + */ + lrank_dimm = (spd_data[12]>>3&0x3) + 1; /* Number of Package Ranks per DIMM */ + if ((spd_data[6] & 0x3) == 0x10) { /* 3DS package Type */ + lrank_dimm *= ((spd_data[6]>>4)&0x3) + 1; /* Die Count */ + } + sdram_cap = ldexp(256,(spd_data[4]&15)); + pri_bus_width = ldexp(8,(spd_data[13]&7)); + sdram_width = ldexp(4,(spd_data[12]&7)); + mem_size = (sdram_cap/8) * (pri_bus_width/sdram_width) * lrank_dimm; + printf(" SDRAM Package Type : %s\n", val2str((spd_data[6]>>7), ddr4_package_type)); + printf(" Technology : %s\n", val2str((spd_data[3]&15), ddr4_technology_type)); + printf(" SDRAM Die Count : %d\n", ((spd_data[6]>>4) & 3)+1); + printf(" SDRAM Capacity : %d Mb\n", sdram_cap ); + printf(" Memory Bank Group : %s\n", val2str((spd_data[4]>>6 & 0x3), ddr4_bank_groups)); + printf(" Memory Banks : %s\n", val2str((spd_data[4]>>4 & 0x3), ddr4_banks_vals)); + printf(" Primary Bus Width : %d bits\n", pri_bus_width ); + printf(" SDRAM Device Width : %d bits\n", sdram_width ); + printf(" Logical Rank per DIMM : %d\n", lrank_dimm ); + printf(" Memory size : %d MB\n", mem_size ); + + printf(" Memory Density : %s\n", val2str(spd_data[4]&15, ddr4_density_vals)); + printf(" 1.2 V Nominal Op : %s\n", (((spd_data[11]&3) != 3) ? "No":"Yes" ) ); + printf(" TBD1 V Nominal Op : %s\n", (((spd_data[11]>>2&3) != 3) ? "No":"Yes" ) ); + printf(" TBD2 V Nominal Op : %s\n", (((spd_data[11]>>4&3) != 3) ? "No":"Yes" ) ); + printf(" Error Detect/Cor : %s\n", val2str(spd_data[13]>>3, ddr4_ecc_vals)); + + printf(" Manufacturer : "); + switch (spd_data[320]&127) + { + case 0: + printf("%s\n", val2str(spd_data[321], jedec_id1_vals)); + break; + + case 1: + printf("%s\n", val2str(spd_data[321], jedec_id2_vals)); + break; + + case 2: + printf("%s\n", val2str(spd_data[321], jedec_id3_vals)); + break; + + case 3: + printf("%s\n", val2str(spd_data[321], jedec_id4_vals)); + break; + + case 4: + printf("%s\n", val2str(spd_data[321], jedec_id5_vals)); + break; + + default: + printf("%s\n", "JEDEC JEP106 update required"); + + } + + u_int year = (spd_data[323]>>4)*10 + spd_data[323]&15; + u_int week = (spd_data[324]>>4)*10 + spd_data[324]&15; + printf(" Manufacture Date : year %4d week %2d\n", + 2000 + year, week); + + printf(" Serial Number : %02x%02x%02x%02x\n", + spd_data[325], spd_data[326], spd_data[327], spd_data[328]); + + printf(" Part Number : "); + for (i=329; i <= 348; i++) + { + printf( "%c", spd_data[i]); + } + printf("\n"); } else { @@ -868,7 +1013,7 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id) struct ipmi_rs * rsp; struct ipmi_rq req; struct fru_info fru; - uint8_t spd_data[256], msg_data[4]; + uint8_t *spd_data, msg_data[4]; int len, offset; msg_data[0] = id; @@ -896,11 +1041,20 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id) lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", fru.size, fru.access ? "words" : "bytes"); + if (fru.size < 1) { lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); return -1; } + spd_data = malloc(fru.size); + + if (spd_data == NULL) { + printf(" Unable to malloc memory for spd array of size=%d\n", + fru.size); + return -1; + } + memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_STORAGE; req.msg.cmd = GET_FRU_DATA; @@ -908,22 +1062,27 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id) req.msg.data_len = 4; offset = 0; - memset(spd_data, 0, 256); + memset(spd_data, 0, fru.size); do { + int i; msg_data[0] = id; - msg_data[1] = offset; - msg_data[2] = 0; + msg_data[1] = offset & 0xFF; + msg_data[2] = offset >> 8; msg_data[3] = FRU_DATA_RQST_SIZE; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { printf(" Device not present (No Response)\n"); + free(spd_data); + spd_data = NULL; return -1; } if (rsp->ccode > 0) { printf(" Device not present (%s)\n", val2str(rsp->ccode, completion_code_vals)); + free(spd_data); + spd_data = NULL; /* Timeouts are acceptable. No DIMM in the socket */ if (rsp->ccode == 0xc3) return 1; @@ -938,6 +1097,8 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id) /* now print spd info */ ipmi_spd_print(spd_data, offset); + free(spd_data); + spd_data = NULL; return 0; } |