The stop() and unprepare() callbacks in struct rproc_subdev were void, making it impossible for implementations to report failures. Unlike prepare() and start() which already return int and have their errors checked, errors during teardown were silently discarded.
Change the callback signatures to return int. Update rproc_stop_subdevices() and rproc_unprepare_subdevices() to check each return value and emit a warning on failure while continuing to visit all remaining subdevices (best-effort teardown). rproc_vdev_do_stop() propagates the error from device_for_each_child() which it was already computing but had no way to surface. All other implementations (glink, smd, ssr, pdm, sysmon) gain a return 0 as they have no failure paths. Signed-off-by: Mukesh Ojha <[email protected]> --- drivers/remoteproc/qcom_common.c | 26 +++++++++++++++++++------- drivers/remoteproc/qcom_sysmon.c | 10 +++++++--- drivers/remoteproc/remoteproc_core.c | 16 ++++++++++++---- drivers/remoteproc/remoteproc_virtio.c | 4 +++- drivers/rpmsg/mtk_rpmsg.c | 8 ++++++-- include/linux/remoteproc.h | 4 ++-- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index fd2b6824ad26..05a599318763 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -216,19 +216,23 @@ static int glink_subdev_start(struct rproc_subdev *subdev) return PTR_ERR_OR_ZERO(glink->edge); } -static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed) +static int glink_subdev_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); qcom_glink_smem_unregister(glink->edge); glink->edge = NULL; + + return 0; } -static void glink_subdev_unprepare(struct rproc_subdev *subdev) +static int glink_subdev_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); qcom_glink_ssr_notify(glink->ssr_name); + + return 0; } /** @@ -327,12 +331,14 @@ static int smd_subdev_start(struct rproc_subdev *subdev) return PTR_ERR_OR_ZERO(smd->edge); } -static void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed) +static int smd_subdev_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); qcom_smd_unregister_edge(smd->edge); smd->edge = NULL; + + return 0; } /** @@ -465,7 +471,7 @@ static int ssr_notify_start(struct rproc_subdev *subdev) return 0; } -static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) +static int ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); struct qcom_ssr_notify_data data = { @@ -475,9 +481,11 @@ static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) srcu_notifier_call_chain(&ssr->info->notifier_list, QCOM_SSR_BEFORE_SHUTDOWN, &data); + + return 0; } -static void ssr_notify_unprepare(struct rproc_subdev *subdev) +static int ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); struct qcom_ssr_notify_data data = { @@ -487,6 +495,8 @@ static void ssr_notify_unprepare(struct rproc_subdev *subdev) srcu_notifier_call_chain(&ssr->info->notifier_list, QCOM_SSR_AFTER_SHUTDOWN, &data); + + return 0; } /** @@ -572,16 +582,18 @@ static int pdm_notify_prepare(struct rproc_subdev *subdev) } -static void pdm_notify_unprepare(struct rproc_subdev *subdev) +static int pdm_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_pdm *pdm = to_pdm_subdev(subdev); if (!pdm->adev) - return; + return 0; auxiliary_device_delete(pdm->adev); auxiliary_device_uninit(pdm->adev); pdm->adev = NULL; + + return 0; } /** diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index 913e3b750a86..44b905a7e129 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -531,7 +531,7 @@ static int sysmon_start(struct rproc_subdev *subdev) return 0; } -static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) +static int sysmon_stop(struct rproc_subdev *subdev, bool crashed) { struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); struct sysmon_event event = { @@ -548,7 +548,7 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) /* Don't request graceful shutdown if we've crashed */ if (crashed) - return; + return 0; if (sysmon->ssctl_instance) { if (!wait_for_completion_timeout(&sysmon->ssctl_comp, HZ / 2)) @@ -559,9 +559,11 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed) sysmon->shutdown_acked = ssctl_request_shutdown(sysmon); else if (sysmon->ept) sysmon->shutdown_acked = sysmon_request_shutdown(sysmon); + + return 0; } -static void sysmon_unprepare(struct rproc_subdev *subdev) +static int sysmon_unprepare(struct rproc_subdev *subdev) { struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev); @@ -574,6 +576,8 @@ static void sysmon_unprepare(struct rproc_subdev *subdev) sysmon->state = SSCTL_SSR_EVENT_AFTER_SHUTDOWN; blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event); mutex_unlock(&sysmon->state_lock); + + return 0; } /** diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index f003be006b1b..21127d972bff 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1113,20 +1113,28 @@ static int rproc_start_subdevices(struct rproc *rproc) static void rproc_stop_subdevices(struct rproc *rproc, bool crashed) { struct rproc_subdev *subdev; + int ret; list_for_each_entry_reverse(subdev, &rproc->subdevs, node) { - if (subdev->stop) - subdev->stop(subdev, crashed); + if (subdev->stop) { + ret = subdev->stop(subdev, crashed); + if (ret) + dev_warn(&rproc->dev, "subdev stop failed: %d\n", ret); + } } } static void rproc_unprepare_subdevices(struct rproc *rproc) { struct rproc_subdev *subdev; + int ret; list_for_each_entry_reverse(subdev, &rproc->subdevs, node) { - if (subdev->unprepare) - subdev->unprepare(subdev); + if (subdev->unprepare) { + ret = subdev->unprepare(subdev); + if (ret) + dev_warn(&rproc->dev, "subdev unprepare failed: %d\n", ret); + } } } diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index d5e9ff045a28..128d3088a959 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -480,7 +480,7 @@ static int rproc_vdev_do_start(struct rproc_subdev *subdev) return rproc_add_virtio_dev(rvdev, rvdev->id); } -static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed) +static int rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed) { struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev); struct device *dev = &rvdev->pdev->dev; @@ -489,6 +489,8 @@ static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed) ret = device_for_each_child(dev, NULL, rproc_remove_virtio_dev); if (ret) dev_warn(dev, "can't remove vdev child device: %d\n", ret); + + return ret; } static int rproc_virtio_probe(struct platform_device *pdev) diff --git a/drivers/rpmsg/mtk_rpmsg.c b/drivers/rpmsg/mtk_rpmsg.c index 1b670ed54cfa..d8ea77055f31 100644 --- a/drivers/rpmsg/mtk_rpmsg.c +++ b/drivers/rpmsg/mtk_rpmsg.c @@ -326,7 +326,7 @@ static int mtk_rpmsg_prepare(struct rproc_subdev *subdev) return 0; } -static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev) +static int mtk_rpmsg_unprepare(struct rproc_subdev *subdev) { struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); @@ -334,9 +334,11 @@ static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev) mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); mtk_subdev->ns_ept = NULL; } + + return 0; } -static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) +static int mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) { struct mtk_rpmsg_channel_info *info, *next; struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); @@ -372,6 +374,8 @@ static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) kfree(info); } mutex_unlock(&mtk_subdev->channels_lock); + + return 0; } struct rproc_subdev * diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 7c1546d48008..315c479d163a 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -335,8 +335,8 @@ struct rproc_subdev { int (*prepare)(struct rproc_subdev *subdev); int (*start)(struct rproc_subdev *subdev); - void (*stop)(struct rproc_subdev *subdev, bool crashed); - void (*unprepare)(struct rproc_subdev *subdev); + int (*stop)(struct rproc_subdev *subdev, bool crashed); + int (*unprepare)(struct rproc_subdev *subdev); }; /* we currently support only two vrings per rvdev */ -- 2.53.0

