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

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

m68k: Call timer_interrupt() with interrupts disabled



[ Upstream commit 1efdd4bd254311498123a15fa0acd565f454da97 ]

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 283163a3
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