diff options
| author | Deepak Saxena <dsaxena@net.rmk.(none)> | 2004-12-29 15:30:34 +0000 |
|---|---|---|
| committer | Russell King <rmk@flint.arm.linux.org.uk> | 2004-12-29 15:30:34 +0000 |
| commit | b8ca53f8fb495c09462b15e768bc597d76a9384b (patch) | |
| tree | a9c8926c629022dafee2631f52b8cde33ba2270d | |
| parent | c0620f451df80ae9cec7a6acf396ae49d7420141 (diff) | |
[ARM PATCH] 2326/1: Fix IXP2000 timer implementation
Patch from Deepak Saxena
This patch fixes two issues with the IXP2000 timer implementation:
- We currently to not account for lost timer interrupts
- We currently do not check for rollover within gettimeoffset()
Signed-off-by: Deepak Saxena
Signed-off-by: Russell King
| -rw-r--r-- | arch/arm/mach-ixp2000/core.c | 35 | ||||
| -rw-r--r-- | include/asm-arm/arch-ixp2000/ixp2000-regs.h | 1 |
2 files changed, 30 insertions, 6 deletions
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 0b59703081fc..1ad02ec5afdc 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -167,15 +167,28 @@ void __init ixp2000_map_io(void) *************************************************************************/ static unsigned ticks_per_jiffy; static unsigned ticks_per_usec; +static unsigned next_jiffy_time; unsigned long ixp2000_gettimeoffset (void) { - unsigned long elapsed; + unsigned long elapsed1, elapsed2, pending; + unsigned long offset; - /* Get ticks since last perfect jiffy */ - elapsed = ticks_per_jiffy - *IXP2000_T1_CSR; + elapsed1 = *IXP2000_T1_CSR; + pending = (*IXP2000_IRQ_STATUS & IRQ_MASK_TIMER1); + elapsed2 = *IXP2000_T1_CSR; - return elapsed / ticks_per_usec; + offset = ticks_per_jiffy - elapsed2; + + /* + * We have two cases to cover, one where we were pending + * already, and another where it overflowed while we were + * checking the timers. + */ + if ((elapsed2 > elapsed1) || pending) + offset += ticks_per_jiffy; + + return offset / ticks_per_usec; } static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -185,7 +198,10 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* clear timer 1 */ ixp2000_reg_write(IXP2000_T1_CLR, 1); - timer_tick(regs); + while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) { + timer_tick(regs); + next_jiffy_time -= ticks_per_jiffy; + } write_sequnlock(&xtime_lock); @@ -201,7 +217,7 @@ static struct irqaction ixp2000_timer_irq = { void __init ixp2000_init_time(unsigned long tick_rate) { ixp2000_reg_write(IXP2000_T1_CLR, 0); - ixp2000_reg_write(IXP2000_T2_CLR, 0); + ixp2000_reg_write(IXP2000_T4_CLR, 0); ticks_per_jiffy = (tick_rate + HZ/2) / HZ; ticks_per_usec = tick_rate / 1000000; @@ -209,6 +225,13 @@ void __init ixp2000_init_time(unsigned long tick_rate) ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy); ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); + /* + * We use T4 as a monotonic counter to track missed jiffies + */ + ixp2000_reg_write(IXP2000_T4_CLD, -1); + ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); + next_jiffy_time = 0xffffffff - ticks_per_jiffy; + /* register for interrupt */ setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq); } diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index 5e047b38dd5d..99dd524eaecb 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -98,6 +98,7 @@ #define WDT_ENABLE 0x00000001 #define TIMER_DIVIDER_256 0x00000008 #define TIMER_ENABLE 0x00000080 +#define IRQ_MASK_TIMER1 (1 << 4) /* * Interrupt controller registers |
