OSDN Git Service

pinctrl: amd: Detect and mask spurious interrupts
authorKornel Dulęba <korneld@chromium.org>
Fri, 21 Apr 2023 12:06:23 +0000 (07:06 -0500)
committerLinus Walleij <linus.walleij@linaro.org>
Mon, 8 May 2023 13:42:24 +0000 (15:42 +0200)
Leverage gpiochip_line_is_irq to check whether a pin has an irq
associated with it. The previous check ("irq == 0") didn't make much
sense. The irq variable refers to the pinctrl irq, and has nothing do to
with an individual pin.

On some systems, during suspend/resume cycle, the firmware leaves
an interrupt enabled on a pin that is not used by the kernel.
Without this patch that caused an interrupt storm.

Cc: stable@vger.kernel.org
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217315
Signed-off-by: Kornel Dulęba <korneld@chromium.org>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20230421120625.3366-4-mario.limonciello@amd.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/pinctrl-amd.c

index 840f9b8..b4dee32 100644 (file)
@@ -660,21 +660,21 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
                         * We must read the pin register again, in case the
                         * value was changed while executing
                         * generic_handle_domain_irq() above.
-                        * If we didn't find a mapping for the interrupt,
-                        * disable it in order to avoid a system hang caused
-                        * by an interrupt storm.
+                        * If the line is not an irq, disable it in order to
+                        * avoid a system hang caused by an interrupt storm.
                         */
                        raw_spin_lock_irqsave(&gpio_dev->lock, flags);
                        regval = readl(regs + i);
-                       if (irq == 0) {
-                               regval &= ~BIT(INTERRUPT_ENABLE_OFF);
+                       if (!gpiochip_line_is_irq(gc, irqnr + i)) {
+                               regval &= ~BIT(INTERRUPT_MASK_OFF);
                                dev_dbg(&gpio_dev->pdev->dev,
                                        "Disabling spurious GPIO IRQ %d\n",
                                        irqnr + i);
+                       } else {
+                               ret = true;
                        }
                        writel(regval, regs + i);
                        raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
-                       ret = true;
                }
        }
        /* did not cause wake on resume context for shared IRQ */