--- /usr/bin/decode-dimms.pl 2004-10-14 17:06:09.000000000 +0200 +++ /usr/bin/decode-dimms2.pl 2005-06-20 16:56:28.000000000 +0200 @@ -2,6 +2,7 @@ # # Copyright 1998, 1999 Philip Edelbrock # modified by Christian Zuckschwerdt +# modified by Burkart Lingner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,6 +30,8 @@ # miscellaneous formatting enhancements and bug fixes # clearer HTML output (original patch by Nick Kurshev ) # stop decoding on checksum error by default (--checksum option forces) +# Version 0.8 2005-06-20 Burkart Lingner +# adapted to Kernel 2.6's /sys filesystem # # # EEPROM data decoding for SDRAM DIMM modules. @@ -115,6 +118,46 @@ } } +sub readspd16 ($$) { # reads 16 bytes from SPD-EEPROM + my ($offset, $dimm_i) = @_; + if (-e "/sys/bus/i2c/drivers/eeprom") { + # Kernel 2.6 with sysfs + open (HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom"); + binmode HANDLE; + seek (HANDLE, $offset, 0); + read (HANDLE, my $eeprom, 16); + close HANDLE; + my @bytes = (); + for my $i ( 0 .. 15 ) { + $_ = ord substr($eeprom, $i, 1); + push(@bytes, $_); + } + return @bytes; + } else { + # Kernel 2.4 with procfs + if ($offset == 0) { # bytes 0..15 + $_=`cat /proc/sys/dev/sensors/$dimm_i/00`; + } elsif ($offset == 16) { # bytes 16..31 + $_=`cat /proc/sys/dev/sensors/$dimm_i/10`; + } elsif ($offset == 32) { # bytes 32..47 + $_=`cat /proc/sys/dev/sensors/$dimm_i/20`; + } elsif ($offset == 48) { # bytes 48..63 + $_=`cat /proc/sys/dev/sensors/$dimm_i/30`; + } elsif ($offset == 64) { # bytes 64..79 + $_=`cat /proc/sys/dev/sensors/$dimm_i/40`; + } elsif ($offset == 80) { # bytes 80..95 + $_=`cat /proc/sys/dev/sensors/$dimm_i/50`; + } elsif ($offset == 96) { # bytes 96..111 + $_=`cat /proc/sys/dev/sensors/$dimm_i/60`; + } elsif ($offset == 112) { # bytes 112..127 + $_=`cat /proc/sys/dev/sensors/$dimm_i/70`; + } else { # illegal offset + $_='255 'x15 . '255'; + } + return split(" "); + } +} + for (@ARGV) { if (/-h/) { print "Usage: $0 [-f|-b|-h]\n\n", @@ -142,36 +185,47 @@ printh ' PC DIMM Serial Presence Detect Tester/Decoder -By Philip Edelbrock, Christian Zuckschwerdt and others +By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner and others Version 2.6.6 '; - my $dimm_count=0; -$_=`ls /proc/sys/dev/sensors/`; +if (-e "/sys/bus/i2c/drivers/eeprom") { $_=`ls /sys/bus/i2c/drivers/eeprom`; } +else { $_=`ls /proc/sys/dev/sensors/`; } my @dimm_list=split(); for my $i ( 0 .. $#dimm_list ) { $_=$dimm_list[$i]; - if (/^eeprom-/) { + if (-e "/sys/bus/i2c/drivers/eeprom" || /^eeprom-/) { my $dimm_checksum=0; $dimm_count += 1; - + print "

" if $opt_html; - printl2 "Decoding EEPROM" , " /proc/sys/dev/sensors/$dimm_list[$i]"; + if (-e "/sys/bus/i2c/drivers/eeprom") { + printl2 "Decoding EEPROM" , " /sys/bus/i2c/drivers/eeprom/$dimm_list[$i]"; + } else { + printl2 "Decoding EEPROM" , " /proc/sys/dev/sensors/$dimm_list[$i]"; + } print "
" if $opt_html; print "\n" if $opt_html; - if (/^[^-]+-[^-]+-[^-]+-([^-]+)$/) { - my $dimm_num=$1 - 49; - printl "Guessing DIMM is in", "bank $dimm_num"; + if (-e "/sys/bus/i2c/drivers/eeprom") { + if (/^[^-]+-([^-]+)$/) { + my $dimm_num=$1 - 49; + printl "Guessing DIMM is in", "bank $dimm_num"; + } + } else { + if (/^[^-]+-[^-]+-[^-]+-([^-]+)$/) { + my $dimm_num=$1 - 49; + printl "Guessing DIMM is in", "bank $dimm_num"; + } } # Decode first 16 bytes prints "The Following is Required Data and is Applicable to all DIMM Types"; - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/00`; - my @bytes=split(" "); + my @bytes = readspd16 (0, $dimm_list[$i]); + for my $j ( 0 .. 15 ) { $dimm_checksum = $dimm_checksum + $bytes[$j]; } - + printl "# of bytes written to SDRAM EEPROM",$bytes[0]; my $l = "Total number of bytes in EEPROM"; @@ -210,7 +264,8 @@ $l = "Data Width (SDRAM only)"; if ($bytes[7] > 1) { printl $l, "Undefined!" } else { my $temp=($bytes[7]*256) + $bytes[6]; - printl $l, $temp; } + printl $l, $temp; + } $l = "Module Interface Signal Levels"; if ($bytes[8] == 0) { printl $l, "5.0 Volt/TTL";} @@ -220,25 +275,25 @@ elsif ($bytes[8] == 4) { printl $l, "SSTL 2.5";} elsif ($bytes[8] == 255) { printl $l, "New Table";} else { printl $l, "Undefined!";} - + $l = "Cycle Time (SDRAM) highest CAS latency"; my $temp=($bytes[9] >> 4) + ($bytes[9] & 0xf) * 0.1; printl $l, "${temp}ns"; - + $l = "Access Time (SDRAM)"; $temp=($bytes[10] >> 4) + ($bytes[10] & 0xf) * 0.1; printl $l, "${temp}ns"; - + $l = "Module Configuration Type"; if ($bytes[11] == 0) { printl $l, "No Parity"; } elsif ($bytes[11] == 1) { printl $l, "Parity"; } elsif ($bytes[11] == 2) { printl $l, "ECC"; } else { printl $l, "Undefined!"; } - + $l = "Refresh Type"; if ($bytes[12] > 126) { printl $l, "Self Refreshing"; } else { printl $l, "Not Self Refreshing"; } - + $l = "Refresh Rate"; $temp=$bytes[12] & 0x7f; if ($temp == 0) { printl $l, "Normal (15.625uS)"; } @@ -248,36 +303,35 @@ elsif ($temp == 4) { printl $l, "Extended (62.5uS)"; } elsif ($temp == 5) { printl $l, "Extended (125uS)"; } else { printl $l, "Undefined!";} - + $l = "Primary SDRAM Component Bank Config"; if ($bytes[13]>126) { printl $l, "Bank2 = 2 x Bank1";} else { printl $l, "No Bank2 OR Bank2 = Bank1 width";} - + $l = "Primary SDRAM Component Widths"; $temp=$bytes[13] & 0x7f; if ($temp == 0) { printl $l, "Undefined!\n"; } else { printl $l, $temp; } - + $l = "Error Checking SDRAM Component Bank Config"; if ($bytes[14]>126) { printl $l, "Bank2 = 2 x Bank1";} else { printl $l, "No Bank2 OR Bank2 = Bank1 width";} - + $l = "Error Checking SDRAM Component Widths"; $temp=$bytes[14] & 0x7f; if ($temp == 0) { printl $l, "Undefined!"; } else { printl $l, $temp; } - + $l = "Min Clock Delay for Back to Back Random Access"; if ($bytes[15] == 0) { printl $l, "Undefined!"; } else { printl $l, $bytes[15]; } - + prints "The Following Apply to SDRAM DIMMs ONLY"; - + # Decode next 16 bytes - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/10`; - @bytes=split(" "); + @bytes = readspd16 (16, $dimm_list[$i]); for my $j ( 0 .. 15 ) { $dimm_checksum = $dimm_checksum + $bytes[$j]; } - + $l = "Burst lengths supported"; $temp=""; if (($bytes[0] & 1) > 0) { $temp .= "Burst Length = 1\n"; } @@ -290,11 +344,11 @@ if (($bytes[0] & 128) > 0) { $temp .= "Burst Length = Page\n"; } if ($bytes[0] == 0) { $temp .= "(None Supported)\n";} printl $l, $temp; - + $l = "Number of Device Banks"; if ($bytes[1] == 0) { printl $l, "Undefined/Reserved!"; } else { printl $l, $bytes[1]; } - + $l = "Supported CAS Latencies"; $temp=""; if (($bytes[2] & 1) > 0) { $temp .= "CAS Latency = 1\n";} @@ -307,7 +361,7 @@ if (($bytes[2] & 128) > 0) { $temp .= "Undefined (bit 7)\n"; } if ($bytes[2] == 0) { $temp .= "(None Supported)\n";} printl $l, $temp; - + $l = "Supported CS Latencies"; $temp=""; if (($bytes[3] & 1) > 0) { $temp .= "CS Latency = 0\n";} @@ -320,7 +374,7 @@ if (($bytes[3] & 128) > 0) { $temp .= "Undefined (bit 7)\n"; } if ($bytes[3] == 0) { $temp .= "(None Supported)\n";} printl $l, $temp; - + $l = "Supported WE Latencies"; $temp=""; if (($bytes[4] & 1) > 0) { $temp .= "WE Latency = 0\n";} @@ -333,7 +387,7 @@ if (($bytes[4] & 128) > 0) { $temp .= "Undefined (bit 7)\n"; } if ($bytes[4] == 0) { $temp .= "(None Supported)\n";} printl $l, $temp; - + $l = "SDRAM Module Attributes"; $temp=""; if (($bytes[5] & 1) > 0) { $temp .= "Buffered Address/Control Inputs\n";} @@ -346,7 +400,7 @@ if (($bytes[5] & 128) > 0) { $temp .= "Undefined (bit 7)\n"; } if ($bytes[5] == 0) { $temp .= "(None Reported)\n";} printl $l, $temp; - + $l = "SDRAM Device Attributes (General)"; $temp=""; if (($bytes[6] & 1) > 0) { $temp .= "Supports Early RAS# Recharge\n";} @@ -360,7 +414,7 @@ if (($bytes[6] & 64) > 0) { $temp .= "Undefined (bit 6)\n"; } if (($bytes[6] & 128) > 0) { $temp .= "Undefined (bit 7)\n"; } printl $l, $temp; - + $l = "SDRAM Cycle Time (2nd highest CAS)"; $temp = $bytes[7] >> 4; if ($temp == 0) { printl $l, "Undefined!"; } @@ -368,7 +422,7 @@ if ($temp < 4 ) {$temp=$temp + 15;} printl $l, $temp + (($bytes[7] & 0xf) * 0.1) . "nS"; } - + $l = "SDRAM Access from Clock Time (2nd highest CAS)"; $temp = $bytes[8] >> 4; if ($temp == 0) { printl $l, "Undefined!"; } @@ -376,40 +430,40 @@ if ($temp < 4 ) {$temp=$temp + 15;} printl $l, $temp + (($bytes[8] & 0xf) * 0.1) . "nS"; } - + prints "The Following are Optional (may be Bogus)"; - + $l = "SDRAM Cycle Time (3rd highest CAS)"; $temp = $bytes[9] >> 2; if ($temp == 0) { printl $l, "Undefined!"; } else { printl $l, $temp + ($bytes[9] & 0x3) * 0.25 . "nS"; } - + $l = "SDRAM Access from Clock Time (3rd highest CAS)"; $temp = $bytes[10] >> 2; if ($temp == 0) { printl $l, "Undefined!"; } else { printl $l, $temp + ($bytes[10] & 0x3) * 0.25 . "nS"; } - + prints "The Following are Required (for SDRAMs)"; - + $l = "Minumum Row Precharge Time"; if ($bytes[11] == 0) { printl $l, "Undefined!"; } else { printl $l, "$bytes[11]nS"; } - + $l = "Row Active to Row Active Min"; if ($bytes[12] == 0) { printl $l, "Undefined!"; } else { printl $l, "$bytes[12]nS"; } - + $l = "RAS to CAS Delay"; if ($bytes[13] == 0) { printl $l, "Undefined!"; } else { printl $l, "$bytes[13]nS"; } - + $l = "Min RAS Pulse Width"; if ($bytes[14] == 0) { printl $l, "Undefined!"; } else { printl $l, "$bytes[14]nS"; } - - + + prints "The Following are Required and Apply to ALL DIMMs"; - + $l = "Row Densities"; $temp=""; if (($bytes[15] & 1) > 0) { $temp .= "4 MByte\n";} @@ -422,35 +476,35 @@ if (($bytes[15] & 128) > 0) { $temp .= "512 MByte\n"; } if ($bytes[15] == 0) { $temp .= "(Undefined! -- None Reported!)\n";} printl $l, $temp; - - + + # Decode next 16 bytes (32-47) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/20`; - @bytes=split(" "); + @bytes = readspd16 (32, $dimm_list[$i]); + for my $j ( 0 .. 15 ) { $dimm_checksum = $dimm_checksum + $bytes[$j]; } - + prints "The Following are Proposed and Apply to SDRAM DIMMs"; - + $l = "Command and Address Signal Setup Time"; $temp = (($bytes[0] & 0x7f) >> 4) + ($bytes[0] & 0xf) * 0.1; printl $l, ( ($bytes[0] >> 7) ? -$temp : $temp ) . "nS"; - + $l = "Command and Address Signal Hold Time"; $temp = (($bytes[1] & 0x7f) >> 4) + ($bytes[1] & 0xf) * 0.1; printl $l, ( ($bytes[1] >> 7) ? -$temp : $temp ) . "nS"; - + $l = "Data Signal Setup Time"; $temp =(($bytes[2] & 0x7f) >> 4) + ($bytes[2] & 0xf) * 0.1; printl $l, ( ($bytes[2] >> 7) ? -$temp : $temp ) . "nS"; - + $l = "Data Signal Hold Time"; $temp = (($bytes[3] & 0x7f) >> 4) + ($bytes[3] & 0xf) * 0.1; printl $l, ( ($bytes[3] >> 7) ? -$temp : $temp ) . "nS"; # That's it for the lower part of an SDRAM EEPROM's memory! # Decode next 16 bytes (48-63) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/30`; - @bytes=split(" "); + @bytes = readspd16 (48, $dimm_list[$i]); + for my $j ( 0 .. 14 ) { $dimm_checksum = $dimm_checksum + $bytes[$j]; } printl "SPD Revision code ", sprintf("%x", $bytes[14]); @@ -462,51 +516,48 @@ if($bytes[15]==$dimm_checksum || $opt_igncheck) { # Decode next 16 bytes (64-79) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/40`; - @bytes=split(" "); - + @bytes = readspd16 (64, $dimm_list[$i]); + $l = "Manufacturer's JEDEC ID Code"; $temp = sprintf("0x%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X\n",$bytes[0],$bytes[1],$bytes[2],$bytes[3],$bytes[4],$bytes[5],$bytes[6],$bytes[7]); printl $l, $temp; $temp = pack("c8", $bytes[0],$bytes[1],$bytes[2],$bytes[3],$bytes[4],$bytes[5],$bytes[6],$bytes[7]); printl $l, "(\"$temp\")"; - + $l = "Manufacturing Location Code"; $temp = sprintf("0x%.2X\n",$bytes[8]); printl $l, $temp; - + $l = "Manufacurer's Part Number"; # Decode next 16 bytes (80-95) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/50`; - my @bytes2 = split ' '; + my @bytes2= readspd16 (80, $dimm_list[$i]); + $temp = pack("c18",$bytes[9],$bytes[10],$bytes[11],$bytes[12],$bytes[13],$bytes[14],$bytes[15], $bytes2[0],$bytes2[1],$bytes2[2],$bytes2[3],$bytes2[4],$bytes2[5],$bytes2[6],$bytes2[7],$bytes2[8],$bytes2[9],$bytes2[10]); printl $l, $temp; - + $l = "Revision Code"; $temp = sprintf("0x%.2X%.2X\n",$bytes2[11],$bytes2[12]); printl $l, $temp; - + $l = "Manufacturing Date"; $temp = sprintf("0x%.2X%.2X\n",$bytes2[13],$bytes2[14]); printl $l, $temp; - + $l = "Assembly Serial Number"; # Decode next 16 bytes (96-111) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/60`; - @bytes=split(" "); - + @bytes = readspd16 (96, $dimm_list[$i]); + $temp = sprintf("0x%.2X%.2X%.2X%.2X\n",$bytes2[15],$bytes[0],$bytes[1],$bytes[2]); # Decode next 16 bytes (112-127) - $_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/70`; - @bytes=split(" "); - + @bytes = readspd16 (112, $dimm_list[$i]); + $l = "Intel Specification for Frequency"; if ($bytes[14] == 102) { printl $l, "66MHz\n"; } elsif ($bytes[14] == 100) { printl $l, "100MHz\n"; } else { printl $l, "Undefined!\n"; } - + $l = "Intel Spec Details for 100MHz Support"; $temp=""; if (($bytes[15] & 1) > 0) { $temp .= "Intel Concurrent AutoPrecharge\n";} @@ -522,7 +573,7 @@ else { $temp .= "Single Sided DIMM\n";} printl $l, $temp; } - + print "
\n" if $opt_html; } }