diff options
author | Jeeja KP <jeeja.kp@intel.com> | 2017-03-13 19:41:31 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-03-15 20:28:18 +0300 |
commit | b7d0254c51f3ce79a8931690e8a2f035208f6b55 (patch) | |
tree | b13a6487b7f2cb4d069d3419da67a082bfce790d /sound/soc/intel/skylake/skl-sst.c | |
parent | 7bd86a30599de479bd863e18472207337485d339 (diff) | |
download | linux-b7d0254c51f3ce79a8931690e8a2f035208f6b55.tar.xz |
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.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-sst.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index b30bd384c8d3..39d4aaac73bf 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -52,7 +52,8 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, { int ret = 0; - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size, + true); if (ret < 0) return ret; @@ -323,22 +324,49 @@ static struct skl_module_table *skl_module_get_from_id( return NULL; } -static int skl_transfer_module(struct sst_dsp *ctx, - struct skl_load_module_info *module) +static int skl_transfer_module(struct sst_dsp *ctx, const void *data, + u32 size, u16 mod_id) { - int ret; + int ret, bytes_left, curr_pos; struct skl_sst *skl = ctx->thread_context; + skl->mod_load_complete = false; + init_waitqueue_head(&skl->mod_load_wait); - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data, - module->fw->size); - if (ret < 0) - return ret; + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); + if (bytes_left < 0) + return bytes_left; - ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, - (void *)&module->mod_id); - if (ret < 0) + ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); + if (ret < 0) { dev_err(ctx->dev, "Failed to Load module: %d\n", ret); + goto out; + } + + /* + * if bytes_left > 0 then wait for BDL complete interrupt and + * copy the next chunk till bytes_left is 0. if bytes_left is + * is zero, then wait for load module IPC reply + */ + while (bytes_left > 0) { + curr_pos = size - bytes_left; + + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) + goto out; + + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, + data + curr_pos, + bytes_left, false); + } + + ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0 || !skl->mod_load_status) { + dev_err(ctx->dev, "Module Load failed\n"); + ret = -EIO; + } +out: ctx->cl_dev.ops.cl_stop_dma(ctx); return ret; @@ -365,7 +393,8 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) } if (!module_entry->usage_cnt) { - ret = skl_transfer_module(ctx, module_entry->mod_info); + ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data, + module_entry->mod_info->fw->size, mod_id); if (ret < 0) { dev_err(ctx->dev, "Failed to Load module\n"); return ret; |