Commit b333a99e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull powerpc fix from Michael Ellerman:
 "One fix for a bug in our soft interrupt masking, which could lead to
  interrupt replaying recursing, causing spurious interrupts.

  Thanks to Nicholas Piggin"

* tag 'powerpc-5.11-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s: prevent recursive replay_soft_interrupts causing superfluous interrupt
parents 1188866d 4025c784
Loading
Loading
Loading
Loading
+16 −12
Original line number Diff line number Diff line
@@ -180,13 +180,18 @@ void notrace restore_interrupts(void)

void replay_soft_interrupts(void)
{
	struct pt_regs regs;

	/*
	 * We use local_paca rather than get_paca() to avoid all
	 * the debug_smp_processor_id() business in this low level
	 * function
	 * Be careful here, calling these interrupt handlers can cause
	 * softirqs to be raised, which they may run when calling irq_exit,
	 * which will cause local_irq_enable() to be run, which can then
	 * recurse into this function. Don't keep any state across
	 * interrupt handler calls which may change underneath us.
	 *
	 * We use local_paca rather than get_paca() to avoid all the
	 * debug_smp_processor_id() business in this low level function.
	 */
	unsigned char happened = local_paca->irq_happened;
	struct pt_regs regs;

	ppc_save_regs(&regs);
	regs.softe = IRQS_ENABLED;
@@ -209,7 +214,7 @@ void replay_soft_interrupts(void)
	 * This is a higher priority interrupt than the others, so
	 * replay it first.
	 */
	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) {
	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) {
		local_paca->irq_happened &= ~PACA_IRQ_HMI;
		regs.trap = 0xe60;
		handle_hmi_exception(&regs);
@@ -217,7 +222,7 @@ void replay_soft_interrupts(void)
			hard_irq_disable();
	}

	if (happened & PACA_IRQ_DEC) {
	if (local_paca->irq_happened & PACA_IRQ_DEC) {
		local_paca->irq_happened &= ~PACA_IRQ_DEC;
		regs.trap = 0x900;
		timer_interrupt(&regs);
@@ -225,7 +230,7 @@ void replay_soft_interrupts(void)
			hard_irq_disable();
	}

	if (happened & PACA_IRQ_EE) {
	if (local_paca->irq_happened & PACA_IRQ_EE) {
		local_paca->irq_happened &= ~PACA_IRQ_EE;
		regs.trap = 0x500;
		do_IRQ(&regs);
@@ -233,7 +238,7 @@ void replay_soft_interrupts(void)
			hard_irq_disable();
	}

	if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) {
	if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) {
		local_paca->irq_happened &= ~PACA_IRQ_DBELL;
		if (IS_ENABLED(CONFIG_PPC_BOOK3E))
			regs.trap = 0x280;
@@ -245,7 +250,7 @@ void replay_soft_interrupts(void)
	}

	/* Book3E does not support soft-masking PMI interrupts */
	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) {
	if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) {
		local_paca->irq_happened &= ~PACA_IRQ_PMI;
		regs.trap = 0xf00;
		performance_monitor_exception(&regs);
@@ -253,8 +258,7 @@ void replay_soft_interrupts(void)
			hard_irq_disable();
	}

	happened = local_paca->irq_happened;
	if (happened & ~PACA_IRQ_HARD_DIS) {
	if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) {
		/*
		 * We are responding to the next interrupt, so interrupt-off
		 * latencies should be reset here.