Commit 9df7f15e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'irq_urgent_for_v5.13_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fix from Borislav Petkov:
 "A single fix for GICv3 to not take an interrupt in an NMI context"

* tag 'irq_urgent_for_v5.13_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqchip/gic-v3: Workaround inconsistent PMR setting on NMI entry
parents 8363e795 a13d0f8d
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -642,11 +642,45 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
		nmi_exit();
}

static u32 do_read_iar(struct pt_regs *regs)
{
	u32 iar;

	if (gic_supports_nmi() && unlikely(!interrupts_enabled(regs))) {
		u64 pmr;

		/*
		 * We were in a context with IRQs disabled. However, the
		 * entry code has set PMR to a value that allows any
		 * interrupt to be acknowledged, and not just NMIs. This can
		 * lead to surprising effects if the NMI has been retired in
		 * the meantime, and that there is an IRQ pending. The IRQ
		 * would then be taken in NMI context, something that nobody
		 * wants to debug twice.
		 *
		 * Until we sort this, drop PMR again to a level that will
		 * actually only allow NMIs before reading IAR, and then
		 * restore it to what it was.
		 */
		pmr = gic_read_pmr();
		gic_pmr_mask_irqs();
		isb();

		iar = gic_read_iar();

		gic_write_pmr(pmr);
	} else {
		iar = gic_read_iar();
	}

	return iar;
}

static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
	u32 irqnr;

	irqnr = gic_read_iar();
	irqnr = do_read_iar(regs);

	/* Check for special IDs first */
	if ((irqnr >= 1020 && irqnr <= 1023))