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>
This commit is contained in:
parent
eacc261178
commit
66e3dce787
6 changed files with 195 additions and 5 deletions
|
@ -442,6 +442,13 @@ int bootdev_find_by_label(const char *label, struct udevice **devp,
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
log_debug("- found %s\n", bdev->name);
|
log_debug("- found %s\n", bdev->name);
|
||||||
*devp = bdev;
|
*devp = bdev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if no sequence number was provided, we must scan all
|
||||||
|
* bootdevs for this media uclass
|
||||||
|
*/
|
||||||
|
if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && seq == -1)
|
||||||
|
method_flags |= BOOTFLOW_METHF_SINGLE_UCLASS;
|
||||||
if (method_flagsp)
|
if (method_flagsp)
|
||||||
*method_flagsp = method_flags;
|
*method_flagsp = method_flags;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -458,7 +465,7 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
int method_flags = 0;
|
int method_flags = 0;
|
||||||
int ret, seq;
|
int ret = -ENODEV, seq;
|
||||||
char *endp;
|
char *endp;
|
||||||
|
|
||||||
seq = simple_strtol(name, &endp, 16);
|
seq = simple_strtol(name, &endp, 16);
|
||||||
|
@ -480,8 +487,9 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
|
||||||
ret);
|
ret);
|
||||||
return log_msg_ret("pro", ret);
|
return log_msg_ret("pro", ret);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
|
||||||
ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev);
|
ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev);
|
||||||
|
method_flags |= BOOTFLOW_METHF_SINGLE_DEV;
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Cannot find '%s' (err=%d)\n", name, ret);
|
printf("Cannot find '%s' (err=%d)\n", name, ret);
|
||||||
|
@ -495,6 +503,21 @@ int bootdev_find_by_any(const char *name, struct udevice **devp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
|
||||||
|
int *method_flagsp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = bootdev_hunt(label, false);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("scn", ret);
|
||||||
|
ret = bootdev_find_by_label(label, devp, method_flagsp);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("fnd", ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int default_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
static int default_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
||||||
struct bootflow *bflow)
|
struct bootflow *bflow)
|
||||||
{
|
{
|
||||||
|
|
|
@ -316,6 +316,23 @@ int bootdev_hunt(const char *spec, bool show);
|
||||||
*/
|
*/
|
||||||
int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
|
int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
|
||||||
|
*
|
||||||
|
* Runs the hunter for the label, then tries to find the bootdev, possible
|
||||||
|
* created by the hunter
|
||||||
|
*
|
||||||
|
* @label: Label to look up (e.g. "mmc1" or "mmc0")
|
||||||
|
* @devp: Returns the bootdev device found, or NULL if none (note it does not
|
||||||
|
* return the media device, but its bootdev child)
|
||||||
|
* @method_flagsp: If non-NULL, returns any flags implied by the label
|
||||||
|
* (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
|
||||||
|
* Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
|
||||||
|
* -ENOENT if there is no device with that number
|
||||||
|
*/
|
||||||
|
int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
|
||||||
|
int *method_flagsp);
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(BOOTSTD)
|
#if CONFIG_IS_ENABLED(BOOTSTD)
|
||||||
/**
|
/**
|
||||||
* bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
|
* bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
|
||||||
|
|
|
@ -99,7 +99,10 @@ struct bootflow {
|
||||||
* Internal flags:
|
* Internal flags:
|
||||||
* @BOOTFLOWF_SINGLE_DEV: (internal) Just scan one bootdev
|
* @BOOTFLOWF_SINGLE_DEV: (internal) Just scan one bootdev
|
||||||
* @BOOTFLOWF_SKIP_GLOBAL: (internal) Don't scan global bootmeths
|
* @BOOTFLOWF_SKIP_GLOBAL: (internal) Don't scan global bootmeths
|
||||||
* this uclass
|
* @BOOTFLOWF_SINGLE_UCLASS: (internal) Keep scanning through all devices in
|
||||||
|
* this uclass (used with things like "mmc")
|
||||||
|
* @BOOTFLOWF_SINGLE_MEDIA: (internal) Scan one media device in the uclass (used
|
||||||
|
* with things like "mmc1")
|
||||||
*/
|
*/
|
||||||
enum bootflow_flags_t {
|
enum bootflow_flags_t {
|
||||||
BOOTFLOWF_FIXED = 1 << 0,
|
BOOTFLOWF_FIXED = 1 << 0,
|
||||||
|
@ -113,6 +116,8 @@ enum bootflow_flags_t {
|
||||||
*/
|
*/
|
||||||
BOOTFLOWF_SINGLE_DEV = 1 << 16,
|
BOOTFLOWF_SINGLE_DEV = 1 << 16,
|
||||||
BOOTFLOWF_SKIP_GLOBAL = 1 << 17,
|
BOOTFLOWF_SKIP_GLOBAL = 1 << 17,
|
||||||
|
BOOTFLOWF_SINGLE_UCLASS = 1 << 18,
|
||||||
|
BOOTFLOWF_SINGLE_MEDIA = 1 << 19,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,10 +129,17 @@ enum bootflow_flags_t {
|
||||||
*
|
*
|
||||||
* @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI)
|
* @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI)
|
||||||
* @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot)
|
* @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot)
|
||||||
|
* @BOOTFLOW_METHF_SINGLE_DEV: Scan only a single bootdev (used for labels like
|
||||||
|
* "3"). This is used if a sequence number is provided instead of a label
|
||||||
|
* @BOOTFLOW_METHF_SINGLE_UCLASS: Scan all bootdevs in this one uclass (used
|
||||||
|
* with things like "mmc"). If this is not set, then the bootdev has an integer
|
||||||
|
* value in the label (like "mmc2")
|
||||||
*/
|
*/
|
||||||
enum bootflow_meth_flags_t {
|
enum bootflow_meth_flags_t {
|
||||||
BOOTFLOW_METHF_DHCP_ONLY = 1 << 0,
|
BOOTFLOW_METHF_DHCP_ONLY = 1 << 0,
|
||||||
BOOTFLOW_METHF_PXE_ONLY = 1 << 1,
|
BOOTFLOW_METHF_PXE_ONLY = 1 << 1,
|
||||||
|
BOOTFLOW_METHF_SINGLE_DEV = 1 << 2,
|
||||||
|
BOOTFLOW_METHF_SINGLE_UCLASS = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -113,9 +113,11 @@ static int bootdev_test_labels(struct unit_test_state *uts)
|
||||||
|
|
||||||
/* Check method flags */
|
/* Check method flags */
|
||||||
ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags));
|
ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags));
|
||||||
ut_asserteq(BOOTFLOW_METHF_PXE_ONLY, mflags);
|
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
|
||||||
|
mflags);
|
||||||
ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags));
|
ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags));
|
||||||
ut_asserteq(BOOTFLOW_METHF_DHCP_ONLY, mflags);
|
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY,
|
||||||
|
mflags);
|
||||||
|
|
||||||
/* Check invalid uclass */
|
/* Check invalid uclass */
|
||||||
ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags));
|
ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags));
|
||||||
|
@ -128,6 +130,62 @@ static int bootdev_test_labels(struct unit_test_state *uts)
|
||||||
BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
|
BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
|
||||||
UT_TESTF_ETH_BOOTDEV);
|
UT_TESTF_ETH_BOOTDEV);
|
||||||
|
|
||||||
|
/* Check bootdev_find_by_any() */
|
||||||
|
static int bootdev_test_any(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *dev, *media;
|
||||||
|
int mflags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* with ethernet enabled we have 8 devices ahead of the mmc ones:
|
||||||
|
*
|
||||||
|
* ut_assertok(run_command("bootdev list", 0));
|
||||||
|
* Seq Probed Status Uclass Name
|
||||||
|
* --- ------ ------ -------- ------------------
|
||||||
|
* 0 [ + ] OK ethernet eth@10002000.bootdev
|
||||||
|
* 1 [ ] OK ethernet eth@10003000.bootdev
|
||||||
|
* 2 [ ] OK ethernet sbe5.bootdev
|
||||||
|
* 3 [ ] OK ethernet eth@10004000.bootdev
|
||||||
|
* 4 [ ] OK ethernet phy-test-eth.bootdev
|
||||||
|
* 5 [ ] OK ethernet dsa-test-eth.bootdev
|
||||||
|
* 6 [ ] OK ethernet dsa-test@0.bootdev
|
||||||
|
* 7 [ ] OK ethernet dsa-test@1.bootdev
|
||||||
|
* 8 [ ] OK mmc mmc2.bootdev
|
||||||
|
* 9 [ + ] OK mmc mmc1.bootdev
|
||||||
|
* a [ ] OK mmc mmc0.bootdev
|
||||||
|
*/
|
||||||
|
console_record_reset_enable();
|
||||||
|
ut_assertok(bootdev_find_by_any("8", &dev, &mflags));
|
||||||
|
ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev));
|
||||||
|
ut_asserteq(BOOTFLOW_METHF_SINGLE_DEV, mflags);
|
||||||
|
media = dev_get_parent(dev);
|
||||||
|
ut_asserteq(UCLASS_MMC, device_get_uclass_id(media));
|
||||||
|
ut_asserteq_str("mmc2", media->name);
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
/* there should not be this many bootdevs */
|
||||||
|
ut_asserteq(-ENODEV, bootdev_find_by_any("50", &dev, &mflags));
|
||||||
|
ut_assert_nextline("Cannot find '50' (err=-19)");
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
/* Check method flags */
|
||||||
|
ut_assertok(bootdev_find_by_any("pxe", &dev, &mflags));
|
||||||
|
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
|
||||||
|
mflags);
|
||||||
|
|
||||||
|
/* Check invalid uclass */
|
||||||
|
mflags = 123;
|
||||||
|
ut_asserteq(-EINVAL, bootdev_find_by_any("fred0", &dev, &mflags));
|
||||||
|
ut_assert_nextline("Unknown uclass 'fred0' in label");
|
||||||
|
ut_assert_nextline("Cannot find bootdev 'fred0' (err=-22)");
|
||||||
|
ut_asserteq(123, mflags);
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
|
||||||
|
UT_TESTF_ETH_BOOTDEV);
|
||||||
|
|
||||||
/* Check bootdev ordering with the bootdev-order property */
|
/* Check bootdev ordering with the bootdev-order property */
|
||||||
static int bootdev_test_order(struct unit_test_state *uts)
|
static int bootdev_test_order(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
|
@ -399,3 +457,56 @@ static int bootdev_test_hunt_prio(struct unit_test_state *uts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
|
BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
/* Check hunting for bootdevs with a particular label */
|
||||||
|
static int bootdev_test_hunt_label(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *dev, *old;
|
||||||
|
struct bootstd_priv *std;
|
||||||
|
int mflags;
|
||||||
|
|
||||||
|
/* get access to the used hunters */
|
||||||
|
ut_assertok(bootstd_get_priv(&std));
|
||||||
|
|
||||||
|
/* scan an unknown uclass */
|
||||||
|
console_record_reset_enable();
|
||||||
|
old = (void *)&mflags; /* arbitrary pointer to check against dev */
|
||||||
|
dev = old;
|
||||||
|
mflags = 123;
|
||||||
|
ut_asserteq(-EINVAL,
|
||||||
|
bootdev_hunt_and_find_by_label("fred", &dev, &mflags));
|
||||||
|
ut_assert_nextline("Unknown uclass 'fred' in label");
|
||||||
|
ut_asserteq_ptr(old, dev);
|
||||||
|
ut_asserteq(123, mflags);
|
||||||
|
ut_assert_console_end();
|
||||||
|
ut_asserteq(0, std->hunters_used);
|
||||||
|
|
||||||
|
/* scan an invalid mmc controllers */
|
||||||
|
ut_asserteq(-ENOENT,
|
||||||
|
bootdev_hunt_and_find_by_label("mmc4", &dev, &mflags));
|
||||||
|
ut_asserteq_ptr(old, dev);
|
||||||
|
ut_asserteq(123, mflags);
|
||||||
|
ut_assert_nextline("Unknown seq 4 for label 'mmc4'");
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
ut_assertok(bootstd_test_check_mmc_hunter(uts));
|
||||||
|
|
||||||
|
/* scan for a particular mmc controller */
|
||||||
|
ut_assertok(bootdev_hunt_and_find_by_label("mmc1", &dev, &mflags));
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
ut_asserteq_str("mmc1.bootdev", dev->name);
|
||||||
|
ut_asserteq(0, mflags);
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
/* scan all of usb */
|
||||||
|
test_set_skip_delays(true);
|
||||||
|
ut_assertok(bootdev_hunt_and_find_by_label("usb", &dev, &mflags));
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
ut_asserteq_str("usb_mass_storage.lun0.bootdev", dev->name);
|
||||||
|
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
|
||||||
|
ut_assert_nextlinen("Bus usb@1: scanning bus usb@1");
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <bootdev.h>
|
||||||
#include <bootstd.h>
|
#include <bootstd.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <memalign.h>
|
#include <memalign.h>
|
||||||
|
@ -67,6 +68,24 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bootstd_test_check_mmc_hunter(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct bootdev_hunter *start, *mmc;
|
||||||
|
struct bootstd_priv *std;
|
||||||
|
uint seq;
|
||||||
|
|
||||||
|
/* get access to the used hunters */
|
||||||
|
ut_assertok(bootstd_get_priv(&std));
|
||||||
|
|
||||||
|
/* check that the hunter was used */
|
||||||
|
start = ll_entry_start(struct bootdev_hunter, bootdev_hunter);
|
||||||
|
mmc = BOOTDEV_HUNTER_GET(mmc_bootdev_hunter);
|
||||||
|
seq = mmc - start;
|
||||||
|
ut_asserteq(BIT(seq), std->hunters_used);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd_test);
|
||||||
|
|
|
@ -40,4 +40,12 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts);
|
||||||
*/
|
*/
|
||||||
int bootstd_setup_for_tests(void);
|
int bootstd_setup_for_tests(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootstd_test_check_mmc_hunter() - Check that the mmc bootdev hunter was used
|
||||||
|
*
|
||||||
|
* @uts: Unit test state to use for ut_assert...() functions
|
||||||
|
* Returns: 0 if OK (used), other value on error (not used)
|
||||||
|
*/
|
||||||
|
int bootstd_test_check_mmc_hunter(struct unit_test_state *uts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue