diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ceca776530af65..6b44f6d02082fe 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -107,10 +107,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) "nothing to do in IPC IRQ thread\n"); } - /* re-enable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index c61ca3a1d696ab..1a32e75f1ad755 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -230,14 +230,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) "nothing to do in IPC IRQ thread\n"); } - /* re-enable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - return IRQ_HANDLED; } -/* Check if it is an IPC and disable IPC interrupt if yes */ +/* Check if an IPC IRQ occurred */ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) { bool ret = false; @@ -256,10 +252,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) /* IPC message ? */ if (irq_status & HDA_DSP_ADSPIS_IPC) { - /* disable IPC interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, 0); + sdev->irq_event |= SOF_HDA_IRQ_IPC; ret = true; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 38f8bb3db4b946..2f05b61cc332c2 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -553,7 +553,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - bool ret = true; + bool ret = false; u32 status; /* The function can be called at irq thread, so use spin_lock_irq */ @@ -562,9 +562,11 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) status = snd_hdac_chip_readl(bus, INTSTS); dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); - /* Register inaccessible, ignore it.*/ - if (status == 0xffffffff) - ret = false; + /* if Register inaccessible, ignore it.*/ + if (status != 0xffffffff) { + sdev->irq_event |= SOF_HDA_IRQ_STREAM; + ret = true; + } spin_unlock_irq(&bus->reg_lock); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f2df5cc9197298..83dbfac9525e5e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -406,9 +406,20 @@ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (hda_dsp_check_ipc_irq(sdev) || - hda_dsp_check_stream_irq(sdev)) + /* clear flags for interrupt sources */ + sdev->irq_event = 0; + + if (hda_dsp_check_stream_irq(sdev) || + hda_dsp_check_ipc_irq(sdev)) { + + /* disable GIE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_INTCTL, + SOF_HDA_INT_GLOBAL_EN, + 0); + return IRQ_WAKE_THREAD; + } return IRQ_NONE; } @@ -417,11 +428,21 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (hda_dsp_check_ipc_irq(sdev)) - sof_ops(sdev)->irq_thread(irq, sdev); - if (hda_dsp_check_stream_irq(sdev)) + /* deal with streams and controller first */ + if (sdev->irq_event & SOF_HDA_IRQ_STREAM || + hda_dsp_check_stream_irq(sdev)) hda_dsp_stream_threaded_handler(irq, sdev); + if (sdev->irq_event & SOF_HDA_IRQ_IPC || + hda_dsp_check_ipc_irq(sdev)) + sof_ops(sdev)->irq_thread(irq, sdev); + + /* enable GIE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_INTCTL, + SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_GLOBAL_EN); + return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 41e3671406f9ff..8b55e88412e345 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -389,6 +389,11 @@ struct sof_intel_dsp_bdl { #define SOF_HDA_PLAYBACK 0 #define SOF_HDA_CAPTURE 1 +/* flags to memorize IPC source (not hardware-defined) */ +#define SOF_HDA_IRQ_IPC BIT(0) +#define SOF_HDA_IRQ_STREAM BIT(1) +#define SOF_HDA_IRQ_SDW BIT(2) + /* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 54dd6d4b4c128e..65f006845cbf79 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -387,6 +387,7 @@ struct snd_sof_dev { u32 dtrace_draining; bool msi_enabled; + u32 irq_event; void *private; /* core does not touch this */ };