[PATCH 4/7] slimbus: qcom-ngd-ctrl: Register callbacks after creating the ngd

From: Bjorn Andersson

Date: Tue Mar 10 2026 - 00:11:42 EST


When the remoteproc starts in parallel with the NGD driver being probed,
or the remoteproc is already up when the PDR lookup is being registered,
or in the theoretical event that we get an interrupt from the hardware,
these callbacks will operate on uninitialized data. This result in
issues to boot the affected boards.

One such example can be seen in the following fault, where
qcom_slim_ngd_ssr_pdr_notify() schedules work on the NULL ngd_up_work.

[ 21.858578] ------------[ cut here ]------------
[ 21.858745] WARNING: kernel/workqueue.c:2338 at __queue_work+0x5e0/0x790, CPU#2: kworker/2:2/116
...
[ 21.859251] Call trace:
[ 21.859255] __queue_work+0x5e0/0x790 (P)
[ 21.859265] queue_work_on+0x6c/0xf0
[ 21.859273] qcom_slim_ngd_ssr_pdr_notify+0x110/0x150 [slim_qcom_ngd_ctrl]
[ 21.859304] qcom_slim_ngd_ssr_notify+0x24/0x40 [slim_qcom_ngd_ctrl]
[ 21.859318] notifier_call_chain+0xa4/0x230
[ 21.859329] srcu_notifier_call_chain+0x64/0xb8
[ 21.859338] ssr_notify_start+0x40/0x78 [qcom_common]
[ 21.859355] rproc_start+0x130/0x230
[ 21.859367] rproc_boot+0x3d4/0x518
...

Move the three registrations of interrupts, SSR and PDR until after the
NGD device has been registered.

This could be further refined by moving initialization to the control
driver probe and by removing the platform driver model from the picture.

Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxxxxxxxx>
---
drivers/slimbus/qcom-ngd-ctrl.c | 52 ++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 22 deletions(-)

diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 09ce3299e15c25b1b9cf6b1559850adf4aa20737..76944c515291a62fb9cb192bec5cd5c2caa542f4 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1613,6 +1613,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
struct qcom_slim_ngd_ctrl *ctrl;
int ret;
struct pdr_service *pds;
+ int irq;

ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
@@ -1624,19 +1625,9 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
if (IS_ERR(ctrl->base))
return PTR_ERR(ctrl->base);

- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
-
- ret = devm_request_irq(dev, ret, qcom_slim_ngd_interrupt,
- IRQF_TRIGGER_HIGH, "slim-ngd", ctrl);
- if (ret)
- return dev_err_probe(&pdev->dev, ret, "request IRQ failed\n");
-
- ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify;
- ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb);
- if (IS_ERR(ctrl->notifier))
- return PTR_ERR(ctrl->notifier);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;

ctrl->dev = dev;
ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
@@ -1659,24 +1650,41 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
init_completion(&ctrl->qmi_up);

ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl);
- if (IS_ERR(ctrl->pdr)) {
- ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr),
- "Failed to init PDR handle\n");
- goto err_unregister_ssr;
- }
+ if (IS_ERR(ctrl->pdr))
+ return dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n");
+
+ ret = of_qcom_slim_ngd_register(dev, ctrl);
+ if (ret)
+ goto err_pdr_release;

pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd");
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
ret = dev_err_probe(dev, PTR_ERR(pds), "pdr add lookup failed\n");
- goto err_pdr_release;
+ goto err_unregister_ngd;
}

- return of_qcom_slim_ngd_register(dev, ctrl);
+ ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify;
+ ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb);
+ if (IS_ERR(ctrl->notifier)) {
+ ret = PTR_ERR(ctrl->notifier);
+ goto err_unregister_ngd;
+ }
+
+ ret = devm_request_irq(dev, irq, qcom_slim_ngd_interrupt,
+ IRQF_TRIGGER_HIGH, "slim-ngd", ctrl);
+ if (ret) {
+ ret = dev_err_probe(&pdev->dev, ret, "request IRQ failed\n");
+ goto err_unregister_ssr;
+ }
+
+ return 0;

-err_pdr_release:
- pdr_handle_release(ctrl->pdr);
err_unregister_ssr:
qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
+err_unregister_ngd:
+ qcom_slim_ngd_unregister(ctrl);
+err_pdr_release:
+ pdr_handle_release(ctrl->pdr);

return ret;
}

--
2.51.0