소스 검색

gpio: brcmstb: release the bgpio lock during irq handlers

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>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Doug Berger 7 년 전
부모
커밋
142c168e0e
1개의 변경된 파일16개의 추가작업 그리고 5개의 파일을 삭제
  1. 16 5
      drivers/gpio/gpio-brcmstb.c

+ 16 - 5
drivers/gpio/gpio-brcmstb.c

@@ -63,6 +63,21 @@ brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
 	return bank->parent_priv;
 	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,
 static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
 		unsigned int offset, bool enable)
 		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;
 	struct irq_domain *irq_domain = bank->gc.irqdomain;
 	void __iomem *reg_base = priv->reg_base;
 	void __iomem *reg_base = priv->reg_base;
 	unsigned long status;
 	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;
 		int bit;
 
 
 		for_each_set_bit(bit, &status, 32) {
 		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));
 			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 */
 /* Each UPG GIO block has one IRQ for all banks */