summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Eichenberger <stefan.eichenberger@toradex.com>2024-03-11 16:49:45 +0100
committerStefan Eichenberger <eichest@gmail.com>2024-04-05 09:31:47 +0200
commitf744d56e84b8b0b4467ca18c3e76f3fec17ced6d (patch)
tree9046fb8b27ce0cff9814c018ed798597a5973f74
parent23a8e831749daa8b77e349d827715dd1d7f8e9a5 (diff)
dmaengine: imx-sdma: register sdma after firmware has loaded
On an i.MX8M Plus we have the use case where a Bluetooth controller is attached to a imx-uart that uses the SDMA engine. We use serdev to load the Bluetooth driver as follows: &uart4 { bluetooth { compatible = "mrvl,88w8997"; max-speed = <921600>; }; } From time to time we see that the SDMA engine is not ready when the Bluetooth driver tries to load. This will result in the following error: [ 5.833037] imx-sdma 30bd0000.dma-controller: firmware found. [ 5.835034] Bluetooth: HCI UART protocol Three-wire (H5) registered [ 5.835305] Bluetooth: HCI UART protocol Broadcom registered [ 5.835330] Bluetooth: HCI UART protocol QCA registered [ 5.835378] Bluetooth: HCI UART protocol Marvell registered [ 5.837497] ------------[ cut here ]------------ [ 5.841549] imx-sdma 30e00000.dma-controller: firmware found. [ 5.847712] WARNING: CPU: 3 PID: 143 at kernel/dma/mapping.c:528 dma_free_attrs+0xb0/0xe0 [ 5.847730] Modules linked in: snd_soc_wm8904(+) sec_mipi_dsim_imx(+) hci_uart sec_dsim [ 5.853442] imx-sdma 30e10000.dma-controller: firmware found. [ 5.858637] btqca btbcm dw_hdmi_cec lontium_lt8912b(+) ina2xx bluetooth snd_soc_fsl_sai snd_soc_fsl_aud2htx rfkill imx_sdma lm75 flexcan can_dev caam [ 5.864530] imx-sdma 30bd0000.dma-controller: loaded firmware 4.5 [ 5.868870] secvio error display_connector galcore(O) fuse [ 5.868890] CPU: 3 PID: 143 Comm: kworker/u8:2 Tainted: G O 5.15.148-6.6.0-devel+git.23a8e831749d #1 [ 5.868896] Hardware name: Toradex Verdin iMX8M Plus WB on Dahlia Board (DT) [ 5.868900] Workqueue: events_unbound async_run_entry_fn [ 5.915483] lt8912 3-0048: supply vcclvdspll not found, using dummy regulator [ 5.919370] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 5.919377] pc : dma_free_attrs+0xb0/0xe0 [ 5.919384] lr : dma_free_attrs+0x50/0xe0 [ 5.919390] sp : ffff80000a07b8f0 [ 5.919393] x29: ffff80000a07b8f0 x28: 0000000000000000 x27: ffff80000a2c5200 [ 5.919401] x26: ffff0000c6453100 x25: 0000000000000000 x24: 0000000000000000 [ 5.919408] x23: 00000000de081000 x22: 0000000000000000 [ 6.021103] lt8912 3-0048: supply vcchdmipll not found, using dummy regulator [ 6.021961] x21: ffff800009f17000 [ 6.052001] x20: 00000000000000c0 x19: ffff0000c056bc10 x18: ffff800009bcddcc [ 6.059145] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 [ 6.066293] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000001000 [ 6.073448] x11: 0000000000000000 x10: 0000000000000000 x9 : 0000000000000000 [ 6.080595] x8 : ffff800009f18000 x7 : 0000000000000000 x6 : 000000000000003f [ 6.087744] x5 : 0000000000000040 x4 : 0000000000000000 x3 : 00000000de081000 [ 6.094887] x2 : ffff800009f17000 x1 : 00000000000000c0 x0 : 0000000000000080 [ 6.102034] Call trace: [ 6.104482] dma_free_attrs+0xb0/0xe0 [ 6.108154] sdma_free_bd+0x60/0x70 [imx_sdma] [ 6.112609] sdma_transfer_init+0x208/0x344 [imx_sdma] [ 6.117760] sdma_prep_dma_cyclic+0xa4/0x364 [imx_sdma] [ 6.122995] imx_uart_startup+0x468/0x780 [ 6.127011] uart_port_startup+0x138/0x2fc [ 6.131111] uart_port_activate+0x54/0xd0 [ 6.135124] tty_port_open+0x90/0x130 [ 6.138791] uart_open+0x1c/0x30 [ 6.142023] ttyport_open+0x70/0x17c [ 6.145602] serdev_device_open+0x2c/0xe0 [ 6.149615] hci_uart_register_device+0x5c/0x33c [hci_uart] [ 6.155228] mrvl_serdev_probe+0x78/0x9c [hci_uart] [ 6.160140] serdev_drv_probe+0x38/0x80 [ 6.163984] really_probe+0xbc/0x46c [ 6.167562] __driver_probe_device+0x104/0x160 [ 6.172008] driver_probe_device+0x40/0x120 [ 6.176198] __driver_attach_async_helper+0x4c/0xf0 [ 6.181082] async_run_entry_fn+0x34/0x160 [ 6.185181] process_one_work+0x1d0/0x374 [ 6.189196] worker_thread+0x13c/0x490 [ 6.192949] kthread+0x150/0x160 [ 6.196180] ret_from_fork+0x10/0x20 [ 6.199764] ---[ end trace 906604ec7108d636 ]--- [ 6.204403] imx-uart 30a60000.serial: We cannot prepare for the RX slave dma! When the issue appears the sdma firmware is loaded after the uart requests a dma channel. This results in the above error. With this commit we make sure that the firmware is loaded before the sdma is registered and thus making sure that the sdma is ready when a driver requests a dma channel. Upstream-Status: Inappropriate [other] The upstream driver is not affected by this issue because it works even if the firmware is not loaded yet. It then uses the preprogrammed sdma firmware and switches to the new firmware as soon as it is ready. However, in comparison to the downstream driver it does not support suspend/resume and the drivers are therefore different. Trying to make the downstream driver work without the firmware loaded resulted in spare "Timeout waiting for CH0 ready" errors. Most likely it is an issue with the clock enable/disable sequence in the sdma driver that doesn't foresee this use case. Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
-rw-r--r--drivers/dma/imx-sdma.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 5bc67b7c33ed..ef5235cd8c03 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -2338,10 +2338,15 @@ static int sdma_get_firmware(struct sdma_engine *sdma,
const char *fw_name)
{
int ret;
+ const struct firmware *fw;
- ret = request_firmware_nowait(THIS_MODULE,
- FW_ACTION_UEVENT, fw_name, sdma->dev,
- GFP_KERNEL, sdma, sdma_load_firmware);
+ ret = request_firmware(&fw, fw_name, sdma->dev);
+ if (ret < 0) {
+ dev_err(sdma->dev, "failed to request firmware %s\n", fw_name);
+ return ret;
+ }
+
+ sdma_load_firmware(fw, sdma);
return ret;
}
@@ -2550,6 +2555,22 @@ static int sdma_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sdma);
+ /*
+ * Because that device tree does not encode ROM script address,
+ * the RAM script in firmware is mandatory for device tree
+ * probe, otherwise it fails.
+ */
+ ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+ &fw_name);
+ if (ret)
+ 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");
+
ret = dma_async_device_register(&sdma->dma_device);
if (ret) {
dev_err(&pdev->dev, "unable to register\n");
@@ -2572,22 +2593,6 @@ static int sdma_probe(struct platform_device *pdev)
of_node_put(spba_bus);
}
- /*
- * Because that device tree does not encode ROM script address,
- * the RAM script in firmware is mandatory for device tree
- * probe, otherwise it fails.
- */
- ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
- &fw_name);
- if (ret)
- 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 */
if (sdma->drvdata->pm_runtime) {
pm_runtime_set_autosuspend_delay(&pdev->dev, 8000);