summaryrefslogtreecommitdiff
path: root/cpu/at32ap
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-05-26 12:19:10 +0200
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-05-27 15:27:31 +0200
commita8092c021d27f27f4b323b7d49979ca01b3fc19d (patch)
tree6abca9359bef605709b18b85ecde8d0d0dc1cb97 /cpu/at32ap
parent48ea623eae8674793372e3e7c95e72e5a44d7a95 (diff)
avr32: Fix theoretical race in udelay()
If the specified delay is very short, the cycle counter may go past the "end" time we are waiting for before we get around to reading it. Fix it by checking the different between the cycle count "now" and the cycle count at the beginning. This will work as long as the delay measured in number of cycles is below 2^31. Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Diffstat (limited to 'cpu/at32ap')
-rw-r--r--cpu/at32ap/interrupts.c16
1 files changed, 7 insertions, 9 deletions
diff --git a/cpu/at32ap/interrupts.c b/cpu/at32ap/interrupts.c
index bef1f30d7..160838eee 100644
--- a/cpu/at32ap/interrupts.c
+++ b/cpu/at32ap/interrupts.c
@@ -98,18 +98,16 @@ void set_timer(unsigned long t)
*/
void udelay(unsigned long usec)
{
- unsigned long now, end;
+ unsigned long cycles;
+ unsigned long base;
+ unsigned long now;
- now = sysreg_read(COUNT);
+ base = sysreg_read(COUNT);
+ cycles = ((usec * (get_tbclk() / 10000)) + 50) / 100;
- end = ((usec * (get_tbclk() / 10000)) + 50) / 100;
- end += now;
-
- while (now > end)
- now = sysreg_read(COUNT);
-
- while (now < end)
+ do {
now = sysreg_read(COUNT);
+ } while ((now - base) < cycles);
}
static int set_interrupt_handler(unsigned int nr, void (*handler)(void),