summary refs log tree commit diff
path: root/sound/soc/sof/amd/acp.c
diff options
context:
space:
mode:
authorAjit Kumar Pandey <AjitKumar.Pandey@amd.com>2022-03-04 14:57:28 -0600
committerMark Brown <broonie@kernel.org>2022-03-07 13:12:49 +0000
commitdc0d4ed26dd2166b47c29d6a9829ac798e62a0fc (patch)
tree381545b3c98719ce2e92ab0dc32ab3e41d005380 /sound/soc/sof/amd/acp.c
parentb7485ec850591ad62fde0526bd7fdc56cdc04efd (diff)
downloadlinux-dc0d4ed26dd2166b47c29d6a9829ac798e62a0fc.tar.gz
ASoC: SOF: amd: Use semaphore register to synchronize ipc's irq
Add lock and unlock around ipc irq handling code using hw semaphore
register that exhibit special property for register read calls. As
host and DSP firmware uses few shared registers, there is a possible
race condition around those shared registers values. This lock ensure
synchronization between Firmware and host ipc interrupts.

Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20220304205733.62233-6-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/amd/acp.c')
-rw-r--r--sound/soc/sof/amd/acp.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index fe9b7dc5bc86..ba8b6427b59f 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -273,7 +273,7 @@ static int acp_memory_init(struct snd_sof_dev *sdev)
 static irqreturn_t acp_irq_thread(int irq, void *context)
 {
 	struct snd_sof_dev *sdev = context;
-	unsigned int val;
+	unsigned int val, count = ACP_HW_SEM_RETRY_COUNT;
 
 	val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT);
 	if (val & ACP_SHA_STAT) {
@@ -284,9 +284,22 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
 
 	val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT);
 	if (val & ACP_DSP_TO_HOST_IRQ) {
+		while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0)) {
+			/* Wait until acquired HW Semaphore lock or timeout */
+			count--;
+			if (!count) {
+				dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
+				return IRQ_NONE;
+			}
+		};
+
 		sof_ops(sdev)->irq_thread(irq, sdev);
 		val |= ACP_DSP_TO_HOST_IRQ;
 		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT, val);
+
+		/* Unlock or Release HW Semaphore */
+		snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0);
+
 		return IRQ_HANDLED;
 	}