* [PATCH 0/6] decode-dimms: Implement DDR5 decoding
@ 2024-11-14 6:37 Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 1/6] decode-dimms: Implement DDR5 checksum parsing Stephen Horvath via B4 Relay
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
Hi, this series of patches adds DDR5 support to decode-dimms.
I'm not too experienced with perl or the JEDEC specs, so there's probably
going to be some questionable choices here, but I'd love to hear
feedback.
The first 4 patches (1, 2, 3, 4) add the essential information to
decode-dimms.
The next 2 patches (5, 6) haven't really been tested on hardware
implementations so I'm happy for them to be dropped if they're not
useful.
I also wrote these a few months ago, but wasn't sure if I'd be free
enough for any revisions at the time.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
Stephen Horvath (6):
decode-dimms: Implement DDR5 checksum parsing
decode-dimms: Decode DDR5 Manufacturer Data
decode-dimms: Decode timings and other data for DDR5
decode-dimms: Decode DDR5 common module information
decode-dimms: Add basic decoding of type specific information for DDR5
decode-dimms: Decode DDR5 error log
eeprom/decode-dimms | 517 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 513 insertions(+), 4 deletions(-)
---
base-commit: cd435c853bc9df0058620a471d4191c7de27a2f9
change-id: 20240625-decode-ddr5-b8aa4545812e
Best regards,
--
Stephen Horvath <s.horvath@outlook.com.au>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/6] decode-dimms: Implement DDR5 checksum parsing
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 2/6] decode-dimms: Decode DDR5 Manufacturer Data Stephen Horvath via B4 Relay
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
The code here was mostly written by Guenter Roeck with some modifications
for compatibility with other types by me, but it was originally written
only to verify that the eeprom is being read correctly while developing
spd5118. It looks okay to me, although there might be a better way of
figuring out the amount of bytes needed to check the checksum.
Link: https://lore.kernel.org/linux-hwmon/efb77b37-30e5-48a8-b4af-eb9995a2882b@roeck-us.net/
Cc: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index 32e840a107cd3425039fcbc6ce317e2ef610acc1..88ebe67d86d52486c8ce439d885fb3f9c89526b6 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2402,7 +2402,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 = 256 * ((($bytes->[0] >> 4) & 7) + 1);
+ 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 +2516,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 +2628,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 +2654,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-/;
}
@@ -2684,6 +2697,9 @@ for my $i (0 .. $#dimm) {
$dimm[$i]->{chk_spd}, $dimm[$i]->{chk_calc}) =
checksum(\@bytes);
} else {
+ if (($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.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/6] decode-dimms: Decode DDR5 Manufacturer Data
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 1/6] decode-dimms: Implement DDR5 checksum parsing Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 3/6] decode-dimms: Decode timings and other data for DDR5 Stephen Horvath via B4 Relay
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
Decode the DRAM's manufacturer data for DDR5.
There are more manufacturers in the common and type specific sections,
but I decided to limit myself to only reading the
'Manufacturing Information' section of the eeprom.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index 88ebe67d86d52486c8ce439d885fb3f9c89526b6..b395eafca9ba17725e391e18a70d303c0baaa291 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2278,6 +2278,48 @@ sub decode_ddr4_mfg_data($)
sprintf("0x%02X", $bytes->[349]));
}
+# Parameter: EEPROM bytes 0-639 (using 512-554)
+sub decode_ddr5_mfg_data($)
+{
+ my $bytes = shift;
+
+ prints("Manufacturer Data");
+
+ printl("Module Manufacturer",
+ manufacturer_ddr3($bytes->[512], $bytes->[513]));
+
+ printl_cond(spd_written(@{$bytes}[552..553]),
+ "DRAM Manufacturer",
+ manufacturer_ddr3($bytes->[552], $bytes->[553]));
+
+ printl_mfg_location_code($bytes->[514]);
+
+ printl_cond(spd_written(@{$bytes}[515..516]),
+ "Manufacturing Date",
+ manufacture_date($bytes->[515], $bytes->[516]));
+
+ printl_mfg_assembly_serial(@{$bytes}[517..520]);
+
+ printl("Part Number", part_number(@{$bytes}[521..550]));
+
+ printl_cond(spd_written(@{$bytes}[551]),
+ "Revision Code",
+ sprintf("0x%02X", $bytes->[551]));
+
+ if ($bytes->[554] != 0xff) {
+ # DRAM Stepping may be a number or an uppercase ASCII letter
+ # 0x00-0xfe is valid, 0xff is invalid
+ my $stepping = $bytes->[554];
+ if ($stepping < 0x41 || $stepping > 0x5a) {
+ printl("DRAM Stepping",
+ sprintf("0x%02X", $stepping));
+ } else {
+ printl("DRAM Stepping",
+ sprintf("%c", $stepping));
+ }
+ }
+}
+
# Parameter: EEPROM bytes 0-127 (using 64-98)
sub decode_manufacturing_information($)
{
@@ -2828,6 +2870,15 @@ for $current (0 .. $#dimm) {
} elsif (!$use_hexdump && $dimm[$current]->{driver} ne "ee1004") {
print STDERR "HINT: You should be using the ee1004 driver instead of the $dimm[$current]->{driver} driver\n";
}
+ } elsif ($type eq "DDR5 SDRAM" ||
+ $type eq "LPDDR5 SDRAM" ||
+ $type eq "DDR5 NVDIMM-P" ||
+ $type eq "LPDDR5X SDRAM") {
+ if (@bytes >= 640) {
+ # Decode DDR5-specific manufacturing data in bytes
+ # 512-639
+ decode_ddr5_mfg_data(\@bytes);
+ }
} else {
# Decode next 35 bytes (64-98, common to most
# memory types)
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/6] decode-dimms: Decode timings and other data for DDR5
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 1/6] decode-dimms: Implement DDR5 checksum parsing Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 2/6] decode-dimms: Decode DDR5 Manufacturer Data Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 4/6] decode-dimms: Decode DDR5 common module information Stephen Horvath via B4 Relay
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
Decode size, timings, and other data for DDR5. I'm no expert at RAM
timings, so I hope it's correct. The values in my BIOS do seem to match
up with those here.
Although I am a little confused why most of the timings are one cycle
less than it seems they should be (e.g. 40-39-39-77, and not 40-40-40-78),
but the output is correct (according to BIOS and module specs).
There are also more timings that I'd like to add in the future.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 230 insertions(+)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index b395eafca9ba17725e391e18a70d303c0baaa291..4a19e962cd1f837ccdb6660caa8d198f65e3fc4f 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2127,6 +2127,231 @@ sub decode_ddr4_sdram($)
}
}
+# DDR5 Rounding Algorithm
+sub ddr5_round($$)
+{
+ my ($tck, $twr) = @_;
+ my $correction = 3; # 0.30% per the rounding algorithm
+ my $new_twr = $twr * (1000 - $correction);
+ $tck = ($new_twr / $tck) + 1000;
+
+ return $twr / int($tck / 1000);
+}
+
+# Return combined time in ns
+sub ddr5_ns($$)
+{
+ my ($bytes, $index) = @_;
+
+ return (($bytes->[$index + 1] << 8) | $bytes->[$index]) / 1000;
+}
+
+# Parameter: EEPROM bytes 0-639 (using 1-255)
+sub decode_ddr5_sdram($)
+{
+ my $bytes = shift;
+ my ($ctime, $ctime_max);
+ my $ii;
+
+ my @module_types = (
+ { type => "Reserved (0x00)", },
+ { type => "RDIMM", },
+ { type => "UDIMM", },
+ { type => "SODIMM", },
+ { type => "LRDIMM", },
+ { type => "CUDIMM", },
+ { type => "CSOUDIMM", },
+ { type => "MRDIMM", },
+ { type => "CAMM2", },
+ { type => "Reserved (0x09)", },
+ { type => "DDIMM", },
+ { type => "Solder down", },
+ { type => "Reserved (0x0C)", },
+ { type => "Reserved (0x0D)", },
+ { type => "Reserved (0x0E)", },
+ { type => "Reserved (0x0F)", },
+ );
+
+# SPD revision
+ printl("SPD Revision", ($bytes->[1] >> 4) . "." . ($bytes->[1] & 0xf));
+
+ my $raw_type = $bytes->[3];
+ my $type = $raw_type & 0x0f;
+ printl("Module Type", $module_types[$type]->{type});
+
+# time bases
+ if (($bytes->[19] & 0x03) != 0x00 || ($bytes->[19] & 0xc0) != 0x00) {
+ print STDERR "Unknown time base values, can't decode\n";
+ return;
+ }
+
+ my $twr = ddr5_ns($bytes, 40);
+
+# speed
+ prints("Memory Characteristics");
+
+ $ctime = ddr5_ns($bytes, 20);
+ $ctime = ddr5_round($ctime, $twr);
+ $ctime_max = ddr5_ns($bytes, 22);
+ $ctime_max = ddr5_round($ctime_max, $twr);
+
+ my $ddrclk = 2 * (1000 / $ctime);
+ my $tbits = 8 << ($bytes->[235] & 7);
+ my $pcclk = int ($ddrclk * $tbits / 8);
+ # Round down to comply with Jedec
+ $pcclk = $pcclk - ($pcclk % 100);
+ $ddrclk = int ($ddrclk);
+ printl("Maximum module speed", "$ddrclk MT/s (PC5-${pcclk})");
+
+# Size computation
+ my $rank_mix = $bytes->[234] & 0x40;
+ my $sdram_width0 = 4 << (($bytes->[6] >> 5) & 0x07);
+ my $sdram_width1 = 4 << (($bytes->[10] >> 5) & 0x07);
+ my $bus_width = 8 << ($bytes->[235] & 0x07);
+ my $ranks = (($bytes->[234] >> 3) & 0x07) + 1;
+ my $subchannels = 1 << (($bytes->[235] >> 5) & 0x07);
+
+ my $die_count0 = (($bytes->[4] >> 5) & 0x07) + 1;
+ my $die_3ds0 = $die_count0 > 2;
+ if ($die_3ds0) { $die_count0 >>= 1; }
+
+ my $die_count1 = (($bytes->[8] >> 5) & 0x07) + 1;
+ my $die_3ds1 = $die_count1 > 2;
+ if ($die_3ds1) { $die_count1 >>= 1; }
+
+ my $die_count = $die_count0 + $die_count1;
+ my $density0 = ($bytes->[4] & 0x1f) * 4;
+ my $density1 = ($bytes->[8] & 0x1f) * 4;
+
+ my $cap0 = $subchannels * ($bus_width / $sdram_width0) * $die_count0 * ($density0 / 8) * $ranks;
+ my $cap1 = $subchannels * ($bus_width / $sdram_width1) * $die_count1 * ($density1 / 8) * $ranks;
+ my $cap = $cap0 + $cap1;
+
+ printl("Size", $cap . " GB");
+
+ printl("Banks x Rows x Columns x Bits" . ($rank_mix ? " (Even Rank)" : ""),
+ join(' x ', (1 << (($bytes->[7] >> 5) & 0x07)) * (1 << ($bytes->[7] & 0x07)),
+ (( $bytes->[5] & 0x1f) + 16),
+ ((($bytes->[5] >> 5) & 0x05) + 10),
+ (8 << ($bytes->[235] & 0x07))));
+
+ printl_cond($rank_mix, "Banks x Rows x Columns x Bits (Odd Rank)",
+ join(' x ', (1 << (($bytes->[11] >> 5) & 0x07)) * (1 << ($bytes->[11] & 0x07)),
+ (( $bytes->[9] & 0x1f) + 16),
+ ((($bytes->[9] >> 5) & 0x05) + 10),
+ (8 << ($bytes->[235] & 0x07))));
+
+ printl("SDRAM Device Width" . ($rank_mix ? " (Even Rank)" : ""), "$sdram_width0 bits");
+ printl_cond($rank_mix, "SDRAM Device Width (Odd Rank)", "$sdram_width1 bits");
+
+ printl("Ranks", $ranks);
+ printl_cond($ranks > 1, "Rank Mix",
+ $rank_mix ? "Asymmetrical" : "Symmetrical");
+ printl("Primary Bus Width", (8 << ($bytes->[235] & 7))." bits");
+ printl_cond($bytes->[235] & 0x18, "Bus Width Extension", (($bytes->[235] & 0x18) >> 1) ." bits");
+
+ my $taa;
+ my $trcd;
+ my $trp;
+ my $tras;
+
+ $taa = ddr5_ns($bytes, 30);
+ $trcd = ddr5_ns($bytes, 32);
+ $trp = ddr5_ns($bytes, 34);
+ $tras = ddr5_ns($bytes, 36);
+
+ printl("AA-RCD-RP-RAS (cycles)",
+ ddr4_core_timings(ceil(($taa * 997 / $ctime + 1000) / 1000),
+ $ctime, $trcd, $trp, $tras));
+
+# latencies
+ my %cas;
+ my $cas_sup = ($bytes->[28] << 32) + ($bytes->[27] << 24) +
+ ($bytes->[26] << 16) + ($bytes->[25] << 8) + $bytes->[24];
+ my $base_cas = 20;
+
+ for ($ii = 0; $ii < 40; $ii++) {
+ if ($cas_sup & (1 << $ii)) {
+ $cas{$base_cas + ($ii * 2)}++;
+ }
+ }
+ printl("Supported CAS Latencies", cas_latencies(keys %cas));
+
+# standard DDR5 speeds
+ prints("Timings at Standard Speeds");
+ foreach my $ctime_at_speed (5/22, 5/21, 5/20, 5/19, 5/18, 5/17, 5/16,
+ 5/15, 5/14, 5/13, 5/12, 5/11, 5/10, 5/9, 5/8) {
+ my $best_cas = 0;
+
+
+ # Find min CAS latency at this speed
+ for ($ii = 39; $ii >= 0; $ii--) {
+ next unless ($cas_sup & (1 << $ii));
+ if (ceil(($taa * 997 / $ctime_at_speed + 1000) / 1000) <= $base_cas + ($ii * 2)) {
+ $best_cas = $base_cas + ($ii * 2);
+ }
+ }
+
+ printl_cond($best_cas && $ctime_at_speed >= $ctime
+ && $ctime_at_speed <= $ctime_max,
+ "AA-RCD-RP-RAS (cycles)" . as_ddr(5, $ctime_at_speed),
+ ddr4_core_timings($best_cas, $ctime_at_speed,
+ $trcd, $trp, $tras));
+ }
+
+# more timing information
+ prints("Timing Parameters");
+
+ printl("Minimum Cycle Time (tCKmin)", tns3($ctime));
+ printl("Maximum Cycle Time (tCKmax)", tns3($ctime_max));
+ printl("Minimum CAS Latency Time (tAA)", tns3($taa));
+ printl("Minimum RAS to CAS Delay (tRCD)", tns3($trcd));
+ printl("Minimum Row Precharge Delay (tRP)", tns3($trp));
+ printl("Minimum Active to Precharge Delay (tRAS)", tns3($tras));
+ printl("Minimum Active to Auto-Refresh Delay (tRC)", tns3(ddr5_ns($bytes, 38)));
+ printl("Minimum Recovery Delay (tRFC1)", tns3(ddr5_ns($bytes, 42)));
+ printl("Minimum Recovery Delay (tRFC2)", tns3(ddr5_ns($bytes, 44)));
+ printl("Minimum Recovery Delay (tRFCsb)", tns3(ddr5_ns($bytes, 46)));
+ printl("Minimum Four Activate Window Delay (tFAW)", tns3(ddr5_ns($bytes, 82)) . " (" . $bytes->[84] . " cycles)");
+ printl("Minimum Row Active to Row Active Delay (tRRD_L)", tns3(ddr5_ns($bytes, 70)) . " (" . $bytes->[72] . " cycles)");
+ printl("Minimum CAS to CAS Delay (tCCD_L)", tns3(ddr5_ns($bytes, 73)) . " (" . $bytes->[75] . " cycles)");
+ printl("Minimum Write Recovery Time (tWR)", tns3(ddr5_ns($bytes, 40)));
+ printl("Minimum Write to Read Time (tWTR_S)", tns3(ddr5_ns($bytes, 88)) . " (" . $bytes->[90] . " cycles)");
+ printl("Minimum Write to Read Time (tWTR_L)", tns3(ddr5_ns($bytes, 85)) . " (" . $bytes->[87] . " cycles)");
+
+# miscellaneous stuff
+ prints("Other Information");
+
+ my $package_type0 = $die_3ds0 ? "3DS" :
+ $die_count0 > 1 ? "Dual-die package" :
+ $die_count0 == 1 ? "Monolithic" : "Unknown";
+ $package_type0 .= sprintf(" (%u dies)", $die_count0) if $die_count0 >= 2;
+ printl("Package Type" . ($rank_mix ? " (Even Rank)" : ""), $package_type0);
+
+ my $package_type1 = $die_3ds1 ? "3DS" :
+ $die_count1 > 1 ? "Dual-die package" :
+ $die_count1 == 1 ? "Monolithic" : "Unknown";
+ $package_type1 .= sprintf(" (%u dies)", $die_count1) if $die_count1 >= 2;
+ printl_cond($rank_mix, "Package Type (Odd Rank)", $package_type1);
+
+ my $ppr = $bytes->[12] >> 7;
+ printl("Post Package Repair",
+ $ppr == 0x00 ? "One row per bank group" :
+ $ppr == 0x01 ? "One row per bank" : "Unknown");
+ printl("Soft PPR Undo/Lock", $bytes->[12] & 0x20 ?
+ "Supported" : "Not Supported");
+ printl("MBIST PPR", $bytes->[12] & 0x02 ?
+ "Supported" : "Not Supported");
+
+ printl("Module Nominal Voltage",
+ ($bytes->[16] & 0xf0) == 0x00 ? "1.1 V" :
+ ($bytes->[16] & 0x0c) == 0x00 ? "Unknown (1.1 V operable)" :
+ ($bytes->[16] & 0x03) == 0x00 ? "Unknown (1.1 V endurant)" : "Unknown");
+
+ printl("Thermal Sensor",
+ $bytes->[14] & 0x08 ? "Supported" : "No");
+}
+
# Parameter: EEPROM bytes 0-127 (using 4-5)
sub decode_direct_rambus($)
{
@@ -2177,6 +2402,10 @@ sub decode_rambus($)
"DDR4E SDRAM" => \&decode_ddr4_sdram,
"LPDDR4 SDRAM" => \&decode_ddr4_sdram,
"LPDDR4X SDRAM" => \&decode_ddr4_sdram,
+ "DDR5 SDRAM" => \&decode_ddr5_sdram,
+ "LPDDR5 SDRAM" => \&decode_ddr5_sdram,
+ "DDR5 NVDIMM-P" => \&decode_ddr5_sdram,
+ "LPDDR5X SDRAM" => \&decode_ddr5_sdram,
"Direct Rambus" => \&decode_direct_rambus,
"Rambus" => \&decode_rambus,
);
@@ -2841,6 +3070,7 @@ for $current (0 .. $#dimm) {
"DDR4E SDRAM", "LPDDR3 SDRAM", # 14, 15
"LPDDR4 SDRAM", "LPDDR4X SDRAM", # 16, 17
"DDR5 SDRAM", "LPDDR5 SDRAM", # 18, 19
+ "DDR5 NVDIMM-P", "LPDDR5X SDRAM", # 20, 21
);
if ($bytes[2] < @type_list) {
$type = $type_list[$bytes[2]];
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/6] decode-dimms: Decode DDR5 common module information
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
` (2 preceding siblings ...)
2024-11-14 6:37 ` [PATCH 3/6] decode-dimms: Decode timings and other data for DDR5 Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 5/6] decode-dimms: Add basic decoding of type specific information for DDR5 Stephen Horvath via B4 Relay
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
Decode that extra manufacturer information that was mentioned earlier,
but only the info that is common between all DDR5 memory modules.
Also the physical size is here too.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index 4a19e962cd1f837ccdb6660caa8d198f65e3fc4f..f36af056a480d429203abc7e0dfda3751027948b 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2350,6 +2350,42 @@ sub decode_ddr5_sdram($)
printl("Thermal Sensor",
$bytes->[14] & 0x08 ? "Supported" : "No");
+
+# common module information
+ prints("Common Information");
+
+ my $spd_info_rev = $bytes->[192];
+ printl("SPD Module Info Revision", ($spd_info_rev >> 4) . "." . ($spd_info_rev & 0xf));
+
+ printl_cond($bytes->[196] & 0x80,
+ "SPD Manufacturer",
+ manufacturer_ddr3($bytes->[194], $bytes->[195]));
+ printl_cond($bytes->[200] & 0x80,
+ "PMIC0 Manufacturer",
+ manufacturer_ddr3($bytes->[198], $bytes->[199]));
+ printl_cond($bytes->[204] & 0x80,
+ "PMIC1 Manufacturer",
+ manufacturer_ddr3($bytes->[202], $bytes->[203]));
+ printl_cond($bytes->[208] & 0x80,
+ "PMIC2 Manufacturer",
+ manufacturer_ddr3($bytes->[206], $bytes->[207]));
+ printl_cond($bytes->[212] & 0xC0,
+ "Thermal Sensors Manufacturer",
+ manufacturer_ddr3($bytes->[210], $bytes->[211]));
+
+ prints("Physical Characteristics");
+
+ my $height = $bytes->[230] & 0x1f;
+ printl("Module Height",
+ $height == 0x00 ? "15 mm or less" :
+ $height == 0x1f ? "more than 45 mm" :
+ sprintf("%u mm", $height + 15));
+ printl("Module Thickness",
+ sprintf("%d mm front, %d mm back",
+ ($bytes->[231] & 0x0f) + 1,
+ (($bytes->[231] >> 4) & 15) + 1));
+ printl("Module Reference Card",
+ ddr3_reference_card($bytes->[232], $bytes->[232]));
}
# Parameter: EEPROM bytes 0-127 (using 4-5)
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] decode-dimms: Add basic decoding of type specific information for DDR5
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
` (3 preceding siblings ...)
2024-11-14 6:37 ` [PATCH 4/6] decode-dimms: Decode DDR5 common module information Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 6/6] decode-dimms: Decode DDR5 error log Stephen Horvath via B4 Relay
2025-11-05 13:31 ` [PATCH 0/6] decode-dimms: Implement DDR5 decoding Kamil Aronowski
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
Decode more manufacturer information, but only the info that is specific
to certain types of DDR5 memory modules. This is completely untested
since my modules don't expose this. I also only have UDIMMs.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index f36af056a480d429203abc7e0dfda3751027948b..a3b613bc869bbd1d8183958c42d05c3b3e3653ca 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2386,6 +2386,77 @@ sub decode_ddr5_sdram($)
(($bytes->[231] >> 4) & 15) + 1));
printl("Module Reference Card",
ddr3_reference_card($bytes->[232], $bytes->[232]));
+
+# type-specific settings
+ if ($spd_info_rev == 0x11 &&
+ ($type == 0x02 || # UDIMM
+ $type == 0x03 || # SODIMM
+ $type == 0x05 || # CUDIMM
+ $type == 0x06)) { # CSODIMM
+ prints("Unbuffered Memory Module");
+
+ printl("Clock driver manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ }
+
+ if ($spd_info_rev == 0x11 &&
+ ($type == 0x01 || # RDIMM
+ $type == 0x04)) { # LRDIMM
+ prints("Registered Memory Module");
+
+ printl("Clock driver manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ printl("Data buffer manufacturer",
+ manufacturer_ddr3($bytes->[244], $bytes->[245]));
+ }
+
+ if ($spd_info_rev == 0x11 &&
+ ($type == 0x07)) { # MRDIMM
+ prints("Multiplexed Rank Memory Module");
+
+ printl("Clock driver manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ printl("Data buffer manufacturer",
+ manufacturer_ddr3($bytes->[244], $bytes->[245]));
+ }
+
+ if ($spd_info_rev == 0x10 &&
+ ($type == 0x0A)) { # DDIMM
+ prints("Differential Memory Module");
+
+ printl("Memory buffer manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ }
+
+ if ($spd_info_rev == 0x01 &&
+ ($raw_type & 0xf0 == 0x90)) { # NVDIMM-N
+ prints("Non-Volatile Memory Module");
+
+ printl("Clock driver manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ printl("Data buffer manufacturer",
+ manufacturer_ddr3($bytes->[244], $bytes->[245]));
+ }
+
+ if ($spd_info_rev == 0x10 &&
+ ($raw_type & 0xf0 == 0xA0)) { # NVDIMM-P
+ prints("Non-Volatile Memory Module");
+
+ printl("Clock driver manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ printl("Data buffer manufacturer",
+ manufacturer_ddr3($bytes->[244], $bytes->[245]));
+ }
+
+ if ($spd_info_rev == 0x10 &&
+ ($type == 0x08)) { # CAMM2
+ prints("Compression Attached Memory Module");
+
+ printl("Clock driver 0 manufacturer",
+ manufacturer_ddr3($bytes->[240], $bytes->[241]));
+ printl("Clock driver 1 manufacturer",
+ manufacturer_ddr3($bytes->[244], $bytes->[245]));
+ }
}
# Parameter: EEPROM bytes 0-127 (using 4-5)
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/6] decode-dimms: Decode DDR5 error log
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
` (4 preceding siblings ...)
2024-11-14 6:37 ` [PATCH 5/6] decode-dimms: Add basic decoding of type specific information for DDR5 Stephen Horvath via B4 Relay
@ 2024-11-14 6:37 ` Stephen Horvath via B4 Relay
2025-11-05 13:31 ` [PATCH 0/6] decode-dimms: Implement DDR5 decoding Kamil Aronowski
6 siblings, 0 replies; 10+ messages in thread
From: Stephen Horvath via B4 Relay @ 2024-11-14 6:37 UTC (permalink / raw)
To: linux-i2c; +Cc: Jean Delvare, Stephen Horvath, Guenter Roeck
From: Stephen Horvath <s.horvath@outlook.com.au>
JESD400 specifies that an error log can be written to anywhere in the end
user programmable eeprom section, following a specific format. This adds
some code to find and read this error log. This is also completely
untested on actual hardware implementations, only tested by reading some
manually constructed files.
Signed-off-by: Stephen Horvath <s.horvath@outlook.com.au>
---
eeprom/decode-dimms | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index a3b613bc869bbd1d8183958c42d05c3b3e3653ca..a6a16696b126b16b7a8e62b15120f99789d9b762 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2656,6 +2656,108 @@ sub decode_ddr5_mfg_data($)
}
}
+# Parameter: EEPROM bytes 0-1023 (using 640-1023)
+sub decode_ddr5_error_data($)
+{
+ my $bytes = shift;
+
+ # Zero or more error logs may appear anywhere in any End User Programmable blocks of the SPD,
+ # including over SPD Block boundaries. They may be found by searching for a four byte anchor string.
+
+ my $errors = [];
+
+ my $size = scalar @{$bytes} < 1023 ? scalar @{$bytes} : 1023;
+
+ for (my $ii = 0; $ii < $size - 640 - 23; $ii++) {
+ if (join('', @{$bytes}[640 + $ii .. 640 + $ii + 3]) eq "95707695") {
+ push @{$errors}, [@{$bytes}[640 + $ii .. 640 + $ii + 23]];
+ $ii += 23;
+ }
+ }
+
+ if (@{$errors} == 0) {
+ # No error logs found
+ return;
+ }
+
+ prints("Error Log");
+
+ printl("Error Log Count", scalar @{$errors});
+
+ for (my $ii = 0; $ii < scalar @{$errors}; $ii++) {
+ my $error = @{$errors}[$ii];
+
+ # error location
+ printl_cond($error->[4] & (1 << 0), "Error $ii Type", "DRAM Uncorrectable Error");
+ printl_cond($error->[4] & (1 << 1), "Error $ii Type", "DRAM Correctable Error");
+ printl_cond($error->[4] & (1 << 2), "Error $ii Type", "DRAM ECS Error");
+ printl_cond($error->[4] & (1 << 3), "Error $ii Type", "hPPR Was Required");
+ printl_cond($error->[4] & (1 << 4), "Error $ii Type", "hPPR Resource Error");
+
+ printl("Error $ii Location CPU", ($error->[5] >> 3) & 0x07);
+ printl("Error $ii Location CPUMC", (($error->[5] & 3) << 2) | ($error->[6] >> 6));
+ printl("Error $ii Location DIMM", ($error->[6] >> 4) & 0x01);
+
+ # these are active low
+ printl_cond(~$error->[6] & (1 << 3), "Error $ii Location Rank", "0 (sub-channel A)");
+ printl_cond(~$error->[6] & (1 << 2), "Error $ii Location Rank", "1 (sub-channel A)");
+ printl_cond(~$error->[6] & (1 << 1), "Error $ii Location Rank", "0 (sub-channel B)");
+ printl_cond(~$error->[6] & (1 << 0), "Error $ii Location Rank", "1 (sub-channel B)");
+
+ printl("Error $ii Location Parity", ($error->[7] >> 6) & 0x01);
+ if (($error->[7] >> 5) & 1) {
+ # chip identifier?
+ printl("Error $ii Location Chip", ($error->[7] >> 2) & 0x07);
+ } else {
+ # row address?
+ printl("Error $ii Location Bank Group", (($error->[7] & 0x03) << 1) | (($error->[8] & 0x80) >> 7));
+ printl("Error $ii Location Bank Address", ($error->[8] >> 5) & 0x03);
+ printl("Error $ii Location Row Address", (($error->[8] & 0x1f) << 12) | ($error->[9] << 4) | ($error->[10] >> 4));
+ printl("Error $ii Location Column Address", (($error->[10] & 0x0f) << 7) | (($error->[11] & 0xf0) >> 1));
+ }
+
+ # also active low
+ printl_cond(~$error->[11] & (1 << 0), "Error $ii Location Device", "DQS6A");
+ printl_cond(~$error->[11] & (1 << 1), "Error $ii Location Device", "DQS7A");
+ printl_cond(~$error->[11] & (1 << 2), "Error $ii Location Device", "DQS8A");
+ printl_cond(~$error->[11] & (1 << 3), "Error $ii Location Device", "DQS9A");
+
+ printl_cond(~$error->[12] & (1 << 0), "Error $ii Location Device", "DQS8B");
+ printl_cond(~$error->[12] & (1 << 1), "Error $ii Location Device", "DQS9B");
+ printl_cond(~$error->[12] & (1 << 2), "Error $ii Location Device", "DQS0A");
+ printl_cond(~$error->[12] & (1 << 3), "Error $ii Location Device", "DQS1A");
+ printl_cond(~$error->[12] & (1 << 4), "Error $ii Location Device", "DQS2A");
+ printl_cond(~$error->[12] & (1 << 5), "Error $ii Location Device", "DQS3A");
+ printl_cond(~$error->[12] & (1 << 6), "Error $ii Location Device", "DQS4A");
+ printl_cond(~$error->[12] & (1 << 7), "Error $ii Location Device", "DQS5A");
+
+ printl_cond(~$error->[12] & (1 << 0), "Error $ii Location Device", "DQS0B");
+ printl_cond(~$error->[12] & (1 << 1), "Error $ii Location Device", "DQS1B");
+ printl_cond(~$error->[12] & (1 << 2), "Error $ii Location Device", "DQS2B");
+ printl_cond(~$error->[12] & (1 << 3), "Error $ii Location Device", "DQS3B");
+ printl_cond(~$error->[12] & (1 << 4), "Error $ii Location Device", "DQS4B");
+ printl_cond(~$error->[12] & (1 << 5), "Error $ii Location Device", "DQS5B");
+ printl_cond(~$error->[12] & (1 << 6), "Error $ii Location Device", "DQS6B");
+ printl_cond(~$error->[12] & (1 << 7), "Error $ii Location Device", "DQS7B");
+
+ # timestamp
+ my $year = ($error->[14] >> 2) + 2020;
+ my $month = (($error->[14] & 0x03) << 2) | ($error->[15] >> 6);
+ my $day = ($error->[15] & 0x3e) >> 1;
+ my $hour = (($error->[15] & 0x01) << 4) | ($error->[16] >> 4);
+ my $minute = (($error->[16] & 0x0f) << 2) | ($error->[17] >> 6);
+ my $second = $error->[17] & 0x3f;
+ printl("Error $ii Timestamp", sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+ $year, $month, $day, $hour, $minute, $second));
+
+ # DRAM refresh settings
+ # TODO
+
+ # measured temperature
+ # TODO
+ }
+}
+
# Parameter: EEPROM bytes 0-127 (using 64-98)
sub decode_manufacturing_information($)
{
@@ -3215,6 +3317,9 @@ for $current (0 .. $#dimm) {
# Decode DDR5-specific manufacturing data in bytes
# 512-639
decode_ddr5_mfg_data(\@bytes);
+ # Decode DDR5-specific error log
+ # 640-1023 (max)
+ decode_ddr5_error_data(\@bytes);
}
} else {
# Decode next 35 bytes (64-98, common to most
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/6] decode-dimms: Implement DDR5 decoding
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
` (5 preceding siblings ...)
2024-11-14 6:37 ` [PATCH 6/6] decode-dimms: Decode DDR5 error log Stephen Horvath via B4 Relay
@ 2025-11-05 13:31 ` Kamil Aronowski
2025-11-06 1:26 ` Stephen Horvath
6 siblings, 1 reply; 10+ messages in thread
From: Kamil Aronowski @ 2025-11-05 13:31 UTC (permalink / raw)
To: s.horvath, linux-i2c; +Cc: Jean Delvare, Guenter Roeck
[-- Attachment #1.1.1: Type: text/plain, Size: 4116 bytes --]
On 11/14/24 07:37, Stephen Horvath via B4 Relay wrote:
> Hi, this series of patches adds DDR5 support to decode-dimms.
>
> I'm not too experienced with perl or the JEDEC specs, so there's probably
> going to be some questionable choices here, but I'd love to hear
> feedback.
The patchset doesn't seem to work out-of-the-box. When running the patched
`decode-dimms`, an error is thrown:
```
$ sudo ./eeprom/decode-dimms
Cannot read /sys/bus/i2c/drivers/spd5118/16-0050/eeprom at ./eeprom/decode-dimms line 2940.
```
I've checked with more than one machine to confirm, that it's not an individual
case.
Modifying the patched script, so that it reads one byte in a loop does seem to
fix some things, though, at least for the first 128 iterations:
```diff
diff --git a/eeprom/decode-dimms b/eeprom/decode-dimms
index a6a1669..1ff6741 100755
--- a/eeprom/decode-dimms
+++ b/eeprom/decode-dimms
@@ -2937,13 +2937,18 @@ sub readspd($$$)
binmode HANDLE;
sysseek(HANDLE, $offset, SEEK_SET)
or die "Cannot seek $dimm_i/eeprom";
- $read = sysread(HANDLE, my $eeprom, $size)
- or die "Cannot read $dimm_i/eeprom";
+ #$read = sysread(HANDLE, my $eeprom, $size)
+ # or die "Cannot read $dimm_i/eeprom";
+ my $read = '';
+ my $buffer;
+ while (sysread(HANDLE, $buffer, 1) == 1) {
+ $read .= $buffer;
+ }
close HANDLE;
if ($read < $size) {
print STDERR "WARNING: $dimm_i/eeprom is smaller than expected\n";
}
- @bytes = unpack("C*", $eeprom);
+ @bytes = unpack("C*", $buffer);
} else {
# Kernel 2.4 with procfs
for my $i (0 .. ($size-1)/16) {
```
Nevertheless, it still doesn't work as expected. A (trimmed) listing shows only
the following, except all the trimmed warnings:
```
Use of uninitialized value in numeric eq (==) at ./eeprom/decode-dimms line 2945.
Argument "0^P^R^C^D\0 b\0\0\0\0M-^P^B\0\0\0\0\0\0e^A�^Cr�\0\0\0\0,..." isn't numeric in numeric lt (<) at ./eeprom/decode-dimms line 2948.
WARNING: /sys/bus/i2c/drivers/spd5118/20-0050/eeprom is smaller than expected
Use of uninitialized value in addition (+) at ./eeprom/decode-dimms line 2969.
Use of uninitialized value in addition (+) at ./eeprom/decode-dimms line 2969.
[...]
Use of uninitialized value $b in numeric eq (==) at ./eeprom/decode-dimms line 505.
Use of uninitialized value $b in numeric eq (==) at ./eeprom/decode-dimms line 506.
Use of uninitialized value $_[0] in sprintf at ./eeprom/decode-dimms line 2555.
Use of uninitialized value $_[1] in sprintf at ./eeprom/decode-dimms line 2555.
Use of uninitialized value $_[2] in sprintf at ./eeprom/decode-dimms line 2555.
Use of uninitialized value $_[3] in sprintf at ./eeprom/decode-dimms line 2555.
# decode-dimms version 4.4
Memory Serial Presence Detect Decoder
By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
Jean Delvare, Trent Piepho and others
Decoding EEPROM: /sys/bus/i2c/drivers/spd5118/20-0050
Guessing DIMM is in bank 1
Kernel driver used spd5118
---=== SPD EEPROM Information ===---
EEPROM Checksum of bytes 0-62 OK (0x00)
SPD Revision Invalid
Fundamental Memory type Unknown (0x00)
---=== Manufacturing Information ===---
Manufacturer Undefined
Part Number Undefined
Number of SDRAM DIMMs detected and decoded: 1
```
> The first 4 patches (1, 2, 3, 4) add the essential information to
> decode-dimms.
>
> The next 2 patches (5, 6) haven't really been tested on hardware
> implementations so I'm happy for them to be dropped if they're not
> useful.
Was the patchset tested on any hardware or some other intended environment
outside of my use case? The latter is about the most recent revision of Fedora
Rawhide with the spd5118 module on various DDR5-equipped laptops.
--
Kamil Aronowski
Junior Embedded Firmware Engineer
GPG: 3510148A5CD67908
https://3mdeb.com | @3mdeb_com
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 5529 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/6] decode-dimms: Implement DDR5 decoding
2025-11-05 13:31 ` [PATCH 0/6] decode-dimms: Implement DDR5 decoding Kamil Aronowski
@ 2025-11-06 1:26 ` Stephen Horvath
2025-11-06 13:55 ` Kamil Aronowski
0 siblings, 1 reply; 10+ messages in thread
From: Stephen Horvath @ 2025-11-06 1:26 UTC (permalink / raw)
To: Kamil Aronowski, linux-i2c; +Cc: Jean Delvare, Guenter Roeck
Hi Kamil,
On 5/11/25 23:31, Kamil Aronowski wrote:
> On 11/14/24 07:37, Stephen Horvath via B4 Relay wrote:
>> Hi, this series of patches adds DDR5 support to decode-dimms.
>>
>> I'm not too experienced with perl or the JEDEC specs, so there's probably
>> going to be some questionable choices here, but I'd love to hear
>> feedback.
>
> The patchset doesn't seem to work out-of-the-box. When running the patched
> `decode-dimms`, an error is thrown:
>
> ```
> $ sudo ./eeprom/decode-dimms
> Cannot read /sys/bus/i2c/drivers/spd5118/16-0050/eeprom at ./eeprom/
> decode-dimms line 2940.
> ```
That sounds like it's having trouble reading the eeprom, not even
decoding it. I have a feeling this might be related to 'SPD Write
Protection', does your motherboard let you disable it? It's often
enabled by default on Intel, and I don't think it exists on AMD.
spd5118 needs to be able to write to the SPD in order to select which
page to read.
Otherwise, are you able to dump your eeprom and send it?
e.g. `cat /sys/bus/i2c/drivers/spd5118/16-0050/eeprom > eeprom.rom`
> I've checked with more than one machine to confirm, that it's not an
> individual
> case.
>
> Modifying the patched script, so that it reads one byte in a loop does
> seem to
> fix some things, though, at least for the first 128 iterations:
> Nevertheless, it still doesn't work as expected. A (trimmed) listing
> shows only
> the following, except all the trimmed warnings:
I'm fairly certain it's just reading all zeros.
>> The first 4 patches (1, 2, 3, 4) add the essential information to
>> decode-dimms.
>>
>> The next 2 patches (5, 6) haven't really been tested on hardware
>> implementations so I'm happy for them to be dropped if they're not
>> useful.
>
> Was the patchset tested on any hardware or some other intended environment
> outside of my use case? The latter is about the most recent revision of
> Fedora
> Rawhide with the spd5118 module on various DDR5-equipped laptops.
The first 4 patches were tested on my desktop with Kingston DIMMs and
laptop with Crucial DIMMs, both AMD. I don't have any sort of fancy
environment, just consumer grade stuff.
I've made some minor changes since originally submitting it, so I'll
submit a v2 shortly too.
Thanks,
Steve
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/6] decode-dimms: Implement DDR5 decoding
2025-11-06 1:26 ` Stephen Horvath
@ 2025-11-06 13:55 ` Kamil Aronowski
0 siblings, 0 replies; 10+ messages in thread
From: Kamil Aronowski @ 2025-11-06 13:55 UTC (permalink / raw)
To: Stephen Horvath, linux-i2c; +Cc: Jean Delvare, Guenter Roeck
[-- Attachment #1.1.1: Type: text/plain, Size: 2485 bytes --]
Hello, Stephen,
On 11/6/25 02:26, Stephen Horvath wrote:
> Hi Kamil,
>
> On 5/11/25 23:31, Kamil Aronowski wrote:
>> On 11/14/24 07:37, Stephen Horvath via B4 Relay wrote:
>>> Hi, this series of patches adds DDR5 support to decode-dimms.
>>>
>>> I'm not too experienced with perl or the JEDEC specs, so there's probably
>>> going to be some questionable choices here, but I'd love to hear
>>> feedback.
>>
>> The patchset doesn't seem to work out-of-the-box. When running the patched
>> `decode-dimms`, an error is thrown:
>>
>> ```
>> $ sudo ./eeprom/decode-dimms
>> Cannot read /sys/bus/i2c/drivers/spd5118/16-0050/eeprom at ./eeprom/
>> decode-dimms line 2940.
>> ```
>
> That sounds like it's having trouble reading the eeprom, not even
> decoding it. I have a feeling this might be related to 'SPD Write
> Protection', does your motherboard let you disable it? It's often
> enabled by default on Intel, and I don't think it exists on AMD.
>
> spd5118 needs to be able to write to the SPD in order to select which
> page to read.
>
> Otherwise, are you able to dump your eeprom and send it?
> e.g. `cat /sys/bus/i2c/drivers/spd5118/16-0050/eeprom > eeprom.rom`
The SPD Write Protection is likely to have been the cause, since repeating the
experiment on a machine without it worked out-of-the-box.
Any attempts of dumping the eeprom on the incompatible configurations were
unsuccessful, except reading 1 byte in a loop, 128 times.
>>> The first 4 patches (1, 2, 3, 4) add the essential information to
>>> decode-dimms.
>>>
>>> The next 2 patches (5, 6) haven't really been tested on hardware
>>> implementations so I'm happy for them to be dropped if they're not
>>> useful.
>>
>> Was the patchset tested on any hardware or some other intended environment
>> outside of my use case? The latter is about the most recent revision of
>> Fedora
>> Rawhide with the spd5118 module on various DDR5-equipped laptops.
>
> The first 4 patches were tested on my desktop with Kingston DIMMs and
> laptop with Crucial DIMMs, both AMD. I don't have any sort of fancy
> environment, just consumer grade stuff.
>
> I've made some minor changes since originally submitting it, so I'll
> submit a v2 shortly too.
>
> Thanks,
> Steve
Looking forward to the v2 submission. Thank you for the help and the great
work.
--
Kamil Aronowski
Junior Embedded Firmware Engineer
GPG: 3510148A5CD67908
https://3mdeb.com | @3mdeb_com
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 5529 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-11-06 14:50 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-14 6:37 [PATCH 0/6] decode-dimms: Implement DDR5 decoding Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 1/6] decode-dimms: Implement DDR5 checksum parsing Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 2/6] decode-dimms: Decode DDR5 Manufacturer Data Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 3/6] decode-dimms: Decode timings and other data for DDR5 Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 4/6] decode-dimms: Decode DDR5 common module information Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 5/6] decode-dimms: Add basic decoding of type specific information for DDR5 Stephen Horvath via B4 Relay
2024-11-14 6:37 ` [PATCH 6/6] decode-dimms: Decode DDR5 error log Stephen Horvath via B4 Relay
2025-11-05 13:31 ` [PATCH 0/6] decode-dimms: Implement DDR5 decoding Kamil Aronowski
2025-11-06 1:26 ` Stephen Horvath
2025-11-06 13:55 ` Kamil Aronowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox