diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index dd9ec668e1..7ac42afd7b 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 53a0489b93..67c972e3fe 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 13e2ff486d..ecf8557af8 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 a14c750ff6..225eb18ee6 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 0a49d28670..d59a704ddb 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 28866faac7..5b1efaaee8 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 56dd35b69c..c8b2f5efde 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 deef789048..db03c5c032 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 319dda8e0b..9c6610bb92 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 ea0703fa5c..e6045b05d8 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)