diff options
author | Angel Pons <th3fanbus@gmail.com> | 2020-12-10 22:11:27 +0100 |
---|---|---|
committer | Angel Pons <th3fanbus@gmail.com> | 2020-12-12 14:22:27 +0000 |
commit | 927b1c01611663545da6d2d9048ce1f37bc04dcf (patch) | |
tree | 7eb75d0ffa0746c4c5b28ab789c0e693299796a2 | |
parent | 33cd957866ca8d8c7d86b7cfa50f926c40e8d540 (diff) |
nb/intel/sandybridge: Fix blunder in MR2 shadow code
Commit 7f1363d9b4 (nb/intel/sandybridge: Program MR2 shadow register)
has a bug where the system locks up and power cycles when booting Linux,
but is still able to pass memtest86+ with flying colors. The issue will
occur when the following conditions are true:
- CPU is Ivy Bridge
- Memory speed is not greater than 1066 MHz (DDR3-2133 or slower)
- System contains dual-rank DIMMs
- The second rank of the dual-rank DIMMs is mirrored
- All DIMMs support Extended Temperature Range
- At least one of the DIMMs does not support Auto Self-Refresh
If all of these conditions are met, the final value of the MR2 Shadow
registers configures the memory controller to issue a MRS command to
update MR2 before entering self-refresh mode, but indicates that rank
mirroring is not required (the first rank on a DIMM is never mirrored).
Before the memory controller enters self-refresh, it sends MRS commands
to all ranks to update MR2, but the missing address and bank mirroring
means DRAM chips on mirrored ranks instead clobber MR1 with junk data.
With garbage in MR1, the mirrored ranks no longer function properly,
which ultimately leads to all hell breaking loose (undefined behavior).
The condition is backwards, since only odd ranks can be mirrored. To
avoid this problem completely, simply remove the condition. The final
register value will still be correct, since the bits are always ORed.
Tested on Asus P8Z77-V LX2, fixes booting Linux with dual-rank DIMMs.
Change-Id: Iceff741eb85fab0ae846e50af0080e5ff405404c
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/48550
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
-rw-r--r-- | src/northbridge/intel/sandybridge/raminit_common.c | 13 |
1 files changed, 6 insertions, 7 deletions
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c index 399ba5a16d..80c5186ead 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.c +++ b/src/northbridge/intel/sandybridge/raminit_common.c @@ -815,13 +815,12 @@ static void dram_mr2(ramctr_timing *ctrl, u8 rank, int channel) reg32 |= mr2reg & ~(3 << 6); - if (rank & 1) { - if (srt) - reg32 |= 1 << (rank / 2 + 6); - } else { - if (ctrl->rank_mirror[channel][rank]) - reg32 |= 1 << (rank / 2 + 14); - } + if (srt) + reg32 |= 1 << (rank / 2 + 6); + + if (ctrl->rank_mirror[channel][rank]) + reg32 |= 1 << (rank / 2 + 14); + MCHBAR32(TC_MR2_SHADOW_ch(channel)) = reg32; } |