From 9535ab2b67e1957f70a8fa2482dcb158dfef485b Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Jul 2018 17:35:59 +0800 Subject: [PATCH 1/8] ASoC: SOF: return status in snd_sof_ipc_reply The IPC algorithm depends on the status of snd_sof_ipc_reply. The failed case is processed different with success one Signed-off-by: Rander Wang --- sound/soc/sof/ipc.c | 5 +++-- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 300f33139862a9..6b2b1d12646f6f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -247,7 +247,7 @@ void sof_ipc_drop_all(struct snd_sof_ipc *ipc) EXPORT_SYMBOL(sof_ipc_drop_all); /* handle reply message from DSP */ -void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { struct snd_sof_ipc_msg *msg; @@ -255,11 +255,12 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) if (!msg) { dev_err(sdev->dev, "error: can't find message header 0x%x", msg_id); - return; + return -EINVAL; } /* wake up and return the error if we have waiters on this message ? */ sof_ipc_tx_msg_reply_complete(sdev->ipc, msg); + return 0; } EXPORT_SYMBOL(snd_sof_ipc_reply); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 91115c82e62506..72b8870733094c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -385,7 +385,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset); */ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); void snd_sof_ipc_free(struct snd_sof_dev *sdev); -void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev); int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, From de14e414efc5dd9738c7964d3104bada39ae1c49 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Jul 2018 17:43:35 +0800 Subject: [PATCH 2/8] ASoC: SOF: Add direction param in cmd_done There are two direction now in cmd_done, one is reply of host to DSP, another is reply of DSP to host.The origin cmd_done is for reply of host to DSP. Cmd_done should be called after host has processed the reply msg from dsp. This function is for some platforms to do extra steps to make the following ipc msgs sent safely. Now the direction supported by cmd_done would be host reply to dsp or dsp reply to host. Signed-off-by: Rander Wang --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/cnl.c | 14 ++++++++------ sound/soc/sof/intel/hda-ipc.c | 15 +++++++++------ sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ipc.c | 4 +++- sound/soc/sof/ops.c | 2 +- sound/soc/sof/ops.h | 5 +++-- sound/soc/sof/sof-priv.h | 5 ++++- 8 files changed, 30 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index f76463abe07fa5..7e8fab0e5ded51 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -573,7 +573,7 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return ret; } -static int bdw_cmd_done(struct snd_sof_dev *sdev) +static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir) { /* clear BUSY bit and set DONE bit - accept new messages */ snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 10c98eb1371219..c1b902fd03feb4 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -132,13 +132,15 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) return ret; } -static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev) +static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) { - /* set done bit to ack dsp the msg has been processed */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDA, - CNL_DSP_REG_HIPCTDA_DONE, - CNL_DSP_REG_HIPCTDA_DONE); + if (dir == SOF_IPC_HOST_REPLY) { + /* set done bit to ack dsp the msg has been processed */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDA, + CNL_DSP_REG_HIPCTDA_DONE, + CNL_DSP_REG_HIPCTDA_DONE); + } return 0; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 357d909bfe80d6..e3e0c8fdcff682 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -34,13 +34,16 @@ #include "../ops.h" #include "hda.h" -int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev) +int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) { - /* tell DSP cmd is done - clear busy interrupt */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCT, - HDA_DSP_REG_HIPCT_BUSY, - HDA_DSP_REG_HIPCT_BUSY); + if (dir == SOF_IPC_HOST_REPLY) { + /* tell DSP cmd is done - clear busy interrupt */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCT, + HDA_DSP_REG_HIPCT_BUSY, + HDA_DSP_REG_HIPCT_BUSY); + } + return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 75f5b409d743bc..77a2315223a0da 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -473,7 +473,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); -int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev); +int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* * DSP Code loader. diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 6b2b1d12646f6f..52524fb1064a70 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -119,6 +119,8 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, spin_unlock_irqrestore(&sdev->ipc_lock, flags); + snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); + /* continue to schedule any remaining messages... */ snd_sof_ipc_msgs_tx(sdev); @@ -321,7 +323,7 @@ static void ipc_msgs_rx(struct work_struct *work) dev_dbg(sdev->dev, "ipc rx: 0x%x done\n", hdr.cmd); /* tell DSP we are done */ - snd_sof_dsp_cmd_done(sdev); + snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); } /* schedule work to transmit any IPC in queue */ diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 0668f64e1ef672..d1ea6a0c5f6229 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -205,6 +205,6 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); snd_sof_trace_notify_for_error(sdev); - snd_sof_dsp_cmd_done(sdev); + snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); } EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 340f1ccc40447f..0d6fa6ef1a3e8b 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -185,10 +185,11 @@ static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev) +static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, + int dir) { if (sdev->ops->cmd_done) - return sdev->ops->cmd_done(sdev); + return sdev->ops->cmd_done(sdev, dir); else return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 72b8870733094c..c4162d3973e00a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -43,6 +43,9 @@ /* max number of FE PCMs before BEs */ #define SOF_BE_PCM_BASE 16 +#define SOF_IPC_DSP_REPLY 0 +#define SOF_IPC_HOST_REPLY 1 + /* convenience constructor for DAI driver streams */ #define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \ {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \ @@ -117,7 +120,7 @@ struct snd_sof_dsp_ops { int (*get_reply)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); int (*is_ready)(struct snd_sof_dev *sof_dev); - int (*cmd_done)(struct snd_sof_dev *sof_dev); + int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* debug */ const struct snd_sof_debugfs_map *debug_map; From 3f2510724e462c36e91fa4053632d1b3218f1aba Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Jul 2018 17:46:24 +0800 Subject: [PATCH 3/8] ASoC: SOF: check is_dsp_ready when sending ipc msg Refine the implementation of is_dsp_ready on APL&CNL BUSY bit means dsp is ready, DONE bit means host has processed the reply msg. The next ipc msg should check both bits to make sure both dsp and host is ready Signed-off-by: Rander Wang Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/cnl.c | 8 +++++--- sound/soc/sof/intel/hda-ipc.c | 8 +++++--- sound/soc/sof/ipc.c | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index c1b902fd03feb4..b7b7de9861b85c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -147,10 +147,12 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) static int cnl_ipc_is_ready(struct snd_sof_dev *sdev) { - u64 val; + u64 busy, done; - val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); - if (val & CNL_DSP_REG_HIPCIDR_BUSY) + busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); + done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + if ((busy & CNL_DSP_REG_HIPCIDR_BUSY) || + (done & CNL_DSP_REG_HIPCIDA_DONE)) return 0; return 1; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index e3e0c8fdcff682..38b4111611e559 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -49,11 +49,13 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev) { - u64 val; + u64 busy, done; /* is DSP ready for next IPC command */ - val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); - if (val & HDA_DSP_REG_HIPCI_BUSY) + busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); + done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); + if ((busy & HDA_DSP_REG_HIPCI_BUSY) || + (done & HDA_DSP_REG_HIPCIE_DONE)) return 0; return 1; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 52524fb1064a70..be6a98e9d28049 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -179,7 +179,7 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); /* send message if HW read and message in TX list */ - if (list_empty(&ipc->tx_list)) + if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ready(sdev)) goto out; /* sned first message in TX list */ From 487934868e161eef58edf44bec9bde0b49a8cc5f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 3 Jul 2018 13:47:06 +0800 Subject: [PATCH 4/8] ASoC: SOF: process SOF_IPC_DSP_REPLY case in cmd_done on APL Set DONE bit in cmd_done function which processes msgs, rather than doing it in IRQ function. But if a msg is not in the rx list, it can only be done at IRQ function Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-ipc.c | 45 ++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 38b4111611e559..0fb3f48ef776a6 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -37,11 +37,29 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) { if (dir == SOF_IPC_HOST_REPLY) { - /* tell DSP cmd is done - clear busy interrupt */ + /* + * tell DSP cmd is done - clear busy + * interrupt and send reply msg to dsp + */ snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT, HDA_DSP_REG_HIPCT_BUSY, HDA_DSP_REG_HIPCT_BUSY); + } else { + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE, + HDA_DSP_REG_HIPCIE_DONE, + HDA_DSP_REG_HIPCIE_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); } return 0; @@ -113,6 +131,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; u32 hipci, hipcie, hipct, hipcte, msg = 0, msg_ext = 0; irqreturn_t ret = IRQ_NONE; + int reply = -EINVAL; /* here we handle IPC interrupts only */ if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) @@ -142,19 +161,17 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* handle immediate reply from DSP core - ignore ROM messages */ if (msg != 0x1004000) - snd_sof_ipc_reply(sdev, msg); - - /* clear DONE bit - tell DSP we have completed the operation */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCIE, - HDA_DSP_REG_HIPCIE_DONE, - HDA_DSP_REG_HIPCIE_DONE); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCCTL, - HDA_DSP_REG_HIPCCTL_DONE, - HDA_DSP_REG_HIPCCTL_DONE); + reply = snd_sof_ipc_reply(sdev, msg); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (reply) + hda_dsp_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); ret = IRQ_HANDLED; } From e094e3ece570eaee897898eadfc7bf660cbe8d9c Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 3 Jul 2018 13:53:50 +0800 Subject: [PATCH 5/8] ASoC: SOF: process SOF_IPC_DSP_REPLY case in cmd_done on CNL Set DONE bit in cmd_done function if direction is DSP_REPLY rather than doing it in IRQ function. But if a msg is not in the rx list, it can only be done at IRQ function Signed-off-by: Rander Wang --- sound/soc/sof/intel/cnl.c | 51 ++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index b7b7de9861b85c..f2c616904cbb86 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -40,6 +40,8 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000}, }; +static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); + static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; @@ -69,20 +71,15 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL_DONE, 0); - /* handle immediate reply from DSP core */ - snd_sof_ipc_reply(sdev, msg); - - /* clear DONE bit - tell DSP we have completed the operation */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCIDA, - CNL_DSP_REG_HIPCIDA_DONE, - CNL_DSP_REG_HIPCIDA_DONE); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCCTL, - CNL_DSP_REG_HIPCCTL_DONE, - CNL_DSP_REG_HIPCCTL_DONE); + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, msg)) + cnl_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); ret = IRQ_HANDLED; } @@ -108,8 +105,10 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) snd_sof_ipc_msgs_rx(sdev); } - /* clear busy interrupt to tell dsp controller this */ - /* interrupt has been accepted, not trigger it again */ + /* + * clear busy interrupt to tell dsp controller this + * interrupt has been accepted, not trigger it again + */ snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR, CNL_DSP_REG_HIPCTDR_BUSY, @@ -135,11 +134,29 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) { if (dir == SOF_IPC_HOST_REPLY) { - /* set done bit to ack dsp the msg has been processed */ + /* + * set done bit to ack dsp the msg has been + * processed and send reply msg to dsp + */ snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDA, CNL_DSP_REG_HIPCTDA_DONE, CNL_DSP_REG_HIPCTDA_DONE); + } else { + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDA, + CNL_DSP_REG_HIPCIDA_DONE, + CNL_DSP_REG_HIPCIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, + CNL_DSP_REG_HIPCCTL_DONE); } return 0; From d4c6f29252368657fe17b7e1af47d4f2938ff0c6 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 4 Jul 2018 15:24:21 +0800 Subject: [PATCH 6/8] ASoC: SOF: apply IPC changes to hsw (1) Set DONE bit in cmd_done function which processes msgs, rather than doing it in IRQ function. But if a msg is not in the rx list, it can only be done at IRQ function (2) Check DONE bit in hsw_is_ready function Signed-off-by: Rander Wang --- sound/soc/sof/intel/hsw.c | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index d81f8de3d65608..42d7fa622ff7c6 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -71,6 +71,8 @@ static const struct snd_sof_debugfs_map hsw_debugfs[] = { {"shim", HSW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, }; +static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); + /* * Memory copy. */ @@ -363,15 +365,16 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) /* Handle Immediate reply from DSP Core */ hsw_mailbox_read(sdev, sdev->host_box.offset, &hdr, sizeof(hdr)); - snd_sof_ipc_reply(sdev, hdr); - - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, - SHIM_IPCX_DONE, 0); - /* unmask Done interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, hdr)) + hsw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } ipcd = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); @@ -528,7 +531,7 @@ static int hsw_is_ready(struct snd_sof_dev *sdev) u32 val; val = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); - if (val & SHIM_IPCX_BUSY) + if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) return 0; return 1; @@ -574,16 +577,26 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return ret; } -static int hsw_cmd_done(struct snd_sof_dev *sdev) +static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, - SHIM_IPCD_BUSY | SHIM_IPCD_DONE, - SHIM_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } return 0; } From 06216404d0caac38ee3883606c1beb52ac015672 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 4 Jul 2018 15:28:40 +0800 Subject: [PATCH 7/8] ASoC: SOF: apply IPC changes to bdw (1) Set DONE bit in cmd_done function which processes msgs, rather than doing it in IRQ function. But if a msg is not in the rx list, it can only be done at IRQ function (2) Check DONE bit in bdw_is_ready function Signed-off-by: Rander Wang --- sound/soc/sof/intel/bdw.c | 47 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7e8fab0e5ded51..ada4907d558187 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -70,6 +70,8 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = { {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, }; +static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); + /* * Memory copy. */ @@ -361,15 +363,16 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) /* Handle Immediate reply from DSP Core */ bdw_mailbox_read(sdev, sdev->host_box.offset, &hdr, sizeof(hdr)); - snd_sof_ipc_reply(sdev, hdr); - - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, - SHIM_IPCX_DONE, 0); - /* unmask Done interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, hdr)) + bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -526,7 +529,7 @@ static int bdw_is_ready(struct snd_sof_dev *sdev) u32 val; val = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); - if (val & SHIM_IPCX_BUSY) + if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) return 0; return 1; @@ -575,14 +578,24 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, - SHIM_IPCD_BUSY | SHIM_IPCD_DONE, - SHIM_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } return 0; } From d5972257ab9795fe53d3e2579bacfab43437d69a Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 4 Jul 2018 15:31:08 +0800 Subject: [PATCH 8/8] ASoC: SOF: apply IPC changes to byt (1) Set DONE bit in cmd_done function which processes msgs, rather than doing it in IRQ function. But if a msg is not in the rx list, it can only be done at IRQ function (2) Check DONE bit in byt_is_ready function Signed-off-by: Rander Wang --- sound/soc/sof/intel/byt.c | 54 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 9d06dd312f56d8..e2dd813e44922a 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -95,6 +95,8 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = { {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, }; +static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); + /* * Register IO */ @@ -376,16 +378,15 @@ static irqreturn_t byt_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_BYT_IPCX_DONE) { - /* Handle Immediate reply from DSP Core */ - snd_sof_ipc_reply(sdev, ipcx); - - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, - SHIM_BYT_IPCX_DONE, 0); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, ipcx)) + byt_cmd_done(sdev, SOF_IPC_DSP_REPLY); } /* new message from DSP */ @@ -405,10 +406,11 @@ static irqreturn_t byt_irq_thread(int irq, void *context) static int byt_is_ready(struct snd_sof_dev *sdev) { - u64 imrx; + u64 imrx, ipcx; imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX); - if (imrx & SHIM_IMRX_DONE) + ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); + if ((imrx & SHIM_IMRX_DONE) || (ipcx & SHIM_BYT_IPCX_DONE)) return 0; return 1; @@ -458,17 +460,27 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return ret; } -static int byt_cmd_done(struct snd_sof_dev *sdev) +static int byt_cmd_done(struct snd_sof_dev *sdev, int dir) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, - SHIM_BYT_IPCD_BUSY | - SHIM_BYT_IPCD_DONE, - SHIM_BYT_IPCD_DONE); + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, + SHIM_BYT_IPCD_BUSY | + SHIM_BYT_IPCD_DONE, + SHIM_BYT_IPCD_DONE); - /* unmask busy interrupt */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); + /* unmask busy interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, + SHIM_BYT_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } return 0; }