summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-01-24 14:04:14 -0500
committerTom Rini <[email protected]>2023-01-24 14:04:14 -0500
commit4e1ab2065e21e48a3087144ab826f12cfb797a65 (patch)
tree1dc9e793258c5a4a1be4d5e6d554f7f1a82450f3 /drivers
parentdd31cd58b02729807934cb699b164b1f8736620f (diff)
parent3891c68ef50eda38d78c95ecd03aed030aa6bb53 (diff)
Merge branch '2023-01-24-bootstd-allow-migration-from-distro_bootcmd-script'
To quote the author: So far, standard boot does not replicate all the of the functionality of the distro_bootcmd scripts. In particular it lacks some bootdevs and some of the bootmeths are incomplete. Also there is currently no internal mechanism to enumerate buses in order to discover bootdevs, e.g. with USB. This series addresses these shortcomings: - Adds the concept of a 'bootdev hunter' to enumerate buses, etc. in an effort to find bootdevs of a certain priority - Adds bootdevs for SCSI, IDE, NVMe, virtio, SPI flash - Handles PXE and DHCP properly - Supports reading the device tree with EFI and reading scripts from the network It also tidies up label processing, so it is possible to use: bootflow scan mmc2 to scan just one MMC device (with BOOTSTD_FULL). As before this implementation still relies on CONFIG_CMDLINE being enabled, mostly for the network stack. Further work would be required to disentangle that. Quite a few tests are added but there are some gaps: - SPI flash bootdev - EFI FDT loading Note that SATA works via SCSI (CONFIG_SCSI_AHCI) and does not use driver model. Only pogo_v4 seems to be affected. Probably all thats is needed is to call bootdev_setup_sibling_blk() in the Marvell SATA driver. Also, while it would be possible to init MMC in a bootdev hunter, there is no point since U-Boot always inits MMC on startup, if present. With this series it should be possible to migrate boards to standard boot by removing the inclusion of config_distro_bootcmd.h and instead adding a suitable value for boot_targets to the environment, e.g.: boot_targets=mmc1 mmc0 nvme scsi usb pxe dhcp spi Thus it is possible to boot automatically without scripts and boards can use a text-based environment instead of the config.h files. To demonstrate this, rockpro64-rk3399 is migrated to standard boot in this series. Full migration could probably be automated using a script, similar in concept to moveconfig: - obtain the board environment via 'make u-boot-initial-env' - get the value of "boot_targets" - drop config_distro_bootcmd.h from the config.h file - rebuild again to get the environment without distro scripts - write the environment (adding boot_targets) to board.env - remove CONFIG_EXTRA_ENV_SETTINGS from the config.h file
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/ahci.c6
-rw-r--r--drivers/block/ide.c86
-rw-r--r--drivers/core/dump.c65
-rw-r--r--drivers/mmc/mmc-uclass.c2
-rw-r--r--drivers/mmc/mmc_bootdev.c33
-rw-r--r--drivers/mmc/sandbox_mmc.c2
-rw-r--r--drivers/mtd/spi/Kconfig8
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/sf-uclass.c11
-rw-r--r--drivers/mtd/spi/sf_bootdev.c82
-rw-r--r--drivers/nvme/nvme-uclass.c54
-rw-r--r--drivers/nvme/nvme.c5
-rw-r--r--drivers/scsi/Makefile7
-rw-r--r--drivers/scsi/scsi.c32
-rw-r--r--drivers/scsi/scsi_bootdev.c62
-rw-r--r--drivers/usb/host/usb-uclass.c2
-rw-r--r--drivers/usb/host/usb_bootdev.c36
-rw-r--r--drivers/virtio/virtio-uclass.c62
-rw-r--r--drivers/virtio/virtio_sandbox.c16
19 files changed, 448 insertions, 124 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index de6131f1d9b..272c48b8e57 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -675,6 +675,12 @@ static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv,
/* Read id from sata */
port = pccb->target;
+ /* If this port number is not valid, give up */
+ if (!(uc_priv->port_map & (1 << port))) {
+ debug("Port %x not valid in map %x\n", port, uc_priv->port_map);
+ return -ENODEV;
+ }
+
if (ahci_device_data_io(uc_priv, port, (u8 *)&fis, sizeof(fis),
(u8 *)tmpid, ATA_ID_WORDS * 2, 0)) {
debug("scsi_ahci: SCSI inquiry command failure.\n");
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index eaa58d859c6..1ad9b6c1267 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <ata.h>
#include <blk.h>
+#include <bootdev.h>
#include <dm.h>
#include <ide.h>
#include <log.h>
@@ -443,9 +444,6 @@ static void atapi_inquiry(struct blk_desc *dev_desc)
device = dev_desc->devnum;
dev_desc->type = DEV_TYPE_UNKNOWN; /* not yet valid */
-#ifndef CONFIG_BLK
- dev_desc->block_read = atapi_read;
-#endif
memset(ccb, 0, sizeof(ccb));
memset(iobuf, 0, sizeof(iobuf));
@@ -692,6 +690,7 @@ __weak unsigned char ide_inb(int dev, int port)
void ide_init(void)
{
+ struct udevice *dev;
unsigned char c;
int i, bus;
@@ -759,29 +758,14 @@ void ide_init(void)
ide_dev_desc[i].log2blksz =
LOG2_INVALID(typeof(ide_dev_desc[i].log2blksz));
ide_dev_desc[i].lba = 0;
-#ifndef CONFIG_BLK
- ide_dev_desc[i].block_read = ide_read;
- ide_dev_desc[i].block_write = ide_write;
-#endif
if (!ide_bus_ok[IDE_BUS(i)])
continue;
ide_ident(&ide_dev_desc[i]);
dev_print(&ide_dev_desc[i]);
-
-#ifndef CONFIG_BLK
- if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
- /* initialize partition type */
- part_init(&ide_dev_desc[i]);
- }
-#endif
}
schedule();
-#ifdef CONFIG_BLK
- struct udevice *dev;
-
uclass_first_device(UCLASS_IDE, &dev);
-#endif
}
__weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
@@ -830,17 +814,10 @@ __weak void ide_input_data(int dev, ulong *sect_buf, int words)
}
}
-#ifdef CONFIG_BLK
ulong ide_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
-#else
-ulong ide_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
- void *buffer)
-#endif
{
-#ifdef CONFIG_BLK
struct blk_desc *block_dev = dev_get_uclass_plat(dev);
-#endif
int device = block_dev->devnum;
ulong n = 0;
unsigned char c;
@@ -957,17 +934,10 @@ IDE_READ_E:
return n;
}
-#ifdef CONFIG_BLK
ulong ide_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
-#else
-ulong ide_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
- const void *buffer)
-#endif
{
-#ifdef CONFIG_BLK
struct blk_desc *block_dev = dev_get_uclass_plat(dev);
-#endif
int device = block_dev->devnum;
ulong n = 0;
unsigned char c;
@@ -1056,7 +1026,6 @@ int ide_device_present(int dev)
}
#endif
-#ifdef CONFIG_BLK
static int ide_blk_probe(struct udevice *udev)
{
struct blk_desc *desc = dev_get_uclass_plat(udev);
@@ -1087,6 +1056,45 @@ U_BOOT_DRIVER(ide_blk) = {
.probe = ide_blk_probe,
};
+static int ide_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_5_SCAN_SLOW;
+
+ return 0;
+}
+
+static int ide_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+ ide_init();
+
+ return 0;
+}
+
+struct bootdev_ops ide_bootdev_ops = {
+};
+
+static const struct udevice_id ide_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-ide" },
+ { }
+};
+
+U_BOOT_DRIVER(ide_bootdev) = {
+ .name = "ide_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &ide_bootdev_ops,
+ .bind = ide_bootdev_bind,
+ .of_match = ide_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(ide_bootdev_hunter) = {
+ .prio = BOOTDEVP_5_SCAN_SLOW,
+ .uclass = UCLASS_IDE,
+ .hunt = ide_bootdev_hunt,
+ .drv = DM_DRIVER_REF(ide_bootdev),
+};
+
static int ide_probe(struct udevice *udev)
{
struct udevice *blk_dev;
@@ -1118,6 +1126,10 @@ static int ide_probe(struct udevice *udev)
ret = blk_probe_or_unbind(blk_dev);
if (ret)
return ret;
+
+ ret = bootdev_setup_for_dev(udev, "ide_bootdev");
+ if (ret)
+ return log_msg_ret("bootdev", ret);
}
}
@@ -1141,11 +1153,3 @@ UCLASS_DRIVER(ide) = {
.name = "ide",
.id = UCLASS_IDE,
};
-#else
-U_BOOT_LEGACY_BLK(ide) = {
- .uclass_idname = "ide",
- .uclass_id = UCLASS_IDE,
- .max_devs = CONFIG_SYS_IDE_MAXDEVICE,
- .desc = ide_dev_desc,
-};
-#endif
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 1c1f7e4d308..0c7d2ec4d0c 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -5,12 +5,34 @@
#include <common.h>
#include <dm.h>
+#include <malloc.h>
#include <mapmem.h>
+#include <sort.h>
#include <dm/root.h>
#include <dm/util.h>
#include <dm/uclass-internal.h>
-static void show_devices(struct udevice *dev, int depth, int last_flag)
+/**
+ * struct sort_info - information used for sorting
+ *
+ * @dev: List of devices
+ * @alloced: Maximum number of devices in @dev
+ */
+struct sort_info {
+ struct udevice **dev;
+ int size;
+};
+
+static int h_cmp_uclass_id(const void *d1, const void *d2)
+{
+ const struct udevice *const *dev1 = d1;
+ const struct udevice *const *dev2 = d2;
+
+ return device_get_uclass_id(*dev1) - device_get_uclass_id(*dev2);
+}
+
+static void show_devices(struct udevice *dev, int depth, int last_flag,
+ struct udevice **devs)
{
int i, is_last;
struct udevice *child;
@@ -39,21 +61,52 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
printf("%s\n", dev->name);
- device_foreach_child(child, dev) {
- is_last = list_is_last(&child->sibling_node, &dev->child_head);
- show_devices(child, depth + 1, (last_flag << 1) | is_last);
+ if (devs) {
+ int count;
+ int i;
+
+ count = 0;
+ device_foreach_child(child, dev)
+ devs[count++] = child;
+ qsort(devs, count, sizeof(struct udevice *), h_cmp_uclass_id);
+
+ for (i = 0; i < count; i++) {
+ show_devices(devs[i], depth + 1,
+ (last_flag << 1) | (i == count - 1),
+ devs + count);
+ }
+ } else {
+ device_foreach_child(child, dev) {
+ is_last = list_is_last(&child->sibling_node,
+ &dev->child_head);
+ show_devices(child, depth + 1,
+ (last_flag << 1) | is_last, NULL);
+ }
}
}
-void dm_dump_tree(void)
+void dm_dump_tree(bool sort)
{
struct udevice *root;
root = dm_root();
if (root) {
+ int dev_count, uclasses;
+ struct udevice **devs = NULL;
+
+ dm_get_stats(&dev_count, &uclasses);
+
printf(" Class Index Probed Driver Name\n");
printf("-----------------------------------------------------------\n");
- show_devices(root, -1, 0);
+ if (sort) {
+ devs = calloc(dev_count, sizeof(struct udevice *));
+ if (!devs) {
+ printf("(out of memory)\n");
+ return;
+ }
+ }
+ show_devices(root, -1, 0, devs);
+ free(devs);
}
}
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 759a6b728c8..01d9b0201f2 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -421,7 +421,7 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
mmc->cfg = cfg;
mmc->priv = dev;
- ret = bootdev_setup_for_dev(dev, "mmc_bootdev");
+ ret = bootdev_setup_sibling_blk(bdev, "mmc_bootdev");
if (ret)
return log_msg_ret("bootdev", ret);
diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c
index b4f41fb3a67..b57b8a62276 100644
--- a/drivers/mmc/mmc_bootdev.c
+++ b/drivers/mmc/mmc_bootdev.c
@@ -11,41 +11,16 @@
#include <dm.h>
#include <mmc.h>
-static int mmc_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
- struct bootflow *bflow)
-{
- struct udevice *mmc_dev = dev_get_parent(dev);
- struct udevice *blk;
- int ret;
-
- ret = mmc_get_blk(mmc_dev, &blk);
- /*
- * If there is no media, indicate that no more partitions should be
- * checked
- */
- if (ret == -EOPNOTSUPP)
- ret = -ESHUTDOWN;
- if (ret)
- return log_msg_ret("blk", ret);
- assert(blk);
- ret = bootdev_find_in_blk(dev, blk, iter, bflow);
- if (ret)
- return log_msg_ret("find", ret);
-
- return 0;
-}
-
static int mmc_bootdev_bind(struct udevice *dev)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
- ucp->prio = BOOTDEVP_0_INTERNAL_FAST;
+ ucp->prio = BOOTDEVP_2_INTERNAL_FAST;
return 0;
}
struct bootdev_ops mmc_bootdev_ops = {
- .get_bootflow = mmc_get_bootflow,
};
static const struct udevice_id mmc_bootdev_ids[] = {
@@ -60,3 +35,9 @@ U_BOOT_DRIVER(mmc_bootdev) = {
.bind = mmc_bootdev_bind,
.of_match = mmc_bootdev_ids,
};
+
+BOOTDEV_HUNTER(mmc_bootdev_hunter) = {
+ .prio = BOOTDEVP_2_INTERNAL_FAST,
+ .uclass = UCLASS_MMC,
+ .drv = DM_DRIVER_REF(mmc_bootdev),
+};
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index ba79a5565c3..0ba7940a4db 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -183,7 +183,7 @@ static int sandbox_mmc_probe(struct udevice *dev)
priv->csize = 0;
priv->size = (priv->csize + 1) * SIZE_MULTIPLE; /* 1 MiB */
- priv->buf = malloc(priv->size);
+ priv->buf = calloc(1, priv->size);
if (!priv->buf) {
log_err("%s: Not enough memory (%x bytes)\n",
dev->name, priv->size);
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 7b858a3a919..a9617c6c58c 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -80,6 +80,14 @@ config SF_DEFAULT_SPEED
if SPI_FLASH
+config BOOTDEV_SPI_FLASH
+ bool "SPI Flash bootdev support"
+ help
+ Enable a boot device for SPI flash. This allows reading a script
+ from SPI flash so that it can be used to boot an Operating System.
+
+ If unsure, say N
+
config SPI_FLASH_SFDP_SUPPORT
bool "SFDP table parsing support for SPI NOR flashes"
depends on !SPI_FLASH_BAR
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 99cc4185522..409395382f5 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_SPI_FLASH) += spi-nor.o
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_MTD) += sf_mtd.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_SPI_FLASH) += sf_bootdev.o
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index e6e650ef8c0..df1f75390c4 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -6,6 +6,7 @@
#define LOG_CATEGORY UCLASS_SPI_FLASH
#include <common.h>
+#include <bootdev.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
@@ -13,6 +14,7 @@
#include <spi_flash.h>
#include <asm/global_data.h>
#include <dm/device-internal.h>
+#include <test/test.h>
#include "sf_internal.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -86,6 +88,14 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
static int spi_flash_post_bind(struct udevice *dev)
{
+ int ret;
+
+ if (CONFIG_IS_ENABLED(BOOTDEV_SPI_FLASH) && test_sf_bootdev_enabled()) {
+ ret = bootdev_setup_for_dev(dev, "sf_bootdev");
+ if (ret)
+ return log_msg_ret("bd", ret);
+ }
+
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
struct dm_spi_flash_ops *ops = sf_get_ops(dev);
static int reloc_done;
@@ -101,6 +111,7 @@ static int spi_flash_post_bind(struct udevice *dev)
reloc_done++;
}
#endif
+
return 0;
}
diff --git a/drivers/mtd/spi/sf_bootdev.c b/drivers/mtd/spi/sf_bootdev.c
new file mode 100644
index 00000000000..d6b47b11ce4
--- /dev/null
+++ b/drivers/mtd/spi/sf_bootdev.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Read a bootflow from SPI flash
+ *
+ * Copyright 2022 Google LLC
+ */
+
+#include <common.h>
+#include <bootdev.h>
+#include <bootflow.h>
+#include <bootmeth.h>
+#include <dm.h>
+#include <env.h>
+#include <malloc.h>
+#include <spi_flash.h>
+
+static int sf_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
+ struct bootflow *bflow)
+{
+ struct udevice *sf = dev_get_parent(dev);
+ uint size;
+ char *buf;
+ int ret;
+
+ /* We only support the whole device, not partitions */
+ if (iter->part)
+ return log_msg_ret("max", -ESHUTDOWN);
+
+ size = env_get_hex("script_size_f", 0);
+ if (!size)
+ return log_msg_ret("sz", -EINVAL);
+
+ buf = malloc(size + 1);
+ if (!buf)
+ return log_msg_ret("buf", -ENOMEM);
+
+ ret = spi_flash_read_dm(sf, env_get_hex("script_offset_f", 0),
+ size, buf);
+ if (ret)
+ return log_msg_ret("cmd", -EINVAL);
+ bflow->state = BOOTFLOWST_MEDIA;
+
+ ret = bootmeth_set_bootflow(bflow->method, bflow, buf, size);
+ if (ret) {
+ free(buf);
+ return log_msg_ret("method", ret);
+ }
+
+ return 0;
+}
+
+static int sf_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+ return 0;
+}
+
+struct bootdev_ops sf_bootdev_ops = {
+ .get_bootflow = sf_get_bootflow,
+};
+
+static const struct udevice_id sf_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-sf" },
+ { }
+};
+
+U_BOOT_DRIVER(sf_bootdev) = {
+ .name = "sf_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &sf_bootdev_ops,
+ .bind = sf_bootdev_bind,
+ .of_match = sf_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(sf_bootdev_hunter) = {
+ .prio = BOOTDEVP_4_SCAN_FAST,
+ .uclass = UCLASS_SPI_FLASH,
+ .drv = DM_DRIVER_REF(sf_bootdev),
+};
diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c
index 239a92abba6..f3af6a27b63 100644
--- a/drivers/nvme/nvme-uclass.c
+++ b/drivers/nvme/nvme-uclass.c
@@ -7,9 +7,63 @@
#define LOG_CATEGORY UCLASS_NVME
#include <common.h>
+#include <bootdev.h>
#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <nvme.h>
+
+static int nvme_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+ return 0;
+}
+
+static int nvme_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+ int ret;
+
+ /* init PCI first since this is often used to provide NVMe */
+ if (IS_ENABLED(CONFIG_PCI)) {
+ ret = pci_init();
+ if (ret)
+ log_warning("Failed to init PCI (%dE)\n", ret);
+ }
+
+ ret = nvme_scan_namespace();
+ if (ret)
+ return log_msg_ret("scan", ret);
+
+ return 0;
+}
UCLASS_DRIVER(nvme) = {
.name = "nvme",
.id = UCLASS_NVME,
};
+
+struct bootdev_ops nvme_bootdev_ops = {
+};
+
+static const struct udevice_id nvme_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-nvme" },
+ { }
+};
+
+U_BOOT_DRIVER(nvme_bootdev) = {
+ .name = "nvme_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &nvme_bootdev_ops,
+ .bind = nvme_bootdev_bind,
+ .of_match = nvme_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(nvme_bootdev_hunter) = {
+ .prio = BOOTDEVP_4_SCAN_FAST,
+ .uclass = UCLASS_NVME,
+ .hunt = nvme_bootdev_hunt,
+ .drv = DM_DRIVER_REF(nvme_bootdev),
+};
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 6d0d3f3ca2b..74e7a5b0110 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <blk.h>
+#include <bootdev.h>
#include <cpu_func.h>
#include <dm.h>
#include <errno.h>
@@ -893,6 +894,10 @@ int nvme_init(struct udevice *udev)
if (ret)
goto free_id;
+ ret = bootdev_setup_sibling_blk(ns_udev, "nvme_bootdev");
+ if (ret)
+ return log_msg_ret("bootdev", ret);
+
ret = blk_probe_or_unbind(ns_udev);
if (ret)
goto free_id;
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index d1b40c61401..d8d6de59090 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -6,6 +6,13 @@
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_DM_SCSI) += scsi-uclass.o
obj-$(CONFIG_SCSI) += scsi.o
+
+ifdef CONFIG_SCSI
+ifdef CONFIG_DM_SCSI
+obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += scsi_bootdev.o
+endif
+endif
+
endif
ifdef CONFIG_SPL_BUILD
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a020a7da23a..6caeb3fcdd0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -4,8 +4,11 @@
* Denis Peter, MPL AG Switzerland
*/
+#define LOG_CATEGORY UCLASS_SCSI
+
#include <common.h>
#include <blk.h>
+#include <bootdev.h>
#include <bootstage.h>
#include <dm.h>
#include <env.h>
@@ -558,7 +561,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
struct udevice *bdev;
struct blk_desc bd;
struct blk_desc *bdesc;
- char str[10];
+ char str[10], *name;
/*
* detect the scsi driver to get information about its geometry (block
@@ -574,12 +577,16 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
* block devices created
*/
snprintf(str, sizeof(str), "id%dlun%d", id, lun);
- ret = blk_create_devicef(dev, "scsi_blk", str, UCLASS_SCSI, -1,
+ name = strdup(str);
+ if (!name)
+ return log_msg_ret("nam", -ENOMEM);
+ ret = blk_create_devicef(dev, "scsi_blk", name, UCLASS_SCSI, -1,
bd.blksz, bd.lba, &bdev);
if (ret) {
debug("Can't create device\n");
return ret;
}
+ device_set_name_alloced(bdev);
bdesc = dev_get_uclass_plat(bdev);
bdesc->target = id;
@@ -598,7 +605,11 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
ret = blk_probe_or_unbind(bdev);
if (ret < 0)
/* TODO: undo create */
- return ret;
+ return log_msg_ret("pro", ret);
+
+ ret = bootdev_setup_sibling_blk(bdev, "scsi_bootdev");
+ if (ret)
+ return log_msg_ret("bd", ret);
if (verbose) {
printf(" Device %d: ", bdesc->devnum);
@@ -638,12 +649,23 @@ int scsi_scan(bool verbose)
if (verbose)
printf("scanning bus for devices...\n");
- blk_unbind_all(UCLASS_SCSI);
-
ret = uclass_get(UCLASS_SCSI, &uc);
if (ret)
return ret;
+ /* remove all children of the SCSI devices */
+ uclass_foreach_dev(dev, uc) {
+ log_debug("unbind %s\n", dev->name);
+ ret = device_chld_remove(dev, NULL, DM_REMOVE_NORMAL);
+ if (!ret)
+ ret = device_chld_unbind(dev, NULL);
+ if (ret) {
+ if (verbose)
+ printf("unable to unbind devices (%dE)\n", ret);
+ return log_msg_ret("unb", ret);
+ }
+ }
+
uclass_foreach_dev(dev, uc) {
ret = scsi_scan_dev(dev, verbose);
if (ret)
diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c
new file mode 100644
index 00000000000..991013fe1ef
--- /dev/null
+++ b/drivers/scsi/scsi_bootdev.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Bootdevice for USB
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <[email protected]>
+ */
+
+#include <common.h>
+#include <bootdev.h>
+#include <dm.h>
+#include <init.h>
+#include <scsi.h>
+
+static int scsi_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+ return 0;
+}
+
+static int scsi_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+ int ret;
+
+ if (IS_ENABLED(CONFIG_PCI)) {
+ ret = pci_init();
+ if (ret)
+ return log_msg_ret("pci", ret);
+ }
+
+ ret = scsi_scan(true);
+ if (ret)
+ return log_msg_ret("scs", ret);
+
+ return 0;
+}
+
+struct bootdev_ops scsi_bootdev_ops = {
+};
+
+static const struct udevice_id scsi_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-scsi" },
+ { }
+};
+
+U_BOOT_DRIVER(scsi_bootdev) = {
+ .name = "scsi_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &scsi_bootdev_ops,
+ .bind = scsi_bootdev_bind,
+ .of_match = scsi_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(scsi_bootdev_hunter) = {
+ .prio = BOOTDEVP_4_SCAN_FAST,
+ .uclass = UCLASS_SCSI,
+ .hunt = scsi_bootdev_hunt,
+ .drv = DM_DRIVER_REF(scsi_bootdev),
+};
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 93c318c3d1d..28f7ca9654d 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -563,6 +563,8 @@ static int usb_find_and_bind_driver(struct udevice *parent,
if (!str)
return -ENOMEM;
ret = device_bind_driver(parent, "usb_dev_generic_drv", str, devp);
+ if (!ret)
+ device_set_name_alloced(*devp);
error:
debug("%s: No match found: %d\n", __func__, ret);
diff --git a/drivers/usb/host/usb_bootdev.c b/drivers/usb/host/usb_bootdev.c
index b85f699933d..32919f99286 100644
--- a/drivers/usb/host/usb_bootdev.c
+++ b/drivers/usb/host/usb_bootdev.c
@@ -11,40 +11,21 @@
#include <dm.h>
#include <usb.h>
-static int usb_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
- struct bootflow *bflow)
+static int usb_bootdev_bind(struct udevice *dev)
{
- struct udevice *blk;
- int ret;
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
- ret = bootdev_get_sibling_blk(dev, &blk);
- /*
- * If there is no media, indicate that no more partitions should be
- * checked
- */
- if (ret == -EOPNOTSUPP)
- ret = -ESHUTDOWN;
- if (ret)
- return log_msg_ret("blk", ret);
- assert(blk);
- ret = bootdev_find_in_blk(dev, blk, iter, bflow);
- if (ret)
- return log_msg_ret("find", ret);
+ ucp->prio = BOOTDEVP_5_SCAN_SLOW;
return 0;
}
-static int usb_bootdev_bind(struct udevice *dev)
+static int usb_bootdev_hunt(struct bootdev_hunter *info, bool show)
{
- struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
-
- ucp->prio = BOOTDEVP_3_SCAN_SLOW;
-
- return 0;
+ return usb_init();
}
struct bootdev_ops usb_bootdev_ops = {
- .get_bootflow = usb_get_bootflow,
};
static const struct udevice_id usb_bootdev_ids[] = {
@@ -59,3 +40,10 @@ U_BOOT_DRIVER(usb_bootdev) = {
.bind = usb_bootdev_bind,
.of_match = usb_bootdev_ids,
};
+
+BOOTDEV_HUNTER(usb_bootdev_hunter) = {
+ .prio = BOOTDEVP_5_SCAN_SLOW,
+ .uclass = UCLASS_USB,
+ .hunt = usb_bootdev_hunt,
+ .drv = DM_DRIVER_REF(usb_bootdev),
+};
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index da4f2f26a63..91af412ec1d 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -18,6 +18,7 @@
#define LOG_CATEGORY UCLASS_VIRTIO
#include <common.h>
+#include <bootdev.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
@@ -163,7 +164,7 @@ int virtio_finalize_features(struct udevice *vdev)
return ret;
if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
debug("(%s): device refuses features %x\n", vdev->name, status);
- return -ENODEV;
+ return -EINVAL;
}
return 0;
@@ -214,6 +215,7 @@ static int virtio_uclass_post_probe(struct udevice *udev)
struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
char dev_name[30], *str;
struct udevice *vdev;
+ const char *name;
int ret;
if (uc_priv->device >= VIRTIO_ID_MAX_NUM) {
@@ -222,20 +224,19 @@ static int virtio_uclass_post_probe(struct udevice *udev)
return 0;
}
- if (!virtio_drv_name[uc_priv->device]) {
+ name = virtio_drv_name[uc_priv->device];
+ if (!name) {
debug("(%s): underlying virtio device driver unavailable\n",
udev->name);
return 0;
}
- snprintf(dev_name, sizeof(dev_name), "%s#%d",
- virtio_drv_name[uc_priv->device], dev_seq(udev));
+ snprintf(dev_name, sizeof(dev_name), "%s#%d", name, dev_seq(udev));
str = strdup(dev_name);
if (!str)
return -ENOMEM;
- ret = device_bind_driver(udev, virtio_drv_name[uc_priv->device],
- str, &vdev);
+ ret = device_bind_driver(udev, name, str, &vdev);
if (ret == -ENOENT) {
debug("(%s): no driver configured\n", udev->name);
return 0;
@@ -246,6 +247,12 @@ static int virtio_uclass_post_probe(struct udevice *udev)
}
device_set_name_alloced(vdev);
+ if (uc_priv->device == VIRTIO_ID_BLOCK) {
+ ret = bootdev_setup_for_dev(udev, name);
+ if (ret)
+ return log_msg_ret("bootdev", ret);
+ }
+
INIT_LIST_HEAD(&uc_priv->vqs);
return 0;
@@ -349,6 +356,26 @@ static int virtio_uclass_child_post_probe(struct udevice *vdev)
return 0;
}
+static int virtio_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+ return 0;
+}
+
+static int virtio_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+ int ret;
+
+ ret = uclass_probe_all(UCLASS_VIRTIO);
+ if (ret && ret != -ENOENT)
+ return log_msg_ret("vir", ret);
+
+ return 0;
+}
+
UCLASS_DRIVER(virtio) = {
.name = "virtio",
.id = UCLASS_VIRTIO,
@@ -360,3 +387,26 @@ UCLASS_DRIVER(virtio) = {
.child_post_probe = virtio_uclass_child_post_probe,
.per_device_auto = sizeof(struct virtio_dev_priv),
};
+
+struct bootdev_ops virtio_bootdev_ops = {
+};
+
+static const struct udevice_id virtio_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-virtio" },
+ { }
+};
+
+U_BOOT_DRIVER(virtio_bootdev) = {
+ .name = "virtio_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &virtio_bootdev_ops,
+ .bind = virtio_bootdev_bind,
+ .of_match = virtio_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(virtio_bootdev_hunter) = {
+ .prio = BOOTDEVP_4_SCAN_FAST,
+ .uclass = UCLASS_VIRTIO,
+ .hunt = virtio_bootdev_hunt,
+ .drv = DM_DRIVER_REF(virtio_bootdev),
+};
diff --git a/drivers/virtio/virtio_sandbox.c b/drivers/virtio/virtio_sandbox.c
index 5484ae3a1a0..b34f1d60455 100644
--- a/drivers/virtio/virtio_sandbox.c
+++ b/drivers/virtio/virtio_sandbox.c
@@ -161,24 +161,13 @@ static int virtio_sandbox_probe(struct udevice *udev)
/* fake some information for testing */
priv->device_features = BIT_ULL(VIRTIO_F_VERSION_1);
- uc_priv->device = VIRTIO_ID_RNG;
+ uc_priv->device = dev_read_u32_default(udev, "virtio-type",
+ VIRTIO_ID_RNG);
uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
return 0;
}
-/* check virtio device driver's remove routine was called to reset the device */
-static int virtio_sandbox_child_post_remove(struct udevice *vdev)
-{
- u8 status;
-
- virtio_get_status(vdev, &status);
- if (status)
- panic("virtio device was not reset\n");
-
- return 0;
-}
-
static const struct dm_virtio_ops virtio_sandbox1_ops = {
.get_config = virtio_sandbox_get_config,
.set_config = virtio_sandbox_set_config,
@@ -203,7 +192,6 @@ U_BOOT_DRIVER(virtio_sandbox1) = {
.of_match = virtio_sandbox1_ids,
.ops = &virtio_sandbox1_ops,
.probe = virtio_sandbox_probe,
- .child_post_remove = virtio_sandbox_child_post_remove,
.priv_auto = sizeof(struct virtio_sandbox_priv),
};