The work structs and work queue are controller resources, create and
destroy them in the controller context. Creating them as part of the
child device's probe path seems to be okay now that the controller's
probe has been updated, but if for some reason the child does not probe
successfully a SSR or PDR notification will schedule_work() on an
uninitialized "ngd_up_work".
Move the initialization of these controller resources to the controller
probe function to avoid any issues, and to clarify the ownership.
Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver")
Cc: stable@vger.kernel.org
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
---
drivers/slimbus/qcom-ngd-ctrl.c | 38 ++++++++++++++++----------------------
1 file changed, 16 insertions(+), 22 deletions(-)
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 76944c515291a62fb9cb192bec5cd5c2caa542f4..d932f7fd6170773890f561e3af444ac2c5730338 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1584,25 +1584,8 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_noresume(dev);
ret = qcom_slim_ngd_qmi_svc_event_init(ctrl);
- if (ret) {
+ if (ret)
dev_err(&pdev->dev, "QMI service registration failed:%d", ret);
- return ret;
- }
-
- INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
- INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
- ctrl->mwq = create_singlethread_workqueue("ngd_master");
- if (!ctrl->mwq) {
- dev_err(&pdev->dev, "Failed to start master worker\n");
- ret = -ENOMEM;
- goto wq_err;
- }
-
- return 0;
-wq_err:
- qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
- if (ctrl->mwq)
- destroy_workqueue(ctrl->mwq);
return ret;
}
@@ -1649,9 +1632,18 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
init_completion(&ctrl->qmi.qmi_comp);
init_completion(&ctrl->qmi_up);
+ INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
+ INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
+
+ ctrl->mwq = create_singlethread_workqueue("ngd_master");
+ if (!ctrl->mwq)
+ return dev_err_probe(dev, -ENOMEM, "Failed to start master worker\n");
+
ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl);
- if (IS_ERR(ctrl->pdr))
- return dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
+ if (IS_ERR(ctrl->pdr)) {
+ ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
+ goto err_destroy_mwq;
+ }
ret = of_qcom_slim_ngd_register(dev, ctrl);
if (ret)
@@ -1685,6 +1677,8 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
qcom_slim_ngd_unregister(ctrl);
err_pdr_release:
pdr_handle_release(ctrl->pdr);
+err_destroy_mwq:
+ destroy_workqueue(ctrl->mwq);
return ret;
}
@@ -1697,6 +1691,8 @@ static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev)
qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
qcom_slim_ngd_unregister(ctrl);
+
+ destroy_workqueue(ctrl->mwq);
}
static void qcom_slim_ngd_remove(struct platform_device *pdev)
@@ -1707,8 +1703,6 @@ static void qcom_slim_ngd_remove(struct platform_device *pdev)
qcom_slim_ngd_enable(ctrl, false);
qcom_slim_ngd_exit_dma(ctrl);
qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
- if (ctrl->mwq)
- destroy_workqueue(ctrl->mwq);
kfree(ctrl->ngd);
ctrl->ngd = NULL;
--
2.51.0
On Mon, Mar 09, 2026 at 11:09:06PM -0500, Bjorn Andersson wrote:
> The work structs and work queue are controller resources, create and
> destroy them in the controller context. Creating them as part of the
> child device's probe path seems to be okay now that the controller's
> probe has been updated, but if for some reason the child does not probe
> successfully a SSR or PDR notification will schedule_work() on an
> uninitialized "ngd_up_work".
>
> Move the initialization of these controller resources to the controller
> probe function to avoid any issues, and to clarify the ownership.
>
> Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
> ---
> drivers/slimbus/qcom-ngd-ctrl.c | 38 ++++++++++++++++----------------------
> 1 file changed, 16 insertions(+), 22 deletions(-)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
On Mon, Mar 09, 2026 at 11:09:06PM -0500, Bjorn Andersson wrote:
> The work structs and work queue are controller resources, create and
> destroy them in the controller context. Creating them as part of the
> child device's probe path seems to be okay now that the controller's
> probe has been updated, but if for some reason the child does not probe
> successfully a SSR or PDR notification will schedule_work() on an
> uninitialized "ngd_up_work".
>
> Move the initialization of these controller resources to the controller
> probe function to avoid any issues, and to clarify the ownership.
>
> Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
> ---
> drivers/slimbus/qcom-ngd-ctrl.c | 38 ++++++++++++++++----------------------
> 1 file changed, 16 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
> index 76944c515291a62fb9cb192bec5cd5c2caa542f4..d932f7fd6170773890f561e3af444ac2c5730338 100644
> --- a/drivers/slimbus/qcom-ngd-ctrl.c
> +++ b/drivers/slimbus/qcom-ngd-ctrl.c
> @@ -1584,25 +1584,8 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
> pm_runtime_enable(dev);
> pm_runtime_get_noresume(dev);
> ret = qcom_slim_ngd_qmi_svc_event_init(ctrl);
> - if (ret) {
> + if (ret)
> dev_err(&pdev->dev, "QMI service registration failed:%d", ret);
> - return ret;
> - }
> -
> - INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
> - INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
> - ctrl->mwq = create_singlethread_workqueue("ngd_master");
> - if (!ctrl->mwq) {
> - dev_err(&pdev->dev, "Failed to start master worker\n");
> - ret = -ENOMEM;
> - goto wq_err;
> - }
> -
> - return 0;
> -wq_err:
> - qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
> - if (ctrl->mwq)
> - destroy_workqueue(ctrl->mwq);
>
> return ret;
> }
> @@ -1649,9 +1632,18 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
> init_completion(&ctrl->qmi.qmi_comp);
> init_completion(&ctrl->qmi_up);
>
> + INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
> + INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
> +
> + ctrl->mwq = create_singlethread_workqueue("ngd_master");
> + if (!ctrl->mwq)
> + return dev_err_probe(dev, -ENOMEM, "Failed to start master worker\n");
> +
> ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl);
> - if (IS_ERR(ctrl->pdr))
> - return dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
> + if (IS_ERR(ctrl->pdr)) {
> + ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
> + goto err_destroy_mwq;
> + }
>
> ret = of_qcom_slim_ngd_register(dev, ctrl);
> if (ret)
> @@ -1685,6 +1677,8 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
> qcom_slim_ngd_unregister(ctrl);
> err_pdr_release:
> pdr_handle_release(ctrl->pdr);
> +err_destroy_mwq:
> + destroy_workqueue(ctrl->mwq);
>
> return ret;
> }
> @@ -1697,6 +1691,8 @@ static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev)
> qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
>
> qcom_slim_ngd_unregister(ctrl);
> +
> + destroy_workqueue(ctrl->mwq);
> }
>
> static void qcom_slim_ngd_remove(struct platform_device *pdev)
> @@ -1707,8 +1703,6 @@ static void qcom_slim_ngd_remove(struct platform_device *pdev)
> qcom_slim_ngd_enable(ctrl, false);
> qcom_slim_ngd_exit_dma(ctrl);
> qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
> - if (ctrl->mwq)
> - destroy_workqueue(ctrl->mwq);
>
> kfree(ctrl->ngd);
> ctrl->ngd = NULL;
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
> --
> 2.51.0
>
--
-Mukesh Ojha
© 2016 - 2026 Red Hat, Inc.