m68k: Call timer_interrupt() with interrupts disabled

Some platforms execute their timer handler with the interrupt priority
level set below 6. That means the handler could be interrupted by another
driver and this could lead to re-entry of the timer core.

Avoid this by use of local_irq_save/restore for timer interrupt dispatch.
This provides mutual exclusion around the timer interrupt flag access
which is needed later in this series for the clocksource conversion.

Reported-by: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/alpine.DEB.2.21.1811131407120.2697@nanos.tec.linutronix.de
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
This commit is contained in:
Finn Thain 2018-12-01 11:53:10 +11:00 committed by Geert Uytterhoeven
parent 9e98c678c2
commit 1efdd4bd25
11 changed files with 105 additions and 47 deletions

View File

@ -88,10 +88,19 @@ static irqreturn_t cia_handler(int irq, void *dev_id)
struct ciabase *base = dev_id;
int mach_irq;
unsigned char ints;
unsigned long flags;
/* Interrupts get disabled while the timer irq flag is cleared and
* the timer interrupt serviced.
*/
mach_irq = base->cia_irq;
local_irq_save(flags);
ints = cia_set_irq(base, CIA_ICR_ALL);
amiga_custom.intreq = base->int_mask;
if (ints & 1)
generic_handle_irq(mach_irq);
local_irq_restore(flags);
mach_irq++, ints >>= 1;
for (; ints; mach_irq++, ints >>= 1) {
if (ints & 1)
generic_handle_irq(mach_irq);

View File

@ -142,7 +142,7 @@ struct mfptimerbase {
.name = "MFP Timer D"
};
static irqreturn_t mfptimer_handler(int irq, void *dev_id)
static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id)
{
struct mfptimerbase *base = dev_id;
int mach_irq;
@ -344,7 +344,7 @@ void __init atari_init_IRQ(void)
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
/* request timer D dispatch handler */
if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED,
stmfp_base.name, &stmfp_base))
pr_err("Couldn't register %s interrupt\n", stmfp_base.name);

View File

@ -24,6 +24,18 @@
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL_GPL(rtc_lock);
static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id)
{
irq_handler_t timer_routine = dev_id;
unsigned long flags;
local_irq_save(flags);
timer_routine(0, NULL);
local_irq_restore(flags);
return IRQ_HANDLED;
}
void __init
atari_sched_init(irq_handler_t timer_routine)
{
@ -32,7 +44,8 @@ atari_sched_init(irq_handler_t timer_routine)
/* start timer C, div = 1:100 */
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
/* install interrupt service routine for MFP Timer C */
if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine))
if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer",
timer_routine))
pr_err("Couldn't register timer interrupt\n");
}

View File

@ -44,11 +44,6 @@ extern int bvme6000_hwclk (int, struct rtc_time *);
extern void bvme6000_reset (void);
void bvme6000_set_vectors (void);
/* Save tick handler routine pointer, will point to xtime_update() in
* kernel/timer/timekeeping.c, called via bvme6000_process_int() */
static irq_handler_t tick_handler;
int __init bvme6000_parse_bootinfo(const struct bi_record *bi)
{
@ -157,12 +152,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
{
irq_handler_t timer_routine = dev_id;
unsigned long flags;
volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
unsigned char msr = rtc->msr & 0xc0;
unsigned char msr;
local_irq_save(flags);
msr = rtc->msr & 0xc0;
rtc->msr = msr | 0x20; /* Ack the interrupt */
timer_routine(0, NULL);
local_irq_restore(flags);
return tick_handler(irq, dev_id);
return IRQ_HANDLED;
}
/*
@ -181,9 +182,8 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
rtc->msr = 0; /* Ensure timer registers accessible */
tick_handler = timer_routine;
if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
"timer", bvme6000_timer_int))
if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer",
timer_routine))
panic ("Couldn't register timer int");
rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */

View File

@ -38,13 +38,19 @@
static irqreturn_t hp300_tick(int irq, void *dev_id)
{
irq_handler_t timer_routine = dev_id;
unsigned long flags;
unsigned long tmp;
irq_handler_t vector = dev_id;
local_irq_save(flags);
in_8(CLOCKBASE + CLKSR);
asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
timer_routine(0, NULL);
local_irq_restore(flags);
/* Turn off the network and SCSI leds */
blinken_leds(0, 0xe0);
return vector(irq, NULL);
return IRQ_HANDLED;
}
u32 hp300_gettimeoffset(void)

View File

@ -440,6 +440,8 @@ void via_nubus_irq_shutdown(int irq)
* via6522.c :-), disable/pending masks added.
*/
#define VIA_TIMER_1_INT BIT(6)
void via1_irq(struct irq_desc *desc)
{
int irq_num;
@ -449,6 +451,21 @@ void via1_irq(struct irq_desc *desc)
if (!events)
return;
irq_num = IRQ_MAC_TIMER_1;
irq_bit = VIA_TIMER_1_INT;
if (events & irq_bit) {
unsigned long flags;
local_irq_save(flags);
via1[vIFR] = irq_bit;
generic_handle_irq(irq_num);
local_irq_restore(flags);
events &= ~irq_bit;
if (!events)
return;
}
irq_num = VIA1_SOURCE_BASE;
irq_bit = 1;
do {

View File

@ -45,11 +45,6 @@ extern void mvme147_reset (void);
static int bcd2int (unsigned char b);
/* Save tick handler routine pointer, will point to xtime_update() in
* kernel/time/timekeeping.c, called via mvme147_process_int() */
irq_handler_t tick_handler;
int __init mvme147_parse_bootinfo(const struct bi_record *bi)
{
@ -104,16 +99,23 @@ void __init config_mvme147(void)
static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
{
irq_handler_t timer_routine = dev_id;
unsigned long flags;
local_irq_save(flags);
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
return tick_handler(irq, dev_id);
timer_routine(0, NULL);
local_irq_restore(flags);
return IRQ_HANDLED;
}
void mvme147_sched_init (irq_handler_t timer_routine)
{
tick_handler = timer_routine;
if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL))
if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1",
timer_routine))
pr_err("Couldn't register timer interrupt\n");
/* Init the clock with a value */

View File

@ -50,11 +50,6 @@ extern void mvme16x_reset (void);
int bcd2int (unsigned char b);
/* Save tick handler routine pointer, will point to xtime_update() in
* kernel/time/timekeeping.c, called via mvme16x_process_int() */
static irq_handler_t tick_handler;
unsigned short mvme16x_config;
EXPORT_SYMBOL(mvme16x_config);
@ -352,8 +347,15 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
{
*(volatile unsigned char *)0xfff4201b |= 8;
return tick_handler(irq, dev_id);
irq_handler_t timer_routine = dev_id;
unsigned long flags;
local_irq_save(flags);
*(volatile unsigned char *)0xfff4201b |= 8;
timer_routine(0, NULL);
local_irq_restore(flags);
return IRQ_HANDLED;
}
void mvme16x_sched_init (irq_handler_t timer_routine)
@ -361,14 +363,13 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
uint16_t brdno = be16_to_cpu(mvme_bdid.brdno);
int irq;
tick_handler = timer_routine;
/* Using PCCchip2 or MC2 chip tick timer 1 */
*(volatile unsigned long *)0xfff42008 = 0;
*(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */
*(volatile unsigned char *)0xfff42017 |= 3;
*(volatile unsigned char *)0xfff4201b = 0x16;
if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
"timer", mvme16x_timer_int))
if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, "timer",
timer_routine))
panic ("Couldn't register timer int");
if (brdno == 0x0162 || brdno == 0x172)

View File

@ -127,10 +127,10 @@ void q40_mksound(unsigned int hz, unsigned int ticks)
sound_ticks = ticks << 1;
}
static irq_handler_t q40_timer_routine;
static irqreturn_t q40_timer_int (int irq, void * dev)
static irqreturn_t q40_timer_int(int irq, void *dev_id)
{
irq_handler_t timer_routine = dev_id;
ql_ticks = ql_ticks ? 0 : 1;
if (sound_ticks) {
unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
@ -139,8 +139,13 @@ static irqreturn_t q40_timer_int (int irq, void * dev)
*DAC_RIGHT=sval;
}
if (!ql_ticks)
q40_timer_routine(irq, dev);
if (!ql_ticks) {
unsigned long flags;
local_irq_save(flags);
timer_routine(0, NULL);
local_irq_restore(flags);
}
return IRQ_HANDLED;
}
@ -148,11 +153,9 @@ void q40_sched_init (irq_handler_t timer_routine)
{
int timer_irq;
q40_timer_routine = timer_routine;
timer_irq = Q40_IRQ_FRAME;
if (request_irq(timer_irq, q40_timer_int, 0,
"timer", q40_timer_int))
if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine))
panic("Couldn't register timer int");
master_outb(-1, FRAME_CLEAR_REG);

View File

@ -61,8 +61,10 @@ static irqreturn_t sun3_int7(int irq, void *dev_id)
static irqreturn_t sun3_int5(int irq, void *dev_id)
{
unsigned long flags;
unsigned int cnt;
local_irq_save(flags);
#ifdef CONFIG_SUN3
intersil_clear();
#endif
@ -76,6 +78,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id)
cnt = kstat_irqs_cpu(irq, 0);
if (!(cnt % 20))
sun3_leds(led_pattern[cnt % 160 / 20]);
local_irq_restore(flags);
return IRQ_HANDLED;
}

View File

@ -80,15 +80,19 @@ u32 sun3x_gettimeoffset(void)
}
#if 0
static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t sun3x_timer_tick(int irq, void *dev_id)
{
void (*vector)(int, void *, struct pt_regs *) = dev_id;
irq_handler_t timer_routine = dev_id;
unsigned long flags;
/* Clear the pending interrupt - pulse the enable line low */
disable_irq(5);
enable_irq(5);
local_irq_save(flags);
/* Clear the pending interrupt - pulse the enable line low */
disable_irq(5);
enable_irq(5);
timer_routine(0, NULL);
local_irq_restore(flags);
vector(irq, NULL, regs);
return IRQ_HANDLED;
}
#endif