Skip to content

Commit f32c926

Browse files
Julien Thierryctmarinas
authored andcommitted
irqchip/gic-v3: Handle pseudo-NMIs
Provide a higher priority to be used for pseudo-NMIs. When such an interrupt is received, keep interrupts fully disabled at CPU level to prevent receiving other pseudo-NMIs while handling the current one. Signed-off-by: Julien Thierry <julien.thierry@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent d98d0a9 commit f32c926

1 file changed

Lines changed: 36 additions & 6 deletions

File tree

drivers/irqchip/irq-gic-v3.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141

4242
#include "irq-gic-common.h"
4343

44+
#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
45+
4446
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
4547

4648
struct redist_region {
@@ -381,12 +383,45 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr)
381383
return aff;
382384
}
383385

386+
static void gic_deactivate_unhandled(u32 irqnr)
387+
{
388+
if (static_branch_likely(&supports_deactivate_key)) {
389+
if (irqnr < 8192)
390+
gic_write_dir(irqnr);
391+
} else {
392+
gic_write_eoir(irqnr);
393+
}
394+
}
395+
396+
static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
397+
{
398+
int err;
399+
400+
if (static_branch_likely(&supports_deactivate_key))
401+
gic_write_eoir(irqnr);
402+
/*
403+
* Leave the PSR.I bit set to prevent other NMIs to be
404+
* received while handling this one.
405+
* PSR.I will be restored when we ERET to the
406+
* interrupted context.
407+
*/
408+
err = handle_domain_nmi(gic_data.domain, irqnr, regs);
409+
if (err)
410+
gic_deactivate_unhandled(irqnr);
411+
}
412+
384413
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
385414
{
386415
u32 irqnr;
387416

388417
irqnr = gic_read_iar();
389418

419+
if (gic_supports_nmi() &&
420+
unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) {
421+
gic_handle_nmi(irqnr, regs);
422+
return;
423+
}
424+
390425
if (gic_prio_masking_enabled()) {
391426
gic_pmr_mask_irqs();
392427
gic_arch_enable_irqs();
@@ -403,12 +438,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
403438
err = handle_domain_irq(gic_data.domain, irqnr, regs);
404439
if (err) {
405440
WARN_ONCE(true, "Unexpected interrupt received!\n");
406-
if (static_branch_likely(&supports_deactivate_key)) {
407-
if (irqnr < 8192)
408-
gic_write_dir(irqnr);
409-
} else {
410-
gic_write_eoir(irqnr);
411-
}
441+
gic_deactivate_unhandled(irqnr);
412442
}
413443
return;
414444
}

0 commit comments

Comments
 (0)