The attached diffs provide some preliminary decode of the DDR3 SPD... Warning: I'm no perl expert. The code I've written is probably ugly to most of the readers of this list. But it does work! ---------------------------------------------------------------------- | Paul Goyette | PGP DSS Key fingerprint: | E-mail addresses: | | Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com | | Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net | ---------------------------------------------------------------------- -------------- next part -------------- 872a873,983 > # Parameter: bytes 0-127 > sub decode_ddr3_sdram($) > { > my $bytes = shift; > my $l; > my $temp; > my $ctime; > > # SPD revision > if ($bytes->[62] != 0xff) { > printl "SPD Revision", ($bytes->[62] >> 4) . "." . > ($bytes->[62] & 0xf); > } > > # speed > prints "Memory Characteristics"; > > $l = "Fine time base"; > my $dividend = ($bytes->[9] >> 4) & 15; > my $divisor = $bytes->[9] & 15; > printl $l, sprintf("%.3f", $dividend / $divisor) . " ps"; > > $l = "Medium time base"; > $dividend = $bytes->[10]; > $divisor = $bytes->[11]; > my $mtb = $dividend / $divisor; > printl $l, sprintf("%.3f", $mtb) . " ns"; > > $l = "Maximum module speed"; > $ctime = $bytes->[12] * $mtb; > my $ddrclk = 2 * (1000 / $ctime); > my $tbits = 1 << (($bytes->[8] & 7) + 3); > my $pcclk = int ($ddrclk * $tbits / 8); > $ddrclk = int ($ddrclk); > printl $l, "${ddrclk}MHz (PC3-${pcclk})"; > > # Size computation > > my $cap = ($bytes->[4] & 15) + 28; > $cap += ($bytes->[8] & 7) + 3; > $cap -= ($bytes->[7] & 7) + 2; > $cap -= 20 + 3; > my $k = (($bytes->[7] >> 3) & 31) + 1; > printl "Size", ((1 << $cap) * $k) . " MB"; > > printl "Banks x Rows x Columns x Bits", > join(' x ', 1 << ((($bytes->[4] >> 4) & 7) + 3), > ((($bytes->[5] >> 3) & 31) + 12), > ( ($bytes->[5] & 7) + 9), > ( 1 << (($bytes->[6] & 7) + 3)) ); > printl "Ranks", $k; > > printl "SDRAM Device Width", $bytes->[13]." bits"; > > my $taa; > my $trcd; > my $trp; > my $tras; > > $taa = int($bytes->[16] / $bytes->[12]); > $trcd = int($bytes->[18] / $bytes->[12]); > $trp = int($bytes->[20] / $bytes->[12]); > $tras = int((($bytes->[21] >> 4) * 256 + $bytes->[22]) / $bytes->[12]); > > printl "tCL-tRCD-tRP-tRAS", join("-", $taa, $trcd, $trp, $tras); > > prints "Manufacturer Data"; > > $l = "Module Manufacturer Code"; > printl $l, sprintf("0x%.2X%.2X", $bytes->[118], $bytes->[117]); > > $l = "DRAM Manufacturer Code"; > printl $l, sprintf("0x%.2X%.2X", $bytes->[148], $bytes->[149]); > > $l = "Manufacturing Location"; > $temp = (chr($bytes->[8]) =~ m/^[\w\d]$/) ? chr($bytes->[8]) > : sprintf("0x%.2X", $bytes->[8]); > printl $l, $temp; > > $l = "Part Number"; > $temp = ""; > for (my $i = 128; $i <= 145; $i++) { > $temp .= chr($bytes->[$i]); > }; > printl $l, $temp; > > $l = "Revision"; > $temp = sprintf("0x%02X%02X\n", $bytes->[146], $bytes->[147]); > printl $l, $temp; > > $l = "Manufacturing Date"; > # In theory the year and week are in BCD format, but > # this is not always true in practice :( > if (($bytes->[120] & 0xf0) <= 0x90 > && ($bytes->[120] & 0x0f) <= 0x09 > && ($bytes->[121] & 0xf0) <= 0x90 > && ($bytes->[121] & 0x0f) <= 0x09) { > # Note that this heuristic will break in year 2080 > $temp = sprintf("%d%02X-W%02X\n", > $bytes->[120] >= 0x80 ? 19 : 20, > $bytes->[120], $bytes->[121]); > } else { > $temp = sprintf("0x%02X%02X\n", $bytes->[120], $bytes->[121]); > } > printl $l, $temp; > > $l = "Assembly Serial Number"; > $temp = sprintf("0x%02X%02X%02X%02X\n", $bytes->[122], $bytes->[123]); > printl $l, $temp; > } > 1063a1175 > "DDR3 SDRAM" => \&decode_ddr3_sdram, 1181a1294,1319 > sub readfullspd($$) # reads all bytes from SPD-EEPROM > { > my ($size, $dimm_i) = @_; > my @bytes; > if ($use_hexdump) { > @bytes = read_hexdump($dimm_i); > return @bytes[0..$size]; > } elsif ($use_sysfs) { > # Kernel 2.6 with sysfs > sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY) > or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom"; > binmode HANDLE; > sysseek(HANDLE, 0, SEEK_SET); > sysread(HANDLE, my $eeprom, $size); > close HANDLE; > @bytes = unpack(sprintf("C%d", $size), $eeprom); > } else { > # Kernel 2.4 with procfs > for my $i (0 .. $size/16) { > my $hexoff = sprintf('%02x', $i * 16); > push @bytes, split(" ", `cat /proc/sys/dev/sensors/$dimm_i/$hexoff`); > } > } > return @bytes; > } > 1274,1276d1411 < next unless $bytes[63] == $dimm_checksum || $opt_igncheck; < $dimm_count++; < 1295,1300d1429 < my $l = "EEPROM Checksum of bytes 0-62"; < printl $l, ($bytes[63] == $dimm_checksum ? < sprintf("OK (0x%.2X)", $bytes[63]): < sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n", < $bytes[63], $dimm_checksum)); < 1302c1431,1476 < my $is_rambus = $bytes[0] < 4; --- > my $is_rambus = ($bytes[0] < 4 && $bytes[0] >= 0); > > if ($is_rambus || $bytes[2] <= 8) { > my $l = "EEPROM Checksum of bytes 0-62"; > printl $l, ($bytes[63] == $dimm_checksum ? > sprintf("OK (0x%.2X)", $bytes[63]): > sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n", > $bytes[63], $dimm_checksum)); > next unless $bytes[63] == $dimm_checksum || > $opt_igncheck; > $dimm_count++; > > } else { > my @sizes = ( 128, 176, 256, 0, 0, 0, 0, 0); > my $spdsize = $sizes[($bytes[0] >> 4) & 7]; > > @bytes = readfullspd($spdsize, $dimm_list[$i]); > my $dimm_crc = 0; > my $crc_cover = $bytes[0] & 0x80 ? 116 : 125; > my $crc_ptr = 0; > my $crc_bit; > while ($crc_ptr <= $crc_cover) { > $dimm_crc = $dimm_crc ^ ($bytes[$crc_ptr] << 8); > for ($crc_bit = 0; $crc_bit < 8; $crc_bit++) { > if ($dimm_crc & 0x8000) { > $dimm_crc = ($dimm_crc << 1) ^ > 0x1021; > } else { > $dimm_crc = $dimm_crc << 1 > } > } > $crc_ptr++; > } > $dimm_crc = $dimm_crc & 0xffff; > > my $l = "EEPROM CRC of bytes 0-" . > sprintf("%d", $crc_cover); > my $crc_calc = $bytes[127] << 8 | $bytes[126]; > printl $l, ($dimm_crc == $crc_calc)? > sprintf("OK (0x%.4X)", $dimm_crc): > sprintf("Bad\n(found 0x%.4X, calculated 0x%.4X)\n", > $crc_calc, $dimm_crc); > next unless $crc_calc == $dimm_crc || $opt_igncheck; > $dimm_count++; > } > 1315c1489 < $l = "Total number of bytes in EEPROM"; --- > my $l = "Total number of bytes in EEPROM"; 1335a1510,1512 > elsif ($bytes[2] == 9) { $type = "FB-DIMM"; } > elsif ($bytes[2] == 10) { $type = "FB-DIMM PROBE"; } > elsif ($bytes[2] == 11) { $type = "DDR3 SDRAM"; } 1342a1520,1524 > # DDR3 Manufacturer info is already decoded > # (It's NOT common!) > > next if ($type == "DDR3 SDRAM"); > 1346c1528,1532 < @bytes = readspd64(64, $dimm_list[$i]); --- > if ($#bytes == 63) { > @bytes = readspd64(64, $dimm_list[$i]); > } else { > @bytes = @bytes[64..$#bytes]; > }