regmap: irq: clear status when disable irq
authorYi Zhang <yizhang@marvell.com>
Tue, 22 Oct 2013 10:44:32 +0000 (18:44 +0800)
committerMark Brown <broonie@linaro.org>
Tue, 22 Oct 2013 12:28:08 +0000 (13:28 +0100)
clear the status bit if the mask register doesn't prevent
the chip level irq from being asserted

OR in the following sequence, there will be irq storm happens:
1) interrupt is triggered;
2) another thread disables it(the mask bit is set);
3) _Then_ the interrupt thread is not ACKed(the status bit is not cleared),
   and it's ignored;
4) if the irq is still asserted because of the uncleared status bit,
   the irq storm happens;

Signed-off-by: Yi Zhang <yizhang@marvell.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
drivers/base/regmap/regmap-irq.c

index d10456f..763c60d 100644 (file)
@@ -105,6 +105,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                                        "Failed to sync wakes in %x: %d\n",
                                        reg, ret);
                }
+
+               if (!d->chip->init_ack_masked)
+                       continue;
+               /*
+                * Ack all the masked interrupts uncondictionly,
+                * OR if there is masked interrupt which hasn't been Acked,
+                * it'll be ignored in irq handler, then may introduce irq storm
+                */
+               if (d->mask_buf[i] && d->chip->ack_base) {
+                       reg = d->chip->ack_base +
+                               (i * map->reg_stride * d->irq_reg_stride);
+                       ret = regmap_write(map, reg, d->mask_buf[i]);
+                       if (ret != 0)
+                               dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
+                                       reg, ret);
+               }
        }
 
        if (d->chip->runtime_pm)