From: Robin Gong Date: Thu, 29 Apr 2021 20:09:43 +0000 (+0800) Subject: MLK-25473-3 dmaengine: imx-sdma: split request firmware from runtime X-Git-Tag: rel_imx_5.10.35_2.0.0-somdevices.0~125 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=fe4ccc22d81dcd0fe7d6333784feebff2054607c;p=linux.git MLK-25473-3 dmaengine: imx-sdma: split request firmware from runtime split request_firmware from sdma_runtime_resume, because in nfs case, request_firmware may trigger sleep which cause kernel below complain during runtime_get_sync in atmoic case like audio record. Actually, only one time for request_firmware after kernel boot, split it from runtime resume and only load_scripts instead 'request_firmware + load_script'. [ 63.115924] BUG: scheduling while atomic: arecord/613/0x00000002 [ 63.121970] Modules linked in: [ 63.125031] CPU: 3 PID: 613 Comm: arecord Not tainted 5.10.31-104197-ged911ffb5e2f #339 [ 63.133033] Hardware name: NXP i.MX8MPlus EVK board (DT) [ 63.138343] Call trace: [ 63.140795] dump_backtrace+0x0/0x1c8 [ 63.144458] show_stack+0x14/0x60 [ 63.147775] dump_stack+0xd0/0x128 [ 63.151178] __schedule_bug+0x54/0x78 [ 63.154843] __schedule+0x5c8/0x690 [ 63.158332] schedule+0x6c/0x108 [ 63.161560] rpc_wait_bit_killable+0x24/0xa8 [ 63.165831] __wait_on_bit+0xa4/0xe0 [ 63.169405] out_of_line_wait_on_bit+0x8c/0xb0 [ 63.173848] __rpc_execute+0x138/0x338 [ 63.177596] rpc_execute+0x88/0xa8 [ 63.180998] rpc_run_task+0x154/0x1a8 [ 63.184661] rpc_call_sync+0x54/0xa8 [ 63.188239] nfs3_rpc_wrapper+0x50/0xd0 [ 63.192074] nfs3_proc_access+0x7c/0xe0 [ 63.195910] nfs_do_access+0xa0/0x1b8 [ 63.199571] nfs_permission+0xac/0x1b0 [ 63.203321] inode_permission+0xdc/0x170 [ 63.207243] link_path_walk+0x1f4/0x350 [ 63.211078] path_openat+0x80/0xd50 [ 63.214565] do_file_open_root+0xa4/0x150 [ 63.218576] file_open_root+0xf4/0x178 [ 63.222326] kernel_read_file_from_path_initns+0xb0/0x138 [ 63.227726] _request_firmware+0x39c/0x588 [ 63.231821] request_firmware+0x44/0x68 [ 63.235659] sdma_runtime_resume+0x1a0/0x280 [ 63.239929] pm_generic_runtime_resume+0x28/0x40 [ 63.244546] __genpd_runtime_resume+0x2c/0x80 [ 63.248902] genpd_runtime_resume+0x130/0x1e8 [ 63.253260] __rpm_callback+0xd8/0x150 [ 63.257008] rpm_callback+0x24/0x98 [ 63.260498] rpm_resume+0x338/0x4b0 [ 63.263986] __pm_runtime_resume+0x38/0x88 [ 63.268082] sdma_prep_dma_cyclic+0x264/0x290 Signed-off-by: Robin Gong Reviewed-by: Shengjiu Wang --- diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f2c29a62f74c..9598058b08f7 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -489,6 +489,7 @@ struct sdma_engine { struct gen_pool *iram_pool; bool fw_loaded; u32 fw_fail; + u8 *fw_data; unsigned short ram_code_start; }; @@ -496,9 +497,6 @@ static int sdma_config_write(struct dma_chan *chan, struct dma_slave_config *dmaengine_cfg, enum dma_transfer_direction direction); -static int sdma_get_firmware(struct sdma_engine *sdma, - const char *fw_name); - static struct sdma_driver_data sdma_imx31 = { .chnenbl0 = SDMA_CHNENBL0_IMX31, .num_events = 32, @@ -782,17 +780,54 @@ static int sdma_run_channel0(struct sdma_engine *sdma) return ret; } -static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, - u32 address) +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 47 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 48 + +static void sdma_add_scripts(struct sdma_engine *sdma, + const struct sdma_script_start_addrs *addr) +{ + s32 *addr_arr = (u32 *)addr; + s32 *saddr_arr = (u32 *)sdma->script_addrs; + int i; + + /* use the default firmware in ROM if missing external firmware */ + if (!sdma->script_number) + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + + if (sdma->script_number > sizeof(struct sdma_script_start_addrs) + / sizeof(s32)) { + dev_err(sdma->dev, + "SDMA script number %d not match with firmware.\n", + sdma->script_number); + return; + } + + for (i = 0; i < sdma->script_number; i++) + if (addr_arr[i] > 0) + saddr_arr[i] = addr_arr[i]; +} + +static int sdma_load_script(struct sdma_engine *sdma) { struct sdma_buffer_descriptor *bd0 = sdma->bd0; + const struct sdma_script_start_addrs *addr; + struct sdma_firmware_header *header; + unsigned short *ram_code; void *buf_virt; dma_addr_t buf_phys; int ret; unsigned long flags; - buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys, - GFP_KERNEL); + header = (struct sdma_firmware_header *)sdma->fw_data; + + addr = (void *)header + header->script_addrs_start; + ram_code = (void *)header + header->ram_code_start; + sdma->ram_code_start = header->ram_code_start; + + buf_virt = dma_alloc_coherent(sdma->dev, header->ram_code_size, + &buf_phys, GFP_KERNEL); if (!buf_virt) return -ENOMEM; @@ -800,18 +835,25 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, bd0->mode.command = C0_SETPM; bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD; - bd0->mode.count = size / 2; + bd0->mode.count = header->ram_code_size / 2; bd0->buffer_addr = buf_phys; - bd0->ext_buffer_addr = address; + bd0->ext_buffer_addr = addr->ram_code_start_addr; - memcpy(buf_virt, buf, size); + memcpy(buf_virt, ram_code, header->ram_code_size); ret = sdma_run_channel0(sdma); spin_unlock_irqrestore(&sdma->channel_0_lock, flags); - dma_free_coherent(sdma->dev, size, buf_virt, buf_phys); + dma_free_coherent(sdma->dev, header->ram_code_size, buf_virt, buf_phys); + + sdma_add_scripts(sdma, addr); + sdma->fw_loaded = true; + + dev_info_once(sdma->dev, "loaded firmware %d.%d\n", + header->version_major, + header->version_minor); return ret; } @@ -1586,9 +1628,8 @@ static int sdma_runtime_resume(struct device *dev) /* Initializes channel's priorities */ sdma_set_channel_priority(&sdma->channel[0], 7); - ret = sdma_get_firmware(sdma, sdma->fw_name); - if (ret) - dev_warn(sdma->dev, "failed to get firmware.\n"); + if (sdma_load_script(sdma)) + dev_warn(sdma->dev, "failed to load script.\n"); sdma->is_on = true; @@ -2101,41 +2142,10 @@ static void sdma_issue_pending(struct dma_chan *chan) } } -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 47 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 48 - -static void sdma_add_scripts(struct sdma_engine *sdma, - const struct sdma_script_start_addrs *addr) -{ - s32 *addr_arr = (u32 *)addr; - s32 *saddr_arr = (u32 *)sdma->script_addrs; - int i; - - /* use the default firmware in ROM if missing external firmware */ - if (!sdma->script_number) - sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; - - if (sdma->script_number > sizeof(struct sdma_script_start_addrs) - / sizeof(s32)) { - dev_err(sdma->dev, - "SDMA script number %d not match with firmware.\n", - sdma->script_number); - return; - } - - for (i = 0; i < sdma->script_number; i++) - if (addr_arr[i] > 0) - saddr_arr[i] = addr_arr[i]; -} - static void sdma_load_firmware(const struct firmware *fw, void *context) { struct sdma_engine *sdma = context; const struct sdma_firmware_header *header; - const struct sdma_script_start_addrs *addr; - unsigned short *ram_code; if (!fw) { /* Load firmware once more time if timeout */ @@ -2179,22 +2189,18 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) goto err_firmware; } - addr = (void *)header + header->script_addrs_start; - ram_code = (void *)header + header->ram_code_start; - sdma->ram_code_start = header->ram_code_start; - - /* download the RAM image for SDMA */ - sdma_load_script(sdma, ram_code, - header->ram_code_size, - addr->ram_code_start_addr); + dev_info(sdma->dev, "firmware found.\n"); - sdma_add_scripts(sdma, addr); + if (!sdma->fw_data) { + sdma->fw_data = kmalloc(fw->size, GFP_KERNEL); + if (!sdma->fw_data) + goto err_firmware; - sdma->fw_loaded = true; + memcpy(sdma->fw_data, fw->data, fw->size); - dev_info_once(sdma->dev, "loaded firmware %d.%d\n", - header->version_major, - header->version_minor); + if (!sdma->drvdata->pm_runtime) + pm_runtime_get_sync(sdma->dev); + } err_firmware: release_firmware(fw); @@ -2534,6 +2540,10 @@ static int sdma_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to get firmware name\n"); else sdma->fw_name = fw_name; + + ret = sdma_get_firmware(sdma, sdma->fw_name); + if (ret) + dev_warn(sdma->dev, "failed to get firmware.\n"); } /* enable autosuspend for pm_runtime */ @@ -2545,8 +2555,6 @@ static int sdma_probe(struct platform_device *pdev) } pm_runtime_enable(&pdev->dev); - if (!sdma->drvdata->pm_runtime) - pm_runtime_get_sync(&pdev->dev); return 0; @@ -2569,6 +2577,7 @@ static int sdma_remove(struct platform_device *pdev) devm_free_irq(&pdev->dev, sdma->irq, sdma); dma_async_device_unregister(&sdma->dma_device); kfree(sdma->script_addrs); + kfree(sdma->fw_data); clk_unprepare(sdma->clk_ahb); clk_unprepare(sdma->clk_ipg); /* Kill the tasklet */