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 <s...@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

Reply via email to