Commit 41272490 authored by Finn Thain's avatar Finn Thain Committed by Greg Kroah-Hartman
Browse files

m68k: Call timer_interrupt() with interrupts disabled

[ Upstream commit 1efdd4bd

 ]

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: default avatarThomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/alpine.DEB.2.21.1811131407120.2697@nanos.tec.linutronix.de

Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 7c662630
...@@ -88,10 +88,19 @@ static irqreturn_t cia_handler(int irq, void *dev_id) ...@@ -88,10 +88,19 @@ static irqreturn_t cia_handler(int irq, void *dev_id)
struct ciabase *base = dev_id; struct ciabase *base = dev_id;
int mach_irq; int mach_irq;
unsigned char ints; 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; mach_irq = base->cia_irq;
local_irq_save(flags);
ints = cia_set_irq(base, CIA_ICR_ALL); ints = cia_set_irq(base, CIA_ICR_ALL);
amiga_custom.intreq = base->int_mask; 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) { for (; ints; mach_irq++, ints >>= 1) {
if (ints & 1) if (ints & 1)
generic_handle_irq(mach_irq); generic_handle_irq(mach_irq);
......
...@@ -142,7 +142,7 @@ struct mfptimerbase { ...@@ -142,7 +142,7 @@ struct mfptimerbase {
.name = "MFP Timer D" .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; struct mfptimerbase *base = dev_id;
int mach_irq; int mach_irq;
...@@ -344,7 +344,7 @@ void __init atari_init_IRQ(void) ...@@ -344,7 +344,7 @@ void __init atari_init_IRQ(void)
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
/* request timer D dispatch handler */ /* 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)) stmfp_base.name, &stmfp_base))
pr_err("Couldn't register %s interrupt\n", stmfp_base.name); pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
......
...@@ -24,6 +24,18 @@ ...@@ -24,6 +24,18 @@
DEFINE_SPINLOCK(rtc_lock); DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL_GPL(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 void __init
atari_sched_init(irq_handler_t timer_routine) atari_sched_init(irq_handler_t timer_routine)
{ {
...@@ -32,7 +44,8 @@ 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 */ /* start timer C, div = 1:100 */
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60; st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
/* install interrupt service routine for MFP Timer C */ /* 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"); pr_err("Couldn't register timer interrupt\n");
} }
......
...@@ -45,11 +45,6 @@ extern int bvme6000_set_clock_mmss (unsigned long); ...@@ -45,11 +45,6 @@ extern int bvme6000_set_clock_mmss (unsigned long);
extern void bvme6000_reset (void); extern void bvme6000_reset (void);
void bvme6000_set_vectors (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) int __init bvme6000_parse_bootinfo(const struct bi_record *bi)
{ {
...@@ -159,12 +154,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id) ...@@ -159,12 +154,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
static irqreturn_t bvme6000_timer_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; 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 */ rtc->msr = msr | 0x20; /* Ack the interrupt */
timer_routine(0, NULL);
local_irq_restore(flags);
return tick_handler(irq, dev_id); return IRQ_HANDLED;
} }
/* /*
...@@ -183,9 +184,8 @@ void bvme6000_sched_init (irq_handler_t timer_routine) ...@@ -183,9 +184,8 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
rtc->msr = 0; /* Ensure timer registers accessible */ rtc->msr = 0; /* Ensure timer registers accessible */
tick_handler = timer_routine; if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer",
if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, timer_routine))
"timer", bvme6000_timer_int))
panic ("Couldn't register timer int"); panic ("Couldn't register timer int");
rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */ rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */
......
...@@ -38,13 +38,19 @@ ...@@ -38,13 +38,19 @@
static irqreturn_t hp300_tick(int irq, void *dev_id) static irqreturn_t hp300_tick(int irq, void *dev_id)
{ {
irq_handler_t timer_routine = dev_id;
unsigned long flags;
unsigned long tmp; unsigned long tmp;
irq_handler_t vector = dev_id;
local_irq_save(flags);
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));
timer_routine(0, NULL);
local_irq_restore(flags);
/* Turn off the network and SCSI leds */ /* Turn off the network and SCSI leds */
blinken_leds(0, 0xe0); blinken_leds(0, 0xe0);
return vector(irq, NULL); return IRQ_HANDLED;
} }
u32 hp300_gettimeoffset(void) u32 hp300_gettimeoffset(void)
......
...@@ -398,6 +398,8 @@ void via_nubus_irq_shutdown(int irq) ...@@ -398,6 +398,8 @@ void via_nubus_irq_shutdown(int irq)
* via6522.c :-), disable/pending masks added. * via6522.c :-), disable/pending masks added.
*/ */
#define VIA_TIMER_1_INT BIT(6)
void via1_irq(struct irq_desc *desc) void via1_irq(struct irq_desc *desc)
{ {
int irq_num; int irq_num;
...@@ -407,6 +409,21 @@ void via1_irq(struct irq_desc *desc) ...@@ -407,6 +409,21 @@ void via1_irq(struct irq_desc *desc)
if (!events) if (!events)
return; 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_num = VIA1_SOURCE_BASE;
irq_bit = 1; irq_bit = 1;
do { do {
......
...@@ -46,11 +46,6 @@ extern void mvme147_reset (void); ...@@ -46,11 +46,6 @@ extern void mvme147_reset (void);
static int bcd2int (unsigned char b); 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) int __init mvme147_parse_bootinfo(const struct bi_record *bi)
{ {
...@@ -106,16 +101,23 @@ void __init config_mvme147(void) ...@@ -106,16 +101,23 @@ void __init config_mvme147(void)
static irqreturn_t mvme147_timer_int (int irq, void *dev_id) 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_TIMER_INT_CLR;
m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; 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) 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",
if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL)) timer_routine))
pr_err("Couldn't register timer interrupt\n"); pr_err("Couldn't register timer interrupt\n");
/* Init the clock with a value */ /* Init the clock with a value */
......
...@@ -51,11 +51,6 @@ extern void mvme16x_reset (void); ...@@ -51,11 +51,6 @@ extern void mvme16x_reset (void);
int bcd2int (unsigned char b); 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; unsigned short mvme16x_config;
EXPORT_SYMBOL(mvme16x_config); EXPORT_SYMBOL(mvme16x_config);
...@@ -354,8 +349,15 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) ...@@ -354,8 +349,15 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
{ {
*(volatile unsigned char *)0xfff4201b |= 8; irq_handler_t timer_routine = dev_id;
return tick_handler(irq, 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) void mvme16x_sched_init (irq_handler_t timer_routine)
...@@ -363,14 +365,13 @@ void mvme16x_sched_init (irq_handler_t timer_routine) ...@@ -363,14 +365,13 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); uint16_t brdno = be16_to_cpu(mvme_bdid.brdno);
int irq; int irq;
tick_handler = timer_routine;
/* Using PCCchip2 or MC2 chip tick timer 1 */ /* Using PCCchip2 or MC2 chip tick timer 1 */
*(volatile unsigned long *)0xfff42008 = 0; *(volatile unsigned long *)0xfff42008 = 0;
*(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */
*(volatile unsigned char *)0xfff42017 |= 3; *(volatile unsigned char *)0xfff42017 |= 3;
*(volatile unsigned char *)0xfff4201b = 0x16; *(volatile unsigned char *)0xfff4201b = 0x16;
if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, "timer",
"timer", mvme16x_timer_int)) timer_routine))
panic ("Couldn't register timer int"); panic ("Couldn't register timer int");
if (brdno == 0x0162 || brdno == 0x172) if (brdno == 0x0162 || brdno == 0x172)
......
...@@ -127,10 +127,10 @@ void q40_mksound(unsigned int hz, unsigned int ticks) ...@@ -127,10 +127,10 @@ void q40_mksound(unsigned int hz, unsigned int ticks)
sound_ticks = ticks << 1; sound_ticks = ticks << 1;
} }
static irq_handler_t q40_timer_routine; static irqreturn_t q40_timer_int(int irq, void *dev_id)
static irqreturn_t q40_timer_int (int irq, void * dev)
{ {
irq_handler_t timer_routine = dev_id;
ql_ticks = ql_ticks ? 0 : 1; ql_ticks = ql_ticks ? 0 : 1;
if (sound_ticks) { if (sound_ticks) {
unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
...@@ -139,8 +139,13 @@ static irqreturn_t q40_timer_int (int irq, void * dev) ...@@ -139,8 +139,13 @@ static irqreturn_t q40_timer_int (int irq, void * dev)
*DAC_RIGHT=sval; *DAC_RIGHT=sval;
} }
if (!ql_ticks) if (!ql_ticks) {
q40_timer_routine(irq, dev); unsigned long flags;
local_irq_save(flags);
timer_routine(0, NULL);
local_irq_restore(flags);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -148,11 +153,9 @@ void q40_sched_init (irq_handler_t timer_routine) ...@@ -148,11 +153,9 @@ void q40_sched_init (irq_handler_t timer_routine)
{ {
int timer_irq; int timer_irq;
q40_timer_routine = timer_routine;
timer_irq = Q40_IRQ_FRAME; timer_irq = Q40_IRQ_FRAME;
if (request_irq(timer_irq, q40_timer_int, 0, if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine))
"timer", q40_timer_int))
panic("Couldn't register timer int"); panic("Couldn't register timer int");
master_outb(-1, FRAME_CLEAR_REG); master_outb(-1, FRAME_CLEAR_REG);
......
...@@ -61,8 +61,10 @@ static irqreturn_t sun3_int7(int irq, void *dev_id) ...@@ -61,8 +61,10 @@ static irqreturn_t sun3_int7(int irq, void *dev_id)
static irqreturn_t sun3_int5(int irq, void *dev_id) static irqreturn_t sun3_int5(int irq, void *dev_id)
{ {
unsigned long flags;
unsigned int cnt; unsigned int cnt;
local_irq_save(flags);
#ifdef CONFIG_SUN3 #ifdef CONFIG_SUN3
intersil_clear(); intersil_clear();
#endif #endif
...@@ -76,6 +78,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id) ...@@ -76,6 +78,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id)
cnt = kstat_irqs_cpu(irq, 0); cnt = kstat_irqs_cpu(irq, 0);
if (!(cnt % 20)) if (!(cnt % 20))
sun3_leds(led_pattern[cnt % 160 / 20]); sun3_leds(led_pattern[cnt % 160 / 20]);
local_irq_restore(flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -78,15 +78,19 @@ u32 sun3x_gettimeoffset(void) ...@@ -78,15 +78,19 @@ u32 sun3x_gettimeoffset(void)
} }
#if 0 #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 */ local_irq_save(flags);
disable_irq(5); /* Clear the pending interrupt - pulse the enable line low */
enable_irq(5); disable_irq(5);
enable_irq(5);
timer_routine(0, NULL);
local_irq_restore(flags);
vector(irq, NULL, regs); return IRQ_HANDLED;
} }
#endif #endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment