From e4b694893f6cf1e4ac934f2ecb57c8e77a17e5b2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:10 -0700 Subject: [PATCH] bootstd: Allow iterating to the next label in a list Add a function which moves to the next label in a list of labels. This allows processing the boot_targets environment variable. This works using a new label list in the bootflow iterator. The logic to set this up is included in a subsequent commit. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 26 ++++++++++++-- include/bootdev.h | 16 +++++++++ include/bootflow.h | 4 +++ test/boot/bootdev.c | 80 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 123 insertions(+), 3 deletions(-) diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index dcaed4c269..ae08430ca8 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -566,6 +566,25 @@ void bootdev_clear_bootflows(struct udevice *dev) } } +int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, + int *method_flagsp) +{ + struct udevice *dev; + + log_debug("next\n"); + for (dev = NULL; !dev && iter->labels[++iter->cur_label];) { + log_debug("Scanning: %s\n", iter->labels[iter->cur_label]); + bootdev_hunt_and_find_by_label(iter->labels[iter->cur_label], + &dev, method_flagsp); + } + + if (!dev) + return log_msg_ret("fin", -ENODEV); + *devp = dev; + + return 0; +} + /** * h_cmp_bootdev() - Compare two bootdevs to find out which should go first * @@ -763,8 +782,11 @@ int bootdev_hunt(const char *spec, bool show) log_debug("looking at %.*s for %s\n", (int)max(strlen(name), len), spec, name); - if (spec && strncmp(spec, name, max(strlen(name), len))) - continue; + if (spec && strncmp(spec, name, max(strlen(name), len))) { + if (info->uclass != UCLASS_ETH || + (strcmp("dhcp", spec) && strcmp("pxe", spec))) + continue; + } ret = bootdev_hunt_drv(info, i, show); if (ret) result = ret; diff --git a/include/bootdev.h b/include/bootdev.h index b1e320a7d8..300bc73642 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -333,6 +333,22 @@ int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show); int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp, int *method_flagsp); +/** + * bootdev_next_label() - Move to the next bootdev in the label sequence + * + * Looks through the remaining labels until it finds one that matches a bootdev. + * Bootdev scanners are used as needed. For example a label "mmc1" results in + * running the "mmc" bootdrv. + * + * @iter: Interation info, containing iter->cur_label + * @devp: New bootdev found, if any was found + * @method_flagsp: If non-NULL, returns any flags implied by the label + * (enum bootflow_meth_flags_t), 0 if none + * Returns 0 if OK, -ENODEV if no bootdev was found + */ +int bootdev_next_label(struct bootflow_iter *iter, 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 81dbcd6754..8ab32ffd66 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -175,6 +175,8 @@ enum bootflow_meth_flags_t { * @cur_dev: Current bootdev number, an index into @dev_order[] * @dev_order: List of bootdevs to scan, in order of priority. The scan starts * with the first one on the list + * @labels: List of labels to scan for bootdevs + * @cur_label: Current label being processed * @num_methods: Number of bootmeth devices in @method_order * @cur_method: Current method number, an index into @method_order * @first_glob_method: First global method, if any, else -1 @@ -196,6 +198,8 @@ struct bootflow_iter { int num_devs; int cur_dev; struct udevice **dev_order; + const char *const *labels; + int cur_label; int num_methods; int cur_method; int first_glob_method; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 1fa0909e89..608aef1526 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -355,7 +355,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_console_end(); /* Scan all hunters */ - sandbox_set_eth_enable(false); + test_set_eth_enable(false); test_set_skip_delays(true); ut_assertok(run_command("bootdev hunt", 0)); ut_assert_nextline("Hunting with: ethernet"); @@ -510,3 +510,81 @@ static int bootdev_test_hunt_label(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check iterating to the next label in a list */ +static int bootdev_test_next_label(struct unit_test_state *uts) +{ + const char *const labels[] = {"mmc0", "scsi", "dhcp", "pxe", NULL}; + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + struct udevice *dev; + int mflags; + + test_set_eth_enable(false); + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + memset(&iter, '\0', sizeof(iter)); + memset(&bflow, '\0', sizeof(bflow)); + iter.part = 0; + uclass_first_device(UCLASS_BOOTMETH, &bflow.method); + iter.cur_label = -1; + iter.labels = labels; + + dev = NULL; + mflags = 123; + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + console_record_reset_enable(); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("mmc0.bootdev", dev->name); + ut_asserteq(0, mflags); + + ut_assertok(bootstd_test_check_mmc_hunter(uts)); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line( + " Capacity: 1.9 MB = 0.0 GB (4095 x 512)"); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("scsi.id0lun0.bootdev", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags); + + /* SCSI is fifth in the list, so bit 4 */ + ut_asserteq(BIT(2) | BIT(4), std->hunters_used); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("eth@10002000.bootdev", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY, + mflags); + + /* dhcp: Ethernet is first so bit 0 */ + ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("eth@10002000.bootdev", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, + mflags); + + /* pxe: Ethernet is first so bit 0 */ + ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + + mflags = 123; + ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags)); + ut_asserteq(123, mflags); + ut_assert_console_end(); + + /* no change */ + ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_next_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV | UT_TESTF_SF_BOOTDEV); -- 2.39.5