Nico Huber (nico.huber@secunet.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3254
-gerrit
commit fd1b9ed442b7db42bc4996301f691f0890944f53 Author: Nico Huber nico.huber@secunet.com Date: Tue May 14 11:25:59 2013 +0200
intel/gm45: Handle overflows during DDR3 read training
We halted the machine on any overflow during the read training. However, overflows during the search for a good to bad edge are non-fatal, and should be ignored.
Change-Id: I77085840ade25bce955480689c84603334113d1f Signed-off-by: Nico Huber nico.huber@secunet.com --- .../intel/gm45/raminit_read_write_training.c | 88 +++++++++++++++------- 1 file changed, 60 insertions(+), 28 deletions(-)
diff --git a/src/northbridge/intel/gm45/raminit_read_write_training.c b/src/northbridge/intel/gm45/raminit_read_write_training.c index 6936d07..f13cde8 100644 --- a/src/northbridge/intel/gm45/raminit_read_write_training.c +++ b/src/northbridge/intel/gm45/raminit_read_write_training.c @@ -56,7 +56,7 @@ typedef struct { int t; int p; } read_timing_t; -static void normalize_read_timing(read_timing_t *const timing) +static int normalize_read_timing(read_timing_t *const timing) { while (timing->p >= READ_TIMING_P_BOUND) { timing->t++; @@ -66,18 +66,33 @@ static void normalize_read_timing(read_timing_t *const timing) timing->t--; timing->p += READ_TIMING_P_BOUND; } - if ((timing->t < 0) || (timing->t >= READ_TIMING_T_BOUND)) - die("Timing under-/overflow during read training.\n"); + if (timing->t < 0) { + printk(BIOS_WARNING, + "Timing underflow during read training.\n"); + timing->t = 0; + timing->p = 0; + return -1; + } else if (timing->t >= READ_TIMING_T_BOUND) { + printk(BIOS_WARNING, + "Timing overflow during read training.\n"); + timing->t = READ_TIMING_T_BOUND - 1; + timing->p = READ_TIMING_P_BOUND - 1; + return -1; + } + return 0; } -static void program_read_timing(const int ch, const int lane, - read_timing_t *const timing) +static int program_read_timing(const int ch, const int lane, + read_timing_t *const timing) { - normalize_read_timing(timing); + if (normalize_read_timing(timing) < 0) + return -1;
u32 reg = MCHBAR32(CxRDTy_MCHBAR(ch, lane)); reg &= ~(CxRDTy_T_MASK | CxRDTy_P_MASK); reg |= CxRDTy_T(timing->t) | CxRDTy_P(timing->p); MCHBAR32(CxRDTy_MCHBAR(ch, lane)) = reg; + + return 0; } /* Returns 1 on success, 0 on failure. */ static int read_training_test(const int channel, const int lane, @@ -99,46 +114,60 @@ static int read_training_test(const int channel, const int lane, } return 1; } -static void read_training_find_lower(const int channel, const int lane, - const address_bunch_t *const addresses, - read_timing_t *const lower) +static int read_training_find_lower(const int channel, const int lane, + const address_bunch_t *const addresses, + read_timing_t *const lower) { /* Coarse search for good t. */ program_read_timing(channel, lane, lower); while (!read_training_test(channel, lane, addresses)) { ++lower->t; - program_read_timing(channel, lane, lower); + if (program_read_timing(channel, lane, lower) < 0) + return -1; }
/* Step back, then fine search for good p. */ - if (lower->t > 0) { - --lower->t; - program_read_timing(channel, lane, lower); - while (!read_training_test(channel, lane, addresses)) { - ++lower->p; - program_read_timing(channel, lane, lower); - } + if (lower->t <= 0) + /* Can't step back, zero is good. */ + return 0; + + --lower->t; + program_read_timing(channel, lane, lower); + while (!read_training_test(channel, lane, addresses)) { + ++lower->p; + if (program_read_timing(channel, lane, lower) < 0) + return -1; } + + return 0; } -static void read_training_find_upper(const int channel, const int lane, - const address_bunch_t *const addresses, - read_timing_t *const upper) +static int read_training_find_upper(const int channel, const int lane, + const address_bunch_t *const addresses, + read_timing_t *const upper) { - program_read_timing(channel, lane, upper); - if (!read_training_test(channel, lane, addresses)) - die("Read training failed: limits too narrow.\n"); + if (program_read_timing(channel, lane, upper) < 0) + return -1; + if (!read_training_test(channel, lane, addresses)) { + printk(BIOS_WARNING, + "Read training failure: limits too narrow.\n"); + return -1; + } /* Coarse search for bad t. */ do { ++upper->t; - program_read_timing(channel, lane, upper); + if (program_read_timing(channel, lane, upper) < 0) + return -1; } while (read_training_test(channel, lane, addresses)); /* Fine search for bad p. */ --upper->t; program_read_timing(channel, lane, upper); while (read_training_test(channel, lane, addresses)) { ++upper->p; - program_read_timing(channel, lane, upper); + if (program_read_timing(channel, lane, upper) < 0) + return -1; } + + return 0; } static void read_training_per_lane(const int channel, const int lane, const address_bunch_t *const addresses) @@ -152,17 +181,20 @@ static void read_training_per_lane(const int channel, const int lane, /* Start at zero. */ lower.t = 0; lower.p = 0; - read_training_find_lower(channel, lane, addresses, &lower); + if (read_training_find_lower(channel, lane, addresses, &lower) < 0) + die("Read training failure: lower bound.\n");
/*** Search upper bound. ***/
/* Start at lower + 1t. */ upper.t = lower.t + 1; upper.p = lower.p; + if (read_training_find_upper(channel, lane, addresses, &upper) < 0) + /* Overflow on upper edge is not fatal. */ + printk(BIOS_WARNING, "Read training failure: upper bound.\n");
- read_training_find_upper(channel, lane, addresses, &upper); + /*** Calculate and program mean value. ***/
- /* Calculate and program mean value. */ lower.p += lower.t << READ_TIMING_P_SHIFT; upper.p += upper.t << READ_TIMING_P_SHIFT; const int mean_p = (lower.p + upper.p) >> 1;