From ff1f0e414a6eafd76c6e8ec114bebf6df6c49d68 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:03 -0600 Subject: [PATCH 01/18] dm: sandbox: Drop non-BLK code from host implementation This is not used anymore. Drop it. Signed-off-by: Simon Glass --- cmd/host.c | 4 -- drivers/block/sandbox.c | 102 -------------------------------------- include/sandboxblockdev.h | 3 -- 3 files changed, 109 deletions(-) diff --git a/cmd/host.c b/cmd/host.c index f0d989ac0f9..f09ac8d4396 100644 --- a/cmd/host.c +++ b/cmd/host.c @@ -108,11 +108,7 @@ static int do_host_info(struct cmd_tbl *cmdtp, int flag, int argc, } struct host_block_dev *host_dev; -#ifdef CONFIG_BLK host_dev = dev_get_plat(blk_dev->bdev); -#else - host_dev = blk_dev->priv; -#endif printf("%12lu %s\n", (unsigned long)blk_dev->lba, host_dev->filename); } diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index f2aae89716b..93db1e0dcad 100644 --- a/drivers/block/sandbox.c +++ b/drivers/block/sandbox.c @@ -18,19 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; -#ifndef CONFIG_BLK -static struct host_block_dev host_devices[SANDBOX_HOST_MAX_DEVICES]; - -static struct host_block_dev *find_host_device(int dev) -{ - if (dev >= 0 && dev < SANDBOX_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) @@ -38,18 +25,6 @@ static unsigned long host_block_read(struct udevice *dev, struct host_block_dev *host_dev = dev_get_plat(dev); struct blk_desc *block_dev = dev_get_uclass_plat(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); @@ -61,21 +36,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_plat(dev); struct blk_desc *block_dev = dev_get_uclass_plat(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) { @@ -88,7 +54,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, bool removable) { struct host_block_dev *host_dev; @@ -164,55 +129,9 @@ err: free(str); return ret; } -#else -int host_dev_bind(int dev, char *filename, bool removable) -{ - 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->uclass_id = UCLASS_ROOT; - 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; - blk_dev->removable = removable; - snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot"); - snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile"); - snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0"); - 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; @@ -220,23 +139,10 @@ int host_get_dev_err(int devnum, struct blk_desc **blk_devp) if (ret) return ret; *blk_devp = dev_get_uclass_plat(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; } -#ifdef CONFIG_BLK - int sandbox_host_unbind(struct udevice *dev) { struct host_block_dev *host_dev; @@ -260,11 +166,3 @@ U_BOOT_DRIVER(sandbox_host_blk) = { .unbind = sandbox_host_unbind, .plat_auto = sizeof(struct host_block_dev), }; -#else -U_BOOT_LEGACY_BLK(sandbox_host) = { - .uclass_idname = "host", - .uclass_id = UCLASS_ROOT, - .max_devs = SANDBOX_HOST_MAX_DEVICES, - .get_dev = host_get_dev_err, -}; -#endif diff --git a/include/sandboxblockdev.h b/include/sandboxblockdev.h index dc983f0417b..0528f891b12 100644 --- a/include/sandboxblockdev.h +++ b/include/sandboxblockdev.h @@ -10,9 +10,6 @@ #define SANDBOX_HOST_MAX_DEVICES 4 struct host_block_dev { -#ifndef CONFIG_BLK - struct blk_desc blk_dev; -#endif char *filename; int fd; }; From 6ca4d5b96b54bdd6086c084631500e918b37ceb7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:04 -0600 Subject: [PATCH 02/18] sandbox: Add missing comments for os_alarm() Add the documentation to avoid a warning with 'make htmldocs'. Fixes: 10107efedd5 ("sandbox: add SIGALRM-based watchdog device") Signed-off-by: Simon Glass --- include/os.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/os.h b/include/os.h index 54874f5e0e8..0415f0f0e7a 100644 --- a/include/os.h +++ b/include/os.h @@ -110,6 +110,10 @@ void os_exit(int exit_code) __attribute__((noreturn)); /** * os_alarm() - access to the OS alarm() system call + * + * @seconds: number of seconds before the signal is sent + * Returns: number of seconds remaining until any previously scheduled alarm was + * due to be delivered; 0 if there was no previously scheduled alarm */ unsigned int os_alarm(unsigned int seconds); From 4349ba5977cdc00ff0398353c33ba04fcd9dd762 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:05 -0600 Subject: [PATCH 03/18] test: Split out mk_fs function into a helper This function is useful for other tests. Move it into common code. Signed-off-by: Simon Glass --- test/py/tests/fs_helper.py | 54 ++++++++++++++++++++++++++++ test/py/tests/test_fs/conftest.py | 58 ++++--------------------------- 2 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 test/py/tests/fs_helper.py diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py new file mode 100644 index 00000000000..2d8f1f63add --- /dev/null +++ b/test/py/tests/fs_helper.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Helper functions for dealing with filesystems +# +# Copyright (c) 2018, Linaro Limited +# Author: Takahiro Akashi + +import re +import os +from subprocess import call, check_call, check_output, CalledProcessError + +def mk_fs(config, fs_type, size, prefix): + """Create a file system volume + + Args: + fs_type (str): File system type, e.g. 'ext4' + size (int): Size of file system in bytes + prefix (str): Prefix string of volume's file name + """ + fs_img = '%s.%s.img' % (prefix, fs_type) + fs_img = config.persistent_data_dir + '/' + fs_img + + if fs_type == 'fat16': + mkfs_opt = '-F 16' + elif fs_type == 'fat32': + mkfs_opt = '-F 32' + else: + mkfs_opt = '' + + if re.match('fat', fs_type): + fs_lnxtype = 'vfat' + else: + fs_lnxtype = fs_type + + count = (size + 1048576 - 1) / 1048576 + + # Some distributions do not add /sbin to the default PATH, where mkfs lives + if '/sbin' not in os.environ["PATH"].split(os.pathsep): + os.environ["PATH"] += os.pathsep + '/sbin' + + try: + check_call('rm -f %s' % fs_img, shell=True) + check_call('dd if=/dev/zero of=%s bs=1M count=%d' + % (fs_img, count), shell=True) + check_call('mkfs.%s %s %s' + % (fs_lnxtype, mkfs_opt, fs_img), shell=True) + if fs_type == 'ext4': + sb_content = check_output('tune2fs -l %s' % fs_img, shell=True).decode() + if 'metadata_csum' in sb_content: + check_call('tune2fs -O ^metadata_csum %s' % fs_img, shell=True) + return fs_img + except CalledProcessError: + call('rm -f %s' % fs_img, shell=True) + raise diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index b638284e076..9329ec6f1b2 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -9,6 +9,7 @@ import re from subprocess import call, check_call, check_output, CalledProcessError from fstest_defs import * import u_boot_utils as util +from tests import fs_helper supported_fs_basic = ['fat16', 'fat32', 'ext4'] supported_fs_ext = ['fat16', 'fat32'] @@ -132,53 +133,6 @@ def check_ubconfig(config, fs_type): pytest.skip('.config feature "%s_WRITE" not enabled' % fs_type.upper()) -def mk_fs(config, fs_type, size, id): - """Create a file system volume. - - Args: - fs_type: File system type. - size: Size of file system in MiB. - id: Prefix string of volume's file name. - - Return: - Nothing. - """ - fs_img = '%s.%s.img' % (id, fs_type) - fs_img = config.persistent_data_dir + '/' + fs_img - - if fs_type == 'fat16': - mkfs_opt = '-F 16' - elif fs_type == 'fat32': - mkfs_opt = '-F 32' - else: - mkfs_opt = '' - - if re.match('fat', fs_type): - fs_lnxtype = 'vfat' - else: - fs_lnxtype = fs_type - - count = (size + 1048576 - 1) / 1048576 - - # Some distributions do not add /sbin to the default PATH, where mkfs lives - if '/sbin' not in os.environ["PATH"].split(os.pathsep): - os.environ["PATH"] += os.pathsep + '/sbin' - - try: - check_call('rm -f %s' % fs_img, shell=True) - check_call('dd if=/dev/zero of=%s bs=1M count=%d' - % (fs_img, count), shell=True) - check_call('mkfs.%s %s %s' - % (fs_lnxtype, mkfs_opt, fs_img), shell=True) - if fs_type == 'ext4': - sb_content = check_output('tune2fs -l %s' % fs_img, shell=True).decode() - if 'metadata_csum' in sb_content: - check_call('tune2fs -O ^metadata_csum %s' % fs_img, shell=True) - return fs_img - except CalledProcessError: - call('rm -f %s' % fs_img, shell=True) - raise - # from test/py/conftest.py def tool_is_in_path(tool): """Check whether a given command is available on host. @@ -283,7 +237,7 @@ def fs_obj_basic(request, u_boot_config): try: # 3GiB volume - fs_img = mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB') + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB') except CalledProcessError as err: pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err)) return @@ -405,7 +359,7 @@ def fs_obj_ext(request, u_boot_config): try: # 128MiB volume - fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') except CalledProcessError as err: pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err)) return @@ -500,7 +454,7 @@ def fs_obj_mkdir(request, u_boot_config): try: # 128MiB volume - fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') except: pytest.skip('Setup failed for filesystem: ' + fs_type) return @@ -534,7 +488,7 @@ def fs_obj_unlink(request, u_boot_config): try: # 128MiB volume - fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB') except CalledProcessError as err: pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err)) return @@ -617,7 +571,7 @@ def fs_obj_symlink(request, u_boot_config): try: # 1GiB volume - fs_img = mk_fs(u_boot_config, fs_type, 0x40000000, '1GB') + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x40000000, '1GB') except CalledProcessError as err: pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err)) return From 7cbb57321e632d966fad3f29f93689e9fc7cdc37 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:06 -0600 Subject: [PATCH 04/18] test: Correct pylint warnings in fs_helper Tidy this up so that pylint is happy. Use hex for the 1MB size and make sure it is not a floating-point value. Add a little main program to allow the code to be tried out, since at present is only called from a long-running test. Signed-off-by: Simon Glass --- test/py/tests/fs_helper.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index 2d8f1f63add..9882ddb1daa 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0+ # -# Helper functions for dealing with filesystems -# # Copyright (c) 2018, Linaro Limited # Author: Takahiro Akashi +"""Helper functions for dealing with filesystems""" + import re import os from subprocess import call, check_call, check_output, CalledProcessError @@ -13,12 +13,16 @@ def mk_fs(config, fs_type, size, prefix): """Create a file system volume Args: + config (u_boot_config): U-Boot configuration fs_type (str): File system type, e.g. 'ext4' size (int): Size of file system in bytes prefix (str): Prefix string of volume's file name + + Raises: + CalledProcessError: if any error occurs when creating the filesystem """ - fs_img = '%s.%s.img' % (prefix, fs_type) - fs_img = config.persistent_data_dir + '/' + fs_img + fs_img = f'{prefix}.{fs_type}.img' + fs_img = os.path.join(config.persistent_data_dir, fs_img) if fs_type == 'fat16': mkfs_opt = '-F 16' @@ -32,23 +36,31 @@ def mk_fs(config, fs_type, size, prefix): else: fs_lnxtype = fs_type - count = (size + 1048576 - 1) / 1048576 + count = (size + 0x100000 - 1) // 0x100000 # Some distributions do not add /sbin to the default PATH, where mkfs lives if '/sbin' not in os.environ["PATH"].split(os.pathsep): os.environ["PATH"] += os.pathsep + '/sbin' try: - check_call('rm -f %s' % fs_img, shell=True) - check_call('dd if=/dev/zero of=%s bs=1M count=%d' - % (fs_img, count), shell=True) - check_call('mkfs.%s %s %s' - % (fs_lnxtype, mkfs_opt, fs_img), shell=True) + check_call(f'rm -f {fs_img}', shell=True) + check_call(f'dd if=/dev/zero of={fs_img} bs=1M count={count}', + shell=True) + check_call(f'mkfs.{fs_lnxtype} {mkfs_opt} {fs_img}', shell=True) if fs_type == 'ext4': - sb_content = check_output('tune2fs -l %s' % fs_img, shell=True).decode() + sb_content = check_output(f'tune2fs -l {fs_img}', + shell=True).decode() if 'metadata_csum' in sb_content: - check_call('tune2fs -O ^metadata_csum %s' % fs_img, shell=True) + check_call(f'tune2fs -O ^metadata_csum {fs_img}', shell=True) return fs_img except CalledProcessError: - call('rm -f %s' % fs_img, shell=True) + call(f'rm -f {fs_img}', shell=True) raise + +# Just for trying out +if __name__ == "__main__": + import collections + + CNF= collections.namedtuple('config', 'persistent_data_dir') + + mk_fs(CNF('.'), 'ext4', 0x1000000, 'pref') From fa1e420ab0259b0e8c975a6572dc3086596b980e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:07 -0600 Subject: [PATCH 05/18] dm: test: Drop the special function for running DM tests This is not needed since the flag takes care of all differences. Make use of the common function. Signed-off-by: Simon Glass --- test/dm/test-dm.c | 51 +++++------------------------------------------ 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/test/dm/test-dm.c b/test/dm/test-dm.c index 66cc2bc6cce..e73a1dd8f81 100644 --- a/test/dm/test-dm.c +++ b/test/dm/test-dm.c @@ -4,55 +4,14 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -/** - * dm_test_run() - Run driver model tests - * - * Run all the available driver model tests, or a selection - * - * @test_name: Name of single test to run (e.g. "dm_test_fdt_pre_reloc" or just - * "fdt_pre_reloc"), or NULL to run all - * Return: 0 if all tests passed, 1 if not - */ -static int dm_test_run(const char *test_name, int runs_per_text) -{ - struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test); - const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test); - int ret; - - ret = ut_run_list("driver model", "dm_test_", tests, n_ents, test_name, - runs_per_text, false); - - return ret ? CMD_RET_FAILURE : 0; -} int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - const char *test_name = NULL; - int runs_per_text = 1; + struct unit_test *tests = UNIT_TEST_SUITE_START(dm_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(dm_test); - if (argc > 1 && !strncmp("-r", argv[1], 2)) { - runs_per_text = dectoul(argv[1] + 2, NULL); - argv++; - argc++; - } - if (argc > 1) - test_name = argv[1]; - - return dm_test_run(test_name, runs_per_text); + return cmd_ut_category("driver model", "dm_test_", tests, n_ents, argc, + argv); } From 5ea894ac4285be2bebc2e7bdfd6451c699469f37 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:08 -0600 Subject: [PATCH 06/18] dm: test: Clear the block cache after running a test Some tests access data in block devices and so cause the cache to fill up. This results in memory being allocated. Some tests check the malloc usage at the beginning and then again at the end, to ensure there is no memory leak caused by the test. The block cache makes this difficult, since the any test may cause entries to be allocated or even freed, if the cache becomes full. It is simpler to clear the block cache after each test. This ensures that it will not introduce noise in tests which check malloc usage. Add the logic to clear the cache, using the existing blkcache_invalidate() function. Drop the duplicate code at the same time. Signed-off-by: Simon Glass --- drivers/block/blkcache.c | 23 ++++++++++------------- include/blk.h | 9 +++++++-- test/test-main.c | 3 +++ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/block/blkcache.c b/drivers/block/blkcache.c index b53420a3a88..f99465aa479 100644 --- a/drivers/block/blkcache.c +++ b/drivers/block/blkcache.c @@ -150,8 +150,8 @@ void blkcache_invalidate(int iftype, int devnum) list_for_each_safe(entry, n, &block_cache) { node = (struct block_cache_node *)entry; - if ((node->iftype == iftype) && - (node->devnum == devnum)) { + if (iftype == -1 || + (node->iftype == iftype && node->devnum == devnum)) { list_del(entry); free(node->cache); free(node); @@ -162,18 +162,10 @@ void blkcache_invalidate(int iftype, int devnum) void blkcache_configure(unsigned blocks, unsigned entries) { - struct block_cache_node *node; + /* invalidate cache if there is a change */ if ((blocks != _stats.max_blocks_per_entry) || - (entries != _stats.max_entries)) { - /* invalidate cache */ - while (!list_empty(&block_cache)) { - node = (struct block_cache_node *)block_cache.next; - list_del(&node->lh); - free(node->cache); - free(node); - } - _stats.entries = 0; - } + (entries != _stats.max_entries)) + blkcache_invalidate(-1, 0); _stats.max_blocks_per_entry = blocks; _stats.max_entries = entries; @@ -188,3 +180,8 @@ void blkcache_stats(struct block_cache_stats *stats) _stats.hits = 0; _stats.misses = 0; } + +void blkcache_free(void) +{ + blkcache_invalidate(-1, 0); +} diff --git a/include/blk.h b/include/blk.h index e854166edb9..c8cbb64c7f8 100644 --- a/include/blk.h +++ b/include/blk.h @@ -147,8 +147,8 @@ void blkcache_fill(int iftype, int dev, * blkcache_invalidate() - discard the cache for a set of blocks * because of a write or device (re)initialization. * - * @param iftype - uclass_id_x for type of device - * @param dev - device index of particular type + * @iftype - UCLASS_ID_ for type of device, or -1 for any + * @dev - device index of particular type, if @iftype is not -1 */ void blkcache_invalidate(int iftype, int dev); @@ -178,6 +178,9 @@ struct block_cache_stats { */ void blkcache_stats(struct block_cache_stats *stats); +/** blkcache_free() - free all memory allocated to the block cache */ +void blkcache_free(void); + #else static inline int blkcache_read(int iftype, int dev, @@ -193,6 +196,8 @@ static inline void blkcache_fill(int iftype, int dev, static inline void blkcache_invalidate(int iftype, int dev) {} +static inline void blkcache_free(void) {} + #endif #if CONFIG_IS_ENABLED(BLK) diff --git a/test/test-main.c b/test/test-main.c index fe3ef6daad6..867c57f3e7a 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -352,6 +353,8 @@ static int test_post_run(struct unit_test_state *uts, struct unit_test *test) free(uts->of_other); uts->of_other = NULL; + blkcache_free(); + return 0; } From f7a68d228416deeb279457af8d548603abfad004 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:09 -0600 Subject: [PATCH 07/18] test: Drop an unused parameter to ut_run_test_live_flat() The select_name parameter is not used anymore. Drop it. Signed-off-by: Simon Glass --- test/test-main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test-main.c b/test/test-main.c index 867c57f3e7a..ab3b00a3b3f 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -431,12 +431,11 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, * the first call to this function. On exit, @uts->fail_count is * incremented by the number of failures (0, one hopes) * @test: Test to run - * @name: Name of test, possibly skipping a prefix that should not be displayed * Return: 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if * any failed */ static int ut_run_test_live_flat(struct unit_test_state *uts, - struct unit_test *test, const char *name) + struct unit_test *test) { int runs; @@ -536,7 +535,7 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, } old_fail_count = uts->fail_count; for (i = 0; i < uts->runs_per_test; i++) - ret = ut_run_test_live_flat(uts, test, select_name); + ret = ut_run_test_live_flat(uts, test); if (uts->fail_count != old_fail_count) { printf("Test %s failed %d times\n", select_name, uts->fail_count - old_fail_count); From cdd964e3801e524c4d95099351241209ed237771 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:10 -0600 Subject: [PATCH 08/18] test: Tidy up help for ut command Sort this and put the command summary at the top instead of the bottom. Adjust it so that the newlines are at the start of the strings, so that there is not a blank line at the end. Signed-off-by: Simon Glass --- test/cmd_ut.c | 59 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/test/cmd_ut.c b/test/cmd_ut.c index beebd5ce381..8333eaccff2 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -140,59 +140,66 @@ static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) #ifdef CONFIG_SYS_LONGHELP static char ut_help_text[] = - "all - execute all enabled tests\n" + "[-r] [-f] [] - run unit tests\n" + " -r Number of times to run each test\n" + " -f Force 'manual' tests to run as well\n" + " Test suite to run, or all\n" + "\n" + "Suites:" + "\nall - execute all enabled tests" +#ifdef CONFIG_CMD_ADDRMAP + "\naddrmap - very basic test of addrmap command" +#endif #ifdef CONFIG_SANDBOX - "ut bloblist - Test bloblist implementation\n" - "ut compression - Test compressors and bootm decompression\n" + "\nbloblist - bloblist implementation" #endif #ifdef CONFIG_BOOTSTD - "ut bootstd - Test standard boot implementation\n" + "\nbootstd - standard boot implementation" +#endif +#ifdef CONFIG_SANDBOX + "\ncompression - compressors and bootm decompression" #endif #ifdef CONFIG_UT_DM - "ut dm [test-name]\n" + "\ndm - driver model" #endif #ifdef CONFIG_UT_ENV - "ut env [test-name]\n" + "\nenv - environment" #endif #ifdef CONFIG_CMD_FDT - "ut fdt [test-name] - test of the fdt command\n" + "\nfdt - fdt command" #endif #ifdef CONFIG_CONSOLE_TRUETYPE - "ut font [test-name] - test of the font command\n" + "\nut font - font command\n" +#endif +#ifdef CONFIG_CMD_LOADM + "\nloadm - loadm command parameters and loading memory blob" #endif #ifdef CONFIG_UT_LIB - "ut lib [test-name] - test library functions\n" + "\nlib - library functions" #endif #ifdef CONFIG_UT_LOG - "ut log [test-name] - test logging functions\n" + "\nlog - logging functions" #endif - "ut mem [test-name] - test memory-related commands\n" + "\nmem - memory-related commands" #ifdef CONFIG_UT_OPTEE - "ut optee [test-name]\n" + "\noptee - test OP-TEE" #endif #ifdef CONFIG_UT_OVERLAY - "ut overlay [test-name]\n" + "\noverlay - device tree overlays" #endif - "ut print [test-name] - test printing\n" - "ut setexpr [test-name] - test setexpr command\n" + "\nprint - printing things to the console" + "\nsetexpr - setexpr command" #ifdef CONFIG_SANDBOX - "ut str - Basic test of string functions\n" + "\nstr - basic test of string functions" #endif #ifdef CONFIG_UT_TIME - "ut time - Very basic test of time functions\n" + "\ntime - very basic test of time functions" #endif #if defined(CONFIG_UT_UNICODE) && \ !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) - "ut unicode [test-name] - test Unicode functions\n" + "\nunicode - Unicode functions" #endif -#ifdef CONFIG_CMD_ADDRMAP - "ut addrmap - Very basic test of addrmap command\n" -#endif -#ifdef CONFIG_CMD_LOADM - "ut loadm [test-name]- test of parameters and load memory blob\n" -#endif - "All commands accept an optional [-r] flag before [test-name], to\n" - "run each test multiple times ( is in decimal)"; + ; #endif /* CONFIG_SYS_LONGHELP */ U_BOOT_CMD( From 93e2673982e6005a298ca2bd3450ac130105981e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:11 -0600 Subject: [PATCH 09/18] test: doc: Add documentation for ut command Before adding more options, document this command. Signed-off-by: Simon Glass --- doc/usage/cmd/ut.rst | 102 +++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 103 insertions(+) create mode 100644 doc/usage/cmd/ut.rst diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst new file mode 100644 index 00000000000..9f602ea7917 --- /dev/null +++ b/doc/usage/cmd/ut.rst @@ -0,0 +1,102 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +ut command +========== + +Synopis +------- + +:: + + ut [-r] [-f] [ []] + + Number of times to run each test + -f Force 'manual' tests to run as well + Test suite to run, or `all` + Name of single test to run + +Description +----------- + +The ut command runs unit tests written in C. + +Typically the command is run on :ref:`arch/sandbox/sandbox:sandbox` since it +includes a near-complete set of emulators, no code-size limits, many CONFIG +options enabled and runs easily in CI without needing QEMU. It is also possible +to run some tests on real boards. + +For a list of available test suites, type `ut` by itself. + +Each test is normally run once, although those marked with `UT_TESTF_DM` are +run with livetree and flattree where possible. To run a test more than once, +use the `-r` flag. + +Manual tests are normally skipped by this command. Use `-f` to run them. See +See :ref:`develop/tests_writing:mixing python and c` for more information on +manual test. + +Generally all tests in the suite are run. To run just a single test from the +suite, provide the argument. + +See :ref:`develop/tests_writing:writing c tests` for more information on how to +write unit tests. + +Example +------- + +List available unit-test suites:: + + => ut + ut - unit tests + + Usage: + ut [-r] [-f] [] - run unit tests + -r Number of times to run each test + -f Force 'manual' tests to run as well + Test suite to run, or all + + Suites: + all - execute all enabled tests + addrmap - very basic test of addrmap command + bloblist - bloblist implementation + bootstd - standard boot implementation + compression - compressors and bootm decompression + dm - driver model + env - environment + fdt - fdt command + loadm - loadm command parameters and loading memory blob + lib - library functions + log - logging functions + mem - memory-related commands + overlay - device tree overlays + print - printing things to the console + setexpr - setexpr command + str - basic test of string functions + time - very basic test of time functions + unicode - Unicode functions + +Run one of the suites:: + + => ut bloblist + Running 14 bloblist tests + Test: bloblist_test_align: bloblist.c + Test: bloblist_test_bad_blob: bloblist.c + Test: bloblist_test_blob: bloblist.c + Test: bloblist_test_blob_ensure: bloblist.c + Test: bloblist_test_blob_maxsize: bloblist.c + Test: bloblist_test_checksum: bloblist.c + Test: bloblist_test_cmd_info: bloblist.c + Test: bloblist_test_cmd_list: bloblist.c + Test: bloblist_test_grow: bloblist.c + Test: bloblist_test_init: bloblist.c + Test: bloblist_test_reloc: bloblist.c + Test: bloblist_test_resize_fail: bloblist.c + Test: bloblist_test_resize_last: bloblist.c + Test: bloblist_test_shrink: bloblist.c + Failures: 0 + +Run just a single test in a suite:: + + => ut bloblist bloblist_test_grow + Test: bloblist_test_grow: bloblist.c + Failures: 0 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index df50746c349..f3c8fba2ce2 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -74,6 +74,7 @@ Shell commands cmd/tftpput cmd/true cmd/ums + cmd/ut cmd/wdt cmd/xxd From 6580b618306a24b6ae2974318922c40588ab0284 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:12 -0600 Subject: [PATCH 10/18] test: Allow showing basic information about tests Add a 'ut info' command to show the number of suites and tests. This is useful to get a feel for the scale of the tests. Signed-off-by: Simon Glass --- doc/usage/cmd/ut.rst | 6 ++++++ test/cmd_ut.c | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst index 9f602ea7917..11c64a17793 100644 --- a/doc/usage/cmd/ut.rst +++ b/doc/usage/cmd/ut.rst @@ -100,3 +100,9 @@ Run just a single test in a suite:: => ut bloblist bloblist_test_grow Test: bloblist_test_grow: bloblist.c Failures: 0 + +Show information about tests:: + + => ut info + Test suites: 21 + Total tests: 642 diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 8333eaccff2..76e37f35c84 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -14,6 +14,9 @@ static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); + int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]) @@ -45,6 +48,7 @@ int cmd_ut_category(const char *name, const char *prefix, static struct cmd_tbl cmd_ut_sub[] = { U_BOOT_CMD_MKENT(all, CONFIG_SYS_MAXARGS, 1, do_ut_all, "", ""), + U_BOOT_CMD_MKENT(info, 1, 1, do_ut_info, "", ""), #ifdef CONFIG_BOOTSTD U_BOOT_CMD_MKENT(bootstd, CONFIG_SYS_MAXARGS, 1, do_ut_bootstd, "", ""), @@ -119,6 +123,15 @@ static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc, return any_fail; } +static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + printf("Test suites: %d\n", (int)ARRAY_SIZE(cmd_ut_sub)); + printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT()); + + return 0; +} + static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct cmd_tbl *cp; @@ -145,8 +158,9 @@ static char ut_help_text[] = " -f Force 'manual' tests to run as well\n" " Test suite to run, or all\n" "\n" - "Suites:" + "\nOptions for :" "\nall - execute all enabled tests" + "\ninfo - show info about tests" #ifdef CONFIG_CMD_ADDRMAP "\naddrmap - very basic test of addrmap command" #endif From d1b46595700b063faaec3e33f5754642e68b3d8f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:13 -0600 Subject: [PATCH 11/18] test: Add a way to detect a test that breaks another When running unit tests, some may have side effects which cause a subsequent test to break. This can sometimes be seen when using 'ut dm' or similar. Add a new argument which allows a particular (failing) test to be run immediately after a certain number of tests have run. This allows the test causing the failure to be determined. Update the documentation also. Signed-off-by: Simon Glass --- arch/sandbox/cpu/spl.c | 2 +- doc/develop/tests_sandbox.rst | 69 +++++++++++++++++++++++++++++++++++ doc/usage/cmd/ut.rst | 11 +++++- include/test/ut.h | 7 +++- test/cmd_ut.c | 9 ++++- test/test-main.c | 39 +++++++++++++++++--- 6 files changed, 127 insertions(+), 10 deletions(-) diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 0faf34cc00a..09e3d10d6a5 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -132,7 +132,7 @@ void spl_board_init(void) int ret; ret = ut_run_list("spl", NULL, tests, count, - state->select_unittests, 1, false); + state->select_unittests, 1, false, NULL); /* continue execution into U-Boot */ } } diff --git a/doc/develop/tests_sandbox.rst b/doc/develop/tests_sandbox.rst index 8e42a32afb9..bfd3bdb9270 100644 --- a/doc/develop/tests_sandbox.rst +++ b/doc/develop/tests_sandbox.rst @@ -143,6 +143,75 @@ For example:: Test dm_test_rtc_reset failed 3 times +Isolating a test that breaks another +------------------------------------ + +When running unit tests, some may have side effects which cause a subsequent +test to break. This can sometimes be seen when using 'ut dm' or similar. + +You can use the `-I` argument to the `ut` command to isolate this problem. +First use `ut info` to see how many tests there are, then use a binary search to +home in on the problem. Note that you might need to restart U-Boot after each +iteration, so the `-c` argument to U-Boot is useful. + +For example, let's stay that dm_test_host() is failing:: + + => ut dm + ... + Test: dm_test_get_stats: core.c + Test: dm_test_get_stats: core.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xffffcbb0 (-13392) + Test: dm_test_host: host.c (flat tree) + Test failed 1 times + Test: dm_test_host_dup: host.c + Test: dm_test_host_dup: host.c (flat tree) + ... + +You can then tell U-Boot to run the failing test at different points in the +sequence: + + => ut info + Test suites: 21 + Total tests: 645 + +:: + + $ ./u-boot -T -c "ut dm -I300:dm_test_host" + ... + Test: dm_test_pinctrl_single: pinmux.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xfffffdb0 (-592) + Test: dm_test_host: host.c (flat tree) + Test dm_test_host failed 1 times (position 300) + Failures: 4 + +So it happened before position 300. Trying 150 shows it failing, so we try 75:: + + $ ./u-boot -T -c "ut dm -I75:dm_test_host" + ... + Test: dm_test_autoprobe: core.c + Test: dm_test_autoprobe: core.c (flat tree) + Test: dm_test_host: host.c + Test: dm_test_host: host.c (flat tree) + Failures: 0 + +That succeeds, so we try 120, etc. until eventually we can figure out that the +problem first happens at position 82. + + $ ./u-boot -T -c "ut dm -I82:dm_test_host" + ... + Test: dm_test_blk_flags: blk.c + Test: dm_test_blk_flags: blk.c (flat tree) + Test: dm_test_host: host.c + test/dm/host.c:71, dm_test_host(): 0 == ut_check_delta(mem_start): Expected 0x0 (0), got 0xffffc960 (-13984) + Test: dm_test_host: host.c (flat tree) + Test dm_test_host failed 1 times (position 82) + Failures: 1 + +From this we can deduce that `dm_test_blk_flags()` causes the problem with +`dm_test_host()`. + Running sandbox_spl tests directly ---------------------------------- diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst index 11c64a17793..a3039634f2e 100644 --- a/doc/usage/cmd/ut.rst +++ b/doc/usage/cmd/ut.rst @@ -8,10 +8,12 @@ Synopis :: - ut [-r] [-f] [ []] + ut [-r] [-f] [-I:] [ []] Number of times to run each test -f Force 'manual' tests to run as well + Run after other tests have run + Name of the 'one' test to run Test suite to run, or `all` Name of single test to run @@ -35,6 +37,13 @@ Manual tests are normally skipped by this command. Use `-f` to run them. See See :ref:`develop/tests_writing:mixing python and c` for more information on manual test. +When running unit tests, some may have side effects which cause a subsequent +test to break. This can sometimes be seen when using 'ut dm' or similar. To +fix this, select the 'one' test which breaks. Then tell the 'ut' command to +run this one test after a certain number of other tests have run. Using a +binary search method with `-I` you can quickly figure one which test is causing +the problem. + Generally all tests in the suite are run. To run just a single test from the suite, provide the argument. diff --git a/include/test/ut.h b/include/test/ut.h index e0e618b58c2..4d00b4eeca1 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -410,10 +410,15 @@ void test_set_state(struct unit_test_state *uts); * then all tests are run * @runs_per_test: Number of times to run each test (typically 1) * @force_run: Run tests that are marked as manual-only (UT_TESTF_MANUAL) + * @test_insert: String describing a test to run after n other tests run, in the + * format n:name where n is the number of tests to run before this one and + * name is the name of the test to run. This is used to find which test causes + * another test to fail. If the one test fails, testing stops immediately. + * Pass NULL to disable this * Return: 0 if all tests passed, -1 if any failed */ int ut_run_list(const char *name, const char *prefix, struct unit_test *tests, int count, const char *select_name, int runs_per_test, - bool force_run); + bool force_run, const char *test_insert); #endif diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 76e37f35c84..2736582f11c 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -21,6 +21,7 @@ int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]) { + const char *test_insert = NULL; int runs_per_text = 1; bool force_run = false; int ret; @@ -35,13 +36,17 @@ int cmd_ut_category(const char *name, const char *prefix, case 'f': force_run = true; break; + case 'I': + test_insert = str + 2; + break; } argv++; - argc++; + argc--; } ret = ut_run_list(name, prefix, tests, n_ents, - argc > 1 ? argv[1] : NULL, runs_per_text, force_run); + argc > 1 ? argv[1] : NULL, runs_per_text, force_run, + test_insert); return ret ? CMD_RET_FAILURE : 0; } diff --git a/test/test-main.c b/test/test-main.c index ab3b00a3b3f..5931e94a915 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -498,12 +498,29 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, */ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, struct unit_test *tests, int count, - const char *select_name) + const char *select_name, const char *test_insert) { - struct unit_test *test; + struct unit_test *test, *one; int found = 0; + int pos = 0; + int upto; - for (test = tests; test < tests + count; test++) { + one = NULL; + if (test_insert) { + char *p; + + pos = dectoul(test_insert, NULL); + p = strchr(test_insert, ':'); + if (p) + p++; + + for (test = tests; test < tests + count; test++) { + if (!strcmp(p, test->name)) + one = test; + } + } + + for (upto = 0, test = tests; test < tests + count; test++, upto++) { const char *test_name = test->name; int ret, i, old_fail_count; @@ -534,6 +551,17 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, } } old_fail_count = uts->fail_count; + + if (one && upto == pos) { + ret = ut_run_test_live_flat(uts, one); + if (uts->fail_count != old_fail_count) { + printf("Test %s failed %d times (position %d)\n", + one->name, + uts->fail_count - old_fail_count, pos); + } + return -EBADF; + } + for (i = 0; i < uts->runs_per_test; i++) ret = ut_run_test_live_flat(uts, test); if (uts->fail_count != old_fail_count) { @@ -554,7 +582,7 @@ static int ut_run_tests(struct unit_test_state *uts, const char *prefix, int ut_run_list(const char *category, const char *prefix, struct unit_test *tests, int count, const char *select_name, - int runs_per_test, bool force_run) + int runs_per_test, bool force_run, const char *test_insert) { struct unit_test_state uts = { .fail_count = 0 }; bool has_dm_tests = false; @@ -589,7 +617,8 @@ int ut_run_list(const char *category, const char *prefix, memcpy(uts.fdt_copy, gd->fdt_blob, uts.fdt_size); } uts.force_run = force_run; - ret = ut_run_tests(&uts, prefix, tests, count, select_name); + ret = ut_run_tests(&uts, prefix, tests, count, select_name, + test_insert); /* Best efforts only...ignore errors */ if (has_dm_tests) From 41e751091d7cb1a71ac13ab037e0fcf4fcee67e3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:14 -0600 Subject: [PATCH 12/18] dm: blk: Tidy up obtaining a block device from its parent This function now finds its block-device child by looking for a child device of the correct uclass (UCLASS_BLK). It cannot produce a device of any other type, so drop the superfluous check. Provide a version which does not probe the device, since that is often needed when setting up the device's platdata. Also fix up the function's comment. Signed-off-by: Simon Glass --- drivers/block/blk-uclass.c | 26 +++++++++++++++----------- include/blk.h | 28 +++++++++++++++++++++++++++- test/dm/blk.c | 2 +- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index e82789f4a38..38800a31159 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -508,24 +508,28 @@ ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt) return blk_erase(desc->bdev, start, blkcnt); } -int blk_get_from_parent(struct udevice *parent, struct udevice **devp) +int blk_find_from_parent(struct udevice *parent, struct udevice **devp) { struct udevice *dev; - enum uclass_id id; - int ret; - device_find_first_child(parent, &dev); - if (!dev) { + if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) { debug("%s: No block device found for parent '%s'\n", __func__, parent->name); return -ENODEV; } - id = device_get_uclass_id(dev); - if (id != UCLASS_BLK) { - debug("%s: Incorrect uclass %s for block device '%s'\n", - __func__, uclass_get_name(id), dev->name); - return -ENOTBLK; - } + *devp = dev; + + return 0; +} + +int blk_get_from_parent(struct udevice *parent, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + ret = blk_find_from_parent(parent, &dev); + if (ret) + return ret; ret = device_probe(dev); if (ret) return ret; diff --git a/include/blk.h b/include/blk.h index c8cbb64c7f8..1db203c1bab 100644 --- a/include/blk.h +++ b/include/blk.h @@ -453,10 +453,36 @@ int blk_next_free_devnum(enum uclass_id uclass_id); */ int blk_select_hwpart(struct udevice *dev, int hwpart); +/** + * blk_find_from_parent() - find a block device by looking up its parent + * + * All block devices have a parent 'media' device which provides the block + * driver for the block device, ensuring that access to the underlying medium + * is available. + * + * The block device is not activated by this function. See + * blk_get_from_parent() for that. + * + * @parent: Media device + * @devp: Returns the associated block device, if any + * Returns: 0 if OK, -ENODEV if @parent is not a media device and has no + * UCLASS_BLK child + */ +int blk_find_from_parent(struct udevice *parent, struct udevice **devp); + /** * blk_get_from_parent() - obtain a block device by looking up its parent * - * All devices with + * All block devices have a parent 'media' device which provides the block + * driver for the block device, ensuring that access to the underlying medium + * is available. + * + * The block device is probed and ready for use. + * + * @parent: Media device + * @devp: Returns the associated block device, if any + * Returns: 0 if OK, -ENODEV if @parent is not a media device and has no + * UCLASS_BLK child */ int blk_get_from_parent(struct udevice *parent, struct udevice **devp); diff --git a/test/dm/blk.c b/test/dm/blk.c index 35bd5318f0b..6f0cb98c861 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -160,7 +160,7 @@ static int dm_test_blk_get_from_parent(struct unit_test_state *uts) ut_assertok(blk_get_from_parent(dev, &blk)); ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev)); - ut_asserteq(-ENOTBLK, blk_get_from_parent(dev, &blk)); + ut_asserteq(-ENODEV, blk_get_from_parent(dev, &blk)); ut_assertok(uclass_get_device(UCLASS_GPIO, 0, &dev)); ut_asserteq(-ENODEV, blk_get_from_parent(dev, &blk)); From 9bd1aa8af2ed3efde28250987806aaeb12837c66 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:15 -0600 Subject: [PATCH 13/18] dm: sandbox: Create a new HOST uclass Sandbox supports block devices which can access files on the host machine. At present there is no uclass for this. The devices are attached to the root devic. The block-device type is therefore set to UCLASS_ROOT which is confusing. Block devices should be attached to a 'media' device instead, something which handles access to the actual media and provides the block driver for the block device. Create a new uclass to handle this. It supports two operations, to attach and detach a file on the host machine. For now this is not fully plumbed in. Signed-off-by: Simon Glass --- drivers/block/Makefile | 2 +- drivers/block/host-uclass.c | 176 ++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/sandbox_host.h | 125 +++++++++++++++++++++++++ 4 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 drivers/block/host-uclass.c create mode 100644 include/sandbox_host.h diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 19d9317c825..7f259120456 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -12,7 +12,7 @@ endif ifndef CONFIG_SPL_BUILD obj-$(CONFIG_IDE) += ide.o endif -obj-$(CONFIG_SANDBOX) += sandbox.o +obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c new file mode 100644 index 00000000000..6460d968c23 --- /dev/null +++ b/drivers/block/host-uclass.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass for sandbox host interface, used to access files on the host which + * contain partitions and filesystem + * + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#define LOG_CATEGORY UCLASS_HOST + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * struct host_priv - information kept by the host uclass + * + * @cur_dev: Currently selected host device, or NULL if none + */ +struct host_priv { + struct udevice *cur_dev; +}; + +int host_create_device(const char *label, bool removable, struct udevice **devp) +{ + char dev_name[30], *str, *label_new; + struct host_sb_plat *plat; + struct udevice *dev, *blk; + int ret; + + /* unbind any existing device with this label */ + dev = host_find_by_label(label); + if (dev) { + ret = host_detach_file(dev); + if (ret) + return log_msg_ret("det", ret); + + ret = device_unbind(dev); + if (ret) + return log_msg_ret("unb", ret); + } + + snprintf(dev_name, sizeof(dev_name), "host-%s", label); + str = strdup(dev_name); + if (!str) + return -ENOMEM; + + label_new = strdup(label); + if (!label_new) { + ret = -ENOMEM; + goto no_label; + } + + ret = device_bind_driver(gd->dm_root, "host_sb_drv", str, &dev); + if (ret) + goto no_dev; + device_set_name_alloced(dev); + + if (!blk_find_from_parent(dev, &blk)) { + struct blk_desc *desc = dev_get_uclass_plat(blk); + + desc->removable = removable; + } + + plat = dev_get_plat(dev); + plat->label = label_new; + *devp = dev; + + return 0; + +no_dev: + free(label_new); +no_label: + free(str); + + return ret; +} + +int host_attach_file(struct udevice *dev, const char *filename) +{ + struct host_ops *ops = host_get_ops(dev); + + if (!ops->attach_file) + return -ENOSYS; + + return ops->attach_file(dev, filename); +} + +int host_create_attach_file(const char *label, const char *filename, + bool removable, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + ret = host_create_device(label, removable, &dev); + if (ret) + return log_msg_ret("cre", ret); + + ret = host_attach_file(dev, filename); + if (ret) { + device_unbind(dev); + return log_msg_ret("att", ret); + } + *devp = dev; + + return 0; +} + +int host_detach_file(struct udevice *dev) +{ + struct host_ops *ops = host_get_ops(dev); + + if (!ops->detach_file) + return -ENOSYS; + + if (dev == host_get_cur_dev()) + host_set_cur_dev(NULL); + + return ops->detach_file(dev); +} + +struct udevice *host_find_by_label(const char *label) +{ + struct udevice *dev; + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_HOST, dev, uc) { + struct host_sb_plat *plat = dev_get_plat(dev); + + if (plat->label && !strcmp(label, plat->label)) + return dev; + } + + return NULL; +} + +struct udevice *host_get_cur_dev(void) +{ + struct uclass *uc = uclass_find(UCLASS_HOST); + + if (uc) { + struct host_priv *priv = uclass_get_priv(uc); + + return priv->cur_dev; + } + + return NULL; +} + +void host_set_cur_dev(struct udevice *dev) +{ + struct uclass *uc = uclass_find(UCLASS_HOST); + + if (uc) { + struct host_priv *priv = uclass_get_priv(uc); + + priv->cur_dev = dev; + } +} + +UCLASS_DRIVER(host) = { + .id = UCLASS_HOST, + .name = "host", +#if CONFIG_IS_ENABLED(OF_REAL) + .post_bind = dm_scan_fdt_dev, +#endif + .priv_auto = sizeof(struct host_priv), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 1f3cf8c0853..376f741cc2b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -63,6 +63,7 @@ enum uclass_id { UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */ + UCLASS_HOST, /* Sandbox host device */ UCLASS_I2C, /* I2C bus */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_I2C_GENERIC, /* Generic I2C device */ diff --git a/include/sandbox_host.h b/include/sandbox_host.h new file mode 100644 index 00000000000..2e37ede2354 --- /dev/null +++ b/include/sandbox_host.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * sandbox host uclass + * + * Copyright 2022 Google LLC + */ + +#ifndef __SANDBOX_HOST__ +#define __SANDBOX_HOST__ + +/** + * 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) + */ +struct host_sb_plat { + char *label; + char *filename; + int fd; +}; + +/** + * struct host_ops - operations supported by UCLASS_HOST + * + * @attach_file: Attach a new file to a device + * @detach_file: Detach a file from a device + */ +struct host_ops { + /* + * attach_file() - Attach a new file to the device + * + * @dev: Device to update + * @filename: Name of the file, e.g. "/path/to/disk.img" + * Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on + * other error + */ + int (*attach_file)(struct udevice *dev, const char *filename); + + /** + * detach_file() - Detach a file from the device + * + * @dev: Device to detach from + * Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other + * error + */ + int (*detach_file)(struct udevice *dev); +}; + +#define host_get_ops(dev) ((struct host_ops *)(dev)->driver->ops) + +/** + * host_attach_file() - Attach a new file to the device + * + * @dev: Device to update + * @filename: Name of the file, e.g. "/path/to/disk.img" + * Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on + * other error + */ +int host_attach_file(struct udevice *dev, const char *filename); + +/** + * host_detach_file() - Detach a file from the device + * + * @dev: Device to detach from + * Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other + * error + */ +int host_detach_file(struct udevice *dev); + +/** + * host_create_device() - Create a new host device + * + * Any existing device with the same label is removed and unbound first + * + * @label: Label of the attachment, e.g. "test1" + * @removable: true if the device should be marked as removable, false + * if it is fixed. See enum blk_flag_t + * @devp: Returns the device created, on success + * Returns: 0 if OK, -ve on error + */ +int host_create_device(const char *label, bool removable, + struct udevice **devp); + +/** + * host_create_attach_file() - Create a new host device attached to a file + * + * @label: Label of the attachment, e.g. "test1" + * @filename: Name of the file, e.g. "/path/to/disk.img" + * @removable: true if the device should be marked as removable, false + * if it is fixed. See enum blk_flag_t + * @devp: Returns the device created, on success + * Returns: 0 if OK, -ve on error + */ +int host_create_attach_file(const char *label, const char *filename, + bool removable, struct udevice **devp); + +/** + * host_find_by_label() - Find a host by label + * + * Searches all host devices to find one with the given label + * + * @label: Label to find + * Returns: associated device, or NULL if not found + */ +struct udevice *host_find_by_label(const char *label); + +/** + * host_get_cur_dev() - Get the current device + * + * Returns current device, or NULL if none + */ +struct udevice *host_get_cur_dev(void); + +/** + * host_set_cur_dev() - Set the current device + * + * Sets the current device, or clears it if @dev is NULL + * + * @dev: Device to set as the current one + */ +void host_set_cur_dev(struct udevice *dev); + +#endif /* __SANDBOX_HOST__ */ From 10aae1145c910857053343a2f3e841b38eb77bd0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:16 -0600 Subject: [PATCH 14/18] dm: sandbox: Create a block driver Create a block driver for the new HOST uclass. This handles attaching and detaching host files. For now the uclass is not used but this will be plumbed in with future patches. Signed-off-by: Simon Glass --- drivers/block/Makefile | 2 +- drivers/block/host_dev.c | 142 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 drivers/block/host_dev.c diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 7f259120456..f12447d78d8 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -12,7 +12,7 @@ endif ifndef CONFIG_SPL_BUILD obj-$(CONFIG_IDE) += ide.o endif -obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o diff --git a/drivers/block/host_dev.c b/drivers/block/host_dev.c new file mode 100644 index 00000000000..5885fc358a5 --- /dev/null +++ b/drivers/block/host_dev.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for sandbox host interface, used to access files on the host which + * contain partitions and filesystem + * + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#define LOG_CATEGORY UCLASS_HOST + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int host_sb_attach_file(struct udevice *dev, const char *filename) +{ + struct host_sb_plat *plat = dev_get_plat(dev); + struct blk_desc *desc; + struct udevice *blk; + int ret, fd, size; + char *fname; + + if (!filename) + return -EINVAL; + + if (plat->fd) + return log_msg_ret("fd", -EEXIST); + + /* Sanity check that host_sb_bind() has been used */ + ret = blk_find_from_parent(dev, &blk); + if (ret) + return ret; + + fd = os_open(filename, OS_O_RDWR); + if (fd == -1) { + printf("Failed to access host backing file '%s', trying read-only\n", + filename); + fd = os_open(filename, OS_O_RDONLY); + if (fd == -1) { + printf("- still failed\n"); + return log_msg_ret("open", -ENOENT); + } + } + + fname = strdup(filename); + if (!fname) { + ret = -ENOMEM; + goto err_fname; + } + + size = os_filesize(fd); + desc = dev_get_uclass_plat(blk); + desc->lba = size / desc->blksz; + + /* write this in last, when nothing can go wrong */ + plat = dev_get_plat(dev); + plat->fd = fd; + plat->filename = fname; + + return 0; + +err_fname: + os_close(fd); + + return ret; +} + +int host_sb_detach_file(struct udevice *dev) +{ + struct host_sb_plat *plat = dev_get_plat(dev); + int ret; + + if (!plat->fd) + return log_msg_ret("fd", -ENOENT); + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return log_msg_ret("rem", ret); + + /* Unbind all children */ + ret = device_chld_unbind(dev, NULL); + if (ret) + return log_msg_ret("unb", ret); + + os_close(plat->fd); + plat->fd = 0; + free(plat->filename); + free(plat->label); + + return 0; +} + +static int host_sb_bind(struct udevice *dev) +{ + struct udevice *blk, *bdev; + struct blk_desc *desc; + int ret; + + ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST, + dev_seq(dev), 512, 0, &blk); + if (ret) + return log_msg_ret("blk", ret); + + desc = dev_get_uclass_plat(blk); + snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot"); + snprintf(desc->product, BLK_PRD_SIZE, "hostfile"); + snprintf(desc->revision, BLK_REV_SIZE, "1.0"); + + if (CONFIG_IS_ENABLED(BOOTSTD)) { + ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev); + if (ret) + return log_msg_ret("bd", ret); + } + + return 0; +} + +struct host_ops host_sb_ops = { + .attach_file = host_sb_attach_file, + .detach_file = host_sb_detach_file, +}; + +static const struct udevice_id host_ids[] = { + { .compatible = "sandbox,host" }, + { } +}; + +U_BOOT_DRIVER(host_sb_drv) = { + .name = "host_sb_drv", + .id = UCLASS_HOST, + .of_match = host_ids, + .ops = &host_sb_ops, + .bind = host_sb_bind, + .plat_auto = sizeof(struct host_sb_plat), +}; From 952018117ab4daff5fb4500d5ce0143678473ca4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 29 Oct 2022 19:47:17 -0600 Subject: [PATCH 15/18] dm: sandbox: Switch over to using the new host uclass Update the sandbox implementation to use UCLASS_HOST and adjust all the pieces to continue to work: - Update the 'host' command to use the new API - Replace various uses of UCLASS_ROOT with UCLASS_HOST - Disable test_eficonfig since it doesn't work (this should have a unit test to allow this to be debugged) - Update the blk test to use the new API - Drop the old header file Unfortunately it does not seem to be possible to split this change up further. Signed-off-by: Simon Glass --- arch/sandbox/dts/sandbox.dts | 4 - cmd/host.c | 204 ++++++++++++------ disk/part.c | 4 +- drivers/block/blk-uclass.c | 2 +- drivers/block/sandbox.c | 134 ++---------- include/sandboxblockdev.h | 28 --- lib/efi_loader/efi_device_path.c | 5 +- lib/efi_loader/efi_disk.c | 2 +- test/dm/blk.c | 47 ++-- .../py/tests/test_eficonfig/test_eficonfig.py | 3 + 10 files changed, 184 insertions(+), 249 deletions(-) delete mode 100644 include/sandboxblockdev.h diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 1b60914a01c..2051207f0ba 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -68,10 +68,6 @@ reg = <0x10002000 0x1000>; }; - host-fs { - compatible = "sandbox,bootdev-host"; - }; - i2c_0: i2c@0 { #address-cells = <1>; #size-cells = <0>; diff --git a/cmd/host.c b/cmd/host.c index f09ac8d4396..fb1cb1fdd1a 100644 --- a/cmd/host.c +++ b/cmd/host.c @@ -8,12 +8,12 @@ #include #include #include -#include +#include #include +#include +#include #include -static int host_curr_device = -1; - static int do_host_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -42,10 +42,10 @@ static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { bool removable = false; - const char *dev_str; + struct udevice *dev; + const char *label; char *file; - char *ep; - int dev; + int ret; /* Skip 'bind' */ argc--; @@ -61,97 +61,158 @@ static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc, if (argc > 2) return CMD_RET_USAGE; - dev_str = argv[0]; - dev = hextoul(dev_str, &ep); - if (*ep) { - printf("** Bad device specification %s **\n", dev_str); - return CMD_RET_USAGE; - } + label = argv[0]; file = argc > 1 ? argv[1] : NULL; - return !!host_dev_bind(dev, file, removable); + ret = host_create_attach_file(label, file, removable, &dev); + if (ret) { + printf("Cannot create device / bind file\n"); + return CMD_RET_FAILURE; + } + + return 0; +} + +/** + * parse_host_label() - Parse a device label or sequence number + * + * This shows an error if it returns NULL + * + * @label: String containing the label or sequence number + * Returns: Associated device, or NULL if not found + */ +static struct udevice *parse_host_label(const char *label) +{ + struct udevice *dev; + + dev = host_find_by_label(label); + if (!dev) { + int devnum; + char *ep; + + devnum = hextoul(label, &ep); + if (*ep || + uclass_find_device_by_seq(UCLASS_HOST, devnum, &dev)) { + printf("No such device '%s'\n", label); + return NULL; + } + } + + return dev; +} + +static int do_host_unbind(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *label; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + label = argv[1]; + dev = parse_host_label(label); + if (!dev) + return CMD_RET_FAILURE; + + ret = host_detach_file(dev); + if (ret) { + printf("Cannot detach file (err=%d)\n", ret); + return CMD_RET_FAILURE; + } + + ret = device_unbind(dev); + if (ret) { + printf("Cannot attach file\n"); + ret = device_unbind(dev); + if (ret) + printf("Cannot unbind device '%s'\n", dev->name); + return CMD_RET_FAILURE; + } + + return 0; +} + +static void show_host_dev(struct udevice *dev) +{ + struct host_sb_plat *plat = dev_get_plat(dev); + struct blk_desc *desc; + struct udevice *blk; + int ret; + + printf("%3d ", dev_seq(dev)); + if (!plat->fd) { + printf("Not bound to a backing file\n"); + return; + } + ret = blk_get_from_parent(dev, &blk); + if (ret) /* cannot happen */ + return; + + desc = dev_get_uclass_plat(blk); + printf("%12lu %-15s %s\n", (unsigned long)desc->lba, plat->label, + plat->filename); } static int do_host_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - if (argc < 1 || argc > 2) + struct udevice *dev; + + if (argc < 1) return CMD_RET_USAGE; - int min_dev = 0; - int max_dev = SANDBOX_HOST_MAX_DEVICES - 1; + + dev = NULL; if (argc >= 2) { - char *ep; - char *dev_str = argv[1]; - int dev = hextoul(dev_str, &ep); - if (*ep) { - printf("** Bad device specification %s **\n", dev_str); - return CMD_RET_USAGE; - } - min_dev = dev; - max_dev = dev; + dev = parse_host_label(argv[1]); + if (!dev) + return CMD_RET_FAILURE; } - int dev; - printf("%3s %12s %s\n", "dev", "blocks", "path"); - for (dev = min_dev; dev <= max_dev; dev++) { - struct blk_desc *blk_dev; - int ret; - printf("%3d ", dev); - ret = host_get_dev_err(dev, &blk_dev); - if (ret) { - if (ret == -ENOENT) - puts("Not bound to a backing file\n"); - else if (ret == -ENODEV) - puts("Invalid host device number\n"); + printf("%3s %12s %-15s %s\n", "dev", "blocks", "label", "path"); + if (dev) { + show_host_dev(dev); + } else { + struct uclass *uc; - continue; - } - struct host_block_dev *host_dev; - - host_dev = dev_get_plat(blk_dev->bdev); - printf("%12lu %s\n", (unsigned long)blk_dev->lba, - host_dev->filename); + uclass_id_foreach_dev(UCLASS_HOST, dev, uc) + show_host_dev(dev); } + return 0; } static int do_host_dev(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - int dev; - char *ep; - struct blk_desc *blk_dev; - int ret; + struct udevice *dev; + const char *label; if (argc < 1 || argc > 3) return CMD_RET_USAGE; if (argc == 1) { - if (host_curr_device < 0) { + struct host_sb_plat *plat; + + dev = host_get_cur_dev(); + if (!dev) { printf("No current host device\n"); - return 1; + return CMD_RET_FAILURE; } - printf("Current host device %d\n", host_curr_device); + plat = dev_get_plat(dev); + printf("Current host device: %d: %s\n", dev_seq(dev), + plat->label); return 0; } - dev = hextoul(argv[1], &ep); - if (*ep) { - printf("** Bad device specification %s **\n", argv[2]); - return CMD_RET_USAGE; - } + label = argv[1]; + dev = parse_host_label(argv[1]); + if (!dev) + return CMD_RET_FAILURE; - ret = host_get_dev_err(dev, &blk_dev); - if (ret) { - if (ret == -ENOENT) - puts("Not bound to a backing file\n"); - else if (ret == -ENODEV) - puts("Invalid host device number\n"); + host_set_cur_dev(dev); - return 1; - } - - host_curr_device = dev; return 0; } @@ -161,6 +222,7 @@ static struct cmd_tbl cmd_host_sub[] = { U_BOOT_CMD_MKENT(save, 6, 0, do_host_save, "", ""), U_BOOT_CMD_MKENT(size, 3, 0, do_host_size, "", ""), U_BOOT_CMD_MKENT(bind, 4, 0, do_host_bind, "", ""), + U_BOOT_CMD_MKENT(unbind, 4, 0, do_host_unbind, "", ""), U_BOOT_CMD_MKENT(info, 3, 0, do_host_info, "", ""), U_BOOT_CMD_MKENT(dev, 0, 1, do_host_dev, "", ""), }; @@ -174,8 +236,7 @@ static int do_host(struct cmd_tbl *cmdtp, int flag, int argc, argc--; argv++; - c = find_cmd_tbl(argv[0], cmd_host_sub, - ARRAY_SIZE(cmd_host_sub)); + c = find_cmd_tbl(argv[0], cmd_host_sub, ARRAY_SIZE(cmd_host_sub)); if (c) return c->cmd(cmdtp, flag, argc, argv); @@ -192,10 +253,11 @@ U_BOOT_CMD( "host save hostfs - [] - " "save a file to host\n" "host size hostfs - - determine size of file on host\n" - "host bind [-r] [] - bind \"host\" device to file\n" + "host bind [-r]