diff options
Diffstat (limited to 'sound/soc/sof/intel/hda-ipc.c')
-rw-r--r-- | sound/soc/sof/intel/hda-ipc.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 73ead7070cde..51b285103394 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; struct sof_ipc_cmd_hdr *hdr; - unsigned long flags; int ret = 0; /* @@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } - spin_lock_irqsave(&sdev->ipc_lock, flags); hdr = msg->msg_data; if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { @@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) out: msg->reply_error = ret; - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static bool hda_dsp_ipc_is_sof(uint32_t msg) @@ -172,6 +169,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCCTL, HDA_DSP_REG_HIPCCTL_DONE, 0); + /* + * Make sure the interrupt thread cannot be preempted between + * waking up the sender and re-enabling the interrupt. Also + * protect against a theoretical race with sof_ipc_tx_message(): + * if the DSP is fast enough to receive an IPC message, reply to + * it, and the host interrupt processing calls this function on + * a different core from the one, where the sending is taking + * place, the message might not yet be marked as expecting a + * reply. + */ + spin_lock_irq(&sdev->ipc_lock); + /* handle immediate reply from DSP core - ignore ROM messages */ if (hda_dsp_ipc_is_sof(msg)) { hda_dsp_ipc_get_reply(sdev); @@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* set the done bit */ hda_dsp_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); + ret = IRQ_HANDLED; } |