Allow myusec_calibrate_delay() to indicate errors and abort in cli_classic if that happens.
Signed-off-by: Stefan Tauner stefan.tauner@alumni.tuwien.ac.at --- cli_classic.c | 6 +++++- programmer.h | 2 +- udelay.c | 22 ++++++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-)
Roxfan on IRC had major problems getting flashrom to even start because of some hardware-related timing problems. Without this patch his hardware would (almost?) endlessly loop during timer calibration. This patch aborts instead after a while and should not trigger any regressions.
One can test it by overriding the gettimeofday results in measure_delay() by adding following assignments: start.tv_sec = 0; end.tv_sec = 0; start.tv_usec = 0; end.tv_usec = 0;
diff --git a/cli_classic.c b/cli_classic.c index a2c2014..4a68f0b 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -414,7 +414,11 @@ int main(int argc, char *argv[]) }
/* FIXME: Delay calibration should happen in programmer code. */ - myusec_calibrate_delay(); + if (myusec_calibrate_delay() != 0) { + msg_perr("Error: Custom timer calibration failed.\n"); + ret = 1; + goto out_shutdown; + }
if (programmer_init(prog, pparam)) { msg_perr("Error: Programmer initialization failed.\n"); diff --git a/programmer.h b/programmer.h index bd8e98d..b39fba4 100644 --- a/programmer.h +++ b/programmer.h @@ -268,8 +268,8 @@ extern const struct board_info laptops_known[]; #endif
/* udelay.c */ +int myusec_calibrate_delay(void); void myusec_delay(unsigned int usecs); -void myusec_calibrate_delay(void); void internal_sleep(unsigned int usecs); void internal_delay(unsigned int usecs);
diff --git a/udelay.c b/udelay.c index 7c6961d..3562268 100644 --- a/udelay.c +++ b/udelay.c @@ -85,7 +85,7 @@ static unsigned long measure_delay(unsigned int usecs) return timeusec; }
-void myusec_calibrate_delay(void) +int myusec_calibrate_delay(void) { unsigned long count = 1000; unsigned long timeusec, resolution; @@ -106,16 +106,21 @@ recalibrate: if (timeusec > 1000000 / 4) break; if (count >= ULONG_MAX / 2) { - msg_pinfo("timer loop overflow, reduced precision. "); + msg_pwarn("timer loop overflow (count=%lu, micro=%lu, timeusec=%lu), reduced precision.\n", + count, micro, timeusec); break; } count *= 2; } tries ++;
- /* Avoid division by zero, but in that case the loop is shot anyway. */ - if (!timeusec) - timeusec = 1; + /* Something is completely wrong. Avoid a possible endless loop and fall back to internal_delay(). */ + if (timeusec == 0) { + micro = 0; + msg_pwarn("Timing measurement seems to be broken.\n" + "Falling back to possibly insufficient timing sources!\n"); + return 1; + } /* Compute rounded up number of loops per microsecond. */ micro = (count * micro) / timeusec + 1; @@ -168,6 +173,7 @@ recalibrate: msg_pdbg("%ld myus = %ld us, ", resolution * 4, timeusec);
msg_pinfo("OK.\n"); + return 0; }
/* Not very precise sleep. */ @@ -187,7 +193,7 @@ void internal_sleep(unsigned int usecs) void internal_delay(unsigned int usecs) { /* If the delay is >1 s, use internal_sleep because timing does not need to be so precise. */ - if (usecs > 1000000) { + if (micro == 0 || usecs > 1000000) { internal_sleep(usecs); } else { myusec_delay(usecs); @@ -197,9 +203,9 @@ void internal_delay(unsigned int usecs) #else #include <libpayload.h>
-void myusec_calibrate_delay(void) +int myusec_calibrate_delay(void) { - get_cpu_speed(); + return get_cpu_speed() == 0; // Return 1 on errors, i.e. if get_cpu_speed() returns 0 }
void internal_delay(unsigned int usecs)