RE: [PATCH] ASoC: Intel: sst: ipc command timeout

From: Lu, Brent
Date: Tue Apr 28 2020 - 13:29:19 EST


>
> I've looked at the code and byt_is_dsp_busy seems suspicious to me.
> Can you check if following change fixes problem for you:
>
> diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c
> b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
> index 74274bd38f7a..34746fd871b0 100644
> --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c
> +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
> @@ -666,8 +666,8 @@ static bool byt_is_dsp_busy(struct sst_dsp *dsp)
> {
> u64 ipcx;
>
> - ipcx = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
> - return (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE));
> + ipcx = sst_dsp_shim_read64_unlocked(dsp, SST_IPCX);
> + return (ipcx & (SST_BYT_IPCX_BUSY | SST_BYT_IPCX_DONE));
> }
>
> int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
>
> We seem to treat SST_IPCX as 32 bit register instead of 64 one, which may
> explain wrong behaviour. (Specification says it is 64 bit register).
>
> Thanks,
> Amadeusz

Hi Amadeusz,

The patch does not work but I managed to create a workaround just for
reference. Still don't know why first read in sst_byt_irq_thread returns
incorrect value.

diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
index 5bbaa667bec1..56c557cb722d 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c
@@ -12,6 +12,7 @@
* more details.
*/

+#define DEBUG
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -313,7 +314,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context)
struct sst_dsp *sst = (struct sst_dsp *) context;
struct sst_byt *byt = sst_dsp_get_thread_context(sst);
struct sst_generic_ipc *ipc = &byt->ipc;
- u64 header;
+ u64 header, mask, old, new;
unsigned long flags;

spin_lock_irqsave(&sst->spinlock, flags);
@@ -332,10 +333,32 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context)
* processed the message and can accept new. Clear data part
* of the header
*/
- sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
- SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
- IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
- SST_BYT_IPCD_DONE);
+ /* inline the sst_dsp_shim_update_bits64_unlocked function */
+ mask = SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
+ IPC_HEADER_DATA(IPC_HEADER_DATA_MASK);
+ old = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+ new = (old & (~mask)) | (SST_BYT_IPCD_DONE & mask);
+
+ if (old != new)
+ sst_dsp_shim_write64_unlocked(sst, SST_IPCD, new);
+
+ /*
+ * workaround, give it a second chance if the SST_IPCD
+ * changes
+ */
+ if (old != header) {
+ dev_dbg(ipc->dev, "%s: header 0x%llx old 0x%llx\n",
+ __func__, header, old);
+ if (old & SST_BYT_IPCD_BUSY) {
+ if (old & IPC_NOTIFICATION) {
+ /* message from ADSP */
+ sst_byt_process_notification(byt, &flags);
+ } else {
+ /* reply from ADSP */
+ sst_byt_process_reply(byt, old);
+ }
+ }
+ }
/* unmask message request interrupts */
sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
SST_BYT_IMRX_REQUEST, 0);