[PATCH i2c-tools v4 1/8] decode-dimms: Implement DDR5 checksum parsing
Stephen Horvath <[email protected]> Thu, 23 Jul 2026 13:40:12 +0000
| Newsgroups | org.kernel.vger.linux-i2c |
|---|---|
| Message-ID | <[email protected]> |
The CRC for the DDR5 SPD is located at bytes 510-511 of the SPD data. There is now functionality to read upto byte 512 and calculate the CRC16 if byte 2 indicates DDR5 memory and byte 0 indicates at least 512 bytes. This patch is based off of a patch by Guenter Roeck, linked below. Link: https://lore.kernel.org/linux-hwmon/[email protected]/ Cc: Guenter Roeck <[email protected]> Signed-off-by: Stephen Horvath <[email protected]> --- eeprom/decode-dimms | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms index 7682345..149178f 100755 --- a/eeprom/decode-dimms +++ b/eeprom/decode-dimms @@ -22,7 +22,8 @@ # the legacy eeprom driver (in the kernel tree since v2.6.0). For kernels # older than 2.6.0, the eeprom driver can be found in the lm-sensors 2 # package. For DDR4, you need the ee1004 driver (in the kernel tree since -# kernel v4.20). +# kernel v4.20). For DDR5, you need the spd5118 driver (in the kernel tree +# since v6.11). # # References: # PC SDRAM Serial Presence @@ -2402,7 +2403,12 @@ sub spd_sizes($) my $bytes = shift; my $type = $bytes->[2]; - if ($type == 12 || $type == 14 || $type == 16 || $type == 17) { + if ($type == 18 || $type == 19 || $type == 20 || $type == 21) { + # DDR5 + my $spd_len = 2 ** (7 + (($bytes->[0] >> 4) & 7)); + my $used = $spd_len; + return ($spd_len, $used); + } elsif ($type == 12 || $type == 14 || $type == 16 || $type == 17) { # DDR4 my $spd_len = 256 * (($bytes->[0] >> 4) & 7); my $used = 128 * ($bytes->[0] & 15); @@ -2511,10 +2517,16 @@ sub calculate_crc($$$) sub check_crc($) { my $bytes = shift; + my $is_ddr5 = ($bytes->[0] & 0x70) == 0x30; my $crc_cover = $bytes->[0] & 0x80 ? 116 : 125; + my $crc_start = 126; + if ($is_ddr5) { + $crc_cover = 509; + $crc_start = 510; + } my $crc = calculate_crc($bytes, 0, $crc_cover + 1); - my $dimm_crc = ($bytes->[127] << 8) | $bytes->[126]; + my $dimm_crc = ($bytes->[$crc_start + 1] << 8) | $bytes->[$crc_start]; return ("EEPROM CRC of bytes 0-$crc_cover", ($dimm_crc == $crc) ? 1 : 0, sprintf("0x%04X", $dimm_crc), @@ -2617,7 +2629,8 @@ sub get_dimm_list if ($use_sysfs) { @drivers = ('eeprom', 'at24', - 'ee1004'); # DDR4 + 'ee1004', # DDR4 + 'spd5118'); # DDR5 } else { @drivers = ('eeprom'); $dir = '/proc/sys/dev/sensors'; @@ -2642,7 +2655,8 @@ sub get_dimm_list next unless defined $attr && ($attr eq "eeprom" || $attr eq "spd" || - $attr eq "ee1004"); # DDR4 + $attr eq "ee1004" || # DDR4 + $attr eq "spd5118"); # DDR5 } else { next unless $file =~ /^eeprom-/; } @@ -2654,7 +2668,7 @@ sub get_dimm_list } if (!$opened) { - print STDERR "No EEPROM found, try loading the eeprom, at24 or ee1004 module\n"; + print STDERR "No EEPROM found, try loading the eeprom, at24, ee1004 or spd5118 module\n"; exit; } @@ -2684,6 +2698,11 @@ for my $i (0 .. $#dimm) { $dimm[$i]->{chk_spd}, $dimm[$i]->{chk_calc}) = checksum(\@bytes); } else { + # Check for DDR5 protocol type 18, 19, 20, 21 and size >= 512 + if ($bytes[2] >= 18 && $bytes[2] <= 21 && ($bytes[0] & 0x70) >= 0x30) { + # DDR5's checksum is at 510-511 + push(@bytes, readspd(@bytes, 512, $dimm[$i]->{file})); + } ($dimm[$i]->{chk_label}, $dimm[$i]->{chk_valid}, $dimm[$i]->{chk_spd}, $dimm[$i]->{chk_calc}) = check_crc(\@bytes); -- 2.53.0