From 4059c64d78b5d543dabae332922e763b4c95c79e Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 23 Jul 2026 03:52:29 +0000 Subject: [PATCH] remoteproc: Force shutdown during device removal rproc_del() is subjected to the reference counted shutdown path, as such a remoteproc with more than one reference will be left running as its resources are released underneath it. Refactor the shutdown path such that the reference count value is ignored when called from rproc_del(). Assisted-by: OpenCode:GPT-5.5 Signed-off-by: Bjorn Andersson Reviewed-by: Pradnya Dahiwale Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260723-rproc-rmmod-not-crashing-v1-3-546dfd5de0e6@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_core.c | 95 +++++++++++++++------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 899d2058bc45..1ed406714849 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1988,6 +1988,54 @@ int rproc_boot(struct rproc *rproc) } EXPORT_SYMBOL(rproc_boot); +static int __rproc_shutdown(struct rproc *rproc, bool force) +{ + struct device *dev = &rproc->dev; + bool crashed; + int ret; + + ret = mutex_lock_interruptible(&rproc->lock); + if (ret) { + dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); + return ret; + } + + if (rproc->state != RPROC_RUNNING && + rproc->state != RPROC_ATTACHED && + rproc->state != RPROC_CRASHED) { + ret = -EINVAL; + goto out; + } + crashed = rproc->state == RPROC_CRASHED; + + if (!atomic_dec_and_test(&rproc->power) && !force) { + /* The remote processor is still needed by another user. */ + goto out; + } + + ret = rproc_stop(rproc, crashed); + if (ret) { + atomic_inc(&rproc->power); + goto out; + } + + /* clean up all acquired resources */ + rproc_resource_cleanup(rproc); + + /* release HW resources if needed */ + rproc_unprepare_device(rproc); + + rproc_disable_iommu(rproc); + + /* Free the copy of the resource table */ + kfree(rproc->cached_table); + rproc->cached_table = NULL; + rproc->table_ptr = NULL; +out: + mutex_unlock(&rproc->lock); + return ret; +} + /** * rproc_shutdown() - power off the remote processor * @rproc: the remote processor @@ -2011,49 +2059,7 @@ EXPORT_SYMBOL(rproc_boot); */ int rproc_shutdown(struct rproc *rproc) { - struct device *dev = &rproc->dev; - bool crashed; - int ret; - - ret = mutex_lock_interruptible(&rproc->lock); - if (ret) { - dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); - return ret; - } - - if (rproc->state != RPROC_RUNNING && - rproc->state != RPROC_ATTACHED && - rproc->state != RPROC_CRASHED) { - ret = -EINVAL; - goto out; - } - crashed = rproc->state == RPROC_CRASHED; - - /* if the remote proc is still needed, bail out */ - if (!atomic_dec_and_test(&rproc->power)) - goto out; - - ret = rproc_stop(rproc, crashed); - if (ret) { - atomic_inc(&rproc->power); - goto out; - } - - /* clean up all acquired resources */ - rproc_resource_cleanup(rproc); - - /* release HW resources if needed */ - rproc_unprepare_device(rproc); - - rproc_disable_iommu(rproc); - - /* Free the copy of the resource table */ - kfree(rproc->cached_table); - rproc->cached_table = NULL; - rproc->table_ptr = NULL; -out: - mutex_unlock(&rproc->lock); - return ret; + return __rproc_shutdown(rproc, false); } EXPORT_SYMBOL(rproc_shutdown); @@ -2621,8 +2627,7 @@ int rproc_del(struct rproc *rproc) if (cancel_work_sync(&rproc->crash_handler)) pm_relax(rproc->dev.parent); - /* TODO: make sure this works with rproc->power > 1 */ - rproc_shutdown(rproc); + __rproc_shutdown(rproc, true); rproc_delete_debug_dir(rproc);