summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/bootdev-uclass.c140
-rw-r--r--boot/bootflow.c72
2 files changed, 80 insertions, 132 deletions
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);
+ log_debug("Selected boodev: %s\n", dev->name);
+ method_flags = 0;
+ } else {
+ bool ok;
- ret = build_order(bootstd, order, upto);
- if (ret < 0) {
- free(order);
- return log_msg_ret("build", ret);
+ /* 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) {