The IRQ is level triggered in BXT-M which causes a IRQ storm. Disable
IRQ when handling it and re-enable it when done.

Signed-off-by: Guoqing Zhang <guoqing.zh...@intel.com>
---
 sound/soc/intel/skylake/skl.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index cafcec3..55278b5 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -117,7 +117,9 @@ static irqreturn_t skl_interrupt(int irq, void *dev_id)
 {
        struct hdac_ext_bus *ebus = dev_id;
        struct hdac_bus *bus = ebus_to_hbus(ebus);
+       u32 mask, int_enable;
        u32 status;
+       int ret;
 
        if (!pm_runtime_active(bus->dev))
                return IRQ_NONE;
@@ -138,21 +140,40 @@ static irqreturn_t skl_interrupt(int irq, void *dev_id)
                snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
        }
 
-       spin_unlock(&bus->reg_lock);
 
-       return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+       mask = (0x1 << ebus->num_streams) - 1;
+
+       status = snd_hdac_chip_readl(bus, INTSTS);
+       status &= mask;
+       if (status) {
+               /* Disable stream interrupts; Re-enable in bottom half */
+               int_enable = snd_hdac_chip_readl(bus, INTCTL);
+               snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask)));
+               ret = IRQ_WAKE_THREAD;
+       } else
+               ret = IRQ_HANDLED;
+
+       spin_unlock(&bus->reg_lock);
+       return ret;
 }
 
 static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
 {
        struct hdac_ext_bus *ebus = dev_id;
        struct hdac_bus *bus = ebus_to_hbus(ebus);
+       u32 mask, int_enable;
        u32 status;
-
+       unsigned long flags;
        status = snd_hdac_chip_readl(bus, INTSTS);
 
        snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update);
 
+       /* Re-enable stream interrupts */
+       mask = (0x1 << ebus->num_streams) - 1;
+       spin_lock_irqsave(&bus->reg_lock, flags);
+       int_enable = snd_hdac_chip_readl(bus, INTCTL);
+       snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask));
+       spin_unlock_irqrestore(&bus->reg_lock, flags);
        return IRQ_HANDLED;
 }
 
@@ -160,7 +181,7 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int 
do_disconnect)
 {
        struct skl *skl = ebus_to_skl(ebus);
        struct hdac_bus *bus = ebus_to_hbus(ebus);
-       int ret;
+       int ret =0;
 
        ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
                        skl_threaded_handler,
@@ -563,7 +584,6 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
        int err;
        unsigned short gcap;
        int cp_streams, pb_streams, start_idx;
-
        err = pci_request_regions(pci, "Skylake HD audio");
        if (err < 0)
                return err;
@@ -619,6 +639,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
 
        if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
                err = skl_i915_init(bus);
+
                if (err < 0)
                        return err;
        }
@@ -694,7 +715,6 @@ static int skl_probe(struct pci_dev *pci,
        err = skl_platform_register(bus->dev);
        if (err < 0)
                goto out_dmic_free;
-
        /* create codec instances */
        err = skl_codec_create(ebus);
        if (err < 0)
-- 
2.5.0

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to