Message ID | 20171024195451.30535-4-opendmb@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Oct 24, 2017 at 9:54 PM, Doug Berger <opendmb@gmail.com> wrote: > The basic memory-mapped GPIO controller lock must be released > before calling the registered GPIO interrupt handlers to allow > the interrupt handlers to access the hardware. > > Examples of why a GPIO interrupt handler might want to access > the GPIO hardware include an interrupt that is configured to > trigger on rising and falling edges that needs to read the > current level of the input to know how to respond, or an > interrupt that causes a change in a GPIO output in the same > bank. If the lock is not released before enterring the handler > the hardware accesses will deadlock when they attempt to grab > the lock. > > Since the lock is only needed to protect the calculation of > unmasked pending interrupts create a dedicated function to > perform this and hide the complexity. > > Fixes: 19a7b6940b78 ("gpio: brcmstb: Add interrupt and wakeup source support") > Signed-off-by: Doug Berger <opendmb@gmail.com> > Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> > Acked-by: Gregory Fong <gregory.0xf0@gmail.com> Patch applied. Yours, Linus Walleij
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 2031b73e066c..fd8c0412f8af 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -63,6 +63,21 @@ brcmstb_gpio_gc_to_priv(struct gpio_chip *gc) return bank->parent_priv; } +static unsigned long +brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) +{ + void __iomem *reg_base = bank->parent_priv->reg_base; + unsigned long status; + unsigned long flags; + + spin_lock_irqsave(&bank->gc.bgpio_lock, flags); + status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) & + bank->gc.read_reg(reg_base + GIO_MASK(bank->id)); + spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); + + return status; +} + static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, unsigned int offset, bool enable) { @@ -204,11 +219,8 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank) struct irq_domain *irq_domain = bank->gc.irqdomain; void __iomem *reg_base = priv->reg_base; unsigned long status; - unsigned long flags; - spin_lock_irqsave(&bank->gc.bgpio_lock, flags); - while ((status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) & - bank->gc.read_reg(reg_base + GIO_MASK(bank->id)))) { + while ((status = brcmstb_gpio_get_active_irqs(bank))) { int bit; for_each_set_bit(bit, &status, 32) { @@ -223,7 +235,6 @@ static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank) generic_handle_irq(irq_find_mapping(irq_domain, bit)); } } - spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); } /* Each UPG GIO block has one IRQ for all banks */