Skip to content

Commit 66e3dce

Browse files
sjg20trini
authored andcommitted
bootstd: Allow hunting for a bootdev by label
Add a function to hunt for a bootdev label and find the bootdev produced by the hunter (or already present). Add a few extra flags so that we can distinguish between "mmc1", "mmc" and "1" which all need to be handled differently. Signed-off-by: Simon Glass <sjg@chromium.org>
1 parent eacc261 commit 66e3dce

6 files changed

Lines changed: 195 additions & 5 deletions

File tree

boot/bootdev-uclass.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,13 @@ int bootdev_find_by_label(const char *label, struct udevice **devp,
442442
if (!ret) {
443443
log_debug("- found %s\n", bdev->name);
444444
*devp = bdev;
445+
446+
/*
447+
* if no sequence number was provided, we must scan all
448+
* bootdevs for this media uclass
449+
*/
450+
if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && seq == -1)
451+
method_flags |= BOOTFLOW_METHF_SINGLE_UCLASS;
445452
if (method_flagsp)
446453
*method_flagsp = method_flags;
447454
return 0;
@@ -458,7 +465,7 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
458465
{
459466
struct udevice *dev;
460467
int method_flags = 0;
461-
int ret, seq;
468+
int ret = -ENODEV, seq;
462469
char *endp;
463470

464471
seq = simple_strtol(name, &endp, 16);
@@ -480,8 +487,9 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
480487
ret);
481488
return log_msg_ret("pro", ret);
482489
}
483-
} else {
490+
} else if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
484491
ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev);
492+
method_flags |= BOOTFLOW_METHF_SINGLE_DEV;
485493
}
486494
if (ret) {
487495
printf("Cannot find '%s' (err=%d)\n", name, ret);
@@ -495,6 +503,21 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
495503
return 0;
496504
}
497505

506+
int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
507+
int *method_flagsp)
508+
{
509+
int ret;
510+
511+
ret = bootdev_hunt(label, false);
512+
if (ret)
513+
return log_msg_ret("scn", ret);
514+
ret = bootdev_find_by_label(label, devp, method_flagsp);
515+
if (ret)
516+
return log_msg_ret("fnd", ret);
517+
518+
return 0;
519+
}
520+
498521
static int default_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
499522
struct bootflow *bflow)
500523
{

include/bootdev.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ int bootdev_hunt(const char *spec, bool show);
316316
*/
317317
int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
318318

319+
/**
320+
* bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
321+
*
322+
* Runs the hunter for the label, then tries to find the bootdev, possible
323+
* created by the hunter
324+
*
325+
* @label: Label to look up (e.g. "mmc1" or "mmc0")
326+
* @devp: Returns the bootdev device found, or NULL if none (note it does not
327+
* return the media device, but its bootdev child)
328+
* @method_flagsp: If non-NULL, returns any flags implied by the label
329+
* (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
330+
* Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
331+
* -ENOENT if there is no device with that number
332+
*/
333+
int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
334+
int *method_flagsp);
335+
319336
#if CONFIG_IS_ENABLED(BOOTSTD)
320337
/**
321338
* bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)

include/bootflow.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ struct bootflow {
9999
* Internal flags:
100100
* @BOOTFLOWF_SINGLE_DEV: (internal) Just scan one bootdev
101101
* @BOOTFLOWF_SKIP_GLOBAL: (internal) Don't scan global bootmeths
102-
* this uclass
102+
* @BOOTFLOWF_SINGLE_UCLASS: (internal) Keep scanning through all devices in
103+
* this uclass (used with things like "mmc")
104+
* @BOOTFLOWF_SINGLE_MEDIA: (internal) Scan one media device in the uclass (used
105+
* with things like "mmc1")
103106
*/
104107
enum bootflow_flags_t {
105108
BOOTFLOWF_FIXED = 1 << 0,
@@ -113,6 +116,8 @@ enum bootflow_flags_t {
113116
*/
114117
BOOTFLOWF_SINGLE_DEV = 1 << 16,
115118
BOOTFLOWF_SKIP_GLOBAL = 1 << 17,
119+
BOOTFLOWF_SINGLE_UCLASS = 1 << 18,
120+
BOOTFLOWF_SINGLE_MEDIA = 1 << 19,
116121
};
117122

118123
/**
@@ -124,10 +129,17 @@ enum bootflow_flags_t {
124129
*
125130
* @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI)
126131
* @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot)
132+
* @BOOTFLOW_METHF_SINGLE_DEV: Scan only a single bootdev (used for labels like
133+
* "3"). This is used if a sequence number is provided instead of a label
134+
* @BOOTFLOW_METHF_SINGLE_UCLASS: Scan all bootdevs in this one uclass (used
135+
* with things like "mmc"). If this is not set, then the bootdev has an integer
136+
* value in the label (like "mmc2")
127137
*/
128138
enum bootflow_meth_flags_t {
129139
BOOTFLOW_METHF_DHCP_ONLY = 1 << 0,
130140
BOOTFLOW_METHF_PXE_ONLY = 1 << 1,
141+
BOOTFLOW_METHF_SINGLE_DEV = 1 << 2,
142+
BOOTFLOW_METHF_SINGLE_UCLASS = 1 << 3,
131143
};
132144

133145
/**

test/boot/bootdev.c

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,11 @@ static int bootdev_test_labels(struct unit_test_state *uts)
113113

114114
/* Check method flags */
115115
ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags));
116-
ut_asserteq(BOOTFLOW_METHF_PXE_ONLY, mflags);
116+
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
117+
mflags);
117118
ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags));
118-
ut_asserteq(BOOTFLOW_METHF_DHCP_ONLY, mflags);
119+
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY,
120+
mflags);
119121

120122
/* Check invalid uclass */
121123
ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags));
@@ -128,6 +130,62 @@ static int bootdev_test_labels(struct unit_test_state *uts)
128130
BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
129131
UT_TESTF_ETH_BOOTDEV);
130132

133+
/* Check bootdev_find_by_any() */
134+
static int bootdev_test_any(struct unit_test_state *uts)
135+
{
136+
struct udevice *dev, *media;
137+
int mflags;
138+
139+
/*
140+
* with ethernet enabled we have 8 devices ahead of the mmc ones:
141+
*
142+
* ut_assertok(run_command("bootdev list", 0));
143+
* Seq Probed Status Uclass Name
144+
* --- ------ ------ -------- ------------------
145+
* 0 [ + ] OK ethernet eth@10002000.bootdev
146+
* 1 [ ] OK ethernet eth@10003000.bootdev
147+
* 2 [ ] OK ethernet sbe5.bootdev
148+
* 3 [ ] OK ethernet eth@10004000.bootdev
149+
* 4 [ ] OK ethernet phy-test-eth.bootdev
150+
* 5 [ ] OK ethernet dsa-test-eth.bootdev
151+
* 6 [ ] OK ethernet dsa-test@0.bootdev
152+
* 7 [ ] OK ethernet dsa-test@1.bootdev
153+
* 8 [ ] OK mmc mmc2.bootdev
154+
* 9 [ + ] OK mmc mmc1.bootdev
155+
* a [ ] OK mmc mmc0.bootdev
156+
*/
157+
console_record_reset_enable();
158+
ut_assertok(bootdev_find_by_any("8", &dev, &mflags));
159+
ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev));
160+
ut_asserteq(BOOTFLOW_METHF_SINGLE_DEV, mflags);
161+
media = dev_get_parent(dev);
162+
ut_asserteq(UCLASS_MMC, device_get_uclass_id(media));
163+
ut_asserteq_str("mmc2", media->name);
164+
ut_assert_console_end();
165+
166+
/* there should not be this many bootdevs */
167+
ut_asserteq(-ENODEV, bootdev_find_by_any("50", &dev, &mflags));
168+
ut_assert_nextline("Cannot find '50' (err=-19)");
169+
ut_assert_console_end();
170+
171+
/* Check method flags */
172+
ut_assertok(bootdev_find_by_any("pxe", &dev, &mflags));
173+
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
174+
mflags);
175+
176+
/* Check invalid uclass */
177+
mflags = 123;
178+
ut_asserteq(-EINVAL, bootdev_find_by_any("fred0", &dev, &mflags));
179+
ut_assert_nextline("Unknown uclass 'fred0' in label");
180+
ut_assert_nextline("Cannot find bootdev 'fred0' (err=-22)");
181+
ut_asserteq(123, mflags);
182+
ut_assert_console_end();
183+
184+
return 0;
185+
}
186+
BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
187+
UT_TESTF_ETH_BOOTDEV);
188+
131189
/* Check bootdev ordering with the bootdev-order property */
132190
static int bootdev_test_order(struct unit_test_state *uts)
133191
{
@@ -399,3 +457,56 @@ static int bootdev_test_hunt_prio(struct unit_test_state *uts)
399457
return 0;
400458
}
401459
BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
460+
461+
/* Check hunting for bootdevs with a particular label */
462+
static int bootdev_test_hunt_label(struct unit_test_state *uts)
463+
{
464+
struct udevice *dev, *old;
465+
struct bootstd_priv *std;
466+
int mflags;
467+
468+
/* get access to the used hunters */
469+
ut_assertok(bootstd_get_priv(&std));
470+
471+
/* scan an unknown uclass */
472+
console_record_reset_enable();
473+
old = (void *)&mflags; /* arbitrary pointer to check against dev */
474+
dev = old;
475+
mflags = 123;
476+
ut_asserteq(-EINVAL,
477+
bootdev_hunt_and_find_by_label("fred", &dev, &mflags));
478+
ut_assert_nextline("Unknown uclass 'fred' in label");
479+
ut_asserteq_ptr(old, dev);
480+
ut_asserteq(123, mflags);
481+
ut_assert_console_end();
482+
ut_asserteq(0, std->hunters_used);
483+
484+
/* scan an invalid mmc controllers */
485+
ut_asserteq(-ENOENT,
486+
bootdev_hunt_and_find_by_label("mmc4", &dev, &mflags));
487+
ut_asserteq_ptr(old, dev);
488+
ut_asserteq(123, mflags);
489+
ut_assert_nextline("Unknown seq 4 for label 'mmc4'");
490+
ut_assert_console_end();
491+
492+
ut_assertok(bootstd_test_check_mmc_hunter(uts));
493+
494+
/* scan for a particular mmc controller */
495+
ut_assertok(bootdev_hunt_and_find_by_label("mmc1", &dev, &mflags));
496+
ut_assertnonnull(dev);
497+
ut_asserteq_str("mmc1.bootdev", dev->name);
498+
ut_asserteq(0, mflags);
499+
ut_assert_console_end();
500+
501+
/* scan all of usb */
502+
test_set_skip_delays(true);
503+
ut_assertok(bootdev_hunt_and_find_by_label("usb", &dev, &mflags));
504+
ut_assertnonnull(dev);
505+
ut_asserteq_str("usb_mass_storage.lun0.bootdev", dev->name);
506+
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
507+
ut_assert_nextlinen("Bus usb@1: scanning bus usb@1");
508+
ut_assert_console_end();
509+
510+
return 0;
511+
}
512+
BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);

test/boot/bootstd_common.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <common.h>
10+
#include <bootdev.h>
1011
#include <bootstd.h>
1112
#include <dm.h>
1213
#include <memalign.h>
@@ -67,6 +68,24 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts)
6768
return 0;
6869
}
6970

71+
int bootstd_test_check_mmc_hunter(struct unit_test_state *uts)
72+
{
73+
struct bootdev_hunter *start, *mmc;
74+
struct bootstd_priv *std;
75+
uint seq;
76+
77+
/* get access to the used hunters */
78+
ut_assertok(bootstd_get_priv(&std));
79+
80+
/* check that the hunter was used */
81+
start = ll_entry_start(struct bootdev_hunter, bootdev_hunter);
82+
mmc = BOOTDEV_HUNTER_GET(mmc_bootdev_hunter);
83+
seq = mmc - start;
84+
ut_asserteq(BIT(seq), std->hunters_used);
85+
86+
return 0;
87+
}
88+
7089
int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
7190
{
7291
struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd_test);

test/boot/bootstd_common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,12 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts);
4040
*/
4141
int bootstd_setup_for_tests(void);
4242

43+
/**
44+
* bootstd_test_check_mmc_hunter() - Check that the mmc bootdev hunter was used
45+
*
46+
* @uts: Unit test state to use for ut_assert...() functions
47+
* Returns: 0 if OK (used), other value on error (not used)
48+
*/
49+
int bootstd_test_check_mmc_hunter(struct unit_test_state *uts);
50+
4351
#endif

0 commit comments

Comments
 (0)