Unverified Commit 501935da authored by Mark Brown's avatar Mark Brown
Browse files

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
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)

		if (primary & SOF_IPC4_MSG_DIR_MASK) {
			/* Reply received */
			if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
				struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;

				data->primary = primary;
@@ -71,6 +72,11 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
				snd_sof_ipc_reply(sdev, data->primary);

				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,6 +130,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
					CNL_DSP_REG_HIPCCTL,
					CNL_DSP_REG_HIPCCTL_DONE, 0);

		if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
			spin_lock_irq(&sdev->ipc_lock);

			/* handle immediate reply from DSP core */
@@ -133,6 +140,10 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
			cnl_ipc_dsp_done(sdev);

			spin_unlock_irq(&sdev->ipc_lock);
		} else {
			dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
					    msg);
		}

		ipc_irq = true;
	}
+25 −14
Original line number Diff line number Diff line
@@ -148,6 +148,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)

		if (primary & SOF_IPC4_MSG_DIR_MASK) {
			/* Reply received */
			if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
				struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;

				data->primary = primary;
@@ -159,6 +160,11 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
				snd_sof_ipc_reply(sdev, data->primary);

				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,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
		 * reply.
		 */
		if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
			spin_lock_irq(&sdev->ipc_lock);

			/* handle immediate reply from DSP core */
@@ -235,6 +242,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
			hda_dsp_ipc_dsp_done(sdev);

			spin_unlock_irq(&sdev->ipc_lock);
		} else {
			dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
					    msg);
		}

		ipc_irq = true;
	}
+13 −7
Original line number Diff line number Diff line
@@ -512,6 +512,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
		 */
		if (primary & SOF_IPC4_MSG_DIR_MASK) {
			/* Reply received */
			if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
				struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;

				data->primary = primary;
@@ -523,6 +524,11 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
				snd_sof_ipc_reply(sdev, data->primary);

				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;