gpio: omap: Fix lost edge interrupts
Now acking of edge irqs happens the following way: - omap_gpio_irq_handler - "isr" = read irq status - omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask); ^ clear edge status, so irq can be accepted - loop while "isr" generic_handle_irq() - handle_edge_irq() - desc->irq_data.chip->irq_ack(&desc->irq_data); - omap_gpio_ack_irq() it might be that at this moment edge IRQ was triggered again and it will be cleared and IRQ will be lost. Use handle_simple_irq and clear edge interrupts early without disabling them in omap_gpio_irq_handler to avoid loosing interrupts. [1] https://marc.info/?l=linux-omap&m=149004465313534&w=2 Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: Ladislav Michl <ladis@linux-mips.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Родитель
e4b2ae7a8a
Коммит
80ac93c274
|
@ -518,7 +518,13 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
|||
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
/*
|
||||
* Edge IRQs are already cleared/acked in irq_handler and
|
||||
* not need to be masked, as result handle_edge_irq()
|
||||
* logic is excessed here and may cause lose of interrupts.
|
||||
* So just use handle_simple_irq.
|
||||
*/
|
||||
irq_set_handler_locked(d, handle_simple_irq);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -678,7 +684,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
{
|
||||
void __iomem *isr_reg = NULL;
|
||||
u32 isr;
|
||||
u32 enabled, isr, level_mask;
|
||||
unsigned int bit;
|
||||
struct gpio_bank *bank = gpiobank;
|
||||
unsigned long wa_lock_flags;
|
||||
|
@ -691,23 +697,21 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
|||
pm_runtime_get_sync(bank->chip.parent);
|
||||
|
||||
while (1) {
|
||||
u32 isr_saved, level_mask = 0;
|
||||
u32 enabled;
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, lock_flags);
|
||||
|
||||
enabled = omap_get_gpio_irqbank_mask(bank);
|
||||
isr_saved = isr = readl_relaxed(isr_reg) & enabled;
|
||||
isr = readl_relaxed(isr_reg) & enabled;
|
||||
|
||||
if (bank->level_mask)
|
||||
level_mask = bank->level_mask & enabled;
|
||||
else
|
||||
level_mask = 0;
|
||||
|
||||
/* clear edge sensitive interrupts before handler(s) are
|
||||
called so that we don't miss any interrupt occurred while
|
||||
executing them */
|
||||
omap_disable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
if (isr & ~level_mask)
|
||||
omap_clear_gpio_irqbank(bank, isr & ~level_mask);
|
||||
|
||||
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче