Skip to content

Commit 47aedc2

Browse files
sjg20trini
authored andcommitted
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 <sjg@chromium.org>
1 parent 18552d2 commit 47aedc2

File tree

6 files changed

+147
-152
lines changed

6 files changed

+147
-152
lines changed

boot/bootdev-uclass.c

Lines changed: 26 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -649,96 +649,12 @@ int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp)
649649
return 0;
650650
}
651651

652-
/**
653-
* h_cmp_bootdev() - Compare two bootdevs to find out which should go first
654-
*
655-
* @v1: struct udevice * of first bootdev device
656-
* @v2: struct udevice * of second bootdev device
657-
* Return: sort order (<0 if dev1 < dev2, ==0 if equal, >0 if dev1 > dev2)
658-
*/
659-
static int h_cmp_bootdev(const void *v1, const void *v2)
660-
{
661-
const struct udevice *dev1 = *(struct udevice **)v1;
662-
const struct udevice *dev2 = *(struct udevice **)v2;
663-
const struct bootdev_uc_plat *ucp1 = dev_get_uclass_plat(dev1);
664-
const struct bootdev_uc_plat *ucp2 = dev_get_uclass_plat(dev2);
665-
int diff;
666-
667-
/* Use priority first */
668-
diff = ucp1->prio - ucp2->prio;
669-
if (diff)
670-
return diff;
671-
672-
/* Fall back to seq for devices of the same priority */
673-
diff = dev_seq(dev1) - dev_seq(dev2);
674-
675-
return diff;
676-
}
677-
678-
/**
679-
* build_order() - Build the ordered list of bootdevs to use
680-
*
681-
* This builds an ordered list of devices by one of three methods:
682-
* - using the boot_targets environment variable, if non-empty
683-
* - using the bootdev-order devicetree property, if present
684-
* - sorted by priority and sequence number
685-
*
686-
* @bootstd: BOOTSTD device to use
687-
* @order: Bootdevs listed in default order
688-
* @max_count: Number of entries in @order
689-
* Return: number of bootdevs found in the ordering, or -E2BIG if the
690-
* boot_targets string is too long, or -EXDEV if the ordering produced 0 results
691-
*/
692-
static int build_order(struct udevice *bootstd, struct udevice **order,
693-
int max_count)
694-
{
695-
const char *overflow_target = NULL;
696-
const char *const *labels;
697-
struct udevice *dev;
698-
int i, ret, count;
699-
bool ok;
700-
701-
labels = bootstd_get_bootdev_order(bootstd, &ok);
702-
if (!ok)
703-
return log_msg_ret("ord", -ENOMEM);
704-
if (labels) {
705-
int upto;
706-
707-
upto = 0;
708-
for (i = 0; labels[i]; i++) {
709-
ret = bootdev_find_by_label(labels[i], &dev, NULL);
710-
if (!ret) {
711-
if (upto == max_count) {
712-
overflow_target = labels[i];
713-
break;
714-
}
715-
order[upto++] = dev;
716-
}
717-
}
718-
count = upto;
719-
} else {
720-
/* sort them into priority order */
721-
count = max_count;
722-
qsort(order, count, sizeof(struct udevice *), h_cmp_bootdev);
723-
}
724-
725-
if (overflow_target) {
726-
log_warning("Expected at most %d bootdevs, but overflowed with boot_target '%s'\n",
727-
max_count, overflow_target);
728-
}
729-
730-
if (!count)
731-
return log_msg_ret("targ", -EXDEV);
732-
733-
return count;
734-
}
735-
736-
int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp)
652+
int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp,
653+
int *method_flagsp)
737654
{
738-
struct udevice *bootstd, *dev = *devp, **order;
655+
struct udevice *bootstd, *dev = *devp;
739656
bool show = iter->flags & BOOTFLOWF_SHOW;
740-
struct uclass *uc;
741-
int count, upto;
657+
int method_flags;
742658
int ret;
743659

744660
ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd);
@@ -757,39 +673,33 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp)
757673
/* Handle scanning a single device */
758674
if (dev) {
759675
iter->flags |= BOOTFLOWF_SINGLE_DEV;
760-
return 0;
761-
}
762-
763-
count = uclass_id_count(UCLASS_BOOTDEV);
764-
if (!count)
765-
return log_msg_ret("count", -ENOENT);
766-
767-
order = calloc(count, sizeof(struct udevice *));
768-
if (!order)
769-
return log_msg_ret("order", -ENOMEM);
770-
771-
/* Get the list of bootdevs */
772-
uclass_id_foreach_dev(UCLASS_BOOTDEV, dev, uc)
773-
order[upto++] = dev;
774-
log_debug("Found %d bootdevs\n", count);
775-
if (upto != count)
776-
log_debug("Expected %d bootdevs, found %d using aliases\n",
777-
count, upto);
778-
779-
ret = build_order(bootstd, order, upto);
780-
if (ret < 0) {
781-
free(order);
782-
return log_msg_ret("build", ret);
676+
log_debug("Selected boodev: %s\n", dev->name);
677+
method_flags = 0;
678+
} else {
679+
bool ok;
680+
681+
/* This either returns a non-empty list or NULL */
682+
iter->labels = bootstd_get_bootdev_order(bootstd, &ok);
683+
if (!ok)
684+
return log_msg_ret("ord", -ENOMEM);
685+
log_debug("setup labels %p\n", iter->labels);
686+
if (iter->labels) {
687+
iter->cur_label = -1;
688+
ret = bootdev_next_label(iter, &dev, &method_flags);
689+
} else {
690+
ret = bootdev_next_prio(iter, &dev);
691+
method_flags = 0;
692+
}
693+
if (!dev)
694+
return log_msg_ret("fin", -ENOENT);
695+
log_debug("Selected bootdev: %s\n", dev->name);
783696
}
784697

785-
iter->num_devs = ret;
786-
iter->dev_order = order;
787-
iter->cur_dev = 0;
788-
789-
dev = *order;
790698
ret = device_probe(dev);
791699
if (ret)
792700
return log_msg_ret("probe", ret);
701+
if (method_flagsp)
702+
*method_flagsp = method_flags;
793703
*devp = dev;
794704

795705
return 0;

boot/bootflow.c

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ void bootflow_iter_init(struct bootflow_iter *iter, int flags)
9292

9393
void bootflow_iter_uninit(struct bootflow_iter *iter)
9494
{
95-
free(iter->dev_order);
9695
free(iter->method_order);
9796
}
9897

@@ -113,12 +112,25 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
113112
return 0;
114113
}
115114

115+
/**
116+
* bootflow_iter_set_dev() - switch to the next bootdev when iterating
117+
*
118+
* This sets iter->dev, records the device in the dev_used[] list and shows a
119+
* message if required
120+
*
121+
* @iter: Iterator to update
122+
* @dev: Bootdev to use, or NULL if there are no more
123+
*/
116124
static void bootflow_iter_set_dev(struct bootflow_iter *iter,
117-
struct udevice *dev)
125+
struct udevice *dev, int method_flags)
118126
{
119127
struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method);
120128

129+
log_debug("iter: Setting dev to %s, flags %x\n",
130+
dev ? dev->name : "(none)", method_flags);
121131
iter->dev = dev;
132+
iter->method_flags = method_flags;
133+
122134
if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) ==
123135
BOOTFLOWF_SHOW) {
124136
if (dev)
@@ -144,6 +156,7 @@ static int iter_incr(struct bootflow_iter *iter)
144156
bool global;
145157
int ret;
146158

159+
log_debug("entry: err=%d\n", iter->err);
147160
global = iter->doing_global;
148161

149162
if (iter->err == BF_NO_MORE_DEVICES)
@@ -182,7 +195,7 @@ static int iter_incr(struct bootflow_iter *iter)
182195
return 0;
183196
}
184197

185-
/* No more partitions; start at the first one and...*/
198+
/* No more partitions; start at the first one and... */
186199
iter->part = 0;
187200

188201
/*
@@ -196,16 +209,32 @@ static int iter_incr(struct bootflow_iter *iter)
196209
if (iter->flags & BOOTFLOWF_SINGLE_DEV) {
197210
ret = -ENOENT;
198211
} else {
199-
if (inc_dev)
200-
iter->cur_dev++;
201-
if (iter->cur_dev == iter->num_devs) {
202-
ret = -ENOENT;
203-
bootflow_iter_set_dev(iter, NULL);
212+
int method_flags;
213+
214+
ret = 0;
215+
dev = iter->dev;
216+
log_debug("inc_dev=%d\n", inc_dev);
217+
if (!inc_dev) {
218+
ret = bootdev_setup_iter(iter, &dev, &method_flags);
219+
} else {
220+
log_debug("labels %p\n", iter->labels);
221+
if (iter->labels) {
222+
ret = bootdev_next_label(iter, &dev,
223+
&method_flags);
224+
} else {
225+
ret = bootdev_next_prio(iter, &dev);
226+
method_flags = 0;
227+
}
228+
}
229+
log_debug("ret=%d, dev=%p %s\n", ret, dev,
230+
dev ? dev->name : "none");
231+
if (ret) {
232+
bootflow_iter_set_dev(iter, NULL, 0);
204233
} else {
205-
dev = iter->dev_order[iter->cur_dev];
206234
ret = device_probe(dev);
235+
log_debug("probe %s %d\n", dev->name, ret);
207236
if (!log_msg_ret("probe", ret))
208-
bootflow_iter_set_dev(iter, dev);
237+
bootflow_iter_set_dev(iter, dev, method_flags);
209238
}
210239
}
211240

@@ -230,7 +259,7 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow)
230259
int ret;
231260

232261
if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) {
233-
bootflow_iter_set_dev(iter, NULL);
262+
bootflow_iter_set_dev(iter, NULL, 0);
234263
ret = bootmeth_get_bootflow(iter->method, bflow);
235264
if (ret)
236265
return log_msg_ret("glob", ret);
@@ -274,18 +303,27 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
274303
flags |= BOOTFLOWF_SKIP_GLOBAL;
275304
bootflow_iter_init(iter, flags);
276305

277-
ret = bootdev_setup_iter_order(iter, &dev);
278-
if (ret)
279-
return log_msg_ret("obdev", -ENODEV);
280-
306+
/*
307+
* Set up the ordering of bootmeths. This sets iter->doing_global and
308+
* iter->first_glob_method if we are starting with the global bootmeths
309+
*/
281310
ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWF_SKIP_GLOBAL));
282311
if (ret)
283312
return log_msg_ret("obmeth", -ENODEV);
284313

285314
/* Find the first bootmeth (there must be at least one!) */
286315
iter->method = iter->method_order[iter->cur_method];
287-
if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global)
288-
bootflow_iter_set_dev(iter, dev);
316+
317+
if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global) {
318+
struct udevice *dev = NULL;
319+
int method_flags;
320+
321+
ret = bootdev_setup_iter(iter, &dev, &method_flags);
322+
if (ret)
323+
return log_msg_ret("obdev", -ENODEV);
324+
325+
bootflow_iter_set_dev(iter, dev, method_flags);
326+
}
289327

290328
ret = bootflow_check(iter, bflow);
291329
if (ret) {

include/bootdev.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,21 +265,22 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
265265
int *method_flagsp);
266266

267267
/**
268-
* bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan
268+
* bootdev_setup_iter() - Set up iteration through bootdevs
269269
*
270-
* This sets up the ordering information in @iter, based on the priority of each
271-
* bootdev and the bootdev-order property in the bootstd node
272-
*
273-
* If a single device is requested, no ordering is needed
270+
* This sets up the an interation, based on the priority of each bootdev, the
271+
* bootdev-order property in the bootstd node (or the boot_targets env var).
274272
*
275273
* @iter: Iterator to update with the order
276274
* @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
277275
* device to scan. Returns the first device to use, which is the passed-in
278276
* @devp if it was non-NULL
277+
* @method_flagsp: If non-NULL, returns any flags implied by the label
278+
* (enum bootflow_meth_flags_t), 0 if none
279279
* Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
280280
* on other error
281281
*/
282-
int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp);
282+
int bootdev_setup_iter(struct bootflow_iter *iter, struct udevice **devp,
283+
int *method_flagsp);
283284

284285
/**
285286
* bootdev_list_hunters() - List the available bootdev hunters

include/bootflow.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ enum bootflow_meth_flags_t {
163163
* @flags: Flags to use (see enum bootflow_flags_t). If BOOTFLOWF_GLOBAL_FIRST is
164164
* enabled then the global bootmeths are being scanned, otherwise we have
165165
* moved onto the bootdevs
166-
* @dev: Current bootdev, NULL if none
166+
* @dev: Current bootdev, NULL if none. This is only ever updated in
167+
* bootflow_iter_set_dev()
167168
* @part: Current partition number (0 for whole device)
168169
* @method: Current bootmeth
169170
* @max_part: Maximum hardware partition number in @dev, 0 if there is no
@@ -173,9 +174,6 @@ enum bootflow_meth_flags_t {
173174
* forward (e.g. to skip the current partition because it is not valid)
174175
* -ESHUTDOWN: try next bootdev
175176
* @num_devs: Number of bootdevs in @dev_order
176-
* @cur_dev: Current bootdev number, an index into @dev_order[]
177-
* @dev_order: List of bootdevs to scan, in order of priority. The scan starts
178-
* with the first one on the list
179177
* @labels: List of labels to scan for bootdevs
180178
* @cur_label: Current label being processed
181179
* @num_methods: Number of bootmeth devices in @method_order
@@ -198,8 +196,6 @@ struct bootflow_iter {
198196
int first_bootable;
199197
int err;
200198
int num_devs;
201-
int cur_dev;
202-
struct udevice **dev_order;
203199
const char *const *labels;
204200
int cur_label;
205201
int num_methods;

0 commit comments

Comments
 (0)