Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1efdd4bd authored by Finn Thain's avatar Finn Thain Committed by Geert Uytterhoeven
Browse files

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: 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>
parent 9e98c678
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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);

+14 −1
Original line number Diff line number Diff line
@@ -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");
}

+10 −10
Original line number Diff line number Diff line
@@ -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 */
+8 −2
Original line number Diff line number Diff line
@@ -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)
Loading