]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
boot: Support rescanning the global bootmeths
authorSimon Glass <sjg@chromium.org>
Wed, 15 Oct 2025 15:44:09 +0000 (16:44 +0100)
committerTom Rini <trini@konsulko.com>
Wed, 22 Oct 2025 20:16:56 +0000 (14:16 -0600)
Add the logic to scan through the global bootmeths for every new
bootdev, in preparation for allowing global bootmeths to select where in
the hunter ordering they go.

Use a new bootmeth_glob_allowed() function to check if a bootmeth is
allowed, ensuring that each can run at most once.

For now this has no actual effect, since the global bootmeths are
unconditionally processed at the start, with iter->methods_done being
updated to include all of them. Therefore when scanning again, no
unprocessed global bootmeths will be found.

Signed-off-by: Simon Glass <sjg@chromium.org>
boot/bootflow.c
include/bootflow.h

index 2e4d1a345cd8beac8a263ff650179b2c5b93272c..73deba24d307f939d5e88d9245019df3f4e6bfb7 100644 (file)
@@ -187,19 +187,81 @@ static void scan_next_in_uclass(struct udevice **devp)
        *devp = dev;
 }
 
+/**
+ * bootmeth_glob_allowed() - Check if a global bootmeth is usable at this point
+ *
+ * @iter: Bootflow iterator being used
+ * Return: true if the global bootmeth has not already been used
+ */
+static bool bootmeth_glob_allowed(struct bootflow_iter *iter, int meth_seq)
+{
+       struct udevice *meth = iter->method_order[meth_seq];
+       bool done = iter->methods_done & BIT(meth_seq);
+
+       log_debug("considering glob '%s': done %d\n", meth->name, done);
+
+       /* if this one has already been used, try the next */
+       if (done)
+               return false;
+
+       return true;
+}
+
+/**
+ * next_glob_bootmeth() - Find the next global bootmeth to use
+ *
+ * Scans the global bootmeths to find the first unused one whose priority has
+ * been reached. If found, iter->cur_method and iter->method are set up and
+ * doing_global is set to true
+ *
+ * @iter: Bootflow iterator being used
+ * Return 0 if found, -ENOENT if no more global bootmeths are available
+ */
+static int next_glob_bootmeth(struct bootflow_iter *iter)
+{
+       log_debug("rescan global bootmeths have_global %d\n",
+                 iter->have_global);
+       if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->have_global) {
+               int i;
+
+               /* rescan the global bootmeths */
+               log_debug("first_glob_method %d num_methods %d methods_done %x\n",
+                         iter->first_glob_method, iter->num_methods,
+                         iter->methods_done);
+               for (i = iter->first_glob_method; i < iter->num_methods; i++) {
+                       if (bootmeth_glob_allowed(iter, i)) {
+                               iter->cur_method = i;
+                               iter->method = iter->method_order[i];
+                               iter->doing_global = true;
+                               iter->dev = NULL;
+                               return 0;
+                       }
+               }
+       }
+
+       return -ENOENT;
+}
+
 /**
  * prepare_bootdev() - Get ready to use a bootdev
  *
  * @iter: Bootflow iterator being used
  * @dev: UCLASS_BOOTDEV device to use
  * @method_flags: Method flag for the bootdev
+ * @check_global: true to check global bootmeths before processing @dev
  * Return 0 if OK, -ve if the bootdev failed to probe
  */
 static int prepare_bootdev(struct bootflow_iter *iter, struct udevice *dev,
-                          int method_flags)
+                          int method_flags, bool check_global)
 {
        int ret;
 
+       if (check_global && !next_glob_bootmeth(iter)) {
+               iter->pending_bootdev = dev;
+               iter->pending_method_flags = method_flags;
+               return 0;
+       }
+
        /*
         * Probe the bootdev. This does not probe any attached block device,
         * since they are siblings
@@ -245,6 +307,30 @@ static int iter_incr(struct bootflow_iter *iter)
                iter->num_methods = iter->first_glob_method;
                iter->doing_global = false;
 
+               /*
+                * we've come to the end, so see if we should use a pending
+                * bootdev from when we decided to rescan the global bootmeths
+                */
+               if (iter->pending_bootdev) {
+                       int meth_flags = iter->pending_method_flags;
+
+                       dev = iter->pending_bootdev;
+                       iter->pending_bootdev = NULL;
+                       iter->pending_method_flags = 0;
+
+                       ret = prepare_bootdev(iter, dev, meth_flags, false);
+                       if (ret)
+                               return log_msg_ret("ipb", ret);
+
+                       iter->cur_method = 0;
+                       iter->method = iter->method_order[iter->cur_method];
+
+                       log_debug("-> using pending bootdev '%s' method '%s'\n",
+                                 dev->name, iter->method->name);
+
+                       return 0;
+               }
+
                /*
                 * Don't move to the next dev as we haven't tried this
                 * one yet!
@@ -347,7 +433,7 @@ static int iter_incr(struct bootflow_iter *iter)
                if (ret)
                        bootflow_iter_set_dev(iter, NULL, 0);
                else
-                       ret = prepare_bootdev(iter, dev, method_flags);
+                       ret = prepare_bootdev(iter, dev, method_flags, true);
        }
 
        /* if there are no more bootdevs, give up */
index 58a4ab9f8110f1bfa8a411c6f604f3b2503eb685..059d38251b73d28ff6332e1bc0effeb5816c291d 100644 (file)
@@ -267,6 +267,9 @@ enum {
  * (enum bootflow_meth_flags_t)
  * @methods_done: indicates which methods have been processed, one bit for
  * each method in @method_order[]
+ * @pending_bootdev: if non-NULL, bootdev which will be used when the global
+ * bootmeths are done
+ * @pending_method_flags: method flags which will be used with @pending_bootdev
  */
 struct bootflow_iter {
        int flags;
@@ -290,6 +293,8 @@ struct bootflow_iter {
        bool doing_global;
        int method_flags;
        uint methods_done;
+       struct udevice *pending_bootdev;
+       int pending_method_flags;
 };
 
 /**