Commit 501935da authored by Mark Brown's avatar Mark Brown

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.
parents 274a3e6f 1549a69b
...@@ -60,6 +60,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) ...@@ -60,6 +60,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
if (primary & SOF_IPC4_MSG_DIR_MASK) { if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */ /* Reply received */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
data->primary = primary; data->primary = primary;
...@@ -71,6 +72,11 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) ...@@ -71,6 +72,11 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, data->primary); 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 { } else {
/* Notification received */ /* Notification received */
notification_data.primary = primary; notification_data.primary = primary;
...@@ -124,6 +130,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) ...@@ -124,6 +130,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0); CNL_DSP_REG_HIPCCTL_DONE, 0);
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
spin_lock_irq(&sdev->ipc_lock); spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */ /* handle immediate reply from DSP core */
...@@ -133,6 +140,10 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) ...@@ -133,6 +140,10 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
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; ipc_irq = true;
} }
......
...@@ -148,6 +148,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) ...@@ -148,6 +148,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
if (primary & SOF_IPC4_MSG_DIR_MASK) { if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */ /* Reply received */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
data->primary = primary; data->primary = primary;
...@@ -159,6 +160,11 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) ...@@ -159,6 +160,11 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, data->primary); 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 { } else {
/* Notification received */ /* Notification received */
...@@ -225,6 +231,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) ...@@ -225,6 +231,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
* place, the message might not yet be marked as expecting a * place, the message might not yet be marked as expecting a
* reply. * reply.
*/ */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
spin_lock_irq(&sdev->ipc_lock); spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */ /* handle immediate reply from DSP core */
...@@ -235,6 +242,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) ...@@ -235,6 +242,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
hda_dsp_ipc_dsp_done(sdev); 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; ipc_irq = true;
} }
......
...@@ -512,6 +512,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) ...@@ -512,6 +512,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
*/ */
if (primary & SOF_IPC4_MSG_DIR_MASK) { if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */ /* Reply received */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
data->primary = primary; data->primary = primary;
...@@ -523,6 +524,11 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) ...@@ -523,6 +524,11 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, data->primary); 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 { } else {
/* Notification received */ /* Notification received */
notification_data.primary = primary; notification_data.primary = primary;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment