summaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/skylake/skl-sst-ipc.c
diff options
context:
space:
mode:
authorJeeja KP <jeeja.kp@intel.com>2017-03-13 22:11:31 +0530
committerMark Brown <broonie@kernel.org>2017-03-15 17:28:18 +0000
commitb7d0254c51f3ce79a8931690e8a2f035208f6b55 (patch)
treeb13a6487b7f2cb4d069d3419da67a082bfce790d /sound/soc/intel/skylake/skl-sst-ipc.c
parent7bd86a30599de479bd863e18472207337485d339 (diff)
downloadlinux-stable-b7d0254c51f3ce79a8931690e8a2f035208f6b55.tar.gz
linux-stable-b7d0254c51f3ce79a8931690e8a2f035208f6b55.tar.bz2
linux-stable-b7d0254c51f3ce79a8931690e8a2f035208f6b55.zip
ASoC: Intel: Skylake: Fix module load when module size > DMA buffer size
When module size > DMA buffer size, driver copies first chunk and waits for the BDL complete interrupt. BDL complete interrupt never occurs and wait time expires as module load IPC is not send to start the DMA from DSP. To fix the above issue need to follow the below steps: 1. After copying the first chunk, send the module load IPC to start the DMA. 2. Wait for the BDL interrupt. Once interrupt is received, copy the next chunk. 3. Continue step 2 till all bytes are copied. 4. When all the bytes are copied (bytes_left = 0), wait for module load IPC response 5. Handled module load IPC response messages, check the load module IPC response and wake up the thread to complete module load. Signed-off-by: Jeeja KP <jeeja.kp@intel.com> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/intel/skylake/skl-sst-ipc.c')
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c66
1 files changed, 45 insertions, 21 deletions
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index e1391dfbc9e9..e90fe2c0bf2c 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -34,6 +34,11 @@
#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1)
#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT)
+#define IPC_GLB_REPLY_TYPE_SHIFT 29
+#define IPC_GLB_REPLY_TYPE_MASK 0x1F
+#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \
+ & IPC_GLB_RPLY_TYPE_MASK)
+
#define IPC_TIMEOUT_MSECS 3000
#define IPC_EMPTY_LIST_SIZE 8
@@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
return 0;
}
+static int skl_ipc_set_reply_error_code(u32 reply)
+{
+ switch (reply) {
+ case IPC_GLB_REPLY_OUT_OF_MEMORY:
+ return -ENOMEM;
+
+ case IPC_GLB_REPLY_BUSY:
+ return -EBUSY;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header)
{
struct ipc_message *msg;
u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
u64 *ipc_header = (u64 *)(&header);
+ struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
if (msg == NULL) {
@@ -401,33 +421,37 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
}
/* first process the header */
- switch (reply) {
- case IPC_GLB_REPLY_SUCCESS:
+ if (reply == IPC_GLB_REPLY_SUCCESS) {
dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary);
/* copy the rx data from the mailbox */
sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
- break;
-
- case IPC_GLB_REPLY_OUT_OF_MEMORY:
- dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary);
- msg->errno = -ENOMEM;
- break;
-
- case IPC_GLB_REPLY_BUSY:
- dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary);
- msg->errno = -EBUSY;
- break;
+ switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
+ case IPC_GLB_LOAD_MULTIPLE_MODS:
+ skl->mod_load_complete = true;
+ skl->mod_load_status = true;
+ wake_up(&skl->mod_load_wait);
+ break;
- default:
- dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply);
- msg->errno = -EINVAL;
- break;
- }
+ default:
+ break;
- if (reply != IPC_GLB_REPLY_SUCCESS) {
+ }
+ } else {
+ msg->errno = skl_ipc_set_reply_error_code(reply);
dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
dev_err(ipc->dev, "FW Error Code: %u\n",
ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
+ case IPC_GLB_LOAD_MULTIPLE_MODS:
+ skl->mod_load_complete = true;
+ skl->mod_load_status = false;
+ wake_up(&skl->mod_load_wait);
+ break;
+
+ default:
+ break;
+
+ }
}
list_del(&msg->list);
@@ -811,8 +835,8 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
- (sizeof(u16) * module_cnt), NULL, 0);
+ ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data,
+ (sizeof(u16) * module_cnt));
if (ret < 0)
dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);