summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2022-07-12 19:21:42 +0100
committerMark Brown <broonie@kernel.org>2022-07-12 19:21:42 +0100
commit501935dae855a469d7529500c450c550acc6e633 (patch)
treebbfee05cd874143569f53545c83fc34cbc4c00e6
parent274a3e6f98682ccad508a108312cfb5fb7c7553a (diff)
parent1549a69b89b7e5b1b830da897529344766728a4b (diff)
ASoC: SOF: Intel: Do not process IPC reply before firmware boot
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: By mistake a developer managed to create a 'corrupted' IPC4 firmware image which loaded fine to the DSP and after boot it sent an IPC reply before we would have received the FW_READY message. It turned out that the image was an IPC3 firmware and the IPC reply was the IPC3 FW_READY notification message which got understood as an IPC4 reply message due to the difference between the two IPC mechanism. This caused a NULL pointer dereference since the reply memory will be allocated after the FW_READY message. To make sure this will not bite again, skip any spurious reply messages before the FW_READY.
-rw-r--r--sound/soc/sof/intel/cnl.c37
-rw-r--r--sound/soc/sof/intel/hda-ipc.c39
-rw-r--r--sound/soc/sof/intel/mtl.c20
3 files changed, 62 insertions, 34 deletions
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index ccf46fcd6c9a..a064453f0bc3 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -60,17 +60,23 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */
- struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
- data->primary = primary;
- data->extension = extension;
+ data->primary = primary;
+ data->extension = extension;
- spin_lock_irq(&sdev->ipc_lock);
+ spin_lock_irq(&sdev->ipc_lock);
- snd_sof_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, data->primary);
+ snd_sof_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, data->primary);
- spin_unlock_irq(&sdev->ipc_lock);
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev,
+ "IPC reply before FW_READY: %#x|%#x\n",
+ primary, extension);
+ }
} else {
/* Notification received */
notification_data.primary = primary;
@@ -124,15 +130,20 @@ 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);
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ spin_lock_irq(&sdev->ipc_lock);
- /* handle immediate reply from DSP core */
- hda_dsp_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, msg);
+ /* handle immediate reply from DSP core */
+ hda_dsp_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, msg);
- cnl_ipc_dsp_done(sdev);
+ cnl_ipc_dsp_done(sdev);
- spin_unlock_irq(&sdev->ipc_lock);
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
+ msg);
+ }
ipc_irq = true;
}
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index f08011249955..65e688f749ea 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -148,17 +148,23 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */
- struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
- data->primary = primary;
- data->extension = extension;
+ data->primary = primary;
+ data->extension = extension;
- spin_lock_irq(&sdev->ipc_lock);
+ spin_lock_irq(&sdev->ipc_lock);
- snd_sof_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, data->primary);
+ snd_sof_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, data->primary);
- spin_unlock_irq(&sdev->ipc_lock);
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev,
+ "IPC reply before FW_READY: %#x|%#x\n",
+ primary, extension);
+ }
} else {
/* Notification received */
@@ -225,16 +231,21 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
* place, the message might not yet be marked as expecting a
* reply.
*/
- spin_lock_irq(&sdev->ipc_lock);
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ spin_lock_irq(&sdev->ipc_lock);
- /* handle immediate reply from DSP core */
- hda_dsp_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, msg);
+ /* handle immediate reply from DSP core */
+ hda_dsp_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, msg);
- /* set the done bit */
- hda_dsp_ipc_dsp_done(sdev);
+ /* set the done bit */
+ hda_dsp_ipc_dsp_done(sdev);
- spin_unlock_irq(&sdev->ipc_lock);
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
+ msg);
+ }
ipc_irq = true;
}
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 3a043589c12b..a5e244ea0688 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -512,17 +512,23 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
*/
if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */
- struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
- data->primary = primary;
- data->extension = extension;
+ data->primary = primary;
+ data->extension = extension;
- spin_lock_irq(&sdev->ipc_lock);
+ spin_lock_irq(&sdev->ipc_lock);
- snd_sof_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, data->primary);
+ snd_sof_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, data->primary);
- spin_unlock_irq(&sdev->ipc_lock);
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev,
+ "IPC reply before FW_READY: %#x|%#x\n",
+ primary, extension);
+ }
} else {
/* Notification received */
notification_data.primary = primary;