m68k: hp300: Handle timer counter overflow
Because hp300_read_clk() never checks the timer interrupt flag it may fail to notice that the timer has wrapped, allowing the clock to jump backwards. This is not a new problem. This is resolved by checking the interrupt flag and, if need be, taking wrap-around into account. The interrupt handler clears the flag when it eventually executes. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
This commit is contained in:
Родитель
2ed16626f5
Коммит
4be2ba93cf
|
@ -30,7 +30,7 @@ static struct clocksource hp300_clk = {
|
||||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 clk_total;
|
static u32 clk_total, clk_offset;
|
||||||
|
|
||||||
/* Clock hardware definitions */
|
/* Clock hardware definitions */
|
||||||
|
|
||||||
|
@ -41,9 +41,12 @@ static u32 clk_total;
|
||||||
#define CLKCR3 CLKCR1
|
#define CLKCR3 CLKCR1
|
||||||
#define CLKSR CLKCR2
|
#define CLKSR CLKCR2
|
||||||
#define CLKMSB1 0x5
|
#define CLKMSB1 0x5
|
||||||
|
#define CLKLSB1 0x7
|
||||||
#define CLKMSB2 0x9
|
#define CLKMSB2 0x9
|
||||||
#define CLKMSB3 0xD
|
#define CLKMSB3 0xD
|
||||||
|
|
||||||
|
#define CLKSR_INT1 BIT(0)
|
||||||
|
|
||||||
/* This is for machines which generate the exact clock. */
|
/* This is for machines which generate the exact clock. */
|
||||||
|
|
||||||
#define HP300_TIMER_CLOCK_FREQ 250000
|
#define HP300_TIMER_CLOCK_FREQ 250000
|
||||||
|
@ -60,6 +63,7 @@ static irqreturn_t hp300_tick(int irq, void *dev_id)
|
||||||
in_8(CLOCKBASE + CLKSR);
|
in_8(CLOCKBASE + CLKSR);
|
||||||
asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
|
asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
|
||||||
clk_total += INTVAL;
|
clk_total += INTVAL;
|
||||||
|
clk_offset = 0;
|
||||||
timer_routine(0, NULL);
|
timer_routine(0, NULL);
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
|
@ -70,24 +74,28 @@ static irqreturn_t hp300_tick(int irq, void *dev_id)
|
||||||
|
|
||||||
static u64 hp300_read_clk(struct clocksource *cs)
|
static u64 hp300_read_clk(struct clocksource *cs)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned char lsb, msb1, msb2;
|
unsigned char lsb, msb, msb_new;
|
||||||
u32 ticks;
|
u32 ticks;
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
/* Read current timer 1 value */
|
/* Read current timer 1 value */
|
||||||
msb1 = in_8(CLOCKBASE + 5);
|
msb = in_8(CLOCKBASE + CLKMSB1);
|
||||||
lsb = in_8(CLOCKBASE + 7);
|
again:
|
||||||
msb2 = in_8(CLOCKBASE + 5);
|
if ((in_8(CLOCKBASE + CLKSR) & CLKSR_INT1) && msb > 0)
|
||||||
if (msb1 != msb2)
|
clk_offset = INTVAL;
|
||||||
/* A carry happened while we were reading. Read it again */
|
lsb = in_8(CLOCKBASE + CLKLSB1);
|
||||||
lsb = in_8(CLOCKBASE + 7);
|
msb_new = in_8(CLOCKBASE + CLKMSB1);
|
||||||
|
if (msb_new != msb) {
|
||||||
|
msb = msb_new;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
ticks = INTVAL - ((msb2 << 8) | lsb);
|
ticks = INTVAL - ((msb << 8) | lsb);
|
||||||
ticks += clk_total;
|
ticks += clk_offset + clk_total;
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init hp300_sched_init(irq_handler_t vector)
|
void __init hp300_sched_init(irq_handler_t vector)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче