test: bootdev: scan with a broken high-priority device
Add bootdev_hunt_fallthrough() test to verify that 'bootflow scan -l'
falls back to a lower-priority bootdev when a higher-priority hunter
fails.
Introduce a simple 'sandbox-bootdev' device for the test. The new
bootdev can be configured to produce an error at the hunting stage.
Introduce new host_set_flags_by_label() API and a flags field to
'host_sb_plat' to simulate a bootdev hunter failure for the test.
Adjust boot{dev,flow} tests which depend on bootdev hunters.
Signed-off-by: Denis Mukhin <dmukhin@ford.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -13,7 +13,7 @@ ifndef CONFIG_XPL_BUILD
|
||||
obj-$(CONFIG_IDE) += ide.o
|
||||
obj-$(CONFIG_RKMTD) += rkmtd.o
|
||||
endif
|
||||
obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox.o sandbox-bootdev.o host-uclass.o host_dev.o
|
||||
obj-$(CONFIG_$(PHASE_)BLOCK_CACHE) += blkcache.o
|
||||
obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap.o
|
||||
obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap_helper.o
|
||||
|
||||
@@ -150,6 +150,21 @@ struct udevice *host_find_by_label(const char *label)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int host_set_flags_by_label(const char *label, unsigned int flags)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct host_sb_plat *plat;
|
||||
|
||||
dev = host_find_by_label(label);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
plat = dev_get_plat(dev);
|
||||
plat->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct udevice *host_get_cur_dev(void)
|
||||
{
|
||||
struct uclass *uc = uclass_find(UCLASS_HOST);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#define LOG_CATEGORY UCLASS_HOST
|
||||
|
||||
#include <bootdev.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <sandbox_host.h>
|
||||
|
||||
static int sandbox_bootdev_bind(struct udevice *dev)
|
||||
{
|
||||
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
|
||||
|
||||
ucp->prio = BOOTDEVP_4_SCAN_FAST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sandbox_bootdev_hunt() - Hunt host bootdev.
|
||||
*
|
||||
* Note, this hunter exists for bootdev testing to simulate a failure
|
||||
* mode. Do not use as an example of a real hunter.
|
||||
*
|
||||
* @info: Hunter details.
|
||||
* @show: Enable extra printouts.
|
||||
*
|
||||
* Returns: 0 if OK, -ve on error (expected by the test)
|
||||
*/
|
||||
static int sandbox_bootdev_hunt(struct bootdev_hunter *info, bool show)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct uclass *uc;
|
||||
int ret;
|
||||
|
||||
uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
|
||||
struct host_sb_plat *plat = dev_get_plat(dev);
|
||||
|
||||
log_debug("hunting %s\n", plat->label);
|
||||
|
||||
if (plat->flags & HOST_FLAG_BROKEN) {
|
||||
ret = -ETIME;
|
||||
log_debug("cannot hunt sandbox device '%s': %d\n",
|
||||
plat->label, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bootdev_ops sandbox_bootdev_ops = {
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_bootdev_ids[] = {
|
||||
{ .compatible = "u-boot,bootdev-sandbox" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sandbox_bootdev) = {
|
||||
.name = "sandbox_bootdev",
|
||||
.id = UCLASS_BOOTDEV,
|
||||
.ops = &sandbox_bootdev_ops,
|
||||
.bind = sandbox_bootdev_bind,
|
||||
.of_match = sandbox_bootdev_ids,
|
||||
};
|
||||
|
||||
BOOTDEV_HUNTER(sandbox_bootdev_hunter) = {
|
||||
.prio = BOOTDEVP_4_SCAN_FAST,
|
||||
.uclass = UCLASS_HOST,
|
||||
.hunt = sandbox_bootdev_hunt,
|
||||
.drv = DM_DRIVER_REF(sandbox_bootdev),
|
||||
};
|
||||
@@ -8,17 +8,26 @@
|
||||
#ifndef __SANDBOX_HOST__
|
||||
#define __SANDBOX_HOST__
|
||||
|
||||
/**
|
||||
* Device flags.
|
||||
*/
|
||||
enum host_platform_flags {
|
||||
HOST_FLAG_BROKEN = BIT(0), /** Simulate broken device */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct host_sb_plat - platform data for a host device
|
||||
*
|
||||
* @label: Label for this device (allocated)
|
||||
* @filename: Name of file this is attached to, or NULL (allocated)
|
||||
* @fd: File descriptor of file, or 0 for none (file is not open)
|
||||
* @flags: Device flags (e.g. for unit tests).
|
||||
*/
|
||||
struct host_sb_plat {
|
||||
char *label;
|
||||
char *filename;
|
||||
int fd;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -122,4 +131,13 @@ struct udevice *host_get_cur_dev(void);
|
||||
*/
|
||||
void host_set_cur_dev(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* host_set_flags_by_label() - Set the host device test flags
|
||||
*
|
||||
* @label: Label of the attachment, e.g. "test1"
|
||||
* @flags: Device flags
|
||||
* Returns: 0 if OK, -ve on error
|
||||
*/
|
||||
int host_set_flags_by_label(const char *label, unsigned int flags);
|
||||
|
||||
#endif /* __SANDBOX_HOST__ */
|
||||
|
||||
+12
-11
@@ -384,19 +384,19 @@ static int bootdev_test_hunter(struct unit_test_state *uts)
|
||||
ut_assert_nextline(" 2 mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 nvme nvme_bootdev");
|
||||
ut_assert_nextline(" 4 qfw qfw_bootdev");
|
||||
ut_assert_nextline(" 4 host sandbox_bootdev");
|
||||
ut_assert_nextline(" 4 scsi scsi_bootdev");
|
||||
ut_assert_nextline(" 4 spi_flash sf_bootdev");
|
||||
ut_assert_nextline(" 5 usb usb_bootdev");
|
||||
ut_assert_nextline(" 4 virtio virtio_bootdev");
|
||||
ut_assert_nextline("(total hunters: 9)");
|
||||
ut_assert_nextline("(total hunters: 10)");
|
||||
ut_assert_console_end();
|
||||
|
||||
ut_assertok(bootdev_hunt("usb1", false));
|
||||
ut_assert_skip_to_line("Bus usb@1: 5 USB Device(s) found");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* USB is 8th in the list, so bit 7 */
|
||||
ut_asserteq(BIT(7), std->hunters_used);
|
||||
ut_asserteq(BIT(USB_HUNTER), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextline("Prio Used Uclass Hunter");
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 ethernet eth_bootdev");
|
||||
ut_assert_skip_to_line("(total hunters: 9)");
|
||||
ut_assert_skip_to_line("(total hunters: 10)");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Use the MMC hunter and see that it updates */
|
||||
@@ -425,7 +425,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assertok(run_command("bootdev hunt -l", 0));
|
||||
ut_assert_skip_to_line(" 5 ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 * mmc mmc_bootdev");
|
||||
ut_assert_skip_to_line("(total hunters: 9)");
|
||||
ut_assert_skip_to_line("(total hunters: 10)");
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Scan all hunters */
|
||||
@@ -441,6 +441,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
|
||||
ut_assert_nextline("Hunting with: nvme");
|
||||
ut_assert_nextline("Hunting with: qfw");
|
||||
ut_assert_nextline("Hunting with: host");
|
||||
ut_assert_nextline("Hunting with: scsi");
|
||||
ut_assert_nextline("scanning bus for devices...");
|
||||
ut_assert_skip_to_line("Hunting with: spi_flash");
|
||||
@@ -458,11 +459,12 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextline(" 2 * mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 * nvme nvme_bootdev");
|
||||
ut_assert_nextline(" 4 * qfw qfw_bootdev");
|
||||
ut_assert_nextline(" 4 * host sandbox_bootdev");
|
||||
ut_assert_nextline(" 4 * scsi scsi_bootdev");
|
||||
ut_assert_nextline(" 4 * spi_flash sf_bootdev");
|
||||
ut_assert_nextline(" 5 * usb usb_bootdev");
|
||||
ut_assert_nextline(" 4 * virtio virtio_bootdev");
|
||||
ut_assert_nextline("(total hunters: 9)");
|
||||
ut_assert_nextline("(total hunters: 10)");
|
||||
ut_assert_console_end();
|
||||
|
||||
ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used);
|
||||
@@ -646,8 +648,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
ut_asserteq_str("scsi.id0lun0.bootdev", dev->name);
|
||||
ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
|
||||
|
||||
/* SCSI is 6th in the list, so bit 5 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER), std->hunters_used);
|
||||
|
||||
ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
|
||||
ut_assert_console_end();
|
||||
@@ -657,7 +658,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
mflags);
|
||||
|
||||
/* dhcp: Ethernet is first so bit 0 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), std->hunters_used);
|
||||
|
||||
ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
|
||||
ut_assert_console_end();
|
||||
@@ -667,7 +668,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
mflags);
|
||||
|
||||
/* pxe: Ethernet is first so bit 0 */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), std->hunters_used);
|
||||
|
||||
mflags = 123;
|
||||
ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags));
|
||||
@@ -675,7 +676,7 @@ static int bootdev_test_next_label(struct unit_test_state *uts)
|
||||
ut_assert_console_end();
|
||||
|
||||
/* no change */
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used);
|
||||
ut_asserteq(BIT(MMC_HUNTER) | BIT(SCSI_HUNTER) | BIT(0), std->hunters_used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <mapmem.h>
|
||||
#ifdef CONFIG_SANDBOX
|
||||
#include <asm/test.h>
|
||||
#include <sandbox_host.h>
|
||||
#include <os.h>
|
||||
#endif
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
@@ -1532,3 +1534,48 @@ static int bootstd_images(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
BOOTSTD_TEST(bootstd_images, UTF_CONSOLE);
|
||||
|
||||
#if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL)
|
||||
/*
|
||||
* Check that bootdev scanning does not stop if higher-priority bootdevs
|
||||
* are failed to be hunted.
|
||||
*/
|
||||
static int bootdev_hunt_fallthrough(struct unit_test_state *uts)
|
||||
{
|
||||
struct bootstd_priv *std;
|
||||
struct udevice *dev;
|
||||
|
||||
ut_assertok(bootstd_get_priv(&std));
|
||||
bootstd_test_drop_bootdev_order(uts);
|
||||
test_set_skip_delays(true);
|
||||
bootstd_reset_usb();
|
||||
console_record_reset_enable();
|
||||
|
||||
/*
|
||||
* Create a sandbox block device (BOOTDEVP_4_SCAN_FAST) and mark it as
|
||||
* broken so that bootdev_hunt_prio() returns an error.
|
||||
*/
|
||||
ut_asserteq(0, uclass_id_count(UCLASS_HOST));
|
||||
ut_assertok(host_create_device("test", true, DEFAULT_BLKSZ, &dev));
|
||||
ut_assertok(host_set_flags_by_label("test", HOST_FLAG_BROKEN));
|
||||
ut_asserteq(1, uclass_id_count(UCLASS_HOST));
|
||||
|
||||
/*
|
||||
* Scan with hunting.
|
||||
* The sandbox hunter at priority 4 must fail, but the USB hunter at
|
||||
* priority 5 must still be reached.
|
||||
*/
|
||||
ut_assertok(run_command("bootflow scan -l", 0));
|
||||
|
||||
ut_assert(!(std->hunters_used & BIT(HOST_HUNTER)));
|
||||
ut_assert_skip_to_line("Hunting with: host");
|
||||
|
||||
/* USB was hunted despite the sandbox hunter failure */
|
||||
ut_assert(std->hunters_used & BIT(USB_HUNTER));
|
||||
ut_assert_skip_to_line("Bus usb@1: 5 USB Device(s) found");
|
||||
|
||||
return 0;
|
||||
}
|
||||
BOOTSTD_TEST(bootdev_hunt_fallthrough,
|
||||
UTF_DM | UTF_SCAN_FDT | UTF_SF_BOOTDEV | UTF_CONSOLE);
|
||||
#endif /* CONFIG_SANDBOX */
|
||||
|
||||
@@ -21,8 +21,11 @@
|
||||
#define TEST_VERNUM 0x00010002
|
||||
|
||||
enum {
|
||||
MAX_HUNTER = 8,
|
||||
MMC_HUNTER = 2, /* ID of MMC hunter */
|
||||
HOST_HUNTER = 5,
|
||||
SCSI_HUNTER = 6,
|
||||
USB_HUNTER = 8,
|
||||
MAX_HUNTER = 9,
|
||||
};
|
||||
|
||||
struct unit_test_state;
|
||||
|
||||
Reference in New Issue
Block a user