Patch "irqchip/exiu: Fix acknowledgment of edge triggered interrupts" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    irqchip/exiu: Fix acknowledgment of edge triggered interrupts

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     irqchip-exiu-fix-acknowledgment-of-edge-triggered-in.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit dc9facd381ff3ca5797d541693111bbe875eb1ef
Author: Daniel Thompson <daniel.thompson@xxxxxxxxxx>
Date:   Tue May 3 14:45:41 2022 +0100

    irqchip/exiu: Fix acknowledgment of edge triggered interrupts
    
    [ Upstream commit 4efc851c36e389f7ed432edac0149acc5f94b0c7 ]
    
    Currently the EXIU uses the fasteoi interrupt flow that is configured by
    it's parent (irq-gic-v3.c). With this flow the only chance to clear the
    interrupt request happens during .irq_eoi() and (obviously) this happens
    after the interrupt handler has run. EXIU requires edge triggered
    interrupts to be acked prior to interrupt handling. Without this we
    risk incorrect interrupt dismissal when a new interrupt is delivered
    after the handler reads and acknowledges the peripheral but before the
    irq_eoi() takes place.
    
    Fix this by clearing the interrupt request from .irq_ack() if we are
    configured for edge triggered interrupts. This requires adopting the
    fasteoi-ack flow instead of the fasteoi to ensure the ack gets called.
    
    These changes have been tested using the power button on a
    Developerbox/SC2A11 combined with some hackery in gpio-keys so I can
    play with the different trigger mode [and an mdelay(500) so I can
    can check what happens on a double click in both modes].
    
    Fixes: 706cffc1b912 ("irqchip/exiu: Add support for Socionext Synquacer EXIU controller")
    Signed-off-by: Daniel Thompson <daniel.thompson@xxxxxxxxxx>
    Reviewed-by: Ard Biesheuvel <ardb@xxxxxxxxxx>
    Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220503134541.2566457-1-daniel.thompson@xxxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index b0ce18d4cc98..d7772a4c34fe 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -259,6 +259,7 @@ config ARCH_INTEL_SOCFPGA
 
 config ARCH_SYNQUACER
 	bool "Socionext SynQuacer SoC Family"
+	select IRQ_FASTEOI_HIERARCHY_HANDLERS
 
 config ARCH_TEGRA
 	bool "NVIDIA Tegra SoC Family"
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
index abd011fcecf4..c7db617e1a2f 100644
--- a/drivers/irqchip/irq-sni-exiu.c
+++ b/drivers/irqchip/irq-sni-exiu.c
@@ -37,11 +37,26 @@ struct exiu_irq_data {
 	u32		spi_base;
 };
 
-static void exiu_irq_eoi(struct irq_data *d)
+static void exiu_irq_ack(struct irq_data *d)
 {
 	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
 
 	writel(BIT(d->hwirq), data->base + EIREQCLR);
+}
+
+static void exiu_irq_eoi(struct irq_data *d)
+{
+	struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
+
+	/*
+	 * Level triggered interrupts are latched and must be cleared during
+	 * EOI or the interrupt will be jammed on. Of course if a level
+	 * triggered interrupt is still asserted then the write will not clear
+	 * the interrupt.
+	 */
+	if (irqd_is_level_type(d))
+		writel(BIT(d->hwirq), data->base + EIREQCLR);
+
 	irq_chip_eoi_parent(d);
 }
 
@@ -91,10 +106,13 @@ static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
 	writel_relaxed(val, data->base + EILVL);
 
 	val = readl_relaxed(data->base + EIEDG);
-	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) {
 		val &= ~BIT(d->hwirq);
-	else
+		irq_set_handler_locked(d, handle_fasteoi_irq);
+	} else {
 		val |= BIT(d->hwirq);
+		irq_set_handler_locked(d, handle_fasteoi_ack_irq);
+	}
 	writel_relaxed(val, data->base + EIEDG);
 
 	writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
@@ -104,6 +122,7 @@ static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
 
 static struct irq_chip exiu_irq_chip = {
 	.name			= "EXIU",
+	.irq_ack		= exiu_irq_ack,
 	.irq_eoi		= exiu_irq_eoi,
 	.irq_enable		= exiu_irq_enable,
 	.irq_mask		= exiu_irq_mask,



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux