[PATCH v2 11/17] boot: Support rescanning the global bootmeths

Simon Glass sjg at chromium.org
Wed Oct 1 23:26:36 CEST 2025


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 at chromium.org>
---

(no changes since v1)

 boot/bootflow.c    | 90 ++++++++++++++++++++++++++++++++++++++++++++--
 include/bootflow.h |  5 +++
 2 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/boot/bootflow.c b/boot/bootflow.c
index 4218b53d19f..711b971c419 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -245,19 +245,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
@@ -308,6 +370,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!
@@ -416,7 +502,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 */
diff --git a/include/bootflow.h b/include/bootflow.h
index 6437a6ef5e4..ec19f8dc436 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -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;
 };
 
 /**
-- 
2.43.0



More information about the U-Boot mailing list