[alsa-devel] [PATCH 08/12] ASoC: SOF: ipc: fix a race, leading to IPC timeouts
Takashi Iwai
tiwai at suse.de
Sun May 19 09:20:55 CEST 2019
On Sat, 18 May 2019 22:27:00 +0200,
Pierre-Louis Bossart wrote:
>
> From: Guennadi Liakhovetski <guennadi.liakhovetski at linux.intel.com>
>
> 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")
> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski at linux.intel.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> ---
> sound/soc/sof/intel/bdw.c | 11 ++++++-----
> sound/soc/sof/intel/byt.c | 12 +++++++-----
> sound/soc/sof/intel/cnl.c | 6 ++++++
> sound/soc/sof/intel/hda-ipc.c | 19 ++++++++++++++++---
> sound/soc/sof/ipc.c | 13 -------------
> 5 files changed, 35 insertions(+), 26 deletions(-)
>
> diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
> index 065cb868bdfa..9dfdc02192b7 100644
> --- a/sound/soc/sof/intel/bdw.c
> +++ b/sound/soc/sof/intel/bdw.c
> @@ -278,11 +278,15 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
> /* reply message from DSP */
> if (ipcx & SHIM_IPCX_DONE &&
> !(imrx & SHIM_IMRX_DONE)) {
> + unsigned long flags;
> +
> /* Mask Done interrupt before return */
> snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR,
> SHIM_IMRX, SHIM_IMRX_DONE,
> SHIM_IMRX_DONE);
> + spin_lock_irqsave(&sdev->ipc_lock, flags);
Here is an threaded irq handler, so the irqflag is superfluous.
You can use spin_lock_irq() and spin_unlock_irq().
> diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
> index 7bf9143d3106..5a11a104110b 100644
> --- a/sound/soc/sof/intel/byt.c
> +++ b/sound/soc/sof/intel/byt.c
> @@ -324,11 +324,16 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
> /* reply message from DSP */
> if (ipcx & SHIM_BYT_IPCX_DONE &&
> !(imrx & SHIM_IMRX_DONE)) {
> + unsigned long flags;
> +
> /* Mask Done interrupt before first */
> snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR,
> SHIM_IMRX,
> SHIM_IMRX_DONE,
> SHIM_IMRX_DONE);
BTW, is this usage of _unlocked() version safe? The previous one also
contained that, and I wonder why _unlocked variant must be used here.
thanks,
Takashi
More information about the Alsa-devel
mailing list