diff options
author | Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> | 2019-05-24 21:09:23 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-05-28 16:48:47 +0200 |
commit | 1183e9a634db06825da7faba566bce50afde4357 (patch) | |
tree | d7c016ba144feacc1c5602e165eb9f0a47c725df /sound/soc/sof/intel/bdw.c | |
parent | ASoC: SOF: control: correct the copy size for bytes kcontrol put (diff) | |
download | linux-1183e9a634db06825da7faba566bce50afde4357.tar.xz linux-1183e9a634db06825da7faba566bce50afde4357.zip |
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/bdw.c')
-rw-r--r-- | sound/soc/sof/intel/bdw.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 065cb868bdfa..8ff3ee520aea 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -283,6 +283,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); + spin_lock_irq(&sdev->ipc_lock); + /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -294,6 +296,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) snd_sof_ipc_reply(sdev, ipcx); bdw_dsp_done(sdev); + + spin_unlock_irq(&sdev->ipc_lock); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -485,7 +489,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; - unsigned long flags; int ret = 0; /* @@ -501,8 +504,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - spin_lock_irqsave(&sdev->ipc_lock, flags); - if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -521,8 +522,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) } msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static void bdw_host_done(struct snd_sof_dev *sdev) |