From bd90b092882099afa3786829036c82d6a4241fc8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:33 -0700 Subject: bootstd: Add the concept of a bootdev hunter Some bootdevs must be enumerated before they appear. For example, USB bootdevs are not visible until USB is enumerated. With standard boot this needs to happen automatically, since we only want to enumerate a bus if it is needed. Add a way to define bootdev 'hunters' which can be used to hunt for bootdevs of a given type. Track which ones have been used and add a command to list them. Include a clang work-around which seems to be needed. Signed-off-by: Simon Glass --- test/boot/bootdev.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'test/boot/bootdev.c') diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 1c2a79fb108..a8ca12a3c8f 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -221,3 +221,55 @@ static int bootdev_test_prio(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check listing hunters */ +static int bootdev_test_hunter(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + console_record_reset_enable(); + bootdev_list_hunters(std); + ut_assert_nextline("Prio Used Uclass Hunter"); + ut_assert_nextlinen("----"); + ut_assert_nextline("(total hunters: 0)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootdev hunt' command */ +static int bootdev_test_cmd_hunt(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + console_record_reset_enable(); + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_nextline("Prio Used Uclass Hunter"); + ut_assert_nextlinen("----"); + ut_assert_nextline("(total hunters: 0)"); + ut_assert_console_end(); + + /* Scan all hunters */ + ut_assertok(run_command("bootdev hunt", 0)); + ut_assert_console_end(); + + /* List available hunters */ + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_nextlinen("Prio"); + ut_assert_nextlinen("----"); + ut_assert_nextline("(total hunters: 0)"); + ut_assert_console_end(); + + ut_asserteq(0, std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV); -- cgit v1.3.1 From c7b63d500df707bd9c9041e0dae3a25f56098978 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:34 -0700 Subject: bootstd: Support running bootdev hunters Add a way to run a bootdev hunter to find bootdevs of a certain type. Add this to the 'bootdev hunt' command. Test for this are added in a later patch, since a useful test needs some hunters to work with. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/bootdev.c | 7 +++++- include/bootdev.h | 14 ++++++++++++ test/boot/bootdev.c | 3 +++ 4 files changed, 84 insertions(+), 1 deletion(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 62eb0b617cd..081b94ce332 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -636,6 +636,67 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp) return 0; } +static int bootdev_hunt_drv(struct bootdev_hunter *info, uint seq, bool show) +{ + const char *name = uclass_get_name(info->uclass); + struct bootstd_priv *std; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return log_msg_ret("std", ret); + + if (!(std->hunters_used & BIT(seq))) { + if (show) + printf("Hunting with: %s\n", + uclass_get_name(info->uclass)); + log_debug("Hunting with: %s\n", name); + if (info->hunt) { + ret = info->hunt(info, show); + if (ret) + return ret; + } + std->hunters_used |= BIT(seq); + } + + return 0; +} + +int bootdev_hunt(const char *spec, bool show) +{ + struct bootdev_hunter *start; + const char *end; + int n_ent, i; + int result; + size_t len; + + start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); + n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); + result = 0; + + len = SIZE_MAX; + if (spec) { + trailing_strtoln_end(spec, NULL, &end); + len = end - spec; + } + + for (i = 0; i < n_ent; i++) { + struct bootdev_hunter *info = start + i; + const char *name = uclass_get_name(info->uclass); + int ret; + + 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; + ret = bootdev_hunt_drv(info, i, show); + if (ret) + result = ret; + } + + return result; +} + void bootdev_list_hunters(struct bootstd_priv *std) { struct bootdev_hunter *orig, *start; diff --git a/cmd/bootdev.c b/cmd/bootdev.c index 80bfe2812e4..28866faac76 100644 --- a/cmd/bootdev.c +++ b/cmd/bootdev.c @@ -128,7 +128,12 @@ static int do_bootdev_hunt(struct cmd_tbl *cmdtp, int flag, int argc, if (list) { bootdev_list_hunters(priv); } else { - /* TODO: implement hunting */ + ret = bootdev_hunt(spec, true); + if (ret) { + printf("Failed (err=%dE)\n", ret); + + return CMD_RET_FAILURE; + } } return 0; diff --git a/include/bootdev.h b/include/bootdev.h index cafb5285a28..deef7890489 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -263,6 +263,20 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp); */ void bootdev_list_hunters(struct bootstd_priv *std); +/** + * bootdev_hunt() - Hunt for bootdevs matching a particular spec + * + * This runs the selected hunter (or all if @spec is NULL) to try to find new + * bootdevs. + * + * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must + * match a uclass name so that the hunter can be determined. Any trailing number + * is ignored + * @show: true to show each hunter before using it + * Returns: 0 if OK, -ve on error + */ +int bootdev_hunt(const char *spec, bool show); + #if CONFIG_IS_ENABLED(BOOTSTD) /** * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated) diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index a8ca12a3c8f..45a00c34c0c 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -237,6 +237,9 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline("(total hunters: 0)"); ut_assert_console_end(); + ut_assertok(bootdev_hunt("mmc1", false)); + ut_assert_console_end(); + return 0; } BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From 04fb2b6e45893df45a7d6bed61614fce97c279e4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:37 -0700 Subject: bootstd: Add a USB hunter Add a hunter for USB which enumerates the bus to find new bootdevs. Update the tests and speed up bootdev_test_prio() while we are here, by dropping the USB delays. Signed-off-by: Simon Glass --- drivers/usb/host/usb_bootdev.c | 12 ++++++++++++ test/boot/bootdev.c | 26 +++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/drivers/usb/host/usb_bootdev.c b/drivers/usb/host/usb_bootdev.c index b2d157faf33..66d0b6ae8f5 100644 --- a/drivers/usb/host/usb_bootdev.c +++ b/drivers/usb/host/usb_bootdev.c @@ -20,6 +20,11 @@ static int usb_bootdev_bind(struct udevice *dev) return 0; } +static int usb_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + return usb_init(); +} + struct bootdev_ops usb_bootdev_ops = { }; @@ -35,3 +40,10 @@ U_BOOT_DRIVER(usb_bootdev) = { .bind = usb_bootdev_bind, .of_match = usb_bootdev_ids, }; + +BOOTDEV_HUNTER(usb_bootdev_hunter) = { + .prio = BOOTDEVP_3_SCAN_SLOW, + .uclass = UCLASS_USB, + .hunt = usb_bootdev_hunt, + .drv = DM_DRIVER_REF(usb_bootdev), +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 45a00c34c0c..7a0c5793890 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -190,6 +190,8 @@ static int bootdev_test_prio(struct unit_test_state *uts) struct bootflow bflow; struct udevice *blk; + test_set_skip_delays(true); + /* Start up USB which gives us three additional bootdevs */ usb_started = false; ut_assertok(run_command("usb start", 0)); @@ -227,6 +229,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) { struct bootstd_priv *std; + test_set_skip_delays(true); + /* get access to the used hunters */ ut_assertok(bootstd_get_priv(&std)); @@ -234,12 +238,17 @@ static int bootdev_test_hunter(struct unit_test_state *uts) bootdev_list_hunters(std); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_nextline("(total hunters: 0)"); + ut_assert_nextline(" 40 usb usb_bootdev"); + ut_assert_nextline("(total hunters: 1)"); ut_assert_console_end(); - ut_assertok(bootdev_hunt("mmc1", false)); + ut_assertok(bootdev_hunt("usb1", false)); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); + ut_asserteq(GENMASK(0, 0), std->hunters_used); + return 0; } BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); @@ -249,6 +258,8 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) { struct bootstd_priv *std; + test_set_skip_delays(true); + /* get access to the used hunters */ ut_assertok(bootstd_get_priv(&std)); @@ -256,21 +267,26 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_nextline("(total hunters: 0)"); + ut_assert_nextline(" 40 usb usb_bootdev"); + ut_assert_nextline("(total hunters: 1)"); ut_assert_console_end(); /* Scan all hunters */ ut_assertok(run_command("bootdev hunt", 0)); + ut_assert_nextline("Hunting with: usb"); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); /* List available hunters */ ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); - ut_assert_nextline("(total hunters: 0)"); + ut_assert_nextline(" 40 * usb usb_bootdev"); + ut_assert_nextline("(total hunters: 1)"); ut_assert_console_end(); - ut_asserteq(0, std->hunters_used); + ut_asserteq(GENMASK(0, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From 843160fa7afc682651c5eea7d8e15f0767b66497 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:38 -0700 Subject: bootstd: Add an MMC hunter Add a hunter for MMC. This doesn't do anything at present, since MMC is currently set up when U-Boot starts. If MMC moves to lazy init then we can add a hunter function. Signed-off-by: Simon Glass --- drivers/mmc/mmc_bootdev.c | 6 ++++++ test/boot/bootdev.c | 16 ++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c index 037b67bc0ff..300208f0c71 100644 --- a/drivers/mmc/mmc_bootdev.c +++ b/drivers/mmc/mmc_bootdev.c @@ -35,3 +35,9 @@ U_BOOT_DRIVER(mmc_bootdev) = { .bind = mmc_bootdev_bind, .of_match = mmc_bootdev_ids, }; + +BOOTDEV_HUNTER(mmc_bootdev_hunter) = { + .prio = BOOTDEVP_0_INTERNAL_FAST, + .uclass = UCLASS_MMC, + .drv = DM_DRIVER_REF(mmc_bootdev), +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 7a0c5793890..78cb0ac628a 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -238,8 +238,9 @@ static int bootdev_test_hunter(struct unit_test_state *uts) bootdev_list_hunters(std); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); + ut_assert_nextline(" 10 mmc mmc_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 1)"); + ut_assert_nextline("(total hunters: 2)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -247,7 +248,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - ut_asserteq(GENMASK(0, 0), std->hunters_used); + /* USB is second in the list, so bit 1 */ + ut_asserteq(BIT(1), std->hunters_used); return 0; } @@ -267,12 +269,12 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 1)"); + ut_assert_skip_to_line("(total hunters: 2)"); ut_assert_console_end(); /* Scan all hunters */ ut_assertok(run_command("bootdev hunt", 0)); + ut_assert_nextline("Hunting with: mmc"); ut_assert_nextline("Hunting with: usb"); ut_assert_nextline( "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); @@ -282,11 +284,13 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); + ut_assert_nextline(" 10 * mmc mmc_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline("(total hunters: 1)"); + + ut_assert_nextline("(total hunters: 2)"); ut_assert_console_end(); - ut_asserteq(GENMASK(0, 0), std->hunters_used); + ut_asserteq(GENMASK(1, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From 4146c823fc27c1a4e06d1d25e0a2d4644948a5fc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:40 -0700 Subject: bootstd: Add a hunter for ethernet Sometimes ethernet devices are attached to PCI. Since it is quick to scan, add this into the ethernet hunter. Run dhcp to establish the network connection. Drop this from the bootdev since that is not needed now. Update a log message for clarity. Signed-off-by: Simon Glass --- net/eth_bootdev.c | 64 ++++++++++++++++++++++++++++++++++------------------- test/boot/bootdev.c | 17 +++++++++----- 2 files changed, 52 insertions(+), 29 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/net/eth_bootdev.c b/net/eth_bootdev.c index b735966d2bc..fdf48f00131 100644 --- a/net/eth_bootdev.c +++ b/net/eth_bootdev.c @@ -6,6 +6,8 @@ * Written by Simon Glass */ +#define LOG_CATEGORY UCLASS_BOOTSTD + #include #include #include @@ -13,8 +15,10 @@ #include #include #include +#include #include #include +#include static int eth_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, struct bootflow *bflow) @@ -41,30 +45,8 @@ static int eth_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, if (!bflow->name) return log_msg_ret("name", -ENOMEM); - /* - * There is not a direct interface to the network stack so run - * everything through the command-line interpreter for now. - * - * Don't bother checking the result of dhcp. It can fail with: - * - * DHCP client bound to address 192.168.4.50 (4 ms) - * *** Warning: no boot file name; using 'C0A80432.img' - * Using smsc95xx_eth device - * TFTP from server 192.168.4.1; our IP address is 192.168.4.50 - * Filename 'C0A80432.img'. - * Load address: 0x200000 - * Loading: * - * TFTP error: 'File not found' (1) - * - * This is not a real failure, since we don't actually care if the - * boot file exists. - */ - log_debug("running dhcp\n"); - run_command("dhcp", 0); - bflow->state = BOOTFLOWST_MEDIA; - /* See distro_pxe_read_bootflow() for the standard impl of this */ - log_debug("dhcp complete - reading bootflow with method %s\n", + log_debug("dhcp complete - reading bootflow with method '%s'\n", bflow->method->name); ret = bootmeth_read_bootflow(bflow->method, bflow); log_debug("reading bootflow returned %d\n", ret); @@ -83,6 +65,35 @@ static int eth_bootdev_bind(struct udevice *dev) return 0; } +static int eth_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + int ret; + + if (!test_eth_enabled()) + return 0; + + /* init PCI first since this is often used to provide Ehternet */ + if (IS_ENABLED(CONFIG_PCI)) { + ret = pci_init(); + if (ret) + log_warning("Failed to init PCI (%dE)\n", ret); + } + + /* + * Ethernet devices can also come from USB, but that is a higher + * priority (BOOTDEVP_5_SCAN_SLOW) than ethernet, so it should have been + * enumerated already. If something like 'bootflow scan dhcp' is used + * then the user will need to run 'usb start' first. + */ + if (IS_ENABLED(CONFIG_CMD_DHCP)) { + ret = dhcp_run(0, NULL, false); + if (ret) + return -EINVAL; + } + + return 0; +} + struct bootdev_ops eth_bootdev_ops = { .get_bootflow = eth_get_bootflow, }; @@ -99,3 +110,10 @@ U_BOOT_DRIVER(eth_bootdev) = { .bind = eth_bootdev_bind, .of_match = eth_bootdev_ids, }; + +BOOTDEV_HUNTER(eth_bootdev_hunt) = { + .prio = BOOTDEVP_4_NET_BASE, + .uclass = UCLASS_ETH, + .hunt = eth_bootdev_hunt, + .drv = DM_DRIVER_REF(eth_bootdev), +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 78cb0ac628a..32a31c44609 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -238,9 +238,10 @@ static int bootdev_test_hunter(struct unit_test_state *uts) bootdev_list_hunters(std); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); + ut_assert_nextline(" 50 ethernet eth_bootdev"); ut_assert_nextline(" 10 mmc mmc_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 2)"); + ut_assert_nextline("(total hunters: 3)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -248,8 +249,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is second in the list, so bit 1 */ - ut_asserteq(BIT(1), std->hunters_used); + /* USB is third in the list, so bit 2 */ + ut_asserteq(BIT(2), std->hunters_used); return 0; } @@ -269,11 +270,14 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 2)"); + ut_assert_skip_to_line("(total hunters: 3)"); ut_assert_console_end(); /* Scan all hunters */ + sandbox_set_eth_enable(false); + ut_assertok(run_command("bootdev hunt", 0)); + ut_assert_nextline("Hunting with: ethernet"); ut_assert_nextline("Hunting with: mmc"); ut_assert_nextline("Hunting with: usb"); ut_assert_nextline( @@ -284,13 +288,14 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); + ut_assert_nextline(" 50 * ethernet eth_bootdev"); ut_assert_nextline(" 10 * mmc mmc_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline("(total hunters: 2)"); + ut_assert_nextline("(total hunters: 3)"); ut_assert_console_end(); - ut_asserteq(GENMASK(1, 0), std->hunters_used); + ut_asserteq(GENMASK(2, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From f0e358f07d75579b40eff8f723b280ab5d53d338 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:42 -0700 Subject: bootstd: Only scan bootable partitions At present all partitions are scanned, whether marked bootable or not. Use only bootable partitions, defaulting to partition 1 if none is found. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 10 +++++++++- include/bootflow.h | 2 ++ test/boot/bootdev.c | 37 +++++++++++++++++++++++++++++++++++++ test/boot/bootflow.c | 4 ++-- 4 files changed, 50 insertions(+), 3 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 081b94ce332..3dcf317c150 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -163,7 +163,15 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, */ iter->max_part = MAX_PART_PER_BOOTDEV; - if (iter->part) { + /* If this is the whole disk, check if we have bootable partitions */ + if (!iter->part) { + iter->first_bootable = part_get_bootable(desc); + log_debug("checking bootable=%d\n", iter->first_bootable); + + /* if there are bootable partitions, scan only those */ + } else if (iter->first_bootable ? !info.bootable : iter->part != 1) { + return log_msg_ret("boot", -EINVAL); + } else { ret = fs_set_blk_dev_with_part(desc, bflow->part); bflow->state = BOOTFLOWST_PART; diff --git a/include/bootflow.h b/include/bootflow.h index c201246c6de..3a93e4b5cab 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -123,6 +123,7 @@ enum bootflow_flags_t { * @method: Current bootmeth * @max_part: Maximum hardware partition number in @dev, 0 if there is no * partition table + * @first_bootable: First bootable partition, or 0 if none * @err: Error obtained from checking the last iteration. This is used to skip * forward (e.g. to skip the current partition because it is not valid) * -ESHUTDOWN: try next bootdev @@ -144,6 +145,7 @@ struct bootflow_iter { int part; struct udevice *method; int max_part; + int first_bootable; int err; int num_devs; int cur_dev; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 32a31c44609..db0e0ca20fa 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -301,3 +301,40 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) } BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV); + +/* Check that only bootable partitions are processed */ +static int bootdev_test_bootable(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + struct udevice *blk; + + memset(&iter, '\0', sizeof(iter)); + memset(&bflow, '\0', sizeof(bflow)); + iter.part = 0; + ut_assertok(uclass_get_device_by_name(UCLASS_BLK, "mmc1.blk", &blk)); + iter.dev = blk; + ut_assertok(device_find_next_child(&iter.dev)); + uclass_first_device(UCLASS_BOOTMETH, &bflow.method); + + /* + * initially we don't have any knowledge of which partitions are + * bootable, but mmc1 has two partitions, with the first one being + * bootable + */ + iter.part = 2; + ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + ut_asserteq(0, iter.first_bootable); + + /* scan with part == 0 to get the partition info */ + iter.part = 0; + ut_asserteq(-ENOENT, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + ut_asserteq(1, iter.first_bootable); + + /* now it will refuse to use non-bootable partitions */ + iter.part = 2; + ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + + return 0; +} +BOOTSTD_TEST(bootdev_test_bootable, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 38ffe8fa9be..f852b6e9b6f 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -316,14 +316,14 @@ static int bootflow_iter(struct unit_test_state *uts) bootflow_free(&bflow); /* Then more to partition 2 which exists but is not bootable */ - ut_asserteq(-EPERM, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(-EINVAL, bootflow_scan_next(&iter, &bflow)); ut_asserteq(2, iter.num_methods); ut_asserteq(0, iter.cur_method); ut_asserteq(2, iter.part); ut_asserteq(0x1e, iter.max_part); ut_asserteq_str("syslinux", iter.method->name); ut_asserteq(0, bflow.err); - ut_asserteq(BOOTFLOWST_PART, bflow.state); + ut_asserteq(BOOTFLOWST_MEDIA, bflow.state); bootflow_free(&bflow); bootflow_iter_uninit(&iter); -- cgit v1.3.1 From 8f090b67d07461cb8313ab08a4d6f44ea9902cf7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:45 -0700 Subject: bootstd: Add a SCSI bootdev Add a bootdev for SCSI so that these devices can be used with standard boot. Signed-off-by: Simon Glass --- drivers/scsi/Makefile | 7 +++++ drivers/scsi/scsi.c | 7 ++++- drivers/scsi/scsi_bootdev.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ test/boot/bootdev.c | 18 ++++++++----- 4 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 drivers/scsi/scsi_bootdev.c (limited to 'test/boot/bootdev.c') diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index d1b40c61401..d8d6de59090 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -6,6 +6,13 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_DM_SCSI) += scsi-uclass.o obj-$(CONFIG_SCSI) += scsi.o + +ifdef CONFIG_SCSI +ifdef CONFIG_DM_SCSI +obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += scsi_bootdev.o +endif +endif + endif ifdef CONFIG_SPL_BUILD diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 4a2d8d009a6..6caeb3fcdd0 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -604,7 +605,11 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) ret = blk_probe_or_unbind(bdev); if (ret < 0) /* TODO: undo create */ - return ret; + return log_msg_ret("pro", ret); + + ret = bootdev_setup_sibling_blk(bdev, "scsi_bootdev"); + if (ret) + return log_msg_ret("bd", ret); if (verbose) { printf(" Device %d: ", bdesc->devnum); diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c new file mode 100644 index 00000000000..2367b33da9c --- /dev/null +++ b/drivers/scsi/scsi_bootdev.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Bootdevice for USB + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include + +static int scsi_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_2_SCAN_FAST; + + return 0; +} + +static int scsi_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + int ret; + + if (IS_ENABLED(CONFIG_PCI)) { + ret = pci_init(); + if (ret) + return log_msg_ret("pci", ret); + } + + ret = scsi_scan(true); + if (ret) + return log_msg_ret("scs", ret); + + return 0; +} + +struct bootdev_ops scsi_bootdev_ops = { +}; + +static const struct udevice_id scsi_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-scsi" }, + { } +}; + +U_BOOT_DRIVER(scsi_bootdev) = { + .name = "scsi_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &scsi_bootdev_ops, + .bind = scsi_bootdev_bind, + .of_match = scsi_bootdev_ids, +}; + +BOOTDEV_HUNTER(scsi_bootdev_hunter) = { + .prio = BOOTDEVP_2_SCAN_FAST, + .uclass = UCLASS_SCSI, + .hunt = scsi_bootdev_hunt, + .drv = DM_DRIVER_REF(scsi_bootdev), +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index db0e0ca20fa..5661a3c0009 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -240,8 +240,9 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextlinen("----"); ut_assert_nextline(" 50 ethernet eth_bootdev"); ut_assert_nextline(" 10 mmc mmc_bootdev"); + ut_assert_nextline(" 30 scsi scsi_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 3)"); + ut_assert_nextline("(total hunters: 4)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -249,8 +250,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is third in the list, so bit 2 */ - ut_asserteq(BIT(2), std->hunters_used); + /* USB is fourth in the list, so bit 3 */ + ut_asserteq(BIT(3), std->hunters_used); return 0; } @@ -270,7 +271,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 3)"); + ut_assert_skip_to_line("(total hunters: 4)"); ut_assert_console_end(); /* Scan all hunters */ @@ -279,7 +280,9 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt", 0)); ut_assert_nextline("Hunting with: ethernet"); ut_assert_nextline("Hunting with: mmc"); - ut_assert_nextline("Hunting with: usb"); + ut_assert_nextline("Hunting with: scsi"); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line("Hunting with: usb"); ut_assert_nextline( "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); @@ -290,12 +293,13 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextlinen("----"); ut_assert_nextline(" 50 * ethernet eth_bootdev"); ut_assert_nextline(" 10 * mmc mmc_bootdev"); + ut_assert_nextline(" 30 * scsi scsi_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline("(total hunters: 3)"); + ut_assert_nextline("(total hunters: 4)"); ut_assert_console_end(); - ut_asserteq(GENMASK(2, 0), std->hunters_used); + ut_asserteq(GENMASK(3, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From 0d77f8f1ca870f7ecd710e701d46c565ff72c68b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:46 -0700 Subject: bootstd: Add an IDE bootdev Add a bootdev for IDE so that these devices can be used with standard boot. Signed-off-by: Simon Glass --- configs/sandbox_flattree_defconfig | 8 +++++++ drivers/block/ide.c | 44 ++++++++++++++++++++++++++++++++++++++ test/boot/bootdev.c | 16 ++++++++------ 3 files changed, 62 insertions(+), 6 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 1563a51c3f9..cc1b3ac347b 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -40,6 +40,7 @@ CONFIG_CMD_MEMTEST=y CONFIG_CMD_DEMO=y CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y +CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_OSD=y @@ -90,6 +91,13 @@ CONFIG_ADC=y CONFIG_ADC_SANDBOX=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y +CONFIG_SYS_IDE_MAXBUS=1 +CONFIG_SYS_ATA_BASE_ADDR=0x100 +CONFIG_SYS_ATA_STRIDE=4 +CONFIG_SYS_ATA_DATA_OFFSET=0 +CONFIG_SYS_ATA_REG_OFFSET=1 +CONFIG_SYS_ATA_ALT_OFFSET=2 +CONFIG_SYS_ATA_IDE0_OFFSET=0 CONFIG_CLK=y CONFIG_CLK_COMPOSITE_CCF=y CONFIG_CLK_K210=y diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 13a1cb4b9e4..80c8b64de2f 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1055,6 +1056,45 @@ U_BOOT_DRIVER(ide_blk) = { .probe = ide_blk_probe, }; +static int ide_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_3_SCAN_SLOW; + + return 0; +} + +static int ide_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + ide_init(); + + return 0; +} + +struct bootdev_ops ide_bootdev_ops = { +}; + +static const struct udevice_id ide_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-ide" }, + { } +}; + +U_BOOT_DRIVER(ide_bootdev) = { + .name = "ide_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &ide_bootdev_ops, + .bind = ide_bootdev_bind, + .of_match = ide_bootdev_ids, +}; + +BOOTDEV_HUNTER(ide_bootdev_hunter) = { + .prio = BOOTDEVP_3_SCAN_SLOW, + .uclass = UCLASS_IDE, + .hunt = ide_bootdev_hunt, + .drv = DM_DRIVER_REF(ide_bootdev), +}; + static int ide_probe(struct udevice *udev) { struct udevice *blk_dev; @@ -1086,6 +1126,10 @@ static int ide_probe(struct udevice *udev) ret = blk_probe_or_unbind(blk_dev); if (ret) return ret; + + ret = bootdev_setup_for_dev(udev, "ide_bootdev"); + if (ret) + return log_msg_ret("bootdev", ret); } } diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 5661a3c0009..a3acdcbdba3 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -239,10 +239,11 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); ut_assert_nextline(" 50 ethernet eth_bootdev"); + ut_assert_nextline(" 40 ide ide_bootdev"); ut_assert_nextline(" 10 mmc mmc_bootdev"); ut_assert_nextline(" 30 scsi scsi_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 4)"); + ut_assert_nextline("(total hunters: 5)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -250,8 +251,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is fourth in the list, so bit 3 */ - ut_asserteq(BIT(3), std->hunters_used); + /* USB is fifth in the list, so bit 4 */ + ut_asserteq(BIT(4), std->hunters_used); return 0; } @@ -271,7 +272,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 4)"); + ut_assert_skip_to_line("(total hunters: 5)"); ut_assert_console_end(); /* Scan all hunters */ @@ -279,6 +280,8 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt", 0)); ut_assert_nextline("Hunting with: ethernet"); + ut_assert_nextline("Hunting with: ide"); + ut_assert_nextline("Bus 0: not available "); ut_assert_nextline("Hunting with: mmc"); ut_assert_nextline("Hunting with: scsi"); ut_assert_nextline("scanning bus for devices..."); @@ -292,14 +295,15 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); ut_assert_nextline(" 50 * ethernet eth_bootdev"); + ut_assert_nextline(" 40 * ide ide_bootdev"); ut_assert_nextline(" 10 * mmc mmc_bootdev"); ut_assert_nextline(" 30 * scsi scsi_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline("(total hunters: 4)"); + ut_assert_nextline("(total hunters: 5)"); ut_assert_console_end(); - ut_asserteq(GENMASK(3, 0), std->hunters_used); + ut_asserteq(GENMASK(4, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From 758c706c6873fda806e3ce70d08bbb8ef3b81707 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:47 -0700 Subject: bootstd: Add an NVMe bootdev Add a bootdev for NVMe so that these devices can be used with standard boot. Signed-off-by: Simon Glass --- drivers/nvme/nvme-uclass.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvme/nvme.c | 5 +++++ test/boot/bootdev.c | 15 +++++++------ 3 files changed, 68 insertions(+), 6 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c index 239a92abba6..7a8ff06e78c 100644 --- a/drivers/nvme/nvme-uclass.c +++ b/drivers/nvme/nvme-uclass.c @@ -7,9 +7,63 @@ #define LOG_CATEGORY UCLASS_NVME #include +#include #include +#include +#include +#include + +static int nvme_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_2_SCAN_FAST; + + return 0; +} + +static int nvme_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + int ret; + + /* init PCI first since this is often used to provide NVMe */ + if (IS_ENABLED(CONFIG_PCI)) { + ret = pci_init(); + if (ret) + log_warning("Failed to init PCI (%dE)\n", ret); + } + + ret = nvme_scan_namespace(); + if (ret) + return log_msg_ret("scan", ret); + + return 0; +} UCLASS_DRIVER(nvme) = { .name = "nvme", .id = UCLASS_NVME, }; + +struct bootdev_ops nvme_bootdev_ops = { +}; + +static const struct udevice_id nvme_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-nvme" }, + { } +}; + +U_BOOT_DRIVER(nvme_bootdev) = { + .name = "nvme_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &nvme_bootdev_ops, + .bind = nvme_bootdev_bind, + .of_match = nvme_bootdev_ids, +}; + +BOOTDEV_HUNTER(nvme_bootdev_hunter) = { + .prio = BOOTDEVP_2_SCAN_FAST, + .uclass = UCLASS_NVME, + .hunt = nvme_bootdev_hunt, + .drv = DM_DRIVER_REF(nvme_bootdev), +}; diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 6d0d3f3ca2b..74e7a5b0110 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -893,6 +894,10 @@ int nvme_init(struct udevice *udev) if (ret) goto free_id; + ret = bootdev_setup_sibling_blk(ns_udev, "nvme_bootdev"); + if (ret) + return log_msg_ret("bootdev", ret); + ret = blk_probe_or_unbind(ns_udev); if (ret) goto free_id; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index a3acdcbdba3..6f150175f69 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -241,9 +241,10 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline(" 50 ethernet eth_bootdev"); ut_assert_nextline(" 40 ide ide_bootdev"); ut_assert_nextline(" 10 mmc mmc_bootdev"); + ut_assert_nextline(" 30 nvme nvme_bootdev"); ut_assert_nextline(" 30 scsi scsi_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 5)"); + ut_assert_nextline("(total hunters: 6)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -251,8 +252,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is fifth in the list, so bit 4 */ - ut_asserteq(BIT(4), std->hunters_used); + /* USB is fifth in the list, so bit 5 */ + ut_asserteq(BIT(5), std->hunters_used); return 0; } @@ -272,7 +273,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 5)"); + ut_assert_skip_to_line("(total hunters: 6)"); ut_assert_console_end(); /* Scan all hunters */ @@ -283,6 +284,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline("Hunting with: ide"); ut_assert_nextline("Bus 0: not available "); ut_assert_nextline("Hunting with: mmc"); + ut_assert_nextline("Hunting with: nvme"); ut_assert_nextline("Hunting with: scsi"); ut_assert_nextline("scanning bus for devices..."); ut_assert_skip_to_line("Hunting with: usb"); @@ -297,13 +299,14 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline(" 50 * ethernet eth_bootdev"); ut_assert_nextline(" 40 * ide ide_bootdev"); ut_assert_nextline(" 10 * mmc mmc_bootdev"); + ut_assert_nextline(" 30 * nvme nvme_bootdev"); ut_assert_nextline(" 30 * scsi scsi_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline("(total hunters: 5)"); + ut_assert_nextline("(total hunters: 6)"); ut_assert_console_end(); - ut_asserteq(GENMASK(4, 0), std->hunters_used); + ut_asserteq(GENMASK(5, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From a60f7a3e35bc6da231046a8931072027575c6939 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:47:52 -0700 Subject: bootstd: Add a virtio bootdev Add a bootdev for virtio so that these devices can be used with standard boot. Signed-off-by: Simon Glass --- drivers/virtio/virtio-uclass.c | 50 ++++++++++++++++++++++++++++++++++++++++++ test/boot/bootdev.c | 12 +++++----- 2 files changed, 57 insertions(+), 5 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index a6bff630ca8..27efac0d48e 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -18,6 +18,7 @@ #define LOG_CATEGORY UCLASS_VIRTIO #include +#include #include #include #include @@ -246,6 +247,12 @@ static int virtio_uclass_post_probe(struct udevice *udev) } device_set_name_alloced(vdev); + if (uc_priv->device == VIRTIO_ID_BLOCK) { + ret = bootdev_setup_for_dev(udev, name); + if (ret) + return log_msg_ret("bootdev", ret); + } + INIT_LIST_HEAD(&uc_priv->vqs); return 0; @@ -349,6 +356,26 @@ static int virtio_uclass_child_post_probe(struct udevice *vdev) return 0; } +static int virtio_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_2_SCAN_FAST; + + return 0; +} + +static int virtio_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + int ret; + + ret = uclass_probe_all(UCLASS_VIRTIO); + if (ret && ret != -ENOENT) + return log_msg_ret("vir", ret); + + return 0; +} + UCLASS_DRIVER(virtio) = { .name = "virtio", .id = UCLASS_VIRTIO, @@ -360,3 +387,26 @@ UCLASS_DRIVER(virtio) = { .child_post_probe = virtio_uclass_child_post_probe, .per_device_auto = sizeof(struct virtio_dev_priv), }; + +struct bootdev_ops virtio_bootdev_ops = { +}; + +static const struct udevice_id virtio_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-virtio" }, + { } +}; + +U_BOOT_DRIVER(virtio_bootdev) = { + .name = "virtio_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &virtio_bootdev_ops, + .bind = virtio_bootdev_bind, + .of_match = virtio_bootdev_ids, +}; + +BOOTDEV_HUNTER(virtio_bootdev_hunter) = { + .prio = BOOTDEVP_2_SCAN_FAST, + .uclass = UCLASS_VIRTIO, + .hunt = virtio_bootdev_hunt, + .drv = DM_DRIVER_REF(virtio_bootdev), +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 6f150175f69..2ad31a0ef66 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -244,7 +244,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline(" 30 nvme nvme_bootdev"); ut_assert_nextline(" 30 scsi scsi_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline("(total hunters: 6)"); + ut_assert_nextline(" 30 virtio virtio_bootdev"); + ut_assert_nextline("(total hunters: 7)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -273,7 +274,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 6)"); + ut_assert_skip_to_line("(total hunters: 7)"); ut_assert_console_end(); /* Scan all hunters */ @@ -290,6 +291,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_skip_to_line("Hunting with: usb"); ut_assert_nextline( "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + ut_assert_skip_to_line("Hunting with: virtio"); ut_assert_console_end(); /* List available hunters */ @@ -302,11 +304,11 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline(" 30 * nvme nvme_bootdev"); ut_assert_nextline(" 30 * scsi scsi_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); - - ut_assert_nextline("(total hunters: 6)"); + ut_assert_nextline(" 30 * virtio virtio_bootdev"); + ut_assert_nextline("(total hunters: 7)"); ut_assert_console_end(); - ut_asserteq(GENMASK(5, 0), std->hunters_used); + ut_asserteq(GENMASK(6, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From 0c1f4a9fb13a54780f550d6e5bc4cd37a58f879e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:03 -0700 Subject: bootstd: Add a SPI flash bootdev Add a bootdev for SPI flash so that these devices can be used with standard boot. It only supports loading a script. Add a special case for the label, since we want to use "spi", not "spi_flash". Enable the new bootdev on sandbox. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 10 ++++- boot/bootflow.c | 12 ++++++ configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + drivers/mtd/spi/Kconfig | 8 ++++ drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/sf-uclass.c | 11 +++++ drivers/mtd/spi/sf_bootdev.c | 82 ++++++++++++++++++++++++++++++++++++++ include/bootflow.h | 9 +++++ test/boot/bootdev.c | 19 +++++---- 10 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 drivers/mtd/spi/sf_bootdev.c (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index f43307d006d..dd9ec668e16 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -375,8 +375,14 @@ static int label_to_uclass(const char *label, int *seqp) log_debug("find %s: seq=%d, id=%d/%s\n", label, seq, id, uclass_get_name(id)); if (id == UCLASS_INVALID) { - log_warning("Unknown uclass '%s' in label\n", label); - return -EINVAL; + /* try some special cases */ + if (IS_ENABLED(CONFIG_BOOTDEV_SPI_FLASH) && + !strncmp("spi", label, len)) { + id = UCLASS_SPI_FLASH; + } else { + log_warning("Unknown uclass '%s' in label\n", label); + return -EINVAL; + } } if (id == UCLASS_USB) id = UCLASS_MASS_STORAGE; diff --git a/boot/bootflow.c b/boot/bootflow.c index 52cc2f9d548..d2dbc9d4450 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -440,6 +440,18 @@ int bootflow_iter_check_blk(const struct bootflow_iter *iter) return -ENOTSUPP; } +int bootflow_iter_check_sf(const struct bootflow_iter *iter) +{ + const struct udevice *media = dev_get_parent(iter->dev); + enum uclass_id id = device_get_uclass_id(media); + + log_debug("uclass %d: %s\n", id, uclass_get_name(id)); + if (id == UCLASS_SPI_FLASH) + return 0; + + return -ENOTSUPP; +} + int bootflow_iter_check_net(const struct bootflow_iter *iter) { const struct udevice *media = dev_get_parent(iter->dev); diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 4a2f94f65bc..34c342b6f58 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -211,6 +211,7 @@ CONFIG_MMC_SANDBOX=y CONFIG_MMC_SDHCI=y CONFIG_MTD=y CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_BOOTDEV_SPI_FLASH=y CONFIG_SPI_FLASH_ATMEL=y CONFIG_SPI_FLASH_EON=y CONFIG_SPI_FLASH_GIGADEVICE=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index cc1b3ac347b..477763dc9f1 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -138,6 +138,7 @@ CONFIG_PWRSEQ=y CONFIG_I2C_EEPROM=y CONFIG_MMC_SANDBOX=y CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_BOOTDEV_SPI_FLASH=y CONFIG_SPI_FLASH_ATMEL=y CONFIG_SPI_FLASH_EON=y CONFIG_SPI_FLASH_GIGADEVICE=y diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 7b858a3a919..a9617c6c58c 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -80,6 +80,14 @@ config SF_DEFAULT_SPEED if SPI_FLASH +config BOOTDEV_SPI_FLASH + bool "SPI Flash bootdev support" + help + Enable a boot device for SPI flash. This allows reading a script + from SPI flash so that it can be used to boot an Operating System. + + If unsure, say N + config SPI_FLASH_SFDP_SUPPORT bool "SFDP table parsing support for SPI NOR flashes" depends on !SPI_FLASH_BAR diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 99cc4185522..409395382f5 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o +obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_SPI_FLASH) += sf_bootdev.o diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index e6e650ef8c0..df1f75390c4 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -6,6 +6,7 @@ #define LOG_CATEGORY UCLASS_SPI_FLASH #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include "sf_internal.h" DECLARE_GLOBAL_DATA_PTR; @@ -86,6 +88,14 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, static int spi_flash_post_bind(struct udevice *dev) { + int ret; + + if (CONFIG_IS_ENABLED(BOOTDEV_SPI_FLASH) && test_sf_bootdev_enabled()) { + ret = bootdev_setup_for_dev(dev, "sf_bootdev"); + if (ret) + return log_msg_ret("bd", ret); + } + #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_flash_ops *ops = sf_get_ops(dev); static int reloc_done; @@ -101,6 +111,7 @@ static int spi_flash_post_bind(struct udevice *dev) reloc_done++; } #endif + return 0; } diff --git a/drivers/mtd/spi/sf_bootdev.c b/drivers/mtd/spi/sf_bootdev.c new file mode 100644 index 00000000000..2272e8567ce --- /dev/null +++ b/drivers/mtd/spi/sf_bootdev.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Read a bootflow from SPI flash + * + * Copyright 2022 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int sf_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, + struct bootflow *bflow) +{ + struct udevice *sf = dev_get_parent(dev); + uint size; + char *buf; + int ret; + + /* We only support the whole device, not partitions */ + if (iter->part) + return log_msg_ret("max", -ESHUTDOWN); + + size = env_get_hex("script_size_f", 0); + if (!size) + return log_msg_ret("sz", -EINVAL); + + buf = malloc(size + 1); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + + ret = spi_flash_read_dm(sf, env_get_hex("script_offset_f", 0), + size, buf); + if (ret) + return log_msg_ret("cmd", -EINVAL); + bflow->state = BOOTFLOWST_MEDIA; + + ret = bootmeth_set_bootflow(bflow->method, bflow, buf, size); + if (ret) { + free(buf); + return log_msg_ret("method", ret); + } + + return 0; +} + +static int sf_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_2_SCAN_FAST; + + return 0; +} + +struct bootdev_ops sf_bootdev_ops = { + .get_bootflow = sf_get_bootflow, +}; + +static const struct udevice_id sf_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-sf" }, + { } +}; + +U_BOOT_DRIVER(sf_bootdev) = { + .name = "sf_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &sf_bootdev_ops, + .bind = sf_bootdev_bind, + .of_match = sf_bootdev_ids, +}; + +BOOTDEV_HUNTER(sf_bootdev_hunter) = { + .prio = BOOTDEVP_2_SCAN_FAST, + .uclass = UCLASS_SPI_FLASH, + .drv = DM_DRIVER_REF(sf_bootdev), +}; diff --git a/include/bootflow.h b/include/bootflow.h index 735ed87a001..319dda8e0be 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -331,6 +331,15 @@ void bootflow_remove(struct bootflow *bflow); */ int bootflow_iter_check_blk(const struct bootflow_iter *iter); +/** + * bootflow_iter_check_sf() - Check that a bootflow uses SPI FLASH + * + * This checks the bootdev in the bootflow to make sure it uses SPI flash + * + * Return: 0 if OK, -ENOTSUPP if some other device is used (e.g. ethernet) + */ +int bootflow_iter_check_sf(const struct bootflow_iter *iter); + /** * bootflow_iter_check_net() - Check that a bootflow uses a network device * diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 2ad31a0ef66..ea0703fa5c8 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -243,9 +243,10 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline(" 10 mmc mmc_bootdev"); ut_assert_nextline(" 30 nvme nvme_bootdev"); ut_assert_nextline(" 30 scsi scsi_bootdev"); + ut_assert_nextline(" 30 spi_flash sf_bootdev"); ut_assert_nextline(" 40 usb usb_bootdev"); ut_assert_nextline(" 30 virtio virtio_bootdev"); - ut_assert_nextline("(total hunters: 7)"); + ut_assert_nextline("(total hunters: 8)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -253,8 +254,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is fifth in the list, so bit 5 */ - ut_asserteq(BIT(5), std->hunters_used); + /* USB is fifth in the list, so bit 6 */ + ut_asserteq(BIT(6), std->hunters_used); return 0; } @@ -274,7 +275,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_skip_to_line("(total hunters: 7)"); + ut_assert_skip_to_line("(total hunters: 8)"); ut_assert_console_end(); /* Scan all hunters */ @@ -288,10 +289,11 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline("Hunting with: nvme"); ut_assert_nextline("Hunting with: scsi"); ut_assert_nextline("scanning bus for devices..."); - ut_assert_skip_to_line("Hunting with: usb"); + ut_assert_skip_to_line("Hunting with: spi_flash"); + ut_assert_nextline("Hunting with: usb"); ut_assert_nextline( "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); - ut_assert_skip_to_line("Hunting with: virtio"); + ut_assert_nextline("Hunting with: virtio"); ut_assert_console_end(); /* List available hunters */ @@ -303,12 +305,13 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline(" 10 * mmc mmc_bootdev"); ut_assert_nextline(" 30 * nvme nvme_bootdev"); ut_assert_nextline(" 30 * scsi scsi_bootdev"); + ut_assert_nextline(" 30 * spi_flash sf_bootdev"); ut_assert_nextline(" 40 * usb usb_bootdev"); ut_assert_nextline(" 30 * virtio virtio_bootdev"); - ut_assert_nextline("(total hunters: 7)"); + ut_assert_nextline("(total hunters: 8)"); ut_assert_console_end(); - ut_asserteq(GENMASK(6, 0), std->hunters_used); + ut_asserteq(GENMASK(7, 0), std->hunters_used); return 0; } -- cgit v1.3.1 From d9f48579dced9c897e718a8b0b84d56ac564a486 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:05 -0700 Subject: bootstd: Treat DHCP and PXE as bootdev labels These are associated with the ethernet boot device but do not match its uclass name, so handle them as special cases. Provide a way to pass flags through with the bootdev so that we know how to process it. The flags are checked by the bootmeths, to ensure that only the selected bootmeth is used. While these both use the network device, they work quite differently. It is common to run only one of these, or to run PXE before DHCP. Provide bootflow flags to control which methods are used. Check these in the two bootmeths so that only the chosen one is used. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 53 ++++++++++++++++++++++++++++---------------------- boot/bootmeth_efi.c | 4 ++++ boot/bootmeth_pxe.c | 3 +++ boot/bootmeth_script.c | 2 ++ boot/vbe_simple_fw.c | 2 +- cmd/bootdev.c | 2 +- cmd/bootflow.c | 2 +- include/bootdev.h | 15 ++++++++++---- include/bootflow.h | 15 ++++++++++++++ test/boot/bootdev.c | 17 ++++++++++++---- 10 files changed, 81 insertions(+), 34 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index dd9ec668e16..7ac42afd7b3 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -359,14 +359,17 @@ int bootdev_unbind_dev(struct udevice *parent) * * @label: Label to look up (e.g. "mmc1" or "mmc0") * @seqp: Returns the sequence number, or -1 if none + * @method_flagsp: If non-NULL, returns any flags implied by the label + * (enum bootflow_meth_flags_t), 0 if none * Returns: sequence number on success, else -ve error code */ -static int label_to_uclass(const char *label, int *seqp) +static int label_to_uclass(const char *label, int *seqp, int *method_flagsp) { + int seq, len, method_flags; enum uclass_id id; const char *end; - int seq, len; + method_flags = 0; seq = trailing_strtoln_end(label, NULL, &end); len = end - label; if (!len) @@ -379,6 +382,14 @@ static int label_to_uclass(const char *label, int *seqp) if (IS_ENABLED(CONFIG_BOOTDEV_SPI_FLASH) && !strncmp("spi", label, len)) { id = UCLASS_SPI_FLASH; + } else if (IS_ENABLED(CONFIG_BOOTDEV_ETH) && + !strncmp("pxe", label, len)) { + id = UCLASS_ETH; + method_flags |= BOOTFLOW_METHF_PXE_ONLY; + } else if (IS_ENABLED(CONFIG_BOOTDEV_ETH) && + !strncmp("dhcp", label, len)) { + id = UCLASS_ETH; + method_flags |= BOOTFLOW_METHF_DHCP_ONLY; } else { log_warning("Unknown uclass '%s' in label\n", label); return -EINVAL; @@ -387,31 +398,21 @@ static int label_to_uclass(const char *label, int *seqp) if (id == UCLASS_USB) id = UCLASS_MASS_STORAGE; *seqp = seq; + if (method_flagsp) + *method_flagsp = method_flags; return id; } -/** - * bootdev_find_by_label() - Convert a label string to a bootdev device - * - * Looks up a label name to find the associated bootdev. For example, if the - * label name is "mmc2", this will find a bootdev for an mmc device whose - * sequence number is 2. - * - * @label: Label string to convert, e.g. "mmc2" - * @devp: Returns bootdev device corresponding to that boot label - * Return: 0 if OK, -EINVAL if the label name (e.g. "mmc") does not refer to a - * uclass, -ENOENT if no bootdev for that media has the sequence number - * (e.g. 2) - */ -int bootdev_find_by_label(const char *label, struct udevice **devp) +int bootdev_find_by_label(const char *label, struct udevice **devp, + int *method_flagsp) { + int seq, ret, method_flags = 0; struct udevice *media; struct uclass *uc; enum uclass_id id; - int seq, ret; - ret = label_to_uclass(label, &seq); + ret = label_to_uclass(label, &seq, &method_flags); if (ret < 0) return log_msg_ret("uc", ret); id = ret; @@ -441,6 +442,8 @@ int bootdev_find_by_label(const char *label, struct udevice **devp) if (!ret) { log_debug("- found %s\n", bdev->name); *devp = bdev; + if (method_flagsp) + *method_flagsp = method_flags; return 0; } log_debug("- no device in %s\n", media->name); @@ -450,9 +453,11 @@ int bootdev_find_by_label(const char *label, struct udevice **devp) return -ENOENT; } -int bootdev_find_by_any(const char *name, struct udevice **devp) +int bootdev_find_by_any(const char *name, struct udevice **devp, + int *method_flagsp) { struct udevice *dev; + int method_flags = 0; int ret, seq; char *endp; @@ -462,18 +467,18 @@ int bootdev_find_by_any(const char *name, struct udevice **devp) if (*endp) { ret = uclass_get_device_by_name(UCLASS_BOOTDEV, name, &dev); if (ret == -ENODEV) { - ret = bootdev_find_by_label(name, &dev); + ret = bootdev_find_by_label(name, &dev, &method_flags); if (ret) { printf("Cannot find bootdev '%s' (err=%d)\n", name, ret); - return ret; + return log_msg_ret("lab", ret); } ret = device_probe(dev); } if (ret) { printf("Cannot probe bootdev '%s' (err=%d)\n", name, ret); - return ret; + return log_msg_ret("pro", ret); } } else { ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev); @@ -484,6 +489,8 @@ int bootdev_find_by_any(const char *name, struct udevice **devp) } *devp = dev; + if (method_flagsp) + *method_flagsp = method_flags; return 0; } @@ -593,7 +600,7 @@ static int build_order(struct udevice *bootstd, struct udevice **order, upto = 0; for (i = 0; labels[i]; i++) { - ret = bootdev_find_by_label(labels[i], &dev); + ret = bootdev_find_by_label(labels[i], &dev, NULL); if (!ret) { if (upto == max_count) { overflow_target = labels[i]; diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 53a0489b93c..67c972e3fe4 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -140,6 +140,10 @@ static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter) if (bootflow_iter_check_blk(iter) && bootflow_iter_check_net(iter)) return log_msg_ret("blk", -ENOTSUPP); + /* This works on block devices and network devices */ + if (iter->method_flags & BOOTFLOW_METHF_PXE_ONLY) + return log_msg_ret("pxe", -ENOTSUPP); + return 0; } diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 13e2ff486dc..ecf8557af83 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -48,6 +48,9 @@ static int distro_pxe_check(struct udevice *dev, struct bootflow_iter *iter) if (ret) return log_msg_ret("net", ret); + if (iter->method_flags & BOOTFLOW_METHF_DHCP_ONLY) + return log_msg_ret("dhcp", -ENOTSUPP); + return 0; } diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c index a14c750ff61..225eb18ee6c 100644 --- a/boot/bootmeth_script.c +++ b/boot/bootmeth_script.c @@ -27,6 +27,8 @@ static int script_check(struct udevice *dev, struct bootflow_iter *iter) { /* This works on block devices, network devices and SPI Flash */ + if (iter->method_flags & BOOTFLOW_METHF_PXE_ONLY) + return log_msg_ret("pxe", -ENOTSUPP); return 0; } diff --git a/boot/vbe_simple_fw.c b/boot/vbe_simple_fw.c index 0a49d286703..d59a704ddba 100644 --- a/boot/vbe_simple_fw.c +++ b/boot/vbe_simple_fw.c @@ -176,7 +176,7 @@ static int simple_load_from_image(struct spl_image_info *spl_image, priv = dev_get_priv(meth); log_debug("simple %s\n", priv->storage); - ret = bootdev_find_by_label(priv->storage, &bdev); + ret = bootdev_find_by_label(priv->storage, &bdev, NULL); if (ret) return log_msg_ret("bd", ret); log_debug("bootdev %s\n", bdev->name); diff --git a/cmd/bootdev.c b/cmd/bootdev.c index 28866faac76..5b1efaaee87 100644 --- a/cmd/bootdev.c +++ b/cmd/bootdev.c @@ -57,7 +57,7 @@ static int do_bootdev_select(struct cmd_tbl *cmdtp, int flag, int argc, std->cur_bootdev = NULL; return 0; } - if (bootdev_find_by_any(argv[1], &dev)) + if (bootdev_find_by_any(argv[1], &dev, NULL)) return CMD_RET_FAILURE; std->cur_bootdev = dev; diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 56dd35b69cf..c8b2f5efdeb 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -121,7 +121,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, if (argc > 1) { const char *label = argv[1]; - if (bootdev_find_by_any(label, &dev)) + if (bootdev_find_by_any(label, &dev, NULL)) return CMD_RET_FAILURE; } } else { diff --git a/include/bootdev.h b/include/bootdev.h index deef7890489..db03c5c032e 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -222,19 +222,26 @@ int bootdev_next_bootflow(struct bootflow **bflowp); * @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 + * -ENOENT if there is no device with that number */ -int bootdev_find_by_label(const char *label, struct udevice **devp); +int bootdev_find_by_label(const char *label, struct udevice **devp, + int *method_flagsp); /** * bootdev_find_by_any() - Find a bootdev by name, label or sequence * * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find * @devp: returns the device found, on success - * Return: 0 if OK, -ve on error + * @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_find_by_any(const char *name, struct udevice **devp); +int bootdev_find_by_any(const char *name, struct udevice **devp, + int *method_flagsp); /** * bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan diff --git a/include/bootflow.h b/include/bootflow.h index 319dda8e0be..9c6610bb922 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -104,6 +104,21 @@ enum bootflow_flags_t { BOOTFLOWF_SKIP_GLOBAL = 1 << 4, }; +/** + * enum bootflow_meth_flags_t - flags controlling which bootmeths are used + * + * Used during iteration, e.g. by bootdev_find_by_label(), to determine which + * bootmeths are used for the current bootdev. The flags reset when the bootdev + * changes + * + * @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI) + * @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot) + */ +enum bootflow_meth_flags_t { + BOOTFLOW_METHF_DHCP_ONLY = 1 << 0, + BOOTFLOW_METHF_PXE_ONLY = 1 << 1, +}; + /** * struct bootflow_iter - state for iterating through bootflows * diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index ea0703fa5c8..e6045b05d81 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -102,22 +102,31 @@ BOOTSTD_TEST(bootdev_test_cmd_select, UT_TESTF_DM | UT_TESTF_SCAN_FDT); static int bootdev_test_labels(struct unit_test_state *uts) { struct udevice *dev, *media; + int mflags = 0; - ut_assertok(bootdev_find_by_label("mmc2", &dev)); + ut_assertok(bootdev_find_by_label("mmc2", &dev, &mflags)); ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); + ut_asserteq(0, mflags); media = dev_get_parent(dev); ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); ut_asserteq_str("mmc2", media->name); + /* Check method flags */ + ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags)); + ut_asserteq(BOOTFLOW_METHF_PXE_ONLY, mflags); + ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags)); + ut_asserteq(BOOTFLOW_METHF_DHCP_ONLY, mflags); + /* Check invalid uclass */ - ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev)); + ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags)); /* Check unknown sequence number */ - ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev)); + ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev, &mflags)); return 0; } -BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +BOOTSTD_TEST(bootdev_test_labels, 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) -- cgit v1.3.1 From 79a7d4a61ff34c7745811c7b3090a60b230c2ef9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:07 -0700 Subject: bootstd: Allow hunting for bootdevs of a given priority Add a way to run the hunter function for a particular priority, so that new bootdevs can be found. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 25 +++++++++++++++++++++++++ include/bootdev.h | 11 +++++++++++ test/boot/bootdev.c | 25 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 7ac42afd7b3..e8686159f2b 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -742,6 +742,31 @@ int bootdev_hunt(const char *spec, bool show) return result; } +int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show) +{ + struct bootdev_hunter *start; + int n_ent, i; + int result; + + start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); + n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); + result = 0; + + log_debug("Hunting for priority %d\n", prio); + for (i = 0; i < n_ent; i++) { + struct bootdev_hunter *info = start + i; + int ret; + + if (prio != info->prio) + continue; + ret = bootdev_hunt_drv(info, i, show); + if (ret && ret != -ENOENT) + result = ret; + } + + return result; +} + void bootdev_list_hunters(struct bootstd_priv *std) { struct bootdev_hunter *orig, *start; diff --git a/include/bootdev.h b/include/bootdev.h index db03c5c032e..b7973fa5760 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -284,6 +284,17 @@ void bootdev_list_hunters(struct bootstd_priv *std); */ int bootdev_hunt(const char *spec, bool show); +/** + * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority + * + * This runs all hunters which can find bootdevs of the given priority. + * + * @prio: Priority to use + * @show: true to show each hunter as it is used + * Returns: 0 if OK, -ve on error + */ +int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show); + #if CONFIG_IS_ENABLED(BOOTSTD) /** * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated) diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index e6045b05d81..f9653633a68 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -363,3 +363,28 @@ static int bootdev_test_bootable(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootdev_test_bootable, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check hunting for bootdev of a particular priority */ +static int bootdev_test_hunt_prio(struct unit_test_state *uts) +{ + test_set_skip_delays(true); + + console_record_reset_enable(); + ut_assertok(bootdev_hunt_prio(BOOTDEVP_2_SCAN_FAST, false)); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line(" Type: Hard Disk"); + ut_assert_nextlinen(" Capacity:"); + ut_assert_console_end(); + + /* now try a different priority, verbosely */ + ut_assertok(bootdev_hunt_prio(BOOTDEVP_3_SCAN_SLOW, true)); + ut_assert_nextline("Hunting with: ide"); + ut_assert_nextline("Bus 0: not available "); + ut_assert_nextline("Hunting with: usb"); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From eacc261178b9c8024cb8de89ee4ca6c68d80d96a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:08 -0700 Subject: bootstd: Add a new pre-scan priority for bootdevs We need extensions to be set up before we start trying to boot any of the bootdevs. Add a new priority before all the others for tht sort of thing. Also add a 'none' option, so that the first one is not 0. While we are here, comment enum bootdev_prio_t fully and expand the test for the 'bootdev hunt' command. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 8 +++++++ doc/develop/bootstd.rst | 2 +- drivers/block/ide.c | 4 ++-- drivers/mmc/mmc_bootdev.c | 4 ++-- drivers/mtd/spi/sf_bootdev.c | 4 ++-- drivers/nvme/nvme-uclass.c | 4 ++-- drivers/scsi/scsi_bootdev.c | 4 ++-- drivers/usb/host/usb_bootdev.c | 4 ++-- drivers/virtio/virtio-uclass.c | 4 ++-- include/bootdev.h | 35 +++++++++++++++++++++++------ net/eth_bootdev.c | 4 ++-- test/boot/bootdev.c | 51 +++++++++++++++++++++++++----------------- 12 files changed, 84 insertions(+), 44 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index e8686159f2b..5ed310c554f 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -630,6 +630,7 @@ static int build_order(struct udevice *bootstd, struct udevice **order, int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp) { struct udevice *bootstd, *dev = *devp, **order; + bool show = iter->flags & BOOTFLOWF_SHOW; struct uclass *uc; int count, upto; int ret; @@ -640,6 +641,13 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp) return log_msg_ret("std", ret); } + /* hunt for any pre-scan devices */ + if (iter->flags & BOOTFLOWF_HUNT) { + ret = bootdev_hunt_prio(BOOTDEVP_1_PRE_SCAN, show); + if (ret) + return log_msg_ret("pre", ret); + } + /* Handle scanning a single device */ if (dev) { iter->flags |= BOOTFLOWF_SINGLE_DEV; diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst index 1ccc49424eb..bfa8cbd7561 100644 --- a/doc/develop/bootstd.rst +++ b/doc/develop/bootstd.rst @@ -211,7 +211,7 @@ A bootdev driver is typically fairly simple. Here is one for mmc:: { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_0_INTERNAL_FAST; + ucp->prio = BOOTDEVP_2_INTERNAL_FAST; return 0; } diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 80c8b64de2f..1ad9b6c1267 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1060,7 +1060,7 @@ static int ide_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_3_SCAN_SLOW; + ucp->prio = BOOTDEVP_5_SCAN_SLOW; return 0; } @@ -1089,7 +1089,7 @@ U_BOOT_DRIVER(ide_bootdev) = { }; BOOTDEV_HUNTER(ide_bootdev_hunter) = { - .prio = BOOTDEVP_3_SCAN_SLOW, + .prio = BOOTDEVP_5_SCAN_SLOW, .uclass = UCLASS_IDE, .hunt = ide_bootdev_hunt, .drv = DM_DRIVER_REF(ide_bootdev), diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c index 300208f0c71..b57b8a62276 100644 --- a/drivers/mmc/mmc_bootdev.c +++ b/drivers/mmc/mmc_bootdev.c @@ -15,7 +15,7 @@ static int mmc_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_0_INTERNAL_FAST; + ucp->prio = BOOTDEVP_2_INTERNAL_FAST; return 0; } @@ -37,7 +37,7 @@ U_BOOT_DRIVER(mmc_bootdev) = { }; BOOTDEV_HUNTER(mmc_bootdev_hunter) = { - .prio = BOOTDEVP_0_INTERNAL_FAST, + .prio = BOOTDEVP_2_INTERNAL_FAST, .uclass = UCLASS_MMC, .drv = DM_DRIVER_REF(mmc_bootdev), }; diff --git a/drivers/mtd/spi/sf_bootdev.c b/drivers/mtd/spi/sf_bootdev.c index 2272e8567ce..d6b47b11ce4 100644 --- a/drivers/mtd/spi/sf_bootdev.c +++ b/drivers/mtd/spi/sf_bootdev.c @@ -53,7 +53,7 @@ static int sf_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_2_SCAN_FAST; + ucp->prio = BOOTDEVP_4_SCAN_FAST; return 0; } @@ -76,7 +76,7 @@ U_BOOT_DRIVER(sf_bootdev) = { }; BOOTDEV_HUNTER(sf_bootdev_hunter) = { - .prio = BOOTDEVP_2_SCAN_FAST, + .prio = BOOTDEVP_4_SCAN_FAST, .uclass = UCLASS_SPI_FLASH, .drv = DM_DRIVER_REF(sf_bootdev), }; diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c index 7a8ff06e78c..f3af6a27b63 100644 --- a/drivers/nvme/nvme-uclass.c +++ b/drivers/nvme/nvme-uclass.c @@ -17,7 +17,7 @@ static int nvme_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_2_SCAN_FAST; + ucp->prio = BOOTDEVP_4_SCAN_FAST; return 0; } @@ -62,7 +62,7 @@ U_BOOT_DRIVER(nvme_bootdev) = { }; BOOTDEV_HUNTER(nvme_bootdev_hunter) = { - .prio = BOOTDEVP_2_SCAN_FAST, + .prio = BOOTDEVP_4_SCAN_FAST, .uclass = UCLASS_NVME, .hunt = nvme_bootdev_hunt, .drv = DM_DRIVER_REF(nvme_bootdev), diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c index 2367b33da9c..991013fe1ef 100644 --- a/drivers/scsi/scsi_bootdev.c +++ b/drivers/scsi/scsi_bootdev.c @@ -16,7 +16,7 @@ static int scsi_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_2_SCAN_FAST; + ucp->prio = BOOTDEVP_4_SCAN_FAST; return 0; } @@ -55,7 +55,7 @@ U_BOOT_DRIVER(scsi_bootdev) = { }; BOOTDEV_HUNTER(scsi_bootdev_hunter) = { - .prio = BOOTDEVP_2_SCAN_FAST, + .prio = BOOTDEVP_4_SCAN_FAST, .uclass = UCLASS_SCSI, .hunt = scsi_bootdev_hunt, .drv = DM_DRIVER_REF(scsi_bootdev), diff --git a/drivers/usb/host/usb_bootdev.c b/drivers/usb/host/usb_bootdev.c index 66d0b6ae8f5..32919f99286 100644 --- a/drivers/usb/host/usb_bootdev.c +++ b/drivers/usb/host/usb_bootdev.c @@ -15,7 +15,7 @@ static int usb_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_3_SCAN_SLOW; + ucp->prio = BOOTDEVP_5_SCAN_SLOW; return 0; } @@ -42,7 +42,7 @@ U_BOOT_DRIVER(usb_bootdev) = { }; BOOTDEV_HUNTER(usb_bootdev_hunter) = { - .prio = BOOTDEVP_3_SCAN_SLOW, + .prio = BOOTDEVP_5_SCAN_SLOW, .uclass = UCLASS_USB, .hunt = usb_bootdev_hunt, .drv = DM_DRIVER_REF(usb_bootdev), diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index 27efac0d48e..91af412ec1d 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -360,7 +360,7 @@ static int virtio_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_2_SCAN_FAST; + ucp->prio = BOOTDEVP_4_SCAN_FAST; return 0; } @@ -405,7 +405,7 @@ U_BOOT_DRIVER(virtio_bootdev) = { }; BOOTDEV_HUNTER(virtio_bootdev_hunter) = { - .prio = BOOTDEVP_2_SCAN_FAST, + .prio = BOOTDEVP_4_SCAN_FAST, .uclass = UCLASS_VIRTIO, .hunt = virtio_bootdev_hunt, .drv = DM_DRIVER_REF(virtio_bootdev), diff --git a/include/bootdev.h b/include/bootdev.h index b7973fa5760..65d14f24686 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -21,15 +21,36 @@ struct udevice; * * Smallest value is the highest priority. By default, bootdevs are scanned from * highest to lowest priority + * + * BOOTDEVP_0_NONE: Invalid value, do not use + * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before + * starting any bootflow scan + * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and + * generally very quick to access, e.g. less than 100ms + * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but + * take a significant fraction of a second to access + * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus + * enumeration to find, but this enumeration happens quickly, typically under + * 100ms + * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus + * enumeration to find. The enumeration takes significant fraction of a second + * to complete + * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily + * available. Typically used for an internal Ethernet device + * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time + * to start up, or are less desirable. Typically used for secondary Ethernet + * devices. Note that USB ethernet devices are found during USB enumeration, + * so do not use this priority */ enum bootdev_prio_t { - BOOTDEVP_0_INTERNAL_FAST = 10, - BOOTDEVP_1_INTERNAL_SLOW = 20, - BOOTDEVP_2_SCAN_FAST = 30, - BOOTDEVP_3_SCAN_SLOW = 40, - BOOTDEVP_4_NET_BASE = 50, - BOOTDEVP_5_NET_FALLBACK = 60, - BOOTDEVP_6_SYSTEM = 70, + BOOTDEVP_0_NONE, + BOOTDEVP_1_PRE_SCAN, + BOOTDEVP_2_INTERNAL_FAST, + BOOTDEVP_3_INTERNAL_SLOW, + BOOTDEVP_4_SCAN_FAST, + BOOTDEVP_5_SCAN_SLOW, + BOOTDEVP_6_NET_BASE, + BOOTDEVP_7_NET_FALLBACK, BOOTDEVP_COUNT, }; diff --git a/net/eth_bootdev.c b/net/eth_bootdev.c index bcbb35a74cd..13e5fcd3bdf 100644 --- a/net/eth_bootdev.c +++ b/net/eth_bootdev.c @@ -60,7 +60,7 @@ static int eth_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); - ucp->prio = BOOTDEVP_4_NET_BASE; + ucp->prio = BOOTDEVP_6_NET_BASE; return 0; } @@ -112,7 +112,7 @@ U_BOOT_DRIVER(eth_bootdev) = { }; BOOTDEV_HUNTER(eth_bootdev_hunt) = { - .prio = BOOTDEVP_4_NET_BASE, + .prio = BOOTDEVP_6_NET_BASE, .uclass = UCLASS_ETH, .hunt = eth_bootdev_hunt, .drv = DM_DRIVER_REF(eth_bootdev), diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index f9653633a68..86607f7695e 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -247,14 +247,14 @@ static int bootdev_test_hunter(struct unit_test_state *uts) bootdev_list_hunters(std); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); - ut_assert_nextline(" 50 ethernet eth_bootdev"); - ut_assert_nextline(" 40 ide ide_bootdev"); - ut_assert_nextline(" 10 mmc mmc_bootdev"); - ut_assert_nextline(" 30 nvme nvme_bootdev"); - ut_assert_nextline(" 30 scsi scsi_bootdev"); - ut_assert_nextline(" 30 spi_flash sf_bootdev"); - ut_assert_nextline(" 40 usb usb_bootdev"); - ut_assert_nextline(" 30 virtio virtio_bootdev"); + ut_assert_nextline(" 6 ethernet eth_bootdev"); + ut_assert_nextline(" 5 ide ide_bootdev"); + ut_assert_nextline(" 2 mmc mmc_bootdev"); + ut_assert_nextline(" 4 nvme nvme_bootdev"); + ut_assert_nextline(" 4 scsi scsi_bootdev"); + ut_assert_nextline(" 4 spi_flash sf_bootdev"); + ut_assert_nextline(" 5 usb usb_bootdev"); + ut_assert_nextline(" 4 virtio virtio_bootdev"); ut_assert_nextline("(total hunters: 8)"); ut_assert_console_end(); @@ -284,17 +284,28 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); + ut_assert_nextline(" 6 ethernet eth_bootdev"); + ut_assert_skip_to_line("(total hunters: 8)"); + ut_assert_console_end(); + + /* Use the MMC hunter and see that it updates */ + ut_assertok(run_command("bootdev hunt mmc", 0)); + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_skip_to_line(" 5 ide ide_bootdev"); + ut_assert_nextline(" 2 * mmc mmc_bootdev"); ut_assert_skip_to_line("(total hunters: 8)"); ut_assert_console_end(); /* Scan all hunters */ sandbox_set_eth_enable(false); - + test_set_skip_delays(true); ut_assertok(run_command("bootdev hunt", 0)); ut_assert_nextline("Hunting with: ethernet"); ut_assert_nextline("Hunting with: ide"); ut_assert_nextline("Bus 0: not available "); - ut_assert_nextline("Hunting with: mmc"); + + /* mmc hunter has already been used so should not run again */ + ut_assert_nextline("Hunting with: nvme"); ut_assert_nextline("Hunting with: scsi"); ut_assert_nextline("scanning bus for devices..."); @@ -309,14 +320,14 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); - ut_assert_nextline(" 50 * ethernet eth_bootdev"); - ut_assert_nextline(" 40 * ide ide_bootdev"); - ut_assert_nextline(" 10 * mmc mmc_bootdev"); - ut_assert_nextline(" 30 * nvme nvme_bootdev"); - ut_assert_nextline(" 30 * scsi scsi_bootdev"); - ut_assert_nextline(" 30 * spi_flash sf_bootdev"); - ut_assert_nextline(" 40 * usb usb_bootdev"); - ut_assert_nextline(" 30 * virtio virtio_bootdev"); + ut_assert_nextline(" 6 * ethernet eth_bootdev"); + ut_assert_nextline(" 5 * ide ide_bootdev"); + ut_assert_nextline(" 2 * mmc mmc_bootdev"); + ut_assert_nextline(" 4 * nvme nvme_bootdev"); + ut_assert_nextline(" 4 * scsi scsi_bootdev"); + ut_assert_nextline(" 4 * spi_flash sf_bootdev"); + ut_assert_nextline(" 5 * usb usb_bootdev"); + ut_assert_nextline(" 4 * virtio virtio_bootdev"); ut_assert_nextline("(total hunters: 8)"); ut_assert_console_end(); @@ -370,14 +381,14 @@ static int bootdev_test_hunt_prio(struct unit_test_state *uts) test_set_skip_delays(true); console_record_reset_enable(); - ut_assertok(bootdev_hunt_prio(BOOTDEVP_2_SCAN_FAST, false)); + ut_assertok(bootdev_hunt_prio(BOOTDEVP_4_SCAN_FAST, false)); ut_assert_nextline("scanning bus for devices..."); ut_assert_skip_to_line(" Type: Hard Disk"); ut_assert_nextlinen(" Capacity:"); ut_assert_console_end(); /* now try a different priority, verbosely */ - ut_assertok(bootdev_hunt_prio(BOOTDEVP_3_SCAN_SLOW, true)); + ut_assertok(bootdev_hunt_prio(BOOTDEVP_5_SCAN_SLOW, true)); ut_assert_nextline("Hunting with: ide"); ut_assert_nextline("Bus 0: not available "); ut_assert_nextline("Hunting with: usb"); -- cgit v1.3.1 From 66e3dce78750f6fc4f6a402ce62c20ba95976dd1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:09 -0700 Subject: bootstd: Allow hunting for a bootdev by label 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 --- 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(-) (limited to 'test/boot/bootdev.c') 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 +#include #include #include #include @@ -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 -- cgit v1.3.1 From e4b694893f6cf1e4ac934f2ecb57c8e77a17e5b2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:10 -0700 Subject: 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(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index dcaed4c2692..ae08430ca8c 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 b1e320a7d8e..300bc736427 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 81dbcd6754b..8ab32ffd666 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 1fa0909e893..608aef15265 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); -- cgit v1.3.1 From 43e89a306903117c8cb7105004f236acf1ec3d00 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:11 -0700 Subject: bootstd: Allow iterating to the next bootdev priortiy Add a function which moves to the next priority to be processed. This works by storing the current priority 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 | 64 +++++++++++++++++++++++++++++++++++++++ include/bootdev.h | 14 +++++++++ include/bootflow.h | 3 ++ test/boot/bootdev.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index ae08430ca8c..63005140061 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -585,6 +585,70 @@ int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, return 0; } +int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp) +{ + struct udevice *dev = *devp; + bool found; + int ret; + + /* find the next device with this priority */ + *devp = NULL; + log_debug("next prio %d: dev=%p/%s\n", iter->cur_prio, dev, + dev ? dev->name : "none"); + do { + /* + * Don't probe devices here since they may not be of the + * required priority + */ + if (!dev) + uclass_find_first_device(UCLASS_BOOTDEV, &dev); + else + uclass_find_next_device(&dev); + found = false; + + /* scan for the next device with the correct priority */ + while (dev) { + struct bootdev_uc_plat *plat; + + plat = dev_get_uclass_plat(dev); + log_debug("- %s: %d, want %d\n", dev->name, plat->prio, + iter->cur_prio); + if (plat->prio == iter->cur_prio) + break; + uclass_find_next_device(&dev); + } + + /* none found for this priority, so move to the next */ + if (!dev) { + log_debug("None found at prio %d, moving to %d\n", + iter->cur_prio, iter->cur_prio + 1); + if (++iter->cur_prio == BOOTDEVP_COUNT) + return log_msg_ret("fin", -ENODEV); + + if (iter->flags & BOOTFLOWF_HUNT) { + /* hunt to find new bootdevs */ + ret = bootdev_hunt_prio(iter->cur_prio, + iter->flags & + BOOTFLOWF_SHOW); + log_debug("- hunt ret %d\n", ret); + if (ret) + return log_msg_ret("hun", ret); + } + } else { + ret = device_probe(dev); + if (ret) { + log_debug("Device '%s' failed to probe\n", + dev->name); + dev = NULL; + } + } + } while (!dev); + + *devp = dev; + + return 0; +} + /** * h_cmp_bootdev() - Compare two bootdevs to find out which should go first * diff --git a/include/bootdev.h b/include/bootdev.h index 300bc736427..4b6a8eb8d8f 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -349,6 +349,20 @@ int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp, int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, int *method_flagsp); +/** + * bootdev_next_prio() - Find the next bootdev in priority order + * + * This moves @devp to the next bootdev with the current priority. If there is + * none, then it moves to the next priority and scans for new bootdevs there. + * + * @iter: Interation info, containing iter->cur_prio + * @devp: On entry this is the previous bootdev that was considered. On exit + * this is the new bootdev, if any was found + * Returns 0 on success (*devp is updated), -ENODEV if there are no more + * bootdevs at any priority + */ +int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp); + #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 8ab32ffd666..69ac90483c6 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -7,6 +7,7 @@ #ifndef __bootflow_h #define __bootflow_h +#include #include #include @@ -180,6 +181,7 @@ enum bootflow_meth_flags_t { * @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 + * @cur_prio: Current priority being scanned * @method_order: List of bootmeth devices to use, in order. The normal methods * appear first, then the global ones, if any * @doing_global: true if we are iterating through the global bootmeths (which @@ -203,6 +205,7 @@ struct bootflow_iter { int num_methods; int cur_method; int first_glob_method; + enum bootdev_prio_t cur_prio; struct udevice **method_order; bool doing_global; int method_flags; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 608aef15265..1090b92e510 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -588,3 +588,87 @@ static int bootdev_test_next_label(struct unit_test_state *uts) } BOOTSTD_TEST(bootdev_test_next_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV | UT_TESTF_SF_BOOTDEV); + + +/* Check iterating to the next prioirty in a list */ +static int bootdev_test_next_prio(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + struct udevice *dev; + int ret; + + sandbox_set_eth_enable(false); + test_set_skip_delays(true); + + /* 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_prio = 0; + iter.flags = BOOTFLOWF_SHOW; + + dev = NULL; + console_record_reset_enable(); + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.bootdev", dev->name); + + /* hunt flag not set, so this should not use any hunters */ + ut_asserteq(0, std->hunters_used); + ut_assert_console_end(); + + /* now try again with hunting enabled */ + iter.flags = BOOTFLOWF_SHOW | BOOTFLOWF_HUNT; + iter.cur_prio = 0; + iter.part = 0; + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc2.bootdev", dev->name); + ut_assert_nextline("Hunting with: mmc"); + ut_assert_console_end(); + + ut_assertok(bootstd_test_check_mmc_hunter(uts)); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc1.bootdev", dev->name); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc0.bootdev", dev->name); + ut_assert_console_end(); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("spi.bin@0.bootdev", dev->name); + ut_assert_skip_to_line("Hunting with: spi_flash"); + + /* + * this scans all bootdevs of priority BOOTDEVP_4_SCAN_FAST before it + * starts looking at the devices, so we se virtio as well + */ + ut_assert_nextline("Hunting with: virtio"); + ut_assert_nextlinen("SF: Detected m25p16"); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("spi.bin@1.bootdev", dev->name); + ut_assert_nextlinen("SF: Detected m25p16"); + ut_assert_console_end(); + + /* keep going until there are no more bootdevs */ + do { + ret = bootdev_next_prio(&iter, &dev); + } while (!ret); + ut_asserteq(-ENODEV, ret); + ut_assertnull(dev); + ut_asserteq(GENMASK(7, 0), std->hunters_used); + + ut_assert_skip_to_line("Hunting with: ethernet"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_next_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_SF_BOOTDEV); -- cgit v1.3.1 From 18552d2a7288afd6f125b4ac99e5c27690c129b4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:13 -0700 Subject: bootstd: Add a hunter for the extension feature This needs to run before any bootdev is used, so add a hunter for it. Signed-off-by: Simon Glass --- cmd/extension_board.c | 25 +++++++++++++++++++++++++ test/boot/bootdev.c | 37 +++++++++++++++++++++++-------------- test/boot/bootflow.c | 20 ++++++++++---------- test/boot/bootstd_common.h | 5 +++++ 4 files changed, 63 insertions(+), 24 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/cmd/extension_board.c b/cmd/extension_board.c index f7685d47b8b..2b672d888c6 100644 --- a/cmd/extension_board.c +++ b/cmd/extension_board.c @@ -5,7 +5,9 @@ */ #include +#include #include +#include #include #include #include @@ -176,3 +178,26 @@ U_BOOT_CMD(extension, 3, 1, do_extensionops, "extension list - lists available extension(s) board(s)\n" "extension apply - applies DT overlays corresponding to extension boards\n" ); + +static int extension_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + int ret; + + ret = env_set_hex("extension_overlay_addr", + env_get_hex("fdtoverlay_addr_r", 0)); + if (ret) + return log_msg_ret("env", ret); + + ret = extension_scan(show); + if (ret < 0) + return log_msg_ret("ext", ret); + + return 0; +} + +/* extensions should have a uclass - for now we use UCLASS_SIMPLE_BUS uclass */ +BOOTDEV_HUNTER(extension_bootdev_hunter) = { + .prio = BOOTDEVP_1_PRE_SCAN, + .uclass = UCLASS_SIMPLE_BUS, + .hunt = extension_bootdev_hunt, +}; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 1090b92e510..8ebc27a6435 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -306,6 +306,7 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); ut_assert_nextline(" 6 ethernet eth_bootdev"); + ut_assert_nextline(" 1 simple_bus (none)"); ut_assert_nextline(" 5 ide ide_bootdev"); ut_assert_nextline(" 2 mmc mmc_bootdev"); ut_assert_nextline(" 4 nvme nvme_bootdev"); @@ -313,7 +314,7 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextline(" 4 spi_flash sf_bootdev"); ut_assert_nextline(" 5 usb usb_bootdev"); ut_assert_nextline(" 4 virtio virtio_bootdev"); - ut_assert_nextline("(total hunters: 8)"); + ut_assert_nextline("(total hunters: 9)"); ut_assert_console_end(); ut_assertok(bootdev_hunt("usb1", false)); @@ -321,8 +322,8 @@ static int bootdev_test_hunter(struct unit_test_state *uts) "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); ut_assert_console_end(); - /* USB is fifth in the list, so bit 6 */ - ut_asserteq(BIT(6), std->hunters_used); + /* USB is sixth in the list, so bit 7 */ + ut_asserteq(BIT(7), std->hunters_used); return 0; } @@ -343,7 +344,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline("Prio Used Uclass Hunter"); ut_assert_nextlinen("----"); ut_assert_nextline(" 6 ethernet eth_bootdev"); - ut_assert_skip_to_line("(total hunters: 8)"); + ut_assert_skip_to_line("(total hunters: 9)"); ut_assert_console_end(); /* Use the MMC hunter and see that it updates */ @@ -351,7 +352,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assertok(run_command("bootdev hunt -l", 0)); ut_assert_skip_to_line(" 5 ide ide_bootdev"); ut_assert_nextline(" 2 * mmc mmc_bootdev"); - ut_assert_skip_to_line("(total hunters: 8)"); + ut_assert_skip_to_line("(total hunters: 9)"); ut_assert_console_end(); /* Scan all hunters */ @@ -359,6 +360,10 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) test_set_skip_delays(true); ut_assertok(run_command("bootdev hunt", 0)); ut_assert_nextline("Hunting with: ethernet"); + + /* This is the extension feature which has no uclass at present */ + ut_assert_nextline("Hunting with: simple_bus"); + ut_assert_nextline("Found 2 extension board(s)."); ut_assert_nextline("Hunting with: ide"); ut_assert_nextline("Bus 0: not available "); @@ -379,6 +384,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextlinen("Prio"); ut_assert_nextlinen("----"); ut_assert_nextline(" 6 * ethernet eth_bootdev"); + ut_assert_nextline(" 1 * simple_bus (none)"); ut_assert_nextline(" 5 * ide ide_bootdev"); ut_assert_nextline(" 2 * mmc mmc_bootdev"); ut_assert_nextline(" 4 * nvme nvme_bootdev"); @@ -386,10 +392,10 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextline(" 4 * spi_flash sf_bootdev"); ut_assert_nextline(" 5 * usb usb_bootdev"); ut_assert_nextline(" 4 * virtio virtio_bootdev"); - ut_assert_nextline("(total hunters: 8)"); + ut_assert_nextline("(total hunters: 9)"); ut_assert_console_end(); - ut_asserteq(GENMASK(7, 0), std->hunters_used); + ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); return 0; } @@ -553,8 +559,8 @@ static int bootdev_test_next_label(struct unit_test_state *uts) 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); + /* SCSI is sixth in the list, so bit 5 */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(5), std->hunters_used); ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); ut_assert_console_end(); @@ -564,7 +570,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts) mflags); /* dhcp: Ethernet is first so bit 0 */ - ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); ut_assert_console_end(); @@ -574,7 +580,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts) mflags); /* pxe: Ethernet is first so bit 0 */ - ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); mflags = 123; ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags)); @@ -582,7 +588,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts) ut_assert_console_end(); /* no change */ - ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used); + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); return 0; } @@ -629,10 +635,13 @@ static int bootdev_test_next_prio(struct unit_test_state *uts) ut_assertok(bootdev_next_prio(&iter, &dev)); ut_asserteq_str("mmc2.bootdev", dev->name); + ut_assert_nextline("Hunting with: simple_bus"); + ut_assert_nextline("Found 2 extension board(s)."); ut_assert_nextline("Hunting with: mmc"); ut_assert_console_end(); - ut_assertok(bootstd_test_check_mmc_hunter(uts)); + /* extension in second in the list , so bit 1 */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); ut_assertok(bootdev_next_prio(&iter, &dev)); ut_asserteq_str("mmc1.bootdev", dev->name); @@ -663,7 +672,7 @@ static int bootdev_test_next_prio(struct unit_test_state *uts) } while (!ret); ut_asserteq(-ENODEV, ret); ut_assertnull(dev); - ut_asserteq(GENMASK(7, 0), std->hunters_used); + ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); ut_assert_skip_to_line("Hunting with: ethernet"); ut_assert_console_end(); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index b71ec52eb7a..3a65d06696b 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -51,7 +51,7 @@ static int bootflow_cmd(struct unit_test_state *uts) console_record_reset_enable(); ut_assertok(run_command("bootdev select 1", 0)); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); @@ -77,17 +77,17 @@ BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT); static int bootflow_cmd_label(struct unit_test_state *uts) { console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -l mmc1", 0)); + ut_assertok(run_command("bootflow scan -lH mmc1", 0)); ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); ut_assert_skip_to_line("(1 bootflow, 1 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l mmc0.bootdev", 0)); + ut_assertok(run_command("bootflow scan -lH mmc0.bootdev", 0)); ut_assert_nextline("Scanning for bootflows in bootdev 'mmc0.bootdev'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l 0", 0)); + ut_assertok(run_command("bootflow scan -lH 0", 0)); ut_assert_nextline("Scanning for bootflows in bootdev 'mmc2.bootdev'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); @@ -102,7 +102,7 @@ static int bootflow_cmd_glob(struct unit_test_state *uts) ut_assertok(bootstd_test_drop_bootdev_order(uts)); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -lG", 0)); + ut_assertok(run_command("bootflow scan -lGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); @@ -134,7 +134,7 @@ static int bootflow_cmd_scan_e(struct unit_test_state *uts) ut_assertok(bootstd_test_drop_bootdev_order(uts)); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -aleG", 0)); + ut_assertok(run_command("bootflow scan -aleGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); @@ -352,7 +352,7 @@ static int bootflow_system(struct unit_test_state *uts) /* We should get a single 'bootmgr' method right at the end */ bootstd_clear_glob(); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_skip_to_line( " 0 efi_mgr ready (none) 0 "); ut_assert_skip_to_line("No more bootdevs"); @@ -383,7 +383,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts) bootstd_clear_glob(); console_record_reset_enable(); ut_assertok(inject_response(uts)); - ut_assertok(run_command("bootflow scan -lb", 0)); + ut_assertok(run_command("bootflow scan -lbH", 0)); /* Try to boot the bootmgr flow, which will fail */ console_record_reset_enable(); @@ -419,7 +419,7 @@ static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts) */ console_record_reset_enable(); ut_assertok(bootmeth_set_order("efi firmware0")); - ut_assertok(run_command("bootflow scan -lG", 0)); + ut_assertok(run_command("bootflow scan -lGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline( "Seq Method State Uclass Part Name Filename"); @@ -428,7 +428,7 @@ static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts) ut_assert_nextline("(0 bootflows, 0 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline( "Seq Method State Uclass Part Name Filename"); diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h index 0eb48fa1537..136a79b5178 100644 --- a/test/boot/bootstd_common.h +++ b/test/boot/bootstd_common.h @@ -20,6 +20,11 @@ #define TEST_VERSION "U-Boot v2022.04-local2" #define TEST_VERNUM 0x00010002 +enum { + MAX_HUNTER = 8, + MMC_HUNTER = 3, /* ID of MMC hunter */ +}; + struct unit_test_state; /** -- cgit v1.3.1 From 47aedc29dcb9871e076f6e4aa82004633af513ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:14 -0700 Subject: bootstd: Switch bootdev scanning to use labels At present we set up the bootdev order at the start, then scan the bootdevs one by one. However this approach cannot be used with hunters, since the bootdevs may not exist until the hunter is used. Nor can we just run all the hunters at the start, since that violate's U-Boot's 'lazy init' requirement. It also increases boot time. So we need to adjust the algorithm to scan by labels instead. As a first step, drop the dev_order[] array in favour of a list of labels. Update the name of bootdev_setup_iter_order() to better reflect what it does. Update some related comments and log messages. Also disable a few tests until a later commit where we can use them. Signed-off-by: Simon Glass --- boot/bootdev-uclass.c | 142 +++++++++----------------------------------------- boot/bootflow.c | 72 +++++++++++++++++++------ include/bootdev.h | 13 ++--- include/bootflow.h | 8 +-- test/boot/bootdev.c | 22 +++++++- test/boot/bootflow.c | 42 ++++++++++++--- 6 files changed, 147 insertions(+), 152 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 63005140061..334be7662a1 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -649,96 +649,12 @@ int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp) return 0; } -/** - * h_cmp_bootdev() - Compare two bootdevs to find out which should go first - * - * @v1: struct udevice * of first bootdev device - * @v2: struct udevice * of second bootdev device - * Return: sort order (<0 if dev1 < dev2, ==0 if equal, >0 if dev1 > dev2) - */ -static int h_cmp_bootdev(const void *v1, const void *v2) -{ - const struct udevice *dev1 = *(struct udevice **)v1; - const struct udevice *dev2 = *(struct udevice **)v2; - const struct bootdev_uc_plat *ucp1 = dev_get_uclass_plat(dev1); - const struct bootdev_uc_plat *ucp2 = dev_get_uclass_plat(dev2); - int diff; - - /* Use priority first */ - diff = ucp1->prio - ucp2->prio; - if (diff) - return diff; - - /* Fall back to seq for devices of the same priority */ - diff = dev_seq(dev1) - dev_seq(dev2); - - return diff; -} - -/** - * build_order() - Build the ordered list of bootdevs to use - * - * This builds an ordered list of devices by one of three methods: - * - using the boot_targets environment variable, if non-empty - * - using the bootdev-order devicetree property, if present - * - sorted by priority and sequence number - * - * @bootstd: BOOTSTD device to use - * @order: Bootdevs listed in default order - * @max_count: Number of entries in @order - * Return: number of bootdevs found in the ordering, or -E2BIG if the - * boot_targets string is too long, or -EXDEV if the ordering produced 0 results - */ -static int build_order(struct udevice *bootstd, struct udevice **order, - int max_count) -{ - const char *overflow_target = NULL; - const char *const *labels; - struct udevice *dev; - int i, ret, count; - bool ok; - - labels = bootstd_get_bootdev_order(bootstd, &ok); - if (!ok) - return log_msg_ret("ord", -ENOMEM); - if (labels) { - int upto; - - upto = 0; - for (i = 0; labels[i]; i++) { - ret = bootdev_find_by_label(labels[i], &dev, NULL); - if (!ret) { - if (upto == max_count) { - overflow_target = labels[i]; - break; - } - order[upto++] = dev; - } - } - count = upto; - } else { - /* sort them into priority order */ - count = max_count; - qsort(order, count, sizeof(struct udevice *), h_cmp_bootdev); - } - - if (overflow_target) { - log_warning("Expected at most %d bootdevs, but overflowed with boot_target '%s'\n", - max_count, overflow_target); - } - - if (!count) - return log_msg_ret("targ", -EXDEV); - - return count; -} - -int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp) +int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp, + int *method_flagsp) { - struct udevice *bootstd, *dev = *devp, **order; + struct udevice *bootstd, *dev = *devp; bool show = iter->flags & BOOTFLOWF_SHOW; - struct uclass *uc; - int count, upto; + int method_flags; int ret; ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd); @@ -757,39 +673,33 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp) /* Handle scanning a single device */ if (dev) { iter->flags |= BOOTFLOWF_SINGLE_DEV; - return 0; - } - - count = uclass_id_count(UCLASS_BOOTDEV); - if (!count) - return log_msg_ret("count", -ENOENT); - - order = calloc(count, sizeof(struct udevice *)); - if (!order) - return log_msg_ret("order", -ENOMEM); - - /* Get the list of bootdevs */ - uclass_id_foreach_dev(UCLASS_BOOTDEV, dev, uc) - order[upto++] = dev; - log_debug("Found %d bootdevs\n", count); - if (upto != count) - log_debug("Expected %d bootdevs, found %d using aliases\n", - count, upto); - - ret = build_order(bootstd, order, upto); - if (ret < 0) { - free(order); - return log_msg_ret("build", ret); + log_debug("Selected boodev: %s\n", dev->name); + method_flags = 0; + } else { + bool ok; + + /* This either returns a non-empty list or NULL */ + iter->labels = bootstd_get_bootdev_order(bootstd, &ok); + if (!ok) + return log_msg_ret("ord", -ENOMEM); + log_debug("setup labels %p\n", iter->labels); + if (iter->labels) { + iter->cur_label = -1; + ret = bootdev_next_label(iter, &dev, &method_flags); + } else { + ret = bootdev_next_prio(iter, &dev); + method_flags = 0; + } + if (!dev) + return log_msg_ret("fin", -ENOENT); + log_debug("Selected bootdev: %s\n", dev->name); } - iter->num_devs = ret; - iter->dev_order = order; - iter->cur_dev = 0; - - dev = *order; ret = device_probe(dev); if (ret) return log_msg_ret("probe", ret); + if (method_flagsp) + *method_flagsp = method_flags; *devp = dev; return 0; diff --git a/boot/bootflow.c b/boot/bootflow.c index d2dbc9d4450..32e2aad470d 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -92,7 +92,6 @@ void bootflow_iter_init(struct bootflow_iter *iter, int flags) void bootflow_iter_uninit(struct bootflow_iter *iter) { - free(iter->dev_order); free(iter->method_order); } @@ -113,12 +112,25 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, return 0; } +/** + * bootflow_iter_set_dev() - switch to the next bootdev when iterating + * + * This sets iter->dev, records the device in the dev_used[] list and shows a + * message if required + * + * @iter: Iterator to update + * @dev: Bootdev to use, or NULL if there are no more + */ static void bootflow_iter_set_dev(struct bootflow_iter *iter, - struct udevice *dev) + struct udevice *dev, int method_flags) { struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method); + log_debug("iter: Setting dev to %s, flags %x\n", + dev ? dev->name : "(none)", method_flags); iter->dev = dev; + iter->method_flags = method_flags; + if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) == BOOTFLOWF_SHOW) { if (dev) @@ -144,6 +156,7 @@ static int iter_incr(struct bootflow_iter *iter) bool global; int ret; + log_debug("entry: err=%d\n", iter->err); global = iter->doing_global; if (iter->err == BF_NO_MORE_DEVICES) @@ -182,7 +195,7 @@ static int iter_incr(struct bootflow_iter *iter) return 0; } - /* No more partitions; start at the first one and...*/ + /* No more partitions; start at the first one and... */ iter->part = 0; /* @@ -196,16 +209,32 @@ static int iter_incr(struct bootflow_iter *iter) if (iter->flags & BOOTFLOWF_SINGLE_DEV) { ret = -ENOENT; } else { - if (inc_dev) - iter->cur_dev++; - if (iter->cur_dev == iter->num_devs) { - ret = -ENOENT; - bootflow_iter_set_dev(iter, NULL); + int method_flags; + + ret = 0; + dev = iter->dev; + log_debug("inc_dev=%d\n", inc_dev); + if (!inc_dev) { + ret = bootdev_setup_iter(iter, &dev, &method_flags); + } else { + log_debug("labels %p\n", iter->labels); + if (iter->labels) { + ret = bootdev_next_label(iter, &dev, + &method_flags); + } else { + ret = bootdev_next_prio(iter, &dev); + method_flags = 0; + } + } + log_debug("ret=%d, dev=%p %s\n", ret, dev, + dev ? dev->name : "none"); + if (ret) { + bootflow_iter_set_dev(iter, NULL, 0); } else { - dev = iter->dev_order[iter->cur_dev]; ret = device_probe(dev); + log_debug("probe %s %d\n", dev->name, ret); if (!log_msg_ret("probe", ret)) - bootflow_iter_set_dev(iter, dev); + bootflow_iter_set_dev(iter, dev, method_flags); } } @@ -230,7 +259,7 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) int ret; if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { - bootflow_iter_set_dev(iter, NULL); + bootflow_iter_set_dev(iter, NULL, 0); ret = bootmeth_get_bootflow(iter->method, bflow); if (ret) return log_msg_ret("glob", ret); @@ -274,18 +303,27 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, flags |= BOOTFLOWF_SKIP_GLOBAL; bootflow_iter_init(iter, flags); - ret = bootdev_setup_iter_order(iter, &dev); - if (ret) - return log_msg_ret("obdev", -ENODEV); - + /* + * Set up the ordering of bootmeths. This sets iter->doing_global and + * iter->first_glob_method if we are starting with the global bootmeths + */ ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWF_SKIP_GLOBAL)); if (ret) return log_msg_ret("obmeth", -ENODEV); /* Find the first bootmeth (there must be at least one!) */ iter->method = iter->method_order[iter->cur_method]; - if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global) - bootflow_iter_set_dev(iter, dev); + + if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global) { + struct udevice *dev = NULL; + int method_flags; + + ret = bootdev_setup_iter(iter, &dev, &method_flags); + if (ret) + return log_msg_ret("obdev", -ENODEV); + + bootflow_iter_set_dev(iter, dev, method_flags); + } ret = bootflow_check(iter, bflow); if (ret) { diff --git a/include/bootdev.h b/include/bootdev.h index 4b6a8eb8d8f..8fa67487c63 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -265,21 +265,22 @@ int bootdev_find_by_any(const char *name, struct udevice **devp, int *method_flagsp); /** - * bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan + * bootdev_setup_iter() - Set up iteration through bootdevs * - * This sets up the ordering information in @iter, based on the priority of each - * bootdev and the bootdev-order property in the bootstd node - * - * If a single device is requested, no ordering is needed + * 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). * * @iter: Iterator to update with the order * @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 + * @method_flagsp: If non-NULL, returns any flags implied by the label + * (enum bootflow_meth_flags_t), 0 if none * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve * on other error */ -int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp); +int bootdev_setup_iter(struct bootflow_iter *iter, 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 69ac90483c6..bdb37352ab9 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -163,7 +163,8 @@ enum bootflow_meth_flags_t { * @flags: Flags to use (see enum bootflow_flags_t). If BOOTFLOWF_GLOBAL_FIRST is * enabled then the global bootmeths are being scanned, otherwise we have * moved onto the bootdevs - * @dev: Current bootdev, NULL if none + * @dev: Current bootdev, NULL if none. This is only ever updated in + * bootflow_iter_set_dev() * @part: Current partition number (0 for whole device) * @method: Current bootmeth * @max_part: Maximum hardware partition number in @dev, 0 if there is no @@ -173,9 +174,6 @@ enum bootflow_meth_flags_t { * forward (e.g. to skip the current partition because it is not valid) * -ESHUTDOWN: try next bootdev * @num_devs: Number of bootdevs in @dev_order - * @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 @@ -198,8 +196,6 @@ struct bootflow_iter { int first_bootable; int err; int num_devs; - int cur_dev; - struct udevice **dev_order; const char *const *labels; int cur_label; int num_methods; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 8ebc27a6435..679ffc4d8df 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -186,6 +186,7 @@ static int bootdev_test_any(struct unit_test_state *uts) BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV); +#if 0 /* disable for now */ /* Check bootdev ordering with the bootdev-order property */ static int bootdev_test_order(struct unit_test_state *uts) { @@ -290,6 +291,7 @@ static int bootdev_test_prio(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +#endif /* Check listing hunters */ static int bootdev_test_hunter(struct unit_test_state *uts) @@ -402,6 +404,25 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV); +/* Check searching for bootdevs using the hunters */ +static int bootdev_test_hunt_scan(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + ut_assertok(bootflow_scan_first(&iter, BOOTFLOWF_SHOW | BOOTFLOWF_HUNT | + BOOTFLOWF_SKIP_GLOBAL, &bflow)); + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunt_scan, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + /* Check that only bootable partitions are processed */ static int bootdev_test_bootable(struct unit_test_state *uts) { @@ -640,7 +661,6 @@ static int bootdev_test_next_prio(struct unit_test_state *uts) ut_assert_nextline("Hunting with: mmc"); ut_assert_console_end(); - /* extension in second in the list , so bit 1 */ ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); ut_assertok(bootdev_next_prio(&iter, &dev)); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 3a65d06696b..1a2c54c1119 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -55,7 +55,10 @@ static int bootflow_cmd(struct unit_test_state *uts) ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); + 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("No more bootdevs"); ut_assert_nextlinen("---"); ut_assert_nextline("(1 bootflow, 1 valid)"); ut_assert_console_end(); @@ -73,28 +76,55 @@ static int bootflow_cmd(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -/* Check 'bootflow scan' with a name / label / seq */ +#if 0 /* disable for now */ +/* Check 'bootflow scan' with a label / seq */ static int bootflow_cmd_label(struct unit_test_state *uts) { + test_set_eth_enable(false); + console_record_reset_enable(); ut_assertok(run_command("bootflow scan -lH mmc1", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); + ut_assert_nextline("Scanning for bootflows with label 'mmc1'"); ut_assert_skip_to_line("(1 bootflow, 1 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -lH mmc0.bootdev", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc0.bootdev'"); + ut_assertok(run_command("bootflow scan -lH 0", 0)); + ut_assert_nextline("Scanning for bootflows with label '0'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); + /* + * 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 + */ + ut_assertok(run_command("bootflow scan -lH 9", 0)); + ut_assert_nextline("Scanning for bootflows with label '9'"); + ut_assert_skip_to_line("(1 bootflow, 1 valid)"); + ut_assertok(run_command("bootflow scan -lH 0", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc2.bootdev'"); + ut_assert_nextline("Scanning for bootflows with label '0'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); return 0; } -BOOTSTD_TEST(bootflow_cmd_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +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) -- cgit v1.3.1 From 91943ff7038f9c47fb310dbc22150b5664c8fbf7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:15 -0700 Subject: bootstd: Allow scanning a single bootdev label 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 --- 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(-) (limited to 'test/boot/bootdev.c') 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 * -- cgit v1.3.1 From 4b7cb058df35222632efa3f71aad63757b226440 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:16 -0700 Subject: bootstd: Drop the old bootflow_scan_first() This function is not used outside tests. Drop it and rename bootflow_scan_dev() since it is how we start a scan now. Signed-off-by: Simon Glass --- boot/bootflow.c | 18 +++--------------- cmd/bootflow.c | 2 +- include/bootflow.h | 23 +++-------------------- test/boot/bootdev.c | 16 +++++++++------- test/boot/bootflow.c | 5 +++-- 5 files changed, 19 insertions(+), 45 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootflow.c b/boot/bootflow.c index 50d9c2e813a..750732f7083 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -324,9 +324,9 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) return 0; } -int bootflow_scan_bootdev(struct udevice *dev, const char *label, - struct bootflow_iter *iter, int flags, - struct bootflow *bflow) +int bootflow_scan_first(struct udevice *dev, const char *label, + struct bootflow_iter *iter, int flags, + struct bootflow *bflow) { int ret; @@ -371,18 +371,6 @@ int bootflow_scan_bootdev(struct udevice *dev, const char *label, return 0; } -int bootflow_scan_first(struct bootflow_iter *iter, int flags, - struct bootflow *bflow) -{ - int ret; - - ret = bootflow_scan_bootdev(NULL, NULL, iter, flags, bflow); - if (ret) - return log_msg_ret("start", ret); - - return 0; -} - int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow) { int ret; diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 72d5a8424e9..692bc6d117f 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -161,7 +161,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, else bootstd_clear_glob(); for (i = 0, - ret = bootflow_scan_bootdev(dev, label, &iter, flags, &bflow); + ret = bootflow_scan_first(dev, label, &iter, flags, &bflow); i < 1000 && ret != -ENODEV; i++, ret = bootflow_scan_next(&iter, &bflow)) { bflow.err = ret; diff --git a/include/bootflow.h b/include/bootflow.h index 1b7920a9572..c2368912061 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -249,7 +249,7 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, const struct udevice *bmeth); /** - * bootflow_scan_bootdev() - find the first bootflow in a bootdev + * bootflow_scan_first() - find the first bootflow for a device or label * * If @flags includes BOOTFLOWF_ALL then bootflows with errors are returned too * @@ -264,25 +264,8 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, * Return: 0 if found, -ENODEV if no device, other -ve on other error * (iteration can continue) */ -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 - * - * This works through the available bootdev devices until it finds one that - * can supply a bootflow. It then returns that - * - * If @flags includes BOOTFLOWF_ALL then bootflows with errors are returned too - * - * @iter: Place to store private info (inited by this call), with - * @flags: Flags for bootdev (enum bootflow_flags_t) - * @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_first(struct bootflow_iter *iter, int flags, +int bootflow_scan_first(struct udevice *dev, const char *label, + struct bootflow_iter *iter, int flags, struct bootflow *bflow); /** diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 1724e34af3e..5d5ce7f48cf 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -203,7 +203,7 @@ static int bootdev_test_order(struct unit_test_state *uts) * mmc2 - nothing connected */ ut_assertok(env_set("boot_targets", NULL)); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(2, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); @@ -211,7 +211,7 @@ static int bootdev_test_order(struct unit_test_state *uts) /* Use the environment variable to override it */ ut_assertok(env_set("boot_targets", "mmc1 mmc2")); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(2, iter.num_devs); ut_asserteq_str("mmc1.bootdev", iter.dev_order[0]->name); ut_asserteq_str("mmc2.bootdev", iter.dev_order[1]->name); @@ -224,7 +224,7 @@ static int bootdev_test_order(struct unit_test_state *uts) ut_assertok(env_set("boot_targets", NULL)); ut_assertok(bootstd_test_drop_bootdev_order(uts)); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(3, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); @@ -239,7 +239,7 @@ static int bootdev_test_order(struct unit_test_state *uts) iter.dev_order[2]->seq_ = 2; bootflow_iter_uninit(&iter); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(3, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); ut_asserteq_str("mmc0.bootdev", iter.dev_order[1]->name); @@ -268,7 +268,7 @@ static int bootdev_test_prio(struct unit_test_state *uts) /* 3 MMC and 3 USB bootdevs: MMC should come before USB */ console_record_reset_enable(); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(6, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); ut_asserteq_str("usb_mass_storage.lun0.bootdev", @@ -282,7 +282,8 @@ static int bootdev_test_prio(struct unit_test_state *uts) ucp->prio = 1; bootflow_iter_uninit(&iter); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWF_HUNT, + &bflow)); ut_asserteq(6, iter.num_devs); ut_asserteq_str("usb_mass_storage.lun0.bootdev", iter.dev_order[0]->name); @@ -415,7 +416,8 @@ static int bootdev_test_hunt_scan(struct unit_test_state *uts) ut_assertok(bootstd_get_priv(&std)); ut_assertok(bootstd_test_drop_bootdev_order(uts)); - ut_assertok(bootflow_scan_first(&iter, BOOTFLOWF_SHOW | BOOTFLOWF_HUNT | + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, + BOOTFLOWF_SHOW | BOOTFLOWF_HUNT | BOOTFLOWF_SKIP_GLOBAL, &bflow)); ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 0b3a2fa6acc..b9284fc464a 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -276,7 +276,8 @@ static int bootflow_iter(struct unit_test_state *uts) /* The first device is mmc2.bootdev which has no media */ ut_asserteq(-EPROTONOSUPPORT, - bootflow_scan_first(&iter, BOOTFLOWF_ALL | BOOTFLOWF_SKIP_GLOBAL, &bflow)); + bootflow_scan_first(NULL, NULL, &iter, + BOOTFLOWF_ALL | BOOTFLOWF_SKIP_GLOBAL, &bflow)); ut_asserteq(2, iter.num_methods); ut_asserteq(0, iter.cur_method); ut_asserteq(0, iter.part); @@ -415,7 +416,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts) /* Try to boot the bootmgr flow, which will fail */ console_record_reset_enable(); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(3, iter.num_methods); ut_asserteq_str("sandbox", iter.method->name); ut_assertok(inject_response(uts)); -- cgit v1.3.1 From a950f2855a5fcc1e550aa6786720a3a995b1ceda Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 17 Jan 2023 10:48:17 -0700 Subject: bootstd: Record the bootdevs used during scanning Add a way to record the bootdevs used when scanning for bootflows. This is useful for testing. Enable this only with BOOTSTD_FULL and do the same for the progress reporting. Re-enable and update the affected tests now that we have this feature. For bootdev_test_order_default() there is no-longer any support for using the bootdev aliases to specify an ordering, so drop that part of the test. Signed-off-by: Simon Glass --- boot/bootflow.c | 29 +++++++++++++++-------- include/bootflow.h | 10 +++++++- test/boot/bootdev.c | 67 ++++++++++++++++++++++++++++------------------------- 3 files changed, 63 insertions(+), 43 deletions(-) (limited to 'test/boot/bootdev.c') diff --git a/boot/bootflow.c b/boot/bootflow.c index 750732f7083..03a180bcddc 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -88,6 +88,9 @@ void bootflow_iter_init(struct bootflow_iter *iter, int flags) memset(iter, '\0', sizeof(*iter)); iter->first_glob_method = -1; iter->flags = flags; + + /* remember the first bootdevs we see */ + iter->max_devs = BOOTFLOW_MAX_USED_DEVS; } void bootflow_iter_uninit(struct bootflow_iter *iter) @@ -131,16 +134,22 @@ static void bootflow_iter_set_dev(struct bootflow_iter *iter, iter->dev = dev; iter->method_flags = method_flags; - if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) == - BOOTFLOWF_SHOW) { - if (dev) - printf("Scanning bootdev '%s':\n", dev->name); - else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && - ucp->flags & BOOTMETHF_GLOBAL) - printf("Scanning global bootmeth '%s':\n", - iter->method->name); - else - printf("No more bootdevs\n"); + if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) { + /* record the device for later */ + if (dev && iter->num_devs < iter->max_devs) + iter->dev_used[iter->num_devs++] = dev; + + if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) == + BOOTFLOWF_SHOW) { + if (dev) + printf("Scanning bootdev '%s':\n", dev->name); + else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && + ucp->flags & BOOTMETHF_GLOBAL) + printf("Scanning global bootmeth '%s':\n", + iter->method->name); + else + printf("No more bootdevs\n"); + } } } diff --git a/include/bootflow.h b/include/bootflow.h index c2368912061..f516bf8dea4 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -14,6 +14,10 @@ struct bootstd_priv; struct expo; +enum { + BOOTFLOW_MAX_USED_DEVS = 16, +}; + /** * enum bootflow_state_t - states that a particular bootflow can be in * @@ -173,7 +177,9 @@ enum bootflow_meth_flags_t { * @err: Error obtained from checking the last iteration. This is used to skip * forward (e.g. to skip the current partition because it is not valid) * -ESHUTDOWN: try next bootdev - * @num_devs: Number of bootdevs in @dev_order + * @num_devs: Number of bootdevs in @dev_used + * @max_devs: Maximum number of entries in @dev_used + * @dev_used: List of bootdevs used during iteration * @labels: List of labels to scan for bootdevs * @cur_label: Current label being processed * @num_methods: Number of bootmeth devices in @method_order @@ -196,6 +202,8 @@ struct bootflow_iter { int first_bootable; int err; int num_devs; + int max_devs; + struct udevice *dev_used[BOOTFLOW_MAX_USED_DEVS]; const char *const *labels; int cur_label; int num_methods; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 5d5ce7f48cf..ef5215bbcec 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -186,7 +186,6 @@ static int bootdev_test_any(struct unit_test_state *uts) BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV); -#if 0 /* disable for now */ /* Check bootdev ordering with the bootdev-order property */ static int bootdev_test_order(struct unit_test_state *uts) { @@ -205,18 +204,29 @@ static int bootdev_test_order(struct unit_test_state *uts) ut_assertok(env_set("boot_targets", NULL)); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(2, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); bootflow_iter_uninit(&iter); /* Use the environment variable to override it */ ut_assertok(env_set("boot_targets", "mmc1 mmc2")); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(2, iter.num_devs); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[1]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); bootflow_iter_uninit(&iter); + return 0; +} +BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check default bootdev ordering */ +static int bootdev_test_order_default(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + /* * Now drop both orderings, to check the default (prioriy/sequence) * ordering @@ -225,30 +235,18 @@ static int bootdev_test_order(struct unit_test_state *uts) ut_assertok(bootstd_test_drop_bootdev_order(uts)); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); - ut_asserteq(3, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); - ut_asserteq_str("mmc0.bootdev", iter.dev_order[2]->name); - - /* - * Check that adding aliases for the bootdevs works. We just fake it by - * setting the sequence numbers directly. - */ - iter.dev_order[0]->seq_ = 0; - iter.dev_order[1]->seq_ = 3; - iter.dev_order[2]->seq_ = 2; - bootflow_iter_uninit(&iter); + ut_asserteq(2, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); - ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(3, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc0.bootdev", iter.dev_order[1]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[2]->name); + ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); bootflow_iter_uninit(&iter); return 0; } -BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +BOOTSTD_TEST(bootdev_test_order_default, UT_TESTF_DM | UT_TESTF_SCAN_FDT); /* Check bootdev ordering with the uclass priority */ static int bootdev_test_prio(struct unit_test_state *uts) @@ -260,6 +258,9 @@ static int bootdev_test_prio(struct unit_test_state *uts) test_set_skip_delays(true); + /* disable ethernet since the hunter will run dhcp */ + test_set_eth_enable(false); + /* Start up USB which gives us three additional bootdevs */ usb_started = false; ut_assertok(run_command("usb start", 0)); @@ -269,30 +270,32 @@ static int bootdev_test_prio(struct unit_test_state *uts) /* 3 MMC and 3 USB bootdevs: MMC should come before USB */ console_record_reset_enable(); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(6, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); ut_asserteq_str("usb_mass_storage.lun0.bootdev", - iter.dev_order[3]->name); + iter.dev_used[3]->name); - ut_assertok(bootdev_get_sibling_blk(iter.dev_order[3], &blk)); + ut_assertok(bootdev_get_sibling_blk(iter.dev_used[3], &blk)); ut_asserteq_str("usb_mass_storage.lun0", blk->name); /* adjust the priority of the first USB bootdev to the highest */ - ucp = dev_get_uclass_plat(iter.dev_order[3]); - ucp->prio = 1; + ucp = dev_get_uclass_plat(iter.dev_used[3]); + ucp->prio = BOOTDEVP_1_PRE_SCAN; + /* try again but enable hunting, which brings in SCSI */ bootflow_iter_uninit(&iter); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWF_HUNT, &bflow)); - ut_asserteq(6, iter.num_devs); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(7, iter.num_devs); ut_asserteq_str("usb_mass_storage.lun0.bootdev", - iter.dev_order[0]->name); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[1]->name); + iter.dev_used[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); return 0; } BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -#endif /* Check listing hunters */ static int bootdev_test_hunter(struct unit_test_state *uts) -- cgit v1.3.1