void bootflow_iter_init(struct bootflow_iter *iter, int flags)
{
memset(iter, '\0', sizeof(*iter));
+ iter->first_glob_method = -1;
iter->flags = flags;
}
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");
}
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;
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... */
/* ...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 */
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);
{
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)
/* 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) {
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;
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++;
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
#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 [<num>|<name>] - select a bootflow\n"
"bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n"
* @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,
};
/**
* 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
* 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;
struct udevice **dev_order;
int num_methods;
int cur_method;
+ int first_glob_method;
struct udevice **method_order;
+ bool doing_global;
};
/**