|
@@ -930,6 +930,8 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|
|
struct azx *chip = dev_id;
|
|
|
struct hdac_bus *bus = azx_bus(chip);
|
|
|
u32 status;
|
|
|
+ bool active, handled = false;
|
|
|
+ int repeat = 0; /* count for avoiding endless loop */
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
if (azx_has_pm_runtime(chip))
|
|
@@ -939,33 +941,36 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|
|
|
|
|
spin_lock(&bus->reg_lock);
|
|
|
|
|
|
- if (chip->disabled) {
|
|
|
- spin_unlock(&bus->reg_lock);
|
|
|
- return IRQ_NONE;
|
|
|
- }
|
|
|
-
|
|
|
- status = azx_readl(chip, INTSTS);
|
|
|
- if (status == 0 || status == 0xffffffff) {
|
|
|
- spin_unlock(&bus->reg_lock);
|
|
|
- return IRQ_NONE;
|
|
|
- }
|
|
|
+ if (chip->disabled)
|
|
|
+ goto unlock;
|
|
|
|
|
|
- snd_hdac_bus_handle_stream_irq(bus, status, stream_update);
|
|
|
+ do {
|
|
|
+ status = azx_readl(chip, INTSTS);
|
|
|
+ if (status == 0 || status == 0xffffffff)
|
|
|
+ break;
|
|
|
|
|
|
- /* clear rirb int */
|
|
|
- status = azx_readb(chip, RIRBSTS);
|
|
|
- if (status & RIRB_INT_MASK) {
|
|
|
- if (status & RIRB_INT_RESPONSE) {
|
|
|
- if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
|
|
|
- udelay(80);
|
|
|
- snd_hdac_bus_update_rirb(bus);
|
|
|
+ handled = true;
|
|
|
+ active = false;
|
|
|
+ if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update))
|
|
|
+ active = true;
|
|
|
+
|
|
|
+ /* clear rirb int */
|
|
|
+ status = azx_readb(chip, RIRBSTS);
|
|
|
+ if (status & RIRB_INT_MASK) {
|
|
|
+ active = true;
|
|
|
+ if (status & RIRB_INT_RESPONSE) {
|
|
|
+ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
|
|
|
+ udelay(80);
|
|
|
+ snd_hdac_bus_update_rirb(bus);
|
|
|
+ }
|
|
|
+ azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
|
|
}
|
|
|
- azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
|
|
- }
|
|
|
+ } while (active && ++repeat < 10);
|
|
|
|
|
|
+ unlock:
|
|
|
spin_unlock(&bus->reg_lock);
|
|
|
|
|
|
- return IRQ_HANDLED;
|
|
|
+ return IRQ_RETVAL(handled);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(azx_interrupt);
|
|
|
|