summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel/cnl.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>2019-05-24 14:09:23 -0500
committerMark Brown <broonie@kernel.org>2019-05-28 15:48:47 +0100
commit1183e9a634db06825da7faba566bce50afde4357 (patch)
treed7c016ba144feacc1c5602e165eb9f0a47c725df /sound/soc/sof/intel/cnl.c
parent5661ad9490ee4abdb27295880e524acc656c89e7 (diff)
ASoC: SOF: ipc: fix a race, leading to IPC timeouts
Currently on all supported platforms the IPC IRQ thread first signals the sender when an IPC response is received from the DSP, then unmasks the IPC interrupt. Those actions are performed without holding any locks, so the thread can be interrupted between them. IPC timeouts have been observed in such scenarios: if the sender is woken up and it proceeds with sending the next message without unmasking the IPC interrupt, it can miss the next response. This patch takes a spin-lock to prevent the IRQ thread from being preempted at that point. It also makes sure, that the next IPC transmission by the host cannot take place before the IRQ thread has finished updating all the required IPC registers. Fixes: 53e0c72d98b ("ASoC: SOF: Add support for IPC IO between DSP and Host") Reviewed-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/intel/cnl.c')
-rw-r--r--sound/soc/sof/intel/cnl.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 08a1a3d3c08d..b2eba7adcad8 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);
+ spin_lock_irq(&sdev->ipc_lock);
+
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
@@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev);
+ spin_unlock_irq(&sdev->ipc_lock);
+
ret = IRQ_HANDLED;
}