From b7d0254c51f3ce79a8931690e8a2f035208f6b55 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:31 +0530 Subject: 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 Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 53 ++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'sound/soc/intel/skylake/skl-sst.c') 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; -- cgit v1.2.3 From f7ea77772dfaa404ac0bcdea5c262c24e8b860db Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 24 Mar 2017 23:10:28 +0530 Subject: ASoC: Intel: Skylake: Don't unload module when in use A module may have multiple instances in DSP, so unload only when usage count is zero. Signed-off-by: Vinod Koul Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/intel/skylake/skl-sst.c') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 39d4aaac73bf..539529729e3f 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -417,6 +417,11 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); return -EIO; } + + /* if module is used by others return, no need to unload */ + if (usage_cnt > 0) + return 0; + ret = skl_ipc_unload_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); if (ret < 0) { -- cgit v1.2.3 From 9fe9c71192832a1c63fb94120cb6c2541aca694f Mon Sep 17 00:00:00 2001 From: G Kranthi Date: Tue, 25 Apr 2017 12:18:19 +0530 Subject: ASoC: Intel: Skylake: Move sst common initialization to a helper function Some skl sst context are not dependent of platform and initializing them independently for each platform can lead to errors. So optimize by moving them to a helper function and platform specific init code can call this. Signed-off-by: G Kranthi Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'sound/soc/intel/skylake/skl-sst.c') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 539529729e3f..4fdd503a837c 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -330,7 +330,6 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, 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); bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); if (bytes_left < 0) @@ -489,43 +488,24 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, struct sst_dsp *sst; int ret; - skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); - if (skl == NULL) - return -ENOMEM; - - skl->dev = dev; - skl_dev.thread_context = skl; - INIT_LIST_HEAD(&skl->uuid_list); - - skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); - if (!skl->dsp) { - dev_err(skl->dev, "%s: no device\n", __func__); - return -ENODEV; + ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); + if (ret < 0) { + dev_err(dev, "%s: no device\n", __func__); + return ret; } + skl = *dsp; sst = skl->dsp; - - sst->fw_name = fw_name; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - INIT_LIST_HEAD(&sst->module_list); - sst->dsp_ops = dsp_ops; sst->fw_ops = skl_fw_ops; - ret = skl_ipc_init(dev, skl); - if (ret) - return ret; - skl->cores.count = 2; - skl->is_first_boot = true; - - if (dsp) - *dsp = skl; - return ret; + return 0; } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); -- cgit v1.2.3 From 4e0277d226b578be99cf8899fd1442bf11873d12 Mon Sep 17 00:00:00 2001 From: G Kranthi Date: Tue, 25 Apr 2017 12:18:21 +0530 Subject: ASoC: Intel: Skylake: Modify arguments to reuse module transfer function Kabylake also uses code loader dma for module load and library load. skl_transfer_module can be reused. Modify the arguments to include library index to be passed to lib load ipc and module/lib check to use correct ipc for lib/module load. Signed-off-by: G Kranthi Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sound/soc/intel/skylake/skl-sst.c') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 4fdd503a837c..b4c3b5c63115 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -325,7 +325,7 @@ static struct skl_module_table *skl_module_get_from_id( } static int skl_transfer_module(struct sst_dsp *ctx, const void *data, - u32 size, u16 mod_id) + u32 size, u16 mod_id, u8 table_id, bool is_module) { int ret, bytes_left, curr_pos; struct skl_sst *skl = ctx->thread_context; @@ -335,10 +335,12 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, if (bytes_left < 0) return bytes_left; - 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 (is_module) { /* load module */ + 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; + } } /* @@ -393,7 +395,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->fw->data, - module_entry->mod_info->fw->size, mod_id); + module_entry->mod_info->fw->size, + mod_id, 0, true); if (ret < 0) { dev_err(ctx->dev, "Failed to Load module\n"); return ret; -- cgit v1.2.3 From 89b0d8a5bae91cb8ef23b1834c97d1db367f2db6 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 25 Apr 2017 12:18:22 +0530 Subject: ASoC: Intel: Skylake: Register dsp_fw_ops for kabylake For audio kabylake is same as skylake except the module load approach. This patch registers different dsp_fw_ops for kabylake and next patch adds the module load support for kabylake. Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sound/soc/intel/skylake/skl-sst.c') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index b4c3b5c63115..20968e5ec86d 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -470,6 +470,15 @@ static struct skl_dsp_fw_ops skl_fw_ops = { .unload_mod = skl_unload_module, }; +static struct skl_dsp_fw_ops kbl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, + .load_mod = skl_load_module, + .unload_mod = skl_unload_module, +}; + static struct sst_ops skl_ops = { .irq_handler = skl_dsp_sst_interrupt, .write = sst_shim32_write, @@ -512,6 +521,27 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); +int kbl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_sst **dsp) +{ + struct sst_dsp *sst; + int ret; + + ret = skl_sst_dsp_init(dev, mmio_base, irq, fw_name, dsp_ops, dsp); + if (ret < 0) { + dev_err(dev, "%s: Init failed %d\n", __func__, ret); + return ret; + } + + sst = (*dsp)->dsp; + sst->fw_ops = kbl_fw_ops; + + return 0; + +} +EXPORT_SYMBOL_GPL(kbl_sst_dsp_init); + int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) { int ret; -- cgit v1.2.3 From b6726009af555129c57dfbbf80a1fcf4d5a36ba0 Mon Sep 17 00:00:00 2001 From: "Sodhi, VunnyX" Date: Tue, 25 Apr 2017 12:18:24 +0530 Subject: ASoC: Intel: Skylake: Add loadable module support on KBL platform Kabylake platform expects modules in a library manifest. After loading base firmware library manifest is loaded using load library IPC. This is followed by module load using load multiple modules IPC. Signed-off-by: Sodhi, VunnyX Signed-off-by: G Kranthi Signed-off-by: Subhransu S. Prusty Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 64 +++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) (limited to 'sound/soc/intel/skylake/skl-sst.c') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 20968e5ec86d..155e456b7a3a 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -179,6 +179,18 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) dev_err(ctx->dev, "unable to load firmware\n"); return ret; } + + /* load libs as they are also lost on D3 */ + if (skl->lib_count > 1) { + ret = ctx->fw_ops.load_library(ctx, skl->lib_info, + skl->lib_count); + if (ret < 0) { + dev_err(ctx->dev, "reload libs failed: %d\n", + ret); + return ret; + } + + } } /* @@ -204,7 +216,7 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) skl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; + return 0; } static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) @@ -335,12 +347,16 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, if (bytes_left < 0) return bytes_left; - if (is_module) { /* load module */ + /* check is_module flag to load module or library */ + if (is_module) 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; - } + else + ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false); + + if (ret < 0) { + dev_err(ctx->dev, "Failed to Load %s with err %d\n", + is_module ? "module" : "lib", ret); + goto out; } /* @@ -373,6 +389,32 @@ out: return ret; } +static int +kbl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) +{ + struct skl_sst *skl = ctx->thread_context; + struct firmware stripped_fw; + int ret, i; + + /* library indices start from 1 to N. 0 represents base FW */ + for (i = 1; i < lib_count; i++) { + ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, + SKL_ADSP_FW_BIN_HDR_OFFSET, i); + if (ret < 0) + goto load_library_failed; + ret = skl_transfer_module(ctx, stripped_fw.data, + stripped_fw.size, 0, i, false); + if (ret < 0) + goto load_library_failed; + } + + return 0; + +load_library_failed: + skl_release_library(linfo, lib_count); + return ret; +} + static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) { struct skl_module_table *module_entry = NULL; @@ -475,6 +517,7 @@ static struct skl_dsp_fw_ops kbl_fw_ops = { .set_state_D3 = skl_set_dsp_D3, .load_fw = skl_load_base_firmware, .get_fw_errcode = skl_get_errorcode, + .load_library = kbl_load_library, .load_mod = skl_load_module, .unload_mod = skl_unload_module, }; @@ -554,6 +597,15 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) } skl_dsp_init_core_state(sst); + + if (ctx->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, ctx->lib_info, + ctx->lib_count); + if (ret < 0) { + dev_err(dev, "Load Library failed : %x\n", ret); + return ret; + } + } ctx->is_first_boot = false; return 0; -- cgit v1.2.3