[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