[PATCH v3 65/70] bootstd: Allow scanning a single bootdev label

Simon Glass sjg at chromium.org
Tue Jan 17 18:48:15 CET 2023


We want to support scanning a single label, like 'mmc' or 'usb0'. Add
this feature by plumbing the label through to the iterator, setting a
flag to indicate that only siblings of the initial device should be used.

This means that scanning a bootdev by its name is not supported anymore.
That feature doesn't seem very useful in practice, so it is no great loss.

Add a test for bootdev_find_by_any() while we are here.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v1)

 boot/bootdev-uclass.c | 28 ++++++++++----
 boot/bootflow.c       | 43 +++++++++++++++++++---
 cmd/bootflow.c        | 86 +++++++++++++++++--------------------------
 include/bootdev.h     | 11 ++++--
 include/bootflow.h    | 10 +++--
 test/boot/bootdev.c   |  2 +-
 test/boot/bootflow.c  | 62 ++++++++++++++++++++++++++++++-
 7 files changed, 166 insertions(+), 76 deletions(-)

diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index 334be7662a1..522ecf38eb3 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -649,10 +649,10 @@ int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp)
 	return 0;
 }
 
-int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp,
-		       int *method_flagsp)
+int bootdev_setup_iter(struct bootflow_iter *iter, const char *label,
+		       struct udevice **devp, int *method_flagsp)
 {
-	struct udevice *bootstd, *dev = *devp;
+	struct udevice *bootstd, *dev = NULL;
 	bool show = iter->flags & BOOTFLOWF_SHOW;
 	int method_flags;
 	int ret;
@@ -671,10 +671,24 @@ int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp,
 	}
 
 	/* Handle scanning a single device */
-	if (dev) {
-		iter->flags |= BOOTFLOWF_SINGLE_DEV;
-		log_debug("Selected boodev: %s\n", dev->name);
-		method_flags = 0;
+	if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && label) {
+		if (iter->flags & BOOTFLOWF_HUNT) {
+			ret = bootdev_hunt(label, show);
+			if (ret)
+				return log_msg_ret("hun", ret);
+		}
+		ret = bootdev_find_by_any(label, &dev, &method_flags);
+		if (ret)
+			return log_msg_ret("lab", ret);
+
+		log_debug("method_flags: %x\n", method_flags);
+		if (method_flags & BOOTFLOW_METHF_SINGLE_UCLASS)
+			iter->flags |= BOOTFLOWF_SINGLE_UCLASS;
+		else if (method_flags & BOOTFLOW_METHF_SINGLE_DEV)
+			iter->flags |= BOOTFLOWF_SINGLE_DEV;
+		else
+			iter->flags |= BOOTFLOWF_SINGLE_MEDIA;
+		log_debug("Selected label: %s, flags %x\n", label, iter->flags);
 	} else {
 		bool ok;
 
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 32e2aad470d..50d9c2e813a 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -215,7 +215,37 @@ static int iter_incr(struct bootflow_iter *iter)
 		dev = iter->dev;
 		log_debug("inc_dev=%d\n", inc_dev);
 		if (!inc_dev) {
-			ret = bootdev_setup_iter(iter, &dev, &method_flags);
+			ret = bootdev_setup_iter(iter, NULL, &dev,
+						 &method_flags);
+		} else if (IS_ENABLED(CONFIG_BOOTSTD_FULL) &&
+			   (iter->flags & BOOTFLOWF_SINGLE_UCLASS)) {
+			/* Move to the next bootdev in this uclass */
+			uclass_find_next_device(&dev);
+			if (!dev) {
+				log_debug("finished uclass %s\n",
+					  dev_get_uclass_name(dev));
+				ret = -ENODEV;
+			}
+		} else if (IS_ENABLED(CONFIG_BOOTSTD_FULL) &&
+			   iter->flags & BOOTFLOWF_SINGLE_MEDIA) {
+			log_debug("next in single\n");
+			method_flags = 0;
+			do {
+				/*
+				 * Move to the next bootdev child of this media
+				 * device. This ensures that we cover all the
+				 * available SCSI IDs and LUNs.
+				 */
+				device_find_next_child(&dev);
+				log_debug("- next %s\n",
+					dev ? dev->name : "(none)");
+			} while (dev && device_get_uclass_id(dev) !=
+				UCLASS_BOOTDEV);
+			if (!dev) {
+				log_debug("finished uclass %s\n",
+					  dev_get_uclass_name(dev));
+				ret = -ENODEV;
+			}
 		} else {
 			log_debug("labels %p\n", iter->labels);
 			if (iter->labels) {
@@ -294,12 +324,13 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow)
 	return 0;
 }
 
-int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
-			  int flags, struct bootflow *bflow)
+int bootflow_scan_bootdev(struct udevice *dev, const char *label,
+			  struct bootflow_iter *iter, int flags,
+			  struct bootflow *bflow)
 {
 	int ret;
 
-	if (dev)
+	if (dev || label)
 		flags |= BOOTFLOWF_SKIP_GLOBAL;
 	bootflow_iter_init(iter, flags);
 
@@ -318,7 +349,7 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
 		struct udevice *dev = NULL;
 		int method_flags;
 
-		ret = bootdev_setup_iter(iter, &dev, &method_flags);
+		ret = bootdev_setup_iter(iter, label, &dev, &method_flags);
 		if (ret)
 			return log_msg_ret("obdev", -ENODEV);
 
@@ -345,7 +376,7 @@ int bootflow_scan_first(struct bootflow_iter *iter, int flags,
 {
 	int ret;
 
-	ret = bootflow_scan_bootdev(NULL, iter, flags, bflow);
+	ret = bootflow_scan_bootdev(NULL, NULL, iter, flags, bflow);
 	if (ret)
 		return log_msg_ret("start", ret);
 
diff --git a/cmd/bootflow.c b/cmd/bootflow.c
index fe58de5fa59..72d5a8424e9 100644
--- a/cmd/bootflow.c
+++ b/cmd/bootflow.c
@@ -93,11 +93,12 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
 {
 	struct bootstd_priv *std;
 	struct bootflow_iter iter;
-	struct udevice *dev;
+	struct udevice *dev = NULL;
 	struct bootflow bflow;
 	bool all = false, boot = false, errors = false, no_global = false;
 	bool list = false, no_hunter = false;
 	int num_valid = 0;
+	const char *label = NULL;
 	bool has_args;
 	int ret, i;
 	int flags;
@@ -105,7 +106,6 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
 	ret = bootstd_get_priv(&std);
 	if (ret)
 		return CMD_RET_FAILURE;
-	dev = std->cur_bootdev;
 
 	has_args = argc > 1 && *argv[1] == '-';
 	if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
@@ -119,12 +119,10 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
 			argc--;
 			argv++;
 		}
-		if (argc > 1) {
-			const char *label = argv[1];
-
-			if (bootdev_find_by_any(label, &dev, NULL))
-				return CMD_RET_FAILURE;
-		}
+		if (argc > 1)
+			label = argv[1];
+		if (!label)
+			dev = std->cur_bootdev;
 	} else {
 		if (has_args) {
 			printf("Flags not supported: enable CONFIG_BOOTFLOW_FULL\n");
@@ -148,54 +146,36 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
 	/*
 	 * If we have a device, just scan for bootflows attached to that device
 	 */
-	if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && dev) {
-		if (list) {
-			printf("Scanning for bootflows in bootdev '%s'\n",
-			       dev->name);
-			show_header();
-		}
+	if (list) {
+		printf("Scanning for bootflows ");
+		if (dev)
+			printf("in bootdev '%s'\n", dev->name);
+		else if (label)
+			printf("with label '%s'\n", label);
+		else
+			printf("in all bootdevs\n");
+		show_header();
+	}
+	if (dev)
 		bootdev_clear_bootflows(dev);
-		for (i = 0,
-		     ret = bootflow_scan_bootdev(dev, &iter, flags, &bflow);
-		     i < 1000 && ret != -ENODEV;
-		     i++, ret = bootflow_scan_next(&iter, &bflow)) {
-			bflow.err = ret;
-			if (!ret)
-				num_valid++;
-			ret = bootdev_add_bootflow(&bflow);
-			if (ret) {
-				printf("Out of memory\n");
-				return CMD_RET_FAILURE;
-			}
-			if (list)
-				show_bootflow(i, &bflow, errors);
-			if (boot && !bflow.err)
-				bootflow_run_boot(&iter, &bflow);
-		}
-	} else {
-		if (list) {
-			printf("Scanning for bootflows in all bootdevs\n");
-			show_header();
-		}
+	else
 		bootstd_clear_glob();
-
-		for (i = 0,
-		     ret = bootflow_scan_first(&iter, flags, &bflow);
-		     i < 1000 && ret != -ENODEV;
-		     i++, ret = bootflow_scan_next(&iter, &bflow)) {
-			bflow.err = ret;
-			if (!ret)
-				num_valid++;
-			ret = bootdev_add_bootflow(&bflow);
-			if (ret) {
-				printf("Out of memory\n");
-				return CMD_RET_FAILURE;
-			}
-			if (list)
-				show_bootflow(i, &bflow, errors);
-			if (boot && !bflow.err)
-				bootflow_run_boot(&iter, &bflow);
+	for (i = 0,
+	     ret = bootflow_scan_bootdev(dev, label, &iter, flags, &bflow);
+	     i < 1000 && ret != -ENODEV;
+	     i++, ret = bootflow_scan_next(&iter, &bflow)) {
+		bflow.err = ret;
+		if (!ret)
+			num_valid++;
+		ret = bootdev_add_bootflow(&bflow);
+		if (ret) {
+			printf("Out of memory\n");
+			return CMD_RET_FAILURE;
 		}
+		if (list)
+			show_bootflow(i, &bflow, errors);
+		if (boot && !bflow.err)
+			bootflow_run_boot(&iter, &bflow);
 	}
 	bootflow_iter_uninit(&iter);
 	if (list)
diff --git a/include/bootdev.h b/include/bootdev.h
index 8fa67487c63..b92ff4d4f15 100644
--- a/include/bootdev.h
+++ b/include/bootdev.h
@@ -267,10 +267,13 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
 /**
  * bootdev_setup_iter() - Set up iteration through bootdevs
  *
- * This sets up the an interation, based on the priority of each bootdev, the
- * bootdev-order property in the bootstd node (or the boot_targets env var).
+ * This sets up the an interation, based on the provided device or label. If
+ * neither is provided, the iteration is based on the priority of each bootdev,
+ * the * bootdev-order property in the bootstd node (or the boot_targets env
+ * var).
  *
  * @iter: Iterator to update with the order
+ * @label: label to scan, or NULL to scan all
  * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
  *	device to scan. Returns the first device to use, which is the passed-in
  *	@devp if it was non-NULL
@@ -279,8 +282,8 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
  * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
  *	on other error
  */
-int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp,
-		       int *method_flagsp);
+int bootdev_setup_iter(struct bootflow_iter *iter, const char *label,
+		       struct udevice **devp, int *method_flagsp);
 
 /**
  * bootdev_list_hunters() - List the available bootdev hunters
diff --git a/include/bootflow.h b/include/bootflow.h
index bdb37352ab9..1b7920a9572 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -255,14 +255,18 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
  *
  * @dev:	Boot device to scan, NULL to work through all of them until it
  *	finds one that can supply a bootflow
+ * @label:	Label to control the scan, NULL to work through all devices
+ *	until it finds one that can supply a bootflow
  * @iter:	Place to store private info (inited by this call)
- * @flags:	Flags for iterator (enum bootflow_flags_t)
+ * @flags:	Flags for iterator (enum bootflow_flags_t). Note that if @dev
+ * is NULL, then BOOTFLOWF_SKIP_GLOBAL is set automatically by this function
  * @bflow:	Place to put the bootflow if found
  * Return: 0 if found,  -ENODEV if no device, other -ve on other error
  *	(iteration can continue)
  */
-int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
-			  int flags, struct bootflow *bflow);
+int bootflow_scan_bootdev(struct udevice *dev, const char *label,
+			  struct bootflow_iter *iter, int flags,
+			  struct bootflow *bflow);
 
 /**
  * bootflow_scan_first() - find the first bootflow
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c
index 679ffc4d8df..1724e34af3e 100644
--- a/test/boot/bootdev.c
+++ b/test/boot/bootdev.c
@@ -626,7 +626,7 @@ static int bootdev_test_next_prio(struct unit_test_state *uts)
 	struct udevice *dev;
 	int ret;
 
-	sandbox_set_eth_enable(false);
+	test_set_eth_enable(false);
 	test_set_skip_delays(true);
 
 	/* get access to the used hunters */
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 1a2c54c1119..0b3a2fa6acc 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -76,7 +76,6 @@ static int bootflow_cmd(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
 
-#if 0 /* disable for now */
 /* Check 'bootflow scan' with a label / seq */
 static int bootflow_cmd_label(struct unit_test_state *uts)
 {
@@ -124,7 +123,6 @@ static int bootflow_cmd_label(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_cmd_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
 	     UT_TESTF_ETH_BOOTDEV);
-#endif
 
 /* Check 'bootflow scan/list' commands using all bootdevs */
 static int bootflow_cmd_glob(struct unit_test_state *uts)
@@ -564,6 +562,66 @@ static int bootflow_cmd_menu(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
 
+/* Check searching for a single bootdev using the hunters */
+static int bootflow_cmd_hunt_single(struct unit_test_state *uts)
+{
+	struct bootstd_priv *std;
+
+	/* get access to the used hunters */
+	ut_assertok(bootstd_get_priv(&std));
+
+	ut_assertok(bootstd_test_drop_bootdev_order(uts));
+
+	console_record_reset_enable();
+	ut_assertok(run_command("bootflow scan -l mmc1", 0));
+	ut_assert_nextline("Scanning for bootflows with label 'mmc1'");
+	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
+	ut_assert_console_end();
+
+	/* check that the hunter was used */
+	ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_cmd_hunt_single, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check searching for a uclass label using the hunters */
+static int bootflow_cmd_hunt_label(struct unit_test_state *uts)
+{
+	struct bootstd_priv *std;
+
+	/* get access to the used hunters */
+	ut_assertok(bootstd_get_priv(&std));
+
+	test_set_skip_delays(true);
+	test_set_eth_enable(false);
+	ut_assertok(bootstd_test_drop_bootdev_order(uts));
+
+	console_record_reset_enable();
+	ut_assertok(run_command("bootflow scan -l mmc", 0));
+
+	/* check that the hunter was used */
+	ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
+
+	/* check that we got the mmc1 bootflow */
+	ut_assert_nextline("Scanning for bootflows with label 'mmc'");
+	ut_assert_nextlinen("Seq");
+	ut_assert_nextlinen("---");
+	ut_assert_nextline("Hunting with: simple_bus");
+	ut_assert_nextline("Found 2 extension board(s).");
+	ut_assert_nextline("Hunting with: mmc");
+	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
+	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
+	ut_assert_nextline(
+		"  0  syslinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
+	ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
+	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
+	ut_assert_console_end();
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_cmd_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
 /**
  * check_font() - Check that the font size for an item matches expectations
  *
-- 
2.39.0.246.g2a6d74b583-goog



More information about the U-Boot mailing list