summaryrefslogtreecommitdiff
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2018-07-16 18:57:18 -0600
committerLinus Walleij <linus.walleij@linaro.org>2018-07-29 22:43:31 +0200
commit8bbed1eef001fdfc0ee9595f64cc4f769d265af4 (patch)
tree0bd5c8995a6d5e80ecdbf77bfd72d67918dbaa5c /drivers/pinctrl
parent1766e4b7047acf44cdd15aaeb1d63ed76ee78492 (diff)
pinctrl/amd: only handle irq if it is pending and unmasked
The AMD pinctrl driver demultiplexes GPIO interrupts and fires off their individual handlers. If one of these GPIO irqs is configured as a level interrupt, and its downstream handler is a threaded ONESHOT interrupt, the GPIO interrupt source is masked by handle_level_irq() until the eventual return of the threaded irq handler. During this time the level GPIO interrupt status will still report as high until the actual gpio source is cleared - both in the individual GPIO interrupt status bit (INTERRUPT_STS_OFF) and in its corresponding "WAKE_INT_STATUS_REG" bit. Thus, if another GPIO interrupt occurs during this time, amd_gpio_irq_handler() will see that the (masked-and-not-yet-cleared) level irq is still pending and incorrectly call its handler again. To fix this, have amd_gpio_irq_handler() check for both interrupts status and mask before calling generic_handle_irq(). Note: Is it possible that this bug was the source of the interrupt storm on Ryzen when using chained interrupts before commit ba714a9c1dea85 ("pinctrl/amd: Use regular interrupt instead of chained")? Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/pinctrl-amd.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 5df5e8d64c57..41ccc759b8b8 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -552,7 +552,8 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
/* Each status bit covers four pins */
for (i = 0; i < 4; i++) {
regval = readl(regs + i);
- if (!(regval & PIN_IRQ_PENDING))
+ if (!(regval & PIN_IRQ_PENDING) ||
+ !(regval & BIT(INTERRUPT_MASK_OFF)))
continue;
irq = irq_find_mapping(gc->irq.domain, irqnr + i);
generic_handle_irq(irq);