@@ -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");
@@ -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);
@@ -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)
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;