Disable interrupts early, don't use get_timer() in vboot
After disabling the RO_NORMAL flag so that the RW BIOS was loaded instead of
staying in RO, occasionally (every 40 or 50 tries), we'd get a complete hang
at the dev-mode screen. The AP was getting stuck inside a call to
VbExSleepMs(), which was needed to calibrate the fast-running timer used by
VbExGetTimer().
The core of VbExSleepMs() is simply
while (get_timer(start) < delay)
udelay(100);
which seems pretty simple. get_timer() increments once per millisecond by
means of an interrupt. The first problem is that interrupts are not being
disabled by the RO firmware prior to invoking the RW firmware. That can't be
fixed with a RW update, so the next best thing is to disable them as soon as
possible in the RW firmware.
That cut the frequency of the hang by 50%, but didn't solve the problem
completely. udelay() doesn't rely on interrupts, but instead just busy-waits
on a free-running counter (the same one that triggers the millisecond
interrupt). Since get_timer() still has unresolved issues, we'll just
implement the VbExSleepMs() with a single call to udelay().
That seems to have fixed the problem.
BUG=chrome-os-partner:28461
BRANCH=firmware-parrot-2685.B
TEST=500 iterations of firmware_ConsecutiveBoot
After this change, all 500 reboot iterations succeed.
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/199927
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
(cherry picked from commit bf05d82b2132acbfed47e8bb3c616bb929fbfa39)
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Change-Id: I363a769a6ca60f8c907b0b964f22bf59183f0a7c
Reviewed-on: https://chromium-review.googlesource.com/255921
Reviewed-by: Shawn N <shawnn@chromium.org>
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 91fec79..f847be0 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -107,6 +107,8 @@
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
+ disable_interrupts();
+
return 0;
}
int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f")));
diff --git a/cros/vboot/utility.c b/cros/vboot/utility.c
index ba41c99..b16803a 100644
--- a/cros/vboot/utility.c
+++ b/cros/vboot/utility.c
@@ -85,22 +85,7 @@
void VbExSleepMs(uint32_t msec)
{
- uint32_t delay, start;
-
- /*
- * Can't use entire UINT32_MAX range in the max delay, because it
- * pushes get_timer() too close to wraparound. So use /2.
- */
- while(msec > MAX_MSEC_PER_LOOP) {
- VbExSleepMs(MAX_MSEC_PER_LOOP);
- msec -= MAX_MSEC_PER_LOOP;
- }
-
- delay = msec * TICKS_PER_MSEC;
- start = get_timer(0);
-
- while (get_timer(start) < delay)
- udelay(100);
+ udelay(1000 * msec);
}
VbError_t VbExBeep(uint32_t msec, uint32_t frequency)