summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mvme147
diff options
context:
space:
mode:
authorFinn Thain2018-12-01 01:53:10 +0100
committerGeert Uytterhoeven2019-03-25 10:22:24 +0100
commit7529b90d051e4629884771ba2b1d3a87d2c6a9d7 (patch)
treef95960fd233bf19c0840e65a9281d71576a2abdc /arch/m68k/mvme147
parentm68k: mvme147: Convert to clocksource API (diff)
downloadkernel-qcow2-linux-7529b90d051e4629884771ba2b1d3a87d2c6a9d7.tar.gz
kernel-qcow2-linux-7529b90d051e4629884771ba2b1d3a87d2c6a9d7.tar.xz
kernel-qcow2-linux-7529b90d051e4629884771ba2b1d3a87d2c6a9d7.zip
m68k: mvme147: Handle timer counter overflow
Reading the timer counter races with timer overflow (and the corresponding interrupt). This is resolved by reading the overflow register and taking this value into account. The interrupt handler must clear the overflow register when it eventually executes. Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k/mvme147')
-rw-r--r--arch/m68k/mvme147/config.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index c44a254e8a8c..545a1fe0e119 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -118,7 +118,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
local_irq_save(flags);
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
- m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+ m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF;
clk_total += PCC_TIMER_CYCLES;
timer_routine(0, NULL);
local_irq_restore(flags);
@@ -144,21 +144,22 @@ void mvme147_sched_init (irq_handler_t timer_routine)
clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ);
}
-/* XXX There are race hazards in this code XXX */
static u64 mvme147_read_clk(struct clocksource *cs)
{
unsigned long flags;
- volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
- unsigned short n;
+ u8 overflow, tmp;
+ u16 count;
u32 ticks;
local_irq_save(flags);
- n = *cp;
- while (n != *cp)
- n = *cp;
-
- n -= PCC_TIMER_PRELOAD;
- ticks = clk_total + n;
+ tmp = m147_pcc->t1_cntrl >> 4;
+ count = m147_pcc->t1_count;
+ overflow = m147_pcc->t1_cntrl >> 4;
+ if (overflow != tmp)
+ count = m147_pcc->t1_count;
+ count -= PCC_TIMER_PRELOAD;
+ ticks = count + overflow * PCC_TIMER_CYCLES;
+ ticks += clk_total;
local_irq_restore(flags);
return ticks;