[RFC PATCH] gpio: sifive: Take care of interrupt masking.

Vincent Pelletier plr.vincent at gmail.com
Fri Jul 9 19:00:32 PDT 2021


Rather than relying on the PLIC.
Fixes the inability to trigger PMIC IRQs more than once.
---
Note: intended as an illustration for parent email, for comments, hence
the absence of S-o-b and gpio maintainers not being cc'ed, all as extra
safety nets against accidental inclusion until I get confirmation that this
IRQ issue should in fact be fixed at the gpio level and not somewhere else.

One thing I would like to get feedback on which is maybe secondary to the
"where does the fix go" question is whether it is correct to clear edge
interrupts during unmask: I'm worried it could miss a trigger edge between
the attached chip's handler clearing a source and gpio level unmasking.
For level sources it should not matter, they will immediately re-trigger
anyway.
---
 drivers/gpio/gpio-sifive.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index 9c2d0bf04e58..cd4bb1f9ece5 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -108,7 +108,22 @@ static void sifive_gpio_irq_disable(struct irq_data *d)
 	irq_chip_disable_parent(d);
 }
 
-static void sifive_gpio_irq_eoi(struct irq_data *d)
+static void sifive_gpio_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct sifive_gpio *chip = gpiochip_get_data(gc);
+	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset), 0);
+	regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset), 0);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void sifive_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct sifive_gpio *chip = gpiochip_get_data(gc);
@@ -124,7 +139,7 @@ static void sifive_gpio_irq_eoi(struct irq_data *d)
 	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
-	irq_chip_eoi_parent(d);
+	sifive_gpio_set_ie(chip, offset);
 }
 
 static int sifive_gpio_irq_set_affinity(struct irq_data *data,
@@ -140,11 +155,11 @@ static int sifive_gpio_irq_set_affinity(struct irq_data *data,
 static struct irq_chip sifive_gpio_irqchip = {
 	.name		= "sifive-gpio",
 	.irq_set_type	= sifive_gpio_irq_set_type,
-	.irq_mask	= irq_chip_mask_parent,
-	.irq_unmask	= irq_chip_unmask_parent,
+	.irq_mask	= sifive_gpio_irq_mask,
+	.irq_unmask	= sifive_gpio_irq_unmask,
 	.irq_enable	= sifive_gpio_irq_enable,
 	.irq_disable	= sifive_gpio_irq_disable,
-	.irq_eoi	= sifive_gpio_irq_eoi,
+	.irq_eoi	= irq_chip_eoi_parent,
 	.irq_set_affinity = sifive_gpio_irq_set_affinity,
 };
 
-- 
2.32.0




More information about the linux-riscv mailing list