summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel/mtl.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@linux.intel.com>2022-10-18 15:40:07 +0300
committerMark Brown <broonie@kernel.org>2022-10-18 21:16:44 +0300
commit483e4cdfb502e6bea6b0a226a3ff7c22e60153de (patch)
tree768a591980310a58fc820e3efe9680447816f9c1 /sound/soc/sof/intel/mtl.c
parentc8ed7ce242db83ca2c4e9eab557a88adbae5ef6a (diff)
downloadlinux-483e4cdfb502e6bea6b0a226a3ff7c22e60153de.tar.xz
ASoC: SOF: Intel: ipc4: Wait for channel to be free before sending a message
Before attempting to send a message to the DSP we need to check if the downstream BUSY flag has been cleared by the firmware to avoid lost IPC messages by the firmware. This is required by a firmware which only acks the received message after it has sent a reply to the host. With a bad luck, the host would send a message before the firmware gets to the clearing the flag and thus losing a message. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Link: https://lore.kernel.org/r/20221018124008.6846-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/intel/mtl.c')
-rw-r--r--sound/soc/sof/intel/mtl.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index a9b31b31a4e4..9d1bc74395e7 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -90,8 +90,16 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
+ if (hda_ipc4_tx_is_busy(sdev)) {
+ hdev->delayed_ipc_tx_msg = msg;
+ return 0;
+ }
+
+ hdev->delayed_ipc_tx_msg = NULL;
+
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -492,6 +500,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
+ bool ack_received = false;
bool ipc_irq = false;
u32 hipcida;
u32 hipctdr;
@@ -508,6 +517,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
mtl_ipc_dsp_done(sdev);
ipc_irq = true;
+ ack_received = true;
}
if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
@@ -558,6 +568,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
}
+ if (ack_received) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (hdev->delayed_ipc_tx_msg)
+ mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+ }
+
return IRQ_HANDLED;
}