diff --git a/boot/bootflow.c b/boot/bootflow.c index 37bccb823a..08ea033632 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -86,6 +86,7 @@ int bootflow_next_glob(struct bootflow **bflowp) void bootflow_iter_init(struct bootflow_iter *iter, int flags) { memset(iter, '\0', sizeof(*iter)); + iter->first_glob_method = -1; iter->flags = flags; } @@ -115,11 +116,17 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, static void bootflow_iter_set_dev(struct bootflow_iter *iter, struct udevice *dev) { + struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method); + iter->dev = 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"); } @@ -133,8 +140,12 @@ static void bootflow_iter_set_dev(struct bootflow_iter *iter, static int iter_incr(struct bootflow_iter *iter) { struct udevice *dev; + bool inc_dev = true; + bool global; int ret; + global = iter->doing_global; + if (iter->err == BF_NO_MORE_DEVICES) return BF_NO_MORE_DEVICES; @@ -144,6 +155,21 @@ static int iter_incr(struct bootflow_iter *iter) iter->method = iter->method_order[iter->cur_method]; return 0; } + + /* + * If we have finished scanning the global bootmeths, start the + * normal bootdev scan + */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) { + iter->num_methods = iter->first_glob_method; + iter->doing_global = false; + + /* + * Don't move to the next dev as we haven't tried this + * one yet! + */ + inc_dev = false; + } } /* No more bootmeths; start at the first one, and... */ @@ -169,14 +195,18 @@ static int iter_incr(struct bootflow_iter *iter) /* ...select next bootdev */ if (iter->flags & BOOTFLOWF_SINGLE_DEV) { ret = -ENOENT; - } else if (++iter->cur_dev == iter->num_devs) { - ret = -ENOENT; - bootflow_iter_set_dev(iter, NULL); } else { - dev = iter->dev_order[iter->cur_dev]; - ret = device_probe(dev); - if (!log_msg_ret("probe", ret)) - bootflow_iter_set_dev(iter, dev); + if (inc_dev) + iter->cur_dev++; + if (iter->cur_dev == iter->num_devs) { + ret = -ENOENT; + bootflow_iter_set_dev(iter, NULL); + } else { + dev = iter->dev_order[iter->cur_dev]; + ret = device_probe(dev); + if (!log_msg_ret("probe", ret)) + bootflow_iter_set_dev(iter, dev); + } } /* if there are no more bootdevs, give up */ @@ -199,6 +229,15 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) struct udevice *dev; int ret; + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { + bootflow_iter_set_dev(iter, NULL); + ret = bootmeth_get_bootflow(iter->method, bflow); + if (ret) + return log_msg_ret("glob", ret); + + return 0; + } + dev = iter->dev; ret = bootdev_get_bootflow(dev, iter, bflow); @@ -231,12 +270,13 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, { int ret; + if (dev) + flags |= BOOTFLOWF_SKIP_GLOBAL; bootflow_iter_init(iter, flags); ret = bootdev_setup_iter_order(iter, &dev); if (ret) return log_msg_ret("obdev", -ENODEV); - bootflow_iter_set_dev(iter, dev); ret = bootmeth_setup_iter_order(iter); if (ret) @@ -244,6 +284,8 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, /* 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); ret = bootflow_check(iter, bflow); if (ret) { diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 47899245ee..313103d277 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -95,7 +95,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, struct bootflow_iter iter; struct udevice *dev; struct bootflow bflow; - bool all = false, boot = false, errors = false, list = false; + bool all = false, boot = false, errors = false, no_global = false; + bool list = false; int num_valid = 0; bool has_args; int ret, i; @@ -112,6 +113,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, all = strchr(argv[1], 'a'); boot = strchr(argv[1], 'b'); errors = strchr(argv[1], 'e'); + no_global = strchr(argv[1], 'G'); list = strchr(argv[1], 'l'); argc--; argv++; @@ -137,6 +139,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, flags |= BOOTFLOWF_SHOW; if (all) flags |= BOOTFLOWF_ALL; + if (no_global) + flags |= BOOTFLOWF_SKIP_GLOBAL; /* * If we have a device, just scan for bootflows attached to that device @@ -383,7 +387,7 @@ static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_SYS_LONGHELP static char bootflow_help_text[] = #ifdef CONFIG_CMD_BOOTFLOW_FULL - "scan [-abel] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot)\n" + "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n" "bootflow list [-e] - list scanned bootflows (-e errors)\n" "bootflow select [|] - select a bootflow\n" "bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n" diff --git a/include/bootflow.h b/include/bootflow.h index 4fa482a678..6aa3d1fff8 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -77,12 +77,14 @@ struct bootflow { * @BOOTFLOWF_SHOW: Show each bootdev before scanning it * @BOOTFLOWF_ALL: Return bootflows with errors as well * @BOOTFLOWF_SINGLE_DEV: Just scan one bootmeth + * @BOOTFLOWF_SKIP_GLOBAL: Don't scan global bootmeths */ enum bootflow_flags_t { BOOTFLOWF_FIXED = 1 << 0, BOOTFLOWF_SHOW = 1 << 1, BOOTFLOWF_ALL = 1 << 2, BOOTFLOWF_SINGLE_DEV = 1 << 3, + BOOTFLOWF_SKIP_GLOBAL = 1 << 4, }; /** @@ -102,8 +104,10 @@ enum bootflow_flags_t { * updated to a larger value, no less than the number of available partitions. * This ensures that iteration works through all partitions on the bootdev. * - * @flags: Flags to use (see enum bootflow_flags_t) - * @dev: Current bootdev + * @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 * @part: Current partition number (0 for whole device) * @method: Current bootmeth * @max_part: Maximum hardware partition number in @dev, 0 if there is no @@ -117,7 +121,11 @@ enum bootflow_flags_t { * with the first one on the list * @num_methods: Number of bootmeth devices in @method_order * @cur_method: Current method number, an index into @method_order - * @method_order: List of bootmeth devices to use, in order + * @first_glob_method: First global method, if any, else -1 + * @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 + * happens before the normal ones) */ struct bootflow_iter { int flags; @@ -131,7 +139,9 @@ struct bootflow_iter { struct udevice **dev_order; int num_methods; int cur_method; + int first_glob_method; struct udevice **method_order; + bool doing_global; }; /**