Show
Ignore:
Timestamp:
02/16/11 16:08:25 (15 months ago)
Author:
khali
Message:

Fix detection of SPD EEPROM on DDR3 memory modules. DDR3 uses CRC16 over
128 bytes instead of basic checksum over 64 bytes. Contributed by
Clemens Ladisch.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lm-sensors/trunk/prog/detect/sensors-detect

    r5916 r5930  
    52655265 
    52665266# Registers used: 
    5267 #   0-63: SPD Data and Checksum 
     5267#   0-63: SPD Data and Checksum (up to DDR2) 
     5268#   0-127: SPD data and CRC (DDR3) 
    52685269sub eeprom_detect 
    52695270{ 
    52705271        my ($file, $addr) = @_; 
     5272        my $device_type = i2c_smbus_read_byte_data($file, 2); 
    52715273        my $checksum = 0; 
    52725274 
    5273         # Check the checksum for validity (works for most DIMMs and RIMMs) 
    5274         for (my $i = 0; $i <= 62; $i++) { 
    5275                 $checksum += i2c_smbus_read_byte_data($file, $i); 
    5276         } 
    5277         $checksum &= 255; 
    5278  
    5279         return 8 if $checksum == i2c_smbus_read_byte_data($file, 63); 
     5275        # Check the checksum or CRC16 for validity 
     5276        if ($device_type >= 1 and $device_type <= 8) { 
     5277                for (my $i = 0; $i < 63; $i++) { 
     5278                        $checksum += i2c_smbus_read_byte_data($file, $i); 
     5279                } 
     5280                $checksum &= 0xff; 
     5281 
     5282                return 8 if $checksum == i2c_smbus_read_byte_data($file, 63); 
     5283        } elsif ($device_type => 9 && $device_type <= 11) { 
     5284                # see JEDEC 21-C 4.1.2.11 2.4 
     5285                my $crc_coverage = i2c_smbus_read_byte_data($file, 0); 
     5286                $crc_coverage = ($crc_coverage & 0x80) ? 117 : 126; 
     5287                for (my $i = 0; $i < $crc_coverage; $i++) { 
     5288                        $checksum ^= i2c_smbus_read_byte_data($file, $i) << 8; 
     5289                        for (my $bit = 0; $bit < 8; $bit++) { 
     5290                                if ($checksum & 0x8000) { 
     5291                                        $checksum = ($checksum << 1) ^ 0x1021; 
     5292                                } else { 
     5293                                        $checksum <<= 1; 
     5294                                } 
     5295                        } 
     5296                } 
     5297                $checksum &= 0xffff; 
     5298 
     5299                return 8 if ($checksum & 0xff) == i2c_smbus_read_byte_data($file, 126) and 
     5300                            ($checksum >> 8) == i2c_smbus_read_byte_data($file, 127); 
     5301 
     5302                # note: if bit 7 of byte 32 is set, a jc42 sensor is at $addr-0x38 
     5303        } 
     5304 
    52805305        return; 
    52815306}