diff options
author | Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com> | 2017-05-15 10:14:29 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-05-24 13:25:12 -0400 |
commit | 5cd1f5c32132101955d7f0e1955249a84f9b6fd9 (patch) | |
tree | 49661588fbe3b0e3b083b45bda00e654f21c6e5c | |
parent | ab1b732d53c18f26f51cad49371be3244fe67504 (diff) |
ASoC: Intel: Skylake: Fix IPC rx_list corruption
In SKL+ platforms, all IPC commands are serialised, i.e. the driver sends
a new IPC to DSP, only after receiving a reply from the firmware for the
current IPC.
Hence it seems apparent that there is only a single modifier of the IPC RX
List. However, during an IPC timeout case in a multithreaded environment,
there is a possibility of the list element being deleted two times if not
properly protected.
So, use spin lock save/restore to prevent rx_list corruption.
Signed-off-by: Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 58c525096a7c..498b15345b1a 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c | |||
@@ -413,8 +413,11 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |||
413 | u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; | 413 | u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; |
414 | u64 *ipc_header = (u64 *)(&header); | 414 | u64 *ipc_header = (u64 *)(&header); |
415 | struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); | 415 | struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); |
416 | unsigned long flags; | ||
416 | 417 | ||
418 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
417 | msg = skl_ipc_reply_get_msg(ipc, *ipc_header); | 419 | msg = skl_ipc_reply_get_msg(ipc, *ipc_header); |
420 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
418 | if (msg == NULL) { | 421 | if (msg == NULL) { |
419 | dev_dbg(ipc->dev, "ipc: rx list is empty\n"); | 422 | dev_dbg(ipc->dev, "ipc: rx list is empty\n"); |
420 | return; | 423 | return; |
@@ -456,8 +459,10 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |||
456 | } | 459 | } |
457 | } | 460 | } |
458 | 461 | ||
462 | spin_lock_irqsave(&ipc->dsp->spinlock, flags); | ||
459 | list_del(&msg->list); | 463 | list_del(&msg->list); |
460 | sst_ipc_tx_msg_reply_complete(ipc, msg); | 464 | sst_ipc_tx_msg_reply_complete(ipc, msg); |
465 | spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); | ||
461 | } | 466 | } |
462 | 467 | ||
463 | irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) | 468 | irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) |