From 37f4dfc2597e98c7aa4922c1b32b2337c18a2ca6 Mon Sep 17 00:00:00 2001 From: Tomasz Moń Date: Wed, 21 Dec 2011 14:56:22 +0000 Subject: TMS320DM320: Prevent lockup in udelay() when this function is called with interrupts disabled. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31392 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/tms320dm320/system-dm320.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c index 5d7872f2bc..741516a950 100644 --- a/firmware/target/arm/tms320dm320/system-dm320.c +++ b/firmware/target/arm/tms320dm320/system-dm320.c @@ -412,6 +412,9 @@ void set_cpu_frequency(long frequency) } #endif +/* + * Waits for specified amount of microseconds + */ void udelay(int usec) { unsigned short count = IO_TIMER1_TMCNT; unsigned short stop; @@ -432,16 +435,28 @@ void udelay(int usec) { stop -= tmp; } + /* + * Status in IO_INTC_IRQ0 is changed even when interrupts are + * masked. If IRQ_TIMER1 bit in IO_INTC_IRQ0 is set to 0, then + * there is pending current_tick update. + * + * Relaying solely on current_tick value when interrupts are disabled + * can lead to lockup. + * Interrupt status bit check below is used to prevent this lockup. + */ + if (stop < count) { /* udelay will end after counter reset (tick) */ while ((IO_TIMER1_TMCNT < stop) || - (current_tick == prev_tick)); /* ensure new tick */ + ((current_tick == prev_tick) /* ensure new tick */ && + (IO_INTC_IRQ0 & IRQ_TIMER1))); /* prevent lock */ } else { /* udelay will end before counter reset (tick) */ - while ((IO_TIMER1_TMCNT < stop) && (current_tick == prev_tick)); + while ((IO_TIMER1_TMCNT < stop) && + ((current_tick == prev_tick) && (IO_INTC_IRQ0 & IRQ_TIMER1))); } } -- cgit v1.2.3