[flashrom] [PATCH] Work around very broken timers.
Stefan Tauner
stefan.tauner at alumni.tuwien.ac.at
Sat Jul 30 21:56:53 CEST 2016
Allow myusec_calibrate_delay() to indicate errors and abort
in cli_classic if that happens.
Signed-off-by: Stefan Tauner <stefan.tauner at 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)
--
Kind regards, Stefan Tauner
More information about the flashrom
mailing list