From 60a1cd10b222e004f860d14651e80089c77e8e6b Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Thu, 12 Aug 2021 12:09:42 +0200 Subject: irqchip/apple-aic: Fix irq_disable from within irq handlers When disable_irq_nosync for an interrupt is called from within its interrupt handler, this interrupt is only marked as disabled with the intention to mask it when it triggers again. The AIC hardware however automatically masks the interrupt when it is read. aic_irq_eoi then unmasks it again if it's not disabled *and* not masked. This results in a state mismatch between the hardware state and the state kept in irq_data: The hardware interrupt is masked but IRQD_IRQ_MASKED is not set. Any further calls to unmask_irq will directly return and the interrupt can never be enabled again. Fix this by keeping the hardware and irq_data state in sync by unmasking in aic_irq_eoi if and only if the irq_data state also assumes the interrupt to be unmasked. Fixes: 76cde2639411 ("irqchip/apple-aic: Add support for the Apple Interrupt Controller") Signed-off-by: Sven Peter Acked-by: Hector Martin Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20210812100942.17206-1-sven@svenpeter.dev --- drivers/irqchip/irq-apple-aic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c index b8c06bd8659e..6fc145aacaf0 100644 --- a/drivers/irqchip/irq-apple-aic.c +++ b/drivers/irqchip/irq-apple-aic.c @@ -226,7 +226,7 @@ static void aic_irq_eoi(struct irq_data *d) * Reading the interrupt reason automatically acknowledges and masks * the IRQ, so we just unmask it here if needed. */ - if (!irqd_irq_disabled(d) && !irqd_irq_masked(d)) + if (!irqd_irq_masked(d)) aic_irq_unmask(d); } -- cgit v1.2.3 From 8d474deaba2c4dd33a5e2f5be82e6798ffa6b8a5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 12 Aug 2021 01:15:05 +0800 Subject: irqchip/gic-v3: Fix priority comparison when non-secure priorities are used When non-secure priorities are used, compared to the raw priority set, the value read back from RPR is also right-shifted by one and the highest bit set. Add a macro to do the modifications to the raw priority when doing the comparison against the RPR value. This corrects the pseudo-NMI behavior when non-secure priorities in the GIC are used. Tested on 5.10 with the "IPI as pseudo-NMI" series [1] applied on MT8195. [1] https://lore.kernel.org/linux-arm-kernel/1604317487-14543-1-git-send-email-sumit.garg@linaro.org/ Fixes: 336780590990 ("irqchip/gic-v3: Support pseudo-NMIs when SCR_EL3.FIQ == 0") Reviewed-by: Alexandru Elisei Signed-off-by: Chen-Yu Tsai [maz: Added comment contributed by Alex] Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20210811171505.1502090-1-wenst@chromium.org --- drivers/irqchip/irq-gic-v3.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e0f4debe64e1..3e61210da04b 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -100,6 +100,27 @@ EXPORT_SYMBOL(gic_pmr_sync); DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities); EXPORT_SYMBOL(gic_nonsecure_priorities); +/* + * When the Non-secure world has access to group 0 interrupts (as a + * consequence of SCR_EL3.FIQ == 0), reading the ICC_RPR_EL1 register will + * return the Distributor's view of the interrupt priority. + * + * When GIC security is enabled (GICD_CTLR.DS == 0), the interrupt priority + * written by software is moved to the Non-secure range by the Distributor. + * + * If both are true (which is when gic_nonsecure_priorities gets enabled), + * we need to shift down the priority programmed by software to match it + * against the value returned by ICC_RPR_EL1. + */ +#define GICD_INT_RPR_PRI(priority) \ + ({ \ + u32 __priority = (priority); \ + if (static_branch_unlikely(&gic_nonsecure_priorities)) \ + __priority = 0x80 | (__priority >> 1); \ + \ + __priority; \ + }) + /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */ static refcount_t *ppi_nmi_refs; @@ -687,7 +708,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs return; if (gic_supports_nmi() && - unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) { + unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI))) { gic_handle_nmi(irqnr, regs); return; } -- cgit v1.2.3