of_platform_populate() only guarantees that child devices are registered, not that their probes have completed before it returns. This creates a window where fastrpc_cb_init() may not have run for all context bank nodes, leaving the channel context partially initialised.
Introduce fastrpc_cb_devices_create() to iterate over child DT nodes directly and call fastrpc_cb_init() synchronously for each qcom,fastrpc-compute-cb node. This ensures all context banks are fully initialised before fastrpc_rpmsg_probe() returns. Introduce fastrpc_cb_devices_destroy() as the symmetric counterpart. Before destroying the CB platform devices, invalidate all sessions under the channel lock so that any fastrpc_user still holding a reference to the channel context cannot acquire a new session backed by a destroyed device. Since fastrpc_cb_driver is no longer needed as an independent platform driver, remove it along with its match table and remove callback. Use module_rpmsg_driver() now that only a single driver registration remains. Signed-off-by: Vinayak Katoch <[email protected]> --- drivers/misc/fastrpc.c | 95 ++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index af18ff1992ee..caa479f304c1 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2333,7 +2333,7 @@ static const struct file_operations fastrpc_fops = { .compat_ioctl = fastrpc_device_ioctl, }; -static int fastrpc_cb_probe(struct platform_device *pdev) +static int fastrpc_cb_init(struct platform_device *pdev) { struct fastrpc_channel_ctx *cctx; struct fastrpc_session_ctx *sess; @@ -2355,7 +2355,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev) spin_lock_irqsave(&cctx->lock, flags); if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) { spin_unlock_irqrestore(&cctx->lock, flags); - dev_err(&pdev->dev, "too many sessions\n"); + dev_err(dev, "too many sessions\n"); return -ENOSPC; } dma_bits = cctx->soc_data->dma_addr_bits_default; @@ -2363,7 +2363,6 @@ static int fastrpc_cb_probe(struct platform_device *pdev) sess->used = false; sess->valid = true; sess->dev = dev; - dev_set_drvdata(dev, sess); sess->sid = sid; if (cctx->domain_id == CDSP_DOMAIN_ID) @@ -2389,37 +2388,51 @@ static int fastrpc_cb_probe(struct platform_device *pdev) return 0; } -static void fastrpc_cb_remove(struct platform_device *pdev) +static void fastrpc_cb_devices_destroy(struct rpmsg_device *rpdev) { - struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent); - struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev); + struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev); + struct device *rdev = &rpdev->dev; unsigned long flags; int i; spin_lock_irqsave(&cctx->lock, flags); - for (i = 0; i < FASTRPC_MAX_SESSIONS; i++) { - if (cctx->session[i].sid == sess->sid) { - cctx->session[i].valid = false; - cctx->sesscount--; - } - } + for (i = 0; i < cctx->sesscount; i++) + cctx->session[i].valid = false; spin_unlock_irqrestore(&cctx->lock, flags); + + device_for_each_child_reverse(rdev, NULL, of_platform_device_destroy); } -static const struct of_device_id fastrpc_match_table[] = { - { .compatible = "qcom,fastrpc-compute-cb" }, - { } -}; +static int fastrpc_cb_devices_create(struct rpmsg_device *rpdev) +{ + struct device *rdev = &rpdev->dev; + struct platform_device *pdev; + struct device_node *np; + int err; -static struct platform_driver fastrpc_cb_driver = { - .probe = fastrpc_cb_probe, - .remove = fastrpc_cb_remove, - .driver = { - .name = "qcom,fastrpc-cb", - .of_match_table = fastrpc_match_table, - .suppress_bind_attrs = true, - }, -}; + for_each_available_child_of_node(rdev->of_node, np) { + if (!of_device_is_compatible(np, "qcom,fastrpc-compute-cb")) { + of_node_put(np); + continue; + } + + pdev = of_platform_device_create(np, NULL, rdev); + if (!pdev) { + of_node_put(np); + fastrpc_cb_devices_destroy(rpdev); + return -ENODEV; + } + + err = fastrpc_cb_init(pdev); + if (err) { + of_node_put(np); + fastrpc_cb_devices_destroy(rpdev); + return err; + } + } + + return 0; +} static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ctx *cctx, bool is_secured, const char *domain) @@ -2639,7 +2652,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) data->rpdev = rpdev; dev_set_drvdata(&rpdev->dev, data); - err = of_platform_populate(rdev->of_node, NULL, NULL, rdev); + err = fastrpc_cb_devices_create(rpdev); if (err) goto err_deregister_fdev; @@ -2711,7 +2724,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) &cctx->remote_heap_addr, cctx->remote_heap_size, err); } - of_platform_depopulate(&rpdev->dev); + fastrpc_cb_devices_destroy(rpdev); fastrpc_channel_ctx_put(cctx); } @@ -2798,33 +2811,7 @@ static struct rpmsg_driver fastrpc_driver = { }, }; -static int fastrpc_init(void) -{ - int ret; - - ret = platform_driver_register(&fastrpc_cb_driver); - if (ret < 0) { - pr_err("fastrpc: failed to register cb driver\n"); - return ret; - } - - ret = register_rpmsg_driver(&fastrpc_driver); - if (ret < 0) { - pr_err("fastrpc: failed to register rpmsg driver\n"); - platform_driver_unregister(&fastrpc_cb_driver); - return ret; - } - - return 0; -} -module_init(fastrpc_init); - -static void fastrpc_exit(void) -{ - platform_driver_unregister(&fastrpc_cb_driver); - unregister_rpmsg_driver(&fastrpc_driver); -} -module_exit(fastrpc_exit); +module_rpmsg_driver(fastrpc_driver); MODULE_DESCRIPTION("Qualcomm FastRPC"); MODULE_LICENSE("GPL v2"); -- 2.34.1
