Commit a53bb5ce authored by Alexander Potashev's avatar Alexander Potashev

RT73025. ea-lpc1788: fix hang-up in `udelay()` for all Cortex-M3 targets

Hang-up scenario before this patch:
At the time `udelay()` is called, the current value in
    the SYSTICK timer (`systick->val`) may be very close to, but greater
    than the number of clocks left to tick (`clc`).
Since `systick->val` is greater than `clc`, we use the `while` loop from
    the `else` block. But this `while` loops only checks that `systick->val`
    is greater than `(tmp - clc)` which is a very small positive integer
    (because `tmp` is very close to `clc`.) The `while` loop will now
    terminate only if we manage to catch `systick->val` in a very thin
    range between 0 and `(tmp - clc)`. The comparison inside the `while`
    loop condition takes a considerable number of CPU clocks, that makes it
    hard to find `systick->val` between 0 and `(tmp - clc)`, we just step
    over this small range.

This bug manifested when erasing NOR flash on EA-LPC1788-32: the
`udelay(1)` call in `flash_status_check()` in `drivers/mtd/cfi_flash.c`
was hanging.
parent b2039eee
......@@ -77,16 +77,22 @@ void __udelay(ulong usec)
clc = usec * (clock_get(CLOCK_SYSTICK) / 1000000);
/* get current timestamp */
/*
* Get current timestamp
*/
tmp = systick->val;
/*
* Loop till event
*
* The SYSTICK timer count downwards.
*/
if (tmp < clc) {
/* loop till event */
while (systick->val < tmp ||
systick->val > (CM3_SYSTICK_LOAD_RELOAD_MSK - 1 -
clc + tmp)) ; /* nop */
} else {
while (systick->val > (tmp - clc)) ;
while (systick->val > (tmp - clc) && systick->val <= tmp) ;
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment