[U-Boot] [PATCH v3 0/4] dm: Add driver-model support for block drivers

Recent additions of the MMC and DISK uclasses have indicated that it is time to look at adding a uclass for block devices. This series does this and includes a few clean-ups to the partition code also.
A block device is typically a child device of its storage parent. For example an MMC device will have a block-device child. A USB storage device may have multiple block-device children, one for each LUN.
With this series only USB storage and 'host' are converted over to use the new support. Several more remain, including SCSI, IDE and MMC. Each of these should get its own uclass.
The uclass implements only a few basic features. A few tests are added to check that things work as expected.
The code size impact of switching to driver model for block devices is small. One benefit is that it becomes possible to enumerate all block devices, regardless of their type.
Changes in v3: - Expand the commit message - Drop patches already applied
Changes in v2: - Rename to blk_get_device_by_str()
Simon Glass (4): dm: usb: Unbind old block devices when shutting down USB dm: sandbox: Switch over to use DM for block devices dm: sandbox: Drop the pre-DM host implementation dm: blk: Add tests for block devices
configs/sandbox_defconfig | 1 + drivers/block/sandbox.c | 90 ---------------------------------------- drivers/usb/host/usb-uclass.c | 6 ++- test/dm/Makefile | 1 + test/dm/blk.c | 96 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 91 deletions(-) create mode 100644 test/dm/blk.c

When 'usb start' is used, block devices are created for any USB flash sticks and disks, etc. When 'usb stop' is used, these block devices are currently not removed.
We don't want old block devices hanging around since they can still be visible to U-Boot. Therefore, when USB is shut down, remove and unbind all the block devices created by the USB subsystem.
Possibly we should unbind all devices which don't cause problems by being unbound. Most likely we can remove everything except USB controllers, hubs and emulators. We can consider that later.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com ---
Changes in v3: - Expand the commit message
Changes in v2: None
drivers/usb/host/usb-uclass.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 50538e0..69c9a50 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -159,7 +159,11 @@ int usb_stop(void) if (ret && !err) err = ret; } - +#ifdef CONFIG_BLK + ret = blk_unbind_all(IF_TYPE_USB); + if (ret && !err) + err = ret; +#endif #ifdef CONFIG_SANDBOX struct udevice *dev;

On 13 March 2016 at 08:22, Simon Glass sjg@chromium.org wrote:
When 'usb start' is used, block devices are created for any USB flash sticks and disks, etc. When 'usb stop' is used, these block devices are currently not removed.
We don't want old block devices hanging around since they can still be visible to U-Boot. Therefore, when USB is shut down, remove and unbind all the block devices created by the USB subsystem.
Possibly we should unbind all devices which don't cause problems by being unbound. Most likely we can remove everything except USB controllers, hubs and emulators. We can consider that later.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com
Changes in v3:
- Expand the commit message
Changes in v2: None
drivers/usb/host/usb-uclass.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
Applied to u-boot-dm.

Now that the drivers used by sandbox support CONFIG_BLK, we can switch sandbox over to use driver model for block devices.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com ---
Changes in v3: None Changes in v2: None
configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 02534bf..d69c9fc 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -28,6 +28,7 @@ CONFIG_SPL_SYSCON=y CONFIG_DEVRES=y CONFIG_ADC=y CONFIG_ADC_SANDBOX=y +CONFIG_BLK=y CONFIG_CLK=y CONFIG_SANDBOX_GPIO=y CONFIG_SYS_I2C_SANDBOX=y

On 13 March 2016 at 08:22, Simon Glass sjg@chromium.org wrote:
Now that the drivers used by sandbox support CONFIG_BLK, we can switch sandbox over to use driver model for block devices.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com
Changes in v3: None Changes in v2: None
configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+)
Applied to u-boot-dm.

Driver model is used for host device block devices now, so we don't need the old code. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com ---
Changes in v3: None Changes in v2: None
drivers/block/sandbox.c | 90 ------------------------------------------------- 1 file changed, 90 deletions(-)
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index 6d41508..2d340ef 100644 --- a/drivers/block/sandbox.c +++ b/drivers/block/sandbox.c @@ -17,19 +17,6 @@
DECLARE_GLOBAL_DATA_PTR;
-#ifndef CONFIG_BLK -static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES]; - -static struct host_block_dev *find_host_device(int dev) -{ - if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES) - return &host_devices[dev]; - - return NULL; -} -#endif - -#ifdef CONFIG_BLK static unsigned long host_block_read(struct udevice *dev, unsigned long start, lbaint_t blkcnt, void *buffer) @@ -37,18 +24,6 @@ static unsigned long host_block_read(struct udevice *dev, struct host_block_dev *host_dev = dev_get_priv(dev); struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
-#else -static unsigned long host_block_read(struct blk_desc *block_dev, - unsigned long start, lbaint_t blkcnt, - void *buffer) -{ - int dev = block_dev->devnum; - struct host_block_dev *host_dev = find_host_device(dev); - - if (!host_dev) - return -1; -#endif - if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == -1) { printf("ERROR: Invalid block %lx\n", start); @@ -60,21 +35,12 @@ static unsigned long host_block_read(struct blk_desc *block_dev, return -1; }
-#ifdef CONFIG_BLK static unsigned long host_block_write(struct udevice *dev, unsigned long start, lbaint_t blkcnt, const void *buffer) { struct host_block_dev *host_dev = dev_get_priv(dev); struct blk_desc *block_dev = dev_get_uclass_platdata(dev); -#else -static unsigned long host_block_write(struct blk_desc *block_dev, - unsigned long start, lbaint_t blkcnt, - const void *buffer) -{ - int dev = block_dev->devnum; - struct host_block_dev *host_dev = find_host_device(dev); -#endif
if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == -1) { @@ -87,7 +53,6 @@ static unsigned long host_block_write(struct blk_desc *block_dev, return -1; }
-#ifdef CONFIG_BLK int host_dev_bind(int devnum, char *filename) { struct host_block_dev *host_dev; @@ -150,51 +115,9 @@ err: free(str); return ret; } -#else -int host_dev_bind(int dev, char *filename) -{ - struct host_block_dev *host_dev = find_host_device(dev); - - if (!host_dev) - return -1; - if (host_dev->blk_dev.priv) { - os_close(host_dev->fd); - host_dev->blk_dev.priv = NULL; - } - if (host_dev->filename) - free(host_dev->filename); - if (filename && *filename) { - host_dev->filename = strdup(filename); - } else { - host_dev->filename = NULL; - return 0; - } - - host_dev->fd = os_open(host_dev->filename, OS_O_RDWR); - if (host_dev->fd == -1) { - printf("Failed to access host backing file '%s'\n", - host_dev->filename); - return 1; - } - - struct blk_desc *blk_dev = &host_dev->blk_dev; - blk_dev->if_type = IF_TYPE_HOST; - blk_dev->priv = host_dev; - blk_dev->blksz = 512; - blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz; - blk_dev->block_read = host_block_read; - blk_dev->block_write = host_block_write; - blk_dev->devnum = dev; - blk_dev->part_type = PART_TYPE_UNKNOWN; - part_init(blk_dev); - - return 0; -} -#endif
int host_get_dev_err(int devnum, struct blk_desc **blk_devp) { -#ifdef CONFIG_BLK struct udevice *dev; int ret;
@@ -202,17 +125,6 @@ int host_get_dev_err(int devnum, struct blk_desc **blk_devp) if (ret) return ret; *blk_devp = dev_get_uclass_platdata(dev); -#else - struct host_block_dev *host_dev = find_host_device(devnum); - - if (!host_dev) - return -ENODEV; - - if (!host_dev->blk_dev.priv) - return -ENOENT; - - *blk_devp = &host_dev->blk_dev; -#endif
return 0; } @@ -227,7 +139,6 @@ struct blk_desc *host_get_dev(int dev) return blk_dev; }
-#ifdef CONFIG_BLK static const struct blk_ops sandbox_host_blk_ops = { .read = host_block_read, .write = host_block_write, @@ -239,4 +150,3 @@ U_BOOT_DRIVER(sandbox_host_blk) = { .ops = &sandbox_host_blk_ops, .priv_auto_alloc_size = sizeof(struct host_block_dev), }; -#endif

On 13 March 2016 at 08:22, Simon Glass sjg@chromium.org wrote:
Driver model is used for host device block devices now, so we don't need the old code. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com
Changes in v3: None Changes in v2: None
drivers/block/sandbox.c | 90 ------------------------------------------------- 1 file changed, 90 deletions(-)
Applied to u-boot-dm.

Add some tests to check that block devices work as expected.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com ---
Changes in v3: - Drop patches already applied
Changes in v2: - Rename to blk_get_device_by_str()
test/dm/Makefile | 1 + test/dm/blk.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 test/dm/blk.c
diff --git a/test/dm/Makefile b/test/dm/Makefile index fd0198f..df2d71f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o # subsystem you must add sandbox tests here. obj-$(CONFIG_UT_DM) += core.o ifneq ($(CONFIG_SANDBOX),) +obj-$(CONFIG_BLK) += blk.o obj-$(CONFIG_CLK) += clk.o obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o diff --git a/test/dm/blk.c b/test/dm/blk.c new file mode 100644 index 0000000..f4ea32e --- /dev/null +++ b/test/dm/blk.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <usb.h> +#include <asm/state.h> +#include <dm/test.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Test that block devices can be created */ +static int dm_test_blk_base(struct unit_test_state *uts) +{ + struct udevice *blk, *usb_blk, *dev; + + /* Make sure there are no block devices */ + ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_BLK, 0, &blk)); + + /* Create two, one the parent of the other */ + ut_assertok(blk_create_device(gd->dm_root, "sandbox_host_blk", "test", + IF_TYPE_HOST, 1, 512, 1024, &blk)); + ut_assertok(blk_create_device(blk, "usb_storage_blk", "test", + IF_TYPE_USB, 3, 512, 1024, &usb_blk)); + + /* Check we can find them */ + ut_asserteq(-ENODEV, blk_get_device(IF_TYPE_HOST, 0, &dev)); + ut_assertok(blk_get_device(IF_TYPE_HOST, 1, &dev)); + ut_asserteq_ptr(blk, dev); + + ut_asserteq(-ENODEV, blk_get_device(IF_TYPE_USB, 0, &dev)); + ut_assertok(blk_get_device(IF_TYPE_USB, 3, &dev)); + ut_asserteq_ptr(usb_blk, dev); + + /* Check we can iterate */ + ut_assertok(blk_first_device(IF_TYPE_HOST, &dev)); + ut_asserteq_ptr(blk, dev); + ut_asserteq(-ENODEV, blk_next_device(&dev)); + + ut_assertok(blk_first_device(IF_TYPE_USB, &dev)); + ut_asserteq_ptr(usb_blk, dev); + ut_asserteq(-ENODEV, blk_next_device(&dev)); + + return 0; +} +DM_TEST(dm_test_blk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int count_blk_devices(void) +{ + struct udevice *blk; + struct uclass *uc; + int count = 0; + int ret; + + ret = uclass_get(UCLASS_BLK, &uc); + if (ret) + return ret; + + uclass_foreach_dev(blk, uc) + count++; + + return count; +} + +/* Test that block devices work correctly with USB */ +static int dm_test_blk_usb(struct unit_test_state *uts) +{ + struct udevice *usb_dev, *dev; + struct blk_desc *dev_desc; + + /* Get a flash device */ + state_set_skip_delays(true); + ut_assertok(usb_init()); + ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &usb_dev)); + ut_assertok(blk_get_device_by_str("usb", "0", &dev_desc)); + + /* The parent should be a block device */ + ut_assertok(blk_get_device(IF_TYPE_USB, 0, &dev)); + ut_asserteq_ptr(usb_dev, dev_get_parent(dev)); + + /* Check we have one block device for each mass storage device */ + ut_asserteq(3, count_blk_devices()); + + /* Now go around again, making sure the old devices were unbound */ + ut_assertok(usb_stop()); + ut_assertok(usb_init()); + ut_asserteq(3, count_blk_devices()); + ut_assertok(usb_stop()); + + return 0; +} +DM_TEST(dm_test_blk_usb, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

On 13 March 2016 at 08:22, Simon Glass sjg@chromium.org wrote:
Add some tests to check that block devices work as expected.
Signed-off-by: Simon Glass sjg@chromium.org Tested-by: Stephen Warren swarren@nvidia.com
Changes in v3:
- Drop patches already applied
Changes in v2:
- Rename to blk_get_device_by_str()
test/dm/Makefile | 1 + test/dm/blk.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 test/dm/blk.c
Applied to u-boot-dm.
participants (1)
-
Simon Glass