Mian Yousaf Kaukab 9d28b6
From: Daniel Thompson <daniel.thompson@linaro.org>
Mian Yousaf Kaukab 9d28b6
Date: Tue, 3 May 2022 14:45:41 +0100
Mian Yousaf Kaukab 9d28b6
Subject: irqchip/exiu: Fix acknowledgment of edge triggered interrupts
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
Git-commit: 4efc851c36e389f7ed432edac0149acc5f94b0c7
Mian Yousaf Kaukab 9d28b6
Patch-mainline: v5.19-rc1
Mian Yousaf Kaukab 9d28b6
References: git-fixes
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
Currently the EXIU uses the fasteoi interrupt flow that is configured by
Mian Yousaf Kaukab 9d28b6
it's parent (irq-gic-v3.c). With this flow the only chance to clear the
Mian Yousaf Kaukab 9d28b6
interrupt request happens during .irq_eoi() and (obviously) this happens
Mian Yousaf Kaukab 9d28b6
after the interrupt handler has run. EXIU requires edge triggered
Mian Yousaf Kaukab 9d28b6
interrupts to be acked prior to interrupt handling. Without this we
Mian Yousaf Kaukab 9d28b6
risk incorrect interrupt dismissal when a new interrupt is delivered
Mian Yousaf Kaukab 9d28b6
after the handler reads and acknowledges the peripheral but before the
Mian Yousaf Kaukab 9d28b6
irq_eoi() takes place.
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
Fix this by clearing the interrupt request from .irq_ack() if we are
Mian Yousaf Kaukab 9d28b6
configured for edge triggered interrupts. This requires adopting the
Mian Yousaf Kaukab 9d28b6
fasteoi-ack flow instead of the fasteoi to ensure the ack gets called.
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
These changes have been tested using the power button on a
Mian Yousaf Kaukab 9d28b6
Developerbox/SC2A11 combined with some hackery in gpio-keys so I can
Mian Yousaf Kaukab 9d28b6
play with the different trigger mode [and an mdelay(500) so I can
Mian Yousaf Kaukab 9d28b6
can check what happens on a double click in both modes].
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
Fixes: 706cffc1b912 ("irqchip/exiu: Add support for Socionext Synquacer EXIU controller")
Mian Yousaf Kaukab 9d28b6
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Mian Yousaf Kaukab 9d28b6
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Mian Yousaf Kaukab 9d28b6
Signed-off-by: Marc Zyngier <maz@kernel.org>
Mian Yousaf Kaukab 9d28b6
Link: https://lore.kernel.org/r/20220503134541.2566457-1-daniel.thompson@linaro.org
Mian Yousaf Kaukab 9d28b6
Signed-off-by: Mian Yousaf Kaukab <ykaukab@suse.de>
Mian Yousaf Kaukab 9d28b6
---
Mian Yousaf Kaukab 9d28b6
 arch/arm64/Kconfig.platforms   |    1 +
Mian Yousaf Kaukab 9d28b6
 drivers/irqchip/irq-sni-exiu.c |   25 ++++++++++++++++++++++---
Mian Yousaf Kaukab 9d28b6
 2 files changed, 23 insertions(+), 3 deletions(-)
Mian Yousaf Kaukab 9d28b6
Mian Yousaf Kaukab 9d28b6
--- a/arch/arm64/Kconfig.platforms
Mian Yousaf Kaukab 9d28b6
+++ b/arch/arm64/Kconfig.platforms
Mian Yousaf Kaukab 9d28b6
@@ -160,6 +160,7 @@ config ARCH_SHMOBILE
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 config ARCH_SYNQUACER
Mian Yousaf Kaukab 9d28b6
 	bool "Socionext SynQuacer SoC Family"
Mian Yousaf Kaukab 9d28b6
+	select IRQ_FASTEOI_HIERARCHY_HANDLERS
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 config ARCH_RENESAS
Mian Yousaf Kaukab 9d28b6
 	bool "Renesas SoC Platforms"
Mian Yousaf Kaukab 9d28b6
--- a/drivers/irqchip/irq-sni-exiu.c
Mian Yousaf Kaukab 9d28b6
+++ b/drivers/irqchip/irq-sni-exiu.c
Mian Yousaf Kaukab 9d28b6
@@ -39,11 +39,26 @@ struct exiu_irq_data {
Mian Yousaf Kaukab 9d28b6
 	u32		spi_base;
Mian Yousaf Kaukab 9d28b6
 };
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
-static void exiu_irq_eoi(struct irq_data *d)
Mian Yousaf Kaukab 9d28b6
+static void exiu_irq_ack(struct irq_data *d)
Mian Yousaf Kaukab 9d28b6
 {
Mian Yousaf Kaukab 9d28b6
 	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 	writel(BIT(d->hwirq), data->base + EIREQCLR);
Mian Yousaf Kaukab 9d28b6
+}
Mian Yousaf Kaukab 9d28b6
+
Mian Yousaf Kaukab 9d28b6
+static void exiu_irq_eoi(struct irq_data *d)
Mian Yousaf Kaukab 9d28b6
+{
Mian Yousaf Kaukab 9d28b6
+	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
Mian Yousaf Kaukab 9d28b6
+
Mian Yousaf Kaukab 9d28b6
+	/*
Mian Yousaf Kaukab 9d28b6
+	 * Level triggered interrupts are latched and must be cleared during
Mian Yousaf Kaukab 9d28b6
+	 * EOI or the interrupt will be jammed on. Of course if a level
Mian Yousaf Kaukab 9d28b6
+	 * triggered interrupt is still asserted then the write will not clear
Mian Yousaf Kaukab 9d28b6
+	 * the interrupt.
Mian Yousaf Kaukab 9d28b6
+	 */
Mian Yousaf Kaukab 9d28b6
+	if (irqd_is_level_type(d))
Mian Yousaf Kaukab 9d28b6
+		writel(BIT(d->hwirq), data->base + EIREQCLR);
Mian Yousaf Kaukab 9d28b6
+
Mian Yousaf Kaukab 9d28b6
 	irq_chip_eoi_parent(d);
Mian Yousaf Kaukab 9d28b6
 }
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
@@ -93,10 +108,13 @@ static int exiu_irq_set_type(struct irq_
Mian Yousaf Kaukab 9d28b6
 	writel_relaxed(val, data->base + EILVL);
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 	val = readl_relaxed(data->base + EIEDG);
Mian Yousaf Kaukab 9d28b6
-	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
Mian Yousaf Kaukab 9d28b6
+	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) {
Mian Yousaf Kaukab 9d28b6
 		val &= ~BIT(d->hwirq);
Mian Yousaf Kaukab 9d28b6
-	else
Mian Yousaf Kaukab 9d28b6
+		irq_set_handler_locked(d, handle_fasteoi_irq);
Mian Yousaf Kaukab 9d28b6
+	} else {
Mian Yousaf Kaukab 9d28b6
 		val |= BIT(d->hwirq);
Mian Yousaf Kaukab 9d28b6
+		irq_set_handler_locked(d, handle_fasteoi_ack_irq);
Mian Yousaf Kaukab 9d28b6
+	}
Mian Yousaf Kaukab 9d28b6
 	writel_relaxed(val, data->base + EIEDG);
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 	writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
Mian Yousaf Kaukab 9d28b6
@@ -106,6 +124,7 @@ static int exiu_irq_set_type(struct irq_
Mian Yousaf Kaukab 9d28b6
 
Mian Yousaf Kaukab 9d28b6
 static struct irq_chip exiu_irq_chip = {
Mian Yousaf Kaukab 9d28b6
 	.name			= "EXIU",
Mian Yousaf Kaukab 9d28b6
+	.irq_ack		= exiu_irq_ack,
Mian Yousaf Kaukab 9d28b6
 	.irq_eoi		= exiu_irq_eoi,
Mian Yousaf Kaukab 9d28b6
 	.irq_enable		= exiu_irq_enable,
Mian Yousaf Kaukab 9d28b6
 	.irq_mask		= exiu_irq_mask,