Unlike the remoteproc firmware load path where rproc_add() call
rproc_auto_boot_callback() asynchronously and ignores the return value of
rproc_boot(), the attach path calls rproc_boot() synchronously and
propagates its return value back to rproc_add(). This means a failure
during rproc_attach() causes rproc_add() to fail and triggers resource
release, removing the remoteproc from sysfs and making it unavailable for
recovery or further boot attempts.

Align the remoteproc attach path with the firmware load path by
introducing attach_work and scheduling rproc_boot() asynchronously via
schedule_work(). This keeps the remoteproc registered and available in
sysfs even if the initial attach attempt fails, and avoids blocking
rproc_add() on the attach result.

Signed-off-by: Jingyi Wang <[email protected]>
---
 drivers/remoteproc/remoteproc_core.c | 20 ++++++++++++--------
 include/linux/remoteproc.h           |  2 ++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index b087ed21858a..f02db1113fae 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1673,18 +1673,21 @@ static void rproc_auto_boot_callback(const struct 
firmware *fw, void *context)
        release_firmware(fw);
 }
 
+static void rproc_attach_work(struct work_struct *work)
+{
+       struct rproc *rproc = container_of(work, struct rproc, attach_work);
+
+       rproc_boot(rproc);
+}
+
 static int rproc_trigger_auto_boot(struct rproc *rproc)
 {
        int ret;
 
-       /*
-        * Since the remote processor is in a detached state, it has already
-        * been booted by another entity.  As such there is no point in waiting
-        * for a firmware image to be loaded, we can simply initiate the process
-        * of attaching to it immediately.
-        */
-       if (rproc->state == RPROC_DETACHED)
-               return rproc_boot(rproc);
+       if (rproc->state == RPROC_DETACHED) {
+               schedule_work(&rproc->attach_work);
+               return 0;
+       }
 
        /*
         * We're initiating an asynchronous firmware loading, so we can
@@ -2512,6 +2515,7 @@ struct rproc *rproc_alloc(struct device *dev, const char 
*name,
        INIT_LIST_HEAD(&rproc->dump_segments);
 
        INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
+       INIT_WORK(&rproc->attach_work, rproc_attach_work);
 
        rproc->state = RPROC_OFFLINE;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b4795698d8c2..580d324a1e8f 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -526,6 +526,7 @@ enum rproc_features {
  * @subdevs: list of subdevices, to following the running state
  * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
  * @index: index of this rproc device
+ * @attach_work: workqueue for attaching rproc
  * @crash_handler: workqueue for handling a crash
  * @crash_cnt: crash counter
  * @recovery_disabled: flag that state if recovery was disabled
@@ -568,6 +569,7 @@ struct rproc {
        struct list_head subdevs;
        struct idr notifyids;
        int index;
+       struct work_struct attach_work;
        struct work_struct crash_handler;
        unsigned int crash_cnt;
        bool recovery_disabled;

-- 
2.34.1


Reply via email to