Skip to content

Commit

Permalink
ASoC: SOF: amd: Use semaphore register to synchronize ipc's irq
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ajit Kumar Pandey authored and Mark Brown committed Mar 7, 2022
1 parent b7485ec commit dc0d4ed
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 1 deletion.
1 change: 1 addition & 0 deletions sound/soc/sof/amd/acp-dsp-offset.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#define ACP_DSP_SW_INTR_STAT 0x1818
#define ACP_SW_INTR_TRIG 0x181C
#define ACP_ERROR_STATUS 0x18C4
#define ACP_AXI2DAGB_SEM_0 0x1880

/* Registers from ACP_SHA block */
#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70
Expand Down
14 changes: 14 additions & 0 deletions sound/soc/sof/amd/acp-ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,26 @@ int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box);
unsigned int count = ACP_HW_SEM_RETRY_COUNT;

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 -EINVAL;
}
};

acp_mailbox_write(sdev, offset, msg->msg_data, msg->msg_size);
acp_ipc_host_msg_set(sdev);

/* Trigger host to dsp interrupt for the msg */
acpbus_trigger_host_to_dsp_swintr(adata);

/* Unlock or Release HW Semaphore */
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0);

return 0;
}
EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, SND_SOC_SOF_AMD_COMMON);
Expand Down
15 changes: 14 additions & 1 deletion sound/soc/sof/amd/acp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/amd/acp.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#define ACP_DSP_BAR 0

#define ACP_HW_SEM_RETRY_COUNT 10
#define ACP_REG_POLL_INTERVAL 500
#define ACP_REG_POLL_TIMEOUT_US 2000
#define ACP_DMA_COMPLETE_TIMEOUT_US 5000
Expand Down

0 comments on commit dc0d4ed

Please sign in to comment.