--- eeprom/decode-dimms.orig 2014-06-19 15:50:29.000000000 -0400 +++ eeprom/decode-dimms 2014-06-19 16:18:34.000000000 -0400 @@ -42,7 +42,7 @@ use Fcntl qw(:DEFAULT :seek); use File::Basename; use vars qw($opt_html $opt_bodyonly $opt_side_by_side $opt_merge - $opt_igncheck $use_sysfs $use_hexdump $sbs_col_width + $opt_igncheck $opt_smbdev $use_smbdev $use_hexdump $sbs_col_width @vendors %decode_callback $revision @dimm $current %hexdump_cache); use constant LITTLEENDIAN => "little-endian"; @@ -305,7 +305,7 @@ "Silicon Space Technology"] ); -$use_sysfs = -d '/sys/bus'; +$use_smbdev = '/dev/smb0'; # We consider that no data was written to this area of the SPD EEPROM if # all bytes read 0x00 or all bytes read 0xff @@ -1079,6 +1079,9 @@ printl("Module Configuration Type", sdram_module_configuration_type($bytes->[11])); + printl("Module Configuration Type", + sdram_module_configuration_type($bytes->[11])); + printl("Refresh Rate", ddr2_refresh_rate($bytes->[12])); my @burst; @@ -1289,8 +1292,9 @@ printl("DLL-Off Mode supported?", ($bytes->[30] & 128) ? "Yes" : "No"); printl("Operating temperature range", sprintf "0-%d degrees C", ($bytes->[31] & 1) ? 95 : 85); - printl("Refresh Rate in extended temp range", - ($bytes->[31] & 2) ? "2X" : "1X"); + printl_cond($bytes->[31] & 1, + "Refresh Rate in extended temp range", + ($bytes->[31] & 2) ? "1X" : "2X"); printl("Auto Self-Refresh?", ($bytes->[31] & 4) ? "Yes" : "No"); printl("On-Die Thermal Sensor readout?", ($bytes->[31] & 8) ? "Yes" : "No"); @@ -1624,6 +1628,28 @@ } } +sub freebsd_readbyte ($$) { + my ($offset, $dimm_i) = @_; + + my $command = sprintf('/usr/sbin/smbmsg -f %s -s %#02x -c %d -i 1 -F %%02x 2>/dev/null', + $use_smbdev, $dimm_i, $offset); + my $output = `$command`; + chomp($output); + my $byte = hex($output); + return $byte; +} + +sub freebsd_readword ($$) { + my ($offset, $dimm_i) = @_; + + my $command = sprintf('/usr/sbin/smbmsg -f %s -s %#02x -c %d -w -i 2 -F %%04x 2>/dev/null', + $use_smbdev, $dimm_i, $offset); + my $output = `$command`; + chomp($output); + my $word = hex($output); + return $word; +} + # Read bytes from SPD-EEPROM # Note: offset must be a multiple of 16! sub readspd($$$) @@ -1633,22 +1659,14 @@ if ($use_hexdump) { @bytes = read_hexdump($dimm_i); return @bytes[$offset..($offset + $size - 1)]; - } elsif ($use_sysfs) { - # Kernel 2.6 with sysfs - sysopen(HANDLE, "$dimm_i/eeprom", O_RDONLY) - or die "Cannot open $dimm_i/eeprom"; - binmode HANDLE; - sysseek(HANDLE, $offset, SEEK_SET) - or die "Cannot seek $dimm_i/eeprom"; - sysread(HANDLE, my $eeprom, $size) - or die "Cannot read $dimm_i/eeprom"; - close HANDLE; - @bytes = unpack("C*", $eeprom); } else { - # Kernel 2.4 with procfs - for my $i (0 .. ($size-1)/16) { - my $hexoff = sprintf('%02x', $offset + $i * 16); - push @bytes, split(" ", `cat $dimm_i/$hexoff`); +# for my $i (0 .. ($size - 1)) { +# push (@bytes, freebsd_readbyte($offset + $i, $dimm_i)); +# } + for my $i (0 .. (($size - 1) / 2)) { + my $word = freebsd_readword($offset + 2 * $i, $dimm_i); + push (@bytes, $word & 0xff); + push (@bytes, $word >> 8); } } return @bytes; @@ -1702,7 +1720,7 @@ # Parse command-line foreach (@ARGV) { if ($_ eq '-h' || $_ eq '--help') { - print "Usage: $0 [-c] [-f [-b]] [-x|-X file [files..]]\n", + print "Usage: $0 [-c] [-f [-b]] [-d|-x|-X file [files..]]\n", " $0 -h\n\n", " -f, --format Print nice html output\n", " -b, --bodyonly Don't print html header\n", @@ -1711,6 +1729,7 @@ " --merge-cells Merge neighbour cells with identical values\n", " (side-by-side output only)\n", " -c, --checksum Decode completely even if checksum fails\n", + " -d, Read data from the device\n", " -x, Read data from hexdump files\n", " -X, Same as -x except treat multibyte hex\n", " data as little endian\n", @@ -1746,6 +1765,10 @@ $opt_igncheck = 1; next; } + if ($_ eq '-d') { + $opt_smbdev = 1; + next; + } if ($_ eq '-x') { $use_hexdump = BIGENDIAN; next; @@ -1760,7 +1783,11 @@ exit; } - push @dimm, { eeprom => basename($_), file => $_ } if $use_hexdump; + if ($opt_smbdev) { + $use_smbdev = $_; + } else { + push @dimm, { eeprom => basename($_), file => $_ } if $use_hexdump; + } } if ($opt_html && !$opt_bodyonly) { @@ -1777,61 +1804,20 @@ Jean Delvare, Trent Piepho and others'); -# From a sysfs device path and an attribute name, return the attribute -# value, or undef (stolen from sensors-detect) -sub sysfs_device_attribute -{ - my ($device, $attr) = @_; - my $value; - - open(local *FILE, "$device/$attr") or return ""; - $value = ; - close(FILE); - return unless defined $value; - - chomp($value); - return $value; -} - sub get_dimm_list { - my (@dirs, $dir, $opened, $file, @files); - - if ($use_sysfs) { - @dirs = ('/sys/bus/i2c/drivers/eeprom', '/sys/bus/i2c/drivers/at24'); - } else { - @dirs = ('/proc/sys/dev/sensors'); - } - - foreach $dir (@dirs) { - next unless opendir(local *DIR, $dir); - $opened++; - while (defined($file = readdir(DIR))) { - if ($use_sysfs) { - # We look for I2C devices like 0-0050 or 2-0051 - next unless $file =~ /^\d+-[\da-f]+$/i; - next unless -d "$dir/$file"; - - # Device name must be eeprom (driver eeprom) - # or spd (driver at24) - my $attr = sysfs_device_attribute("$dir/$file", "name"); - next unless defined $attr && - ($attr eq "eeprom" || $attr eq "spd"); - } else { - next unless $file =~ /^eeprom-/; - } - push @files, { eeprom => "$file", - file => "$dir/$file" }; - } - close(DIR); - } - - if (!$opened) { - print STDERR "No EEPROM found, try loading the eeprom or at24 module\n"; - exit; + my @dimms; + if (! -c $use_smbdev) { + print "SMBus device not found\n"; + exit; + } + for my $spd (0xA0 .. 0xAE) { + next if ($spd % 2 != 0); + my @test_bytes = readspd(0, 4, $spd); + next unless spd_written(@test_bytes); + push @dimms, { eeprom => sprintf('0x%02X', $spd), file => $spd }; } - - return sort { $a->{file} cmp $b->{file} } @files; + return @dimms; } # @dimm is a list of hashes. There's one hash for each EEPROM we found. @@ -2022,7 +2008,7 @@ print "\n\n"; } else { print "" if $opt_html; - printl2("\n\nDecoding EEPROM", $dimm[$current]->{file}); + printl2("\n\nDecoding EEPROM", $dimm[$current]->{eeprom}); print "" if $opt_html; } print "\n" if $opt_html;