Add a function to hunt for a bootdev label and find the bootdev produced
by the hunter (or already present).

Add a few extra flags so that we can distinguish between "mmc1", "mmc" and
"1" which all need to be handled differently.

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v1)

 boot/bootdev-uclass.c      |  27 ++++++++-
 include/bootdev.h          |  17 ++++++
 include/bootflow.h         |  14 ++++-
 test/boot/bootdev.c        | 115 ++++++++++++++++++++++++++++++++++++-
 test/boot/bootstd_common.c |  19 ++++++
 test/boot/bootstd_common.h |   8 +++
 6 files changed, 195 insertions(+), 5 deletions(-)

diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index 5ed310c554f..dcaed4c2692 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -442,6 +442,13 @@ int bootdev_find_by_label(const char *label, struct 
udevice **devp,
                if (!ret) {
                        log_debug("- found %s\n", bdev->name);
                        *devp = bdev;
+
+                       /*
+                        * if no sequence number was provided, we must scan all
+                        * bootdevs for this media uclass
+                        */
+                       if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && seq == -1)
+                               method_flags |= BOOTFLOW_METHF_SINGLE_UCLASS;
                        if (method_flagsp)
                                *method_flagsp = method_flags;
                        return 0;
@@ -458,7 +465,7 @@ int bootdev_find_by_any(const char *name, struct udevice 
**devp,
 {
        struct udevice *dev;
        int method_flags = 0;
-       int ret, seq;
+       int ret = -ENODEV, seq;
        char *endp;
 
        seq = simple_strtol(name, &endp, 16);
@@ -480,8 +487,9 @@ int bootdev_find_by_any(const char *name, struct udevice 
**devp,
                               ret);
                        return log_msg_ret("pro", ret);
                }
-       } else {
+       } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
                ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev);
+               method_flags |= BOOTFLOW_METHF_SINGLE_DEV;
        }
        if (ret) {
                printf("Cannot find '%s' (err=%d)\n", name, ret);
@@ -495,6 +503,21 @@ int bootdev_find_by_any(const char *name, struct udevice 
**devp,
        return 0;
 }
 
+int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
+                                  int *method_flagsp)
+{
+       int ret;
+
+       ret = bootdev_hunt(label, false);
+       if (ret)
+               return log_msg_ret("scn", ret);
+       ret = bootdev_find_by_label(label, devp, method_flagsp);
+       if (ret)
+               return log_msg_ret("fnd", ret);
+
+       return 0;
+}
+
 static int default_get_bootflow(struct udevice *dev, struct bootflow_iter 
*iter,
                                struct bootflow *bflow)
 {
diff --git a/include/bootdev.h b/include/bootdev.h
index 65d14f24686..b1e320a7d8e 100644
--- a/include/bootdev.h
+++ b/include/bootdev.h
@@ -316,6 +316,23 @@ int bootdev_hunt(const char *spec, bool show);
  */
 int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
 
+/**
+ * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
+ *
+ * Runs the hunter for the label, then tries to find the bootdev, possible
+ * created by the hunter
+ *
+ * @label: Label to look up (e.g. "mmc1" or "mmc0")
+ * @devp: Returns the bootdev device found, or NULL if none (note it does not
+ *     return the media device, but its bootdev child)
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
+ * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
+ * -ENOENT if there is no device with that number
+ */
+int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
+                                  int *method_flagsp);
+
 #if CONFIG_IS_ENABLED(BOOTSTD)
 /**
  * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
diff --git a/include/bootflow.h b/include/bootflow.h
index 4012f4b8a82..81dbcd6754b 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -99,7 +99,10 @@ struct bootflow {
  * Internal flags:
  * @BOOTFLOWF_SINGLE_DEV: (internal) Just scan one bootdev
  * @BOOTFLOWF_SKIP_GLOBAL: (internal) Don't scan global bootmeths
- * this uclass
+ * @BOOTFLOWF_SINGLE_UCLASS: (internal) Keep scanning through all devices in
+ * this uclass (used with things like "mmc")
+ * @BOOTFLOWF_SINGLE_MEDIA: (internal) Scan one media device in the uclass 
(used
+ * with things like "mmc1")
  */
 enum bootflow_flags_t {
        BOOTFLOWF_FIXED         = 1 << 0,
@@ -113,6 +116,8 @@ enum bootflow_flags_t {
         */
        BOOTFLOWF_SINGLE_DEV    = 1 << 16,
        BOOTFLOWF_SKIP_GLOBAL   = 1 << 17,
+       BOOTFLOWF_SINGLE_UCLASS = 1 << 18,
+       BOOTFLOWF_SINGLE_MEDIA  = 1 << 19,
 };
 
 /**
@@ -124,10 +129,17 @@ enum bootflow_flags_t {
  *
  * @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI)
  * @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot)
+ * @BOOTFLOW_METHF_SINGLE_DEV: Scan only a single bootdev (used for labels like
+ * "3"). This is used if a sequence number is provided instead of a label
+ * @BOOTFLOW_METHF_SINGLE_UCLASS: Scan all bootdevs in this one uclass (used
+ * with things like "mmc"). If this is not set, then the bootdev has an integer
+ * value in the label (like "mmc2")
  */
 enum bootflow_meth_flags_t {
        BOOTFLOW_METHF_DHCP_ONLY        = 1 << 0,
        BOOTFLOW_METHF_PXE_ONLY         = 1 << 1,
+       BOOTFLOW_METHF_SINGLE_DEV       = 1 << 2,
+       BOOTFLOW_METHF_SINGLE_UCLASS    = 1 << 3,
 };
 
 /**
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c
index 86607f7695e..1fa0909e893 100644
--- a/test/boot/bootdev.c
+++ b/test/boot/bootdev.c
@@ -113,9 +113,11 @@ static int bootdev_test_labels(struct unit_test_state *uts)
 
        /* Check method flags */
        ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags));
-       ut_asserteq(BOOTFLOW_METHF_PXE_ONLY, mflags);
+       ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
+                   mflags);
        ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags));
-       ut_asserteq(BOOTFLOW_METHF_DHCP_ONLY, mflags);
+       ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY,
+                   mflags);
 
        /* Check invalid uclass */
        ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags));
@@ -128,6 +130,62 @@ static int bootdev_test_labels(struct unit_test_state *uts)
 BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
             UT_TESTF_ETH_BOOTDEV);
 
+/* Check bootdev_find_by_any() */
+static int bootdev_test_any(struct unit_test_state *uts)
+{
+       struct udevice *dev, *media;
+       int mflags;
+
+       /*
+        * with ethernet enabled we have 8 devices ahead of the mmc ones:
+        *
+        * ut_assertok(run_command("bootdev list", 0));
+        * Seq  Probed  Status  Uclass    Name
+        * ---  ------  ------  --------  ------------------
+        * 0   [ + ]      OK  ethernet  eth@10002000.bootdev
+        * 1   [   ]      OK  ethernet  eth@10003000.bootdev
+        * 2   [   ]      OK  ethernet  sbe5.bootdev
+        * 3   [   ]      OK  ethernet  eth@10004000.bootdev
+        * 4   [   ]      OK  ethernet  phy-test-eth.bootdev
+        * 5   [   ]      OK  ethernet  dsa-test-eth.bootdev
+        * 6   [   ]      OK  ethernet  dsa-test@0.bootdev
+        * 7   [   ]      OK  ethernet  dsa-test@1.bootdev
+        * 8   [   ]      OK  mmc       mmc2.bootdev
+        * 9   [ + ]      OK  mmc       mmc1.bootdev
+        * a   [   ]      OK  mmc       mmc0.bootdev
+        */
+       console_record_reset_enable();
+       ut_assertok(bootdev_find_by_any("8", &dev, &mflags));
+       ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev));
+       ut_asserteq(BOOTFLOW_METHF_SINGLE_DEV, mflags);
+       media = dev_get_parent(dev);
+       ut_asserteq(UCLASS_MMC, device_get_uclass_id(media));
+       ut_asserteq_str("mmc2", media->name);
+       ut_assert_console_end();
+
+       /* there should not be this many bootdevs */
+       ut_asserteq(-ENODEV, bootdev_find_by_any("50", &dev, &mflags));
+       ut_assert_nextline("Cannot find '50' (err=-19)");
+       ut_assert_console_end();
+
+       /* Check method flags */
+       ut_assertok(bootdev_find_by_any("pxe", &dev, &mflags));
+       ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
+                   mflags);
+
+       /* Check invalid uclass */
+       mflags = 123;
+       ut_asserteq(-EINVAL, bootdev_find_by_any("fred0", &dev, &mflags));
+       ut_assert_nextline("Unknown uclass 'fred0' in label");
+       ut_assert_nextline("Cannot find bootdev 'fred0' (err=-22)");
+       ut_asserteq(123, mflags);
+       ut_assert_console_end();
+
+       return 0;
+}
+BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
+            UT_TESTF_ETH_BOOTDEV);
+
 /* Check bootdev ordering with the bootdev-order property */
 static int bootdev_test_order(struct unit_test_state *uts)
 {
@@ -399,3 +457,56 @@ static int bootdev_test_hunt_prio(struct unit_test_state 
*uts)
        return 0;
 }
 BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check hunting for bootdevs with a particular label */
+static int bootdev_test_hunt_label(struct unit_test_state *uts)
+{
+       struct udevice *dev, *old;
+       struct bootstd_priv *std;
+       int mflags;
+
+       /* get access to the used hunters */
+       ut_assertok(bootstd_get_priv(&std));
+
+       /* scan an unknown uclass */
+       console_record_reset_enable();
+       old = (void *)&mflags;   /* arbitrary pointer to check against dev */
+       dev = old;
+       mflags = 123;
+       ut_asserteq(-EINVAL,
+                   bootdev_hunt_and_find_by_label("fred", &dev, &mflags));
+       ut_assert_nextline("Unknown uclass 'fred' in label");
+       ut_asserteq_ptr(old, dev);
+       ut_asserteq(123, mflags);
+       ut_assert_console_end();
+       ut_asserteq(0, std->hunters_used);
+
+       /* scan an invalid mmc controllers */
+       ut_asserteq(-ENOENT,
+                   bootdev_hunt_and_find_by_label("mmc4", &dev, &mflags));
+       ut_asserteq_ptr(old, dev);
+       ut_asserteq(123, mflags);
+       ut_assert_nextline("Unknown seq 4 for label 'mmc4'");
+       ut_assert_console_end();
+
+       ut_assertok(bootstd_test_check_mmc_hunter(uts));
+
+       /* scan for a particular mmc controller */
+       ut_assertok(bootdev_hunt_and_find_by_label("mmc1", &dev, &mflags));
+       ut_assertnonnull(dev);
+       ut_asserteq_str("mmc1.bootdev", dev->name);
+       ut_asserteq(0, mflags);
+       ut_assert_console_end();
+
+       /* scan all of usb */
+       test_set_skip_delays(true);
+       ut_assertok(bootdev_hunt_and_find_by_label("usb", &dev, &mflags));
+       ut_assertnonnull(dev);
+       ut_asserteq_str("usb_mass_storage.lun0.bootdev", dev->name);
+       ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
+       ut_assert_nextlinen("Bus usb@1: scanning bus usb@1");
+       ut_assert_console_end();
+
+       return 0;
+}
+BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
diff --git a/test/boot/bootstd_common.c b/test/boot/bootstd_common.c
index 7a40836507a..e71a2975c53 100644
--- a/test/boot/bootstd_common.c
+++ b/test/boot/bootstd_common.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <bootdev.h>
 #include <bootstd.h>
 #include <dm.h>
 #include <memalign.h>
@@ -67,6 +68,24 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state 
*uts)
        return 0;
 }
 
+int bootstd_test_check_mmc_hunter(struct unit_test_state *uts)
+{
+       struct bootdev_hunter *start, *mmc;
+       struct bootstd_priv *std;
+       uint seq;
+
+       /* get access to the used hunters */
+       ut_assertok(bootstd_get_priv(&std));
+
+       /* check that the hunter was used */
+       start = ll_entry_start(struct bootdev_hunter, bootdev_hunter);
+       mmc = BOOTDEV_HUNTER_GET(mmc_bootdev_hunter);
+       seq = mmc - start;
+       ut_asserteq(BIT(seq), std->hunters_used);
+
+       return 0;
+}
+
 int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, char *const 
argv[])
 {
        struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd_test);
diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h
index c5e0fd1ceab..0eb48fa1537 100644
--- a/test/boot/bootstd_common.h
+++ b/test/boot/bootstd_common.h
@@ -40,4 +40,12 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state 
*uts);
  */
 int bootstd_setup_for_tests(void);
 
+/**
+ * bootstd_test_check_mmc_hunter() - Check that the mmc bootdev hunter was used
+ *
+ * @uts: Unit test state to use for ut_assert...() functions
+ * Returns: 0 if OK (used), other value on error (not used)
+ */
+int bootstd_test_check_mmc_hunter(struct unit_test_state *uts);
+
 #endif
-- 
2.39.0.246.g2a6d74b583-goog

Reply via email to