diff options
author | Bard Liao <yung-chuan.liao@linux.intel.com> | 2019-12-05 00:28:59 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-12-09 21:35:56 +0300 |
commit | 7c11af9fcdc425b80f140a218d4fef9f17734bfc (patch) | |
tree | 1316234b4cecc9854d2493dd02840a035e400534 /sound/soc/sof/intel/hda-ipc.c | |
parent | 253f584a0699d12a90bde9d524d499a921cc7827 (diff) | |
download | linux-7c11af9fcdc425b80f140a218d4fef9f17734bfc.tar.xz |
ASoC: SOF: Intel: hda: solve MSI issues by merging ipc and stream irq handlers
The existing code uses two handlers for a shared edge-based MSI interrupts.
In corner cases, interrupts are lost, leading to IPC timeouts. Those
timeouts do not appear in legacy mode.
This patch merges the two handlers and threads into a single one, and
simplifies the mask/unmask operations by using a single top-level mask
(Global Interrupt Enable). The handler only checks for interrupt
sources using the Global Interrupt Status (GIS) field, and all the
actual work happens in the thread. This also enables us to remove the
use of spin locks. Stream events are prioritized over IPC ones.
This patch was tested with HDaudio and SoundWire platforms, and all
known IPC timeout issues are solved in MSI mode. The
SoundWire-specific patches will be provided in follow-up patches,
where the SoundWire interrupts are handled in the same thread as IPC
and stream interrupts.
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191204212859.13239-1-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/intel/hda-ipc.c')
-rw-r--r-- | sound/soc/sof/intel/hda-ipc.c | 23 |
1 files changed, 5 insertions, 18 deletions
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 0fd2153c1769..1837f66e361f 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -230,22 +230,15 @@ 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; } -/* is this IRQ for ADSP ? - we only care about IPC here */ -irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) +/* Check if an IPC IRQ occurred */ +bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) { - struct snd_sof_dev *sdev = context; - int ret = IRQ_NONE; + bool ret = false; u32 irq_status; - spin_lock(&sdev->hw_lock); - /* store status */ irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); @@ -255,16 +248,10 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) goto out; /* 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); - ret = IRQ_WAKE_THREAD; - } + if (irq_status & HDA_DSP_ADSPIS_IPC) + ret = true; out: - spin_unlock(&sdev->hw_lock); return ret; } |