nman external-symbol improvements
Driver model memory-usage reporting patman test-reporting improvements Add bloblist design goals -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmK7BHwRHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIrealpwgAlCLCdEiSncV0t+Q9zvdtAQStvZdjD6CW VhpCS38pWUA0ckKYq/gmmlE2nW6i7pb4RdiOkpOhKdwFQI7SwbF2GdcU2yv08PMm qWHTRDaTm0SiGXUU462+A1Bj/aXPH86uEE9bCYu1FYtRrEtNf6aAeWF3pqNJv4fy CFB9OYyAfMEdywCtW2dCjS4y1FiI95Y2Jvg7lPGLVayHDyuavLSMKC8QEsVS4mR0 91nNLhs6agko/H2i0QXle1lLjkvTIH3VR6dn/CMVjD+goJdDCk7rltHRXHejGun4 n+a1W3EVv2sSQLwQJ0Kw5e2eBKdlM6Lpzhc0b0iJ2jKzBZeLXS+qBg== =2LZO -----END PGP SIGNATURE----- Merge tag 'dm-pull-28jun22' of https://source.denx.de/u-boot/custodians/u-boot-dm into next nman external-symbol improvements Driver model memory-usage reporting patman test-reporting improvements Add bloblist design goals
This commit is contained in:
		
						commit
						9ff4ce8abc
					
				| 
						 | 
				
			
			@ -23,7 +23,7 @@ SECTIONS
 | 
			
		|||
{
 | 
			
		||||
	.text : {
 | 
			
		||||
		. = ALIGN(8);
 | 
			
		||||
		*(.__image_copy_start)
 | 
			
		||||
		__image_copy_start = .;
 | 
			
		||||
		CPUDIR/start.o (.text*)
 | 
			
		||||
		*(.text*)
 | 
			
		||||
	} >.sram
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,11 @@ config SANDBOX64
 | 
			
		|||
 | 
			
		||||
config SANDBOX_RAM_SIZE_MB
 | 
			
		||||
	int "RAM size in MiB"
 | 
			
		||||
	default 128
 | 
			
		||||
	default 256
 | 
			
		||||
	range 64 4095 if !SANDBOX64
 | 
			
		||||
	range 64 268435456 if SANDBOX64
 | 
			
		||||
	help
 | 
			
		||||
	  Memory size of the sandbox in MiB. The default value is 128 MiB.
 | 
			
		||||
	  Memory size of the sandbox in MiB. The default value is 256 MiB.
 | 
			
		||||
	  The minimum value is 64 MiB. The maximum value is 4095 MiB for the
 | 
			
		||||
	  32bit sandbox.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -331,27 +331,27 @@ void *board_fdt_blob_setup(int *ret)
 | 
			
		|||
		err = setup_auto_tree(blob);
 | 
			
		||||
		if (!err)
 | 
			
		||||
			goto done;
 | 
			
		||||
		printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
 | 
			
		||||
		os_printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
 | 
			
		||||
		*ret = -EINVAL;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os_get_filesize(fname, &size);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		printf("Failed to find FDT file '%s'\n", fname);
 | 
			
		||||
		os_printf("Failed to find FDT file '%s'\n", fname);
 | 
			
		||||
		*ret = err;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	fd = os_open(fname, OS_O_RDONLY);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		printf("Failed to open FDT file '%s'\n", fname);
 | 
			
		||||
		os_printf("Failed to open FDT file '%s'\n", fname);
 | 
			
		||||
		*ret = -EACCES;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (os_read(fd, blob, size) != size) {
 | 
			
		||||
		os_close(fd);
 | 
			
		||||
		printf("Failed to read FDT file '%s'\n", fname);
 | 
			
		||||
		os_printf("Failed to read FDT file '%s'\n", fname);
 | 
			
		||||
		*ret =  -EIO;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@
 | 
			
		|||
#include <getopt.h>
 | 
			
		||||
#include <setjmp.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +55,18 @@ ssize_t os_write(int fd, const void *buf, size_t count)
 | 
			
		|||
	return write(fd, buf, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int os_printf(const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list args;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	va_start(args, fmt);
 | 
			
		||||
	i = vfprintf(stdout, fmt, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
off_t os_lseek(int fd, off_t offset, int whence)
 | 
			
		||||
{
 | 
			
		||||
	if (whence == OS_SEEK_SET)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										72
									
								
								cmd/dm.c
								
								
								
								
							
							
						
						
									
										72
									
								
								cmd/dm.c
								
								
								
								
							| 
						 | 
				
			
			@ -8,20 +8,13 @@
 | 
			
		|||
 | 
			
		||||
#include <common.h>
 | 
			
		||||
#include <command.h>
 | 
			
		||||
#include <dm/root.h>
 | 
			
		||||
#include <dm/util.h>
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_all(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
			  char *const argv[])
 | 
			
		||||
static int do_dm_dump_driver_compat(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
				    char * const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_all();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_uclass(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
			     char *const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_uclass();
 | 
			
		||||
	dm_dump_driver_compat();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -42,37 +35,68 @@ static int do_dm_dump_drivers(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_driver_compat(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
				    char * const argv[])
 | 
			
		||||
#if CONFIG_IS_ENABLED(DM_STATS)
 | 
			
		||||
static int do_dm_dump_mem(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
			  char *const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_driver_compat();
 | 
			
		||||
	struct dm_stats mem;
 | 
			
		||||
 | 
			
		||||
	dm_get_mem(&mem);
 | 
			
		||||
	dm_dump_mem(&mem);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* DM_STATS */
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_static_driver_info(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
					 char * const argv[])
 | 
			
		||||
static int do_dm_dump_static_driver_info(struct cmd_tbl *cmdtp, int flag,
 | 
			
		||||
					 int argc, char * const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_static_driver_info();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_tree(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
			   char *const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_tree();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_dm_dump_uclass(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
			
		||||
			     char *const argv[])
 | 
			
		||||
{
 | 
			
		||||
	dm_dump_uclass();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(DM_STATS)
 | 
			
		||||
#define DM_MEM_HELP	"dm mem           Provide a summary of memory usage\n"
 | 
			
		||||
#define DM_MEM		U_BOOT_SUBCMD_MKENT(mem, 1, 1, do_dm_dump_mem),
 | 
			
		||||
#else
 | 
			
		||||
#define DM_MEM_HELP
 | 
			
		||||
#define DM_MEM
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(SYS_LONGHELP)
 | 
			
		||||
static char dm_help_text[] =
 | 
			
		||||
	"tree          Dump driver model tree ('*' = activated)\n"
 | 
			
		||||
	"dm uclass        Dump list of instances for each uclass\n"
 | 
			
		||||
	"compat        Dump list of drivers with compatibility strings\n"
 | 
			
		||||
	"dm devres        Dump list of device resources for each device\n"
 | 
			
		||||
	"dm drivers       Dump list of drivers with uclass and instances\n"
 | 
			
		||||
	"dm compat        Dump list of drivers with compatibility strings\n"
 | 
			
		||||
	"dm static        Dump list of drivers with static platform data"
 | 
			
		||||
	DM_MEM_HELP
 | 
			
		||||
	"dm static        Dump list of drivers with static platform data\n"
 | 
			
		||||
	"dn tree          Dump tree of driver model devices ('*' = activated)\n"
 | 
			
		||||
	"dm uclass        Dump list of instances for each uclass"
 | 
			
		||||
	;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
U_BOOT_CMD_WITH_SUBCMDS(dm, "Driver model low level access", dm_help_text,
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(tree, 1, 1, do_dm_dump_all),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(uclass, 1, 1, do_dm_dump_uclass),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(compat, 1, 1, do_dm_dump_driver_compat),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(devres, 1, 1, do_dm_dump_devres),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(drivers, 1, 1, do_dm_dump_drivers),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(compat, 1, 1, do_dm_dump_driver_compat),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(static, 1, 1, do_dm_dump_static_driver_info));
 | 
			
		||||
	DM_MEM
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(static, 1, 1, do_dm_dump_static_driver_info),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(tree, 1, 1, do_dm_dump_tree),
 | 
			
		||||
	U_BOOT_SUBCMD_MKENT(uclass, 1, 1, do_dm_dump_uclass));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -191,12 +191,25 @@ config SPL_BINMAN_SYMBOLS
 | 
			
		|||
	depends on SPL_FRAMEWORK && BINMAN
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in SPL which refer to U-Boot, enabling SPL
 | 
			
		||||
	  to obtain the location of U-Boot simply by calling spl_get_image_pos()
 | 
			
		||||
	  and spl_get_image_size().
 | 
			
		||||
	  This enables use of symbols in SPL which refer to other entries in
 | 
			
		||||
	  the same binman image as the SPL. These can be declared with the
 | 
			
		||||
	  binman_sym_declare(type, entry, prop) macro and accessed by the
 | 
			
		||||
	  binman_sym(type, entry, prop) macro defined in binman_sym.h.
 | 
			
		||||
 | 
			
		||||
	  For this to work, you must have a U-Boot image in the binman image, so
 | 
			
		||||
	  binman can update SPL with the location of it.
 | 
			
		||||
	  See tools/binman/binman.rst for a detailed explanation.
 | 
			
		||||
 | 
			
		||||
config SPL_BINMAN_UBOOT_SYMBOLS
 | 
			
		||||
	bool "Declare binman symbols for U-Boot phases in SPL"
 | 
			
		||||
	depends on SPL_BINMAN_SYMBOLS
 | 
			
		||||
	default n if ARCH_IMX8M
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in SPL which refer to U-Boot phases,
 | 
			
		||||
	  enabling SPL to obtain the location and size of its next phase simply
 | 
			
		||||
	  by calling spl_get_image_pos() and spl_get_image_size().
 | 
			
		||||
 | 
			
		||||
	  For this to work, you must have all U-Boot phases in the same binman
 | 
			
		||||
	  image, so binman can update SPL with the locations of everything.
 | 
			
		||||
 | 
			
		||||
source "common/spl/Kconfig.nxp"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,16 +9,29 @@ config TPL_SIZE_LIMIT
 | 
			
		|||
	  If this value is zero, it is ignored.
 | 
			
		||||
 | 
			
		||||
config TPL_BINMAN_SYMBOLS
 | 
			
		||||
	bool "Declare binman symbols in TPL"
 | 
			
		||||
	depends on SPL_FRAMEWORK && BINMAN
 | 
			
		||||
	bool "Support binman symbols in TPL"
 | 
			
		||||
	depends on TPL_FRAMEWORK && BINMAN
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in TPL which refer to U-Boot, enabling TPL
 | 
			
		||||
	  to obtain the location of U-Boot simply by calling spl_get_image_pos()
 | 
			
		||||
	  and spl_get_image_size().
 | 
			
		||||
	  This enables use of symbols in TPL which refer to other entries in
 | 
			
		||||
	  the same binman image as the TPL. These can be declared with the
 | 
			
		||||
	  binman_sym_declare(type, entry, prop) macro and accessed by the
 | 
			
		||||
	  binman_sym(type, entry, prop) macro defined in binman_sym.h.
 | 
			
		||||
 | 
			
		||||
	  For this to work, you must have a U-Boot image in the binman image, so
 | 
			
		||||
	  binman can update TPL with the location of it.
 | 
			
		||||
	  See tools/binman/binman.rst for a detailed explanation.
 | 
			
		||||
 | 
			
		||||
config TPL_BINMAN_UBOOT_SYMBOLS
 | 
			
		||||
	bool "Declare binman symbols for U-Boot phases in TPL"
 | 
			
		||||
	depends on TPL_BINMAN_SYMBOLS
 | 
			
		||||
	default n if ARCH_IMX8M
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in TPL which refer to U-Boot phases,
 | 
			
		||||
	  enabling TPL to obtain the location and size of its next phase simply
 | 
			
		||||
	  by calling spl_get_image_pos() and spl_get_image_size().
 | 
			
		||||
 | 
			
		||||
	  For this to work, you must have all U-Boot phases in the same binman
 | 
			
		||||
	  image, so binman can update TPL with the locations of everything.
 | 
			
		||||
 | 
			
		||||
config TPL_FRAMEWORK
 | 
			
		||||
	bool "Support TPL based upon the common SPL framework"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -198,4 +198,29 @@ config VPL_TEXT_BASE
 | 
			
		|||
	help
 | 
			
		||||
	  The address in memory that VPL will be running from.
 | 
			
		||||
 | 
			
		||||
config VPL_BINMAN_SYMBOLS
 | 
			
		||||
	bool "Declare binman symbols in VPL"
 | 
			
		||||
	depends on VPL_FRAMEWORK && BINMAN
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in VPL which refer to other entries in
 | 
			
		||||
	  the same binman image as the VPL. These can be declared with the
 | 
			
		||||
	  binman_sym_declare(type, entry, prop) macro and accessed by the
 | 
			
		||||
	  binman_sym(type, entry, prop) macro defined in binman_sym.h.
 | 
			
		||||
 | 
			
		||||
	  See tools/binman/binman.rst for a detailed explanation.
 | 
			
		||||
 | 
			
		||||
config VPL_BINMAN_UBOOT_SYMBOLS
 | 
			
		||||
	bool "Declare binman symbols for U-Boot phases in VPL"
 | 
			
		||||
	depends on VPL_BINMAN_SYMBOLS
 | 
			
		||||
	default n if ARCH_IMX8M
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  This enables use of symbols in VPL which refer to U-Boot phases,
 | 
			
		||||
	  enabling VPL to obtain the location and size of its next phase simply
 | 
			
		||||
	  by calling spl_get_image_pos() and spl_get_image_size().
 | 
			
		||||
 | 
			
		||||
	  For this to work, you must have all U-Boot phases in the same binman
 | 
			
		||||
	  image, so binman can update VPL with the locations of everything.
 | 
			
		||||
 | 
			
		||||
endmenu
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,12 +34,14 @@
 | 
			
		|||
#include <malloc.h>
 | 
			
		||||
#include <mapmem.h>
 | 
			
		||||
#include <dm/root.h>
 | 
			
		||||
#include <dm/util.h>
 | 
			
		||||
#include <linux/compiler.h>
 | 
			
		||||
#include <fdt_support.h>
 | 
			
		||||
#include <bootcount.h>
 | 
			
		||||
#include <wdt.h>
 | 
			
		||||
 | 
			
		||||
DECLARE_GLOBAL_DATA_PTR;
 | 
			
		||||
DECLARE_BINMAN_MAGIC_SYM;
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_SYS_UBOOT_START
 | 
			
		||||
#define CONFIG_SYS_UBOOT_START	CONFIG_SYS_TEXT_BASE
 | 
			
		||||
| 
						 | 
				
			
			@ -51,11 +53,10 @@ DECLARE_GLOBAL_DATA_PTR;
 | 
			
		|||
 | 
			
		||||
u32 *boot_params_ptr = NULL;
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(BINMAN_SYMBOLS)
 | 
			
		||||
#if CONFIG_IS_ENABLED(BINMAN_UBOOT_SYMBOLS)
 | 
			
		||||
/* See spl.h for information about this */
 | 
			
		||||
binman_sym_declare(ulong, u_boot_any, image_pos);
 | 
			
		||||
binman_sym_declare(ulong, u_boot_any, size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_TPL
 | 
			
		||||
binman_sym_declare(ulong, u_boot_spl, image_pos);
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +68,8 @@ binman_sym_declare(ulong, u_boot_vpl, image_pos);
 | 
			
		|||
binman_sym_declare(ulong, u_boot_vpl, size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* BINMAN_UBOOT_SYMBOLS */
 | 
			
		||||
 | 
			
		||||
/* Define board data structure */
 | 
			
		||||
static struct bd_info bdata __attribute__ ((section(".data")));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,9 +152,11 @@ void spl_fixup_fdt(void *fdt_blob)
 | 
			
		|||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(BINMAN_SYMBOLS)
 | 
			
		||||
ulong spl_get_image_pos(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!CONFIG_IS_ENABLED(BINMAN_UBOOT_SYMBOLS))
 | 
			
		||||
		return BINMAN_SYM_MISSING;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_VPL
 | 
			
		||||
	if (spl_next_phase() == PHASE_VPL)
 | 
			
		||||
		return binman_sym(ulong, u_boot_vpl, image_pos);
 | 
			
		||||
| 
						 | 
				
			
			@ -163,6 +168,9 @@ ulong spl_get_image_pos(void)
 | 
			
		|||
 | 
			
		||||
ulong spl_get_image_size(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!CONFIG_IS_ENABLED(BINMAN_UBOOT_SYMBOLS))
 | 
			
		||||
		return BINMAN_SYM_MISSING;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_VPL
 | 
			
		||||
	if (spl_next_phase() == PHASE_VPL)
 | 
			
		||||
		return binman_sym(ulong, u_boot_vpl, size);
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +179,6 @@ ulong spl_get_image_size(void)
 | 
			
		|||
		binman_sym(ulong, u_boot_spl, size) :
 | 
			
		||||
		binman_sym(ulong, u_boot_any, size);
 | 
			
		||||
}
 | 
			
		||||
#endif /* BINMAN_SYMBOLS */
 | 
			
		||||
 | 
			
		||||
ulong spl_get_image_text_base(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -222,7 +229,7 @@ __weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
 | 
			
		|||
 | 
			
		||||
void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
 | 
			
		||||
{
 | 
			
		||||
	ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
 | 
			
		||||
	ulong u_boot_pos = spl_get_image_pos();
 | 
			
		||||
 | 
			
		||||
	spl_image->size = CONFIG_SYS_MONITOR_LEN;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -780,6 +787,14 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
 | 
			
		|||
 | 
			
		||||
	bootcount_inc();
 | 
			
		||||
 | 
			
		||||
	/* Dump driver model states to aid analysis */
 | 
			
		||||
	if (CONFIG_IS_ENABLED(DM_STATS)) {
 | 
			
		||||
		struct dm_stats mem;
 | 
			
		||||
 | 
			
		||||
		dm_get_mem(&mem);
 | 
			
		||||
		dm_dump_mem(&mem);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(&spl_image, '\0', sizeof(spl_image));
 | 
			
		||||
#ifdef CONFIG_SYS_SPL_ARGS_ADDR
 | 
			
		||||
	spl_image.arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
 | 
			
		|||
		load.read = spl_ram_load_read;
 | 
			
		||||
		spl_load_simple_fit(spl_image, &load, 0, header);
 | 
			
		||||
	} else {
 | 
			
		||||
		ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
 | 
			
		||||
		ulong u_boot_pos = spl_get_image_pos();
 | 
			
		||||
 | 
			
		||||
		debug("Legacy image\n");
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ a central structure. Each record of information is assigned a tag so that its
 | 
			
		|||
owner can find it and update it. Each record is generally described by a C
 | 
			
		||||
structure defined by the code that owns it.
 | 
			
		||||
 | 
			
		||||
For the design goals of bloblist, please see the comments at the top of the
 | 
			
		||||
`bloblist.h` header file.
 | 
			
		||||
 | 
			
		||||
Passing state through the boot process
 | 
			
		||||
--------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,487 @@
 | 
			
		|||
.. SPDX-License-Identifier: GPL-2.0+:
 | 
			
		||||
 | 
			
		||||
dm command
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
Synopis
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
::
 | 
			
		||||
 | 
			
		||||
    dm compat
 | 
			
		||||
    dm devres
 | 
			
		||||
    dm drivers
 | 
			
		||||
    dm static
 | 
			
		||||
    dm tree
 | 
			
		||||
    dm uclass
 | 
			
		||||
 | 
			
		||||
Description
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
The *dm* command allows viewing information about driver model, including the
 | 
			
		||||
tree of devices and list of available uclasses.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm compat
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows the compatible strings associated with each driver. Often there
 | 
			
		||||
is only one, but multiple strings are shown on their own line. These strings
 | 
			
		||||
can be looked up in the device tree files for each board, to see which driver is
 | 
			
		||||
used for each node.
 | 
			
		||||
 | 
			
		||||
dm devres
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows a list of a `devres` (device resource) records for a device. Some
 | 
			
		||||
drivers use the devres API to allocate memory, so that it can be freed
 | 
			
		||||
automatically (without any code needed in the driver's remove() method) when the
 | 
			
		||||
device is removed.
 | 
			
		||||
 | 
			
		||||
This feature is controlled by CONFIG_DEVRES so no useful output is obtained if
 | 
			
		||||
this option is disabled.
 | 
			
		||||
 | 
			
		||||
dm drivers
 | 
			
		||||
~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows all the available drivers, their uclass and a list of devices that
 | 
			
		||||
use that driver, each on its own line. Drivers with no devices are shown with
 | 
			
		||||
`<none>` as the driver name.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm mem
 | 
			
		||||
~~~~~~
 | 
			
		||||
 | 
			
		||||
This subcommand is really just for debugging and exploration. It can be enabled
 | 
			
		||||
with the `CONFIG_DM_STATS` option.
 | 
			
		||||
 | 
			
		||||
All output is in hex except that in brackets which is decimal.
 | 
			
		||||
 | 
			
		||||
The output consists of a header shows the size of the main device model
 | 
			
		||||
structures (struct udevice, struct driver, struct uclass and struct uc_driver)
 | 
			
		||||
and the count and memory used by each (number of devices, memory used by
 | 
			
		||||
devices, memory used by device names, number of uclasses, memory used by
 | 
			
		||||
uclasses).
 | 
			
		||||
 | 
			
		||||
After that is a table of information about each type of data that can be
 | 
			
		||||
attached to a device, showing the number that have non-null data for that type,
 | 
			
		||||
the total size of all that data, the amount of memory used in total, the
 | 
			
		||||
amount that would be used if this type uses tags instead and the amount that
 | 
			
		||||
would be thus saved.
 | 
			
		||||
 | 
			
		||||
The `driver_data` line shows the number of devices which have non-NULL driver
 | 
			
		||||
data.
 | 
			
		||||
 | 
			
		||||
The `tags` line shows the number of tags and the memory used by those.
 | 
			
		||||
 | 
			
		||||
At the bottom is an indication of the total memory usage obtained by undertaking
 | 
			
		||||
various changes, none of which is currently implemented in U-Boot:
 | 
			
		||||
 | 
			
		||||
With tags
 | 
			
		||||
    Using tags instead of all attached types
 | 
			
		||||
 | 
			
		||||
Singly linked
 | 
			
		||||
    Using a singly linked list
 | 
			
		||||
 | 
			
		||||
driver index
 | 
			
		||||
    Using a driver index instead of a pointer
 | 
			
		||||
 | 
			
		||||
uclass index
 | 
			
		||||
    Using a uclass index instead of a pointer
 | 
			
		||||
 | 
			
		||||
Drop device name
 | 
			
		||||
    Using empty device names
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm static
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows devices bound by platform data, i.e. not from the device tree. There
 | 
			
		||||
are normally none of these, but some boards may use static devices for space
 | 
			
		||||
reasons.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm tree
 | 
			
		||||
~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows the full tree of devices including the following fields:
 | 
			
		||||
 | 
			
		||||
uclass
 | 
			
		||||
    Shows the name of the uclass for the device
 | 
			
		||||
 | 
			
		||||
Index
 | 
			
		||||
    Shows the index number of the device, within the uclass. This shows the
 | 
			
		||||
    ordering within the uclass, but not the sequence number.
 | 
			
		||||
 | 
			
		||||
Probed
 | 
			
		||||
    Shows `+` if the device is active
 | 
			
		||||
 | 
			
		||||
Driver
 | 
			
		||||
    Shows the name of the driver that this device uses
 | 
			
		||||
 | 
			
		||||
Name
 | 
			
		||||
    Shows the device name as well as the tree structure, since child devices are
 | 
			
		||||
    shown attached to their parent.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm uclass
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This shows each uclass along with a list of devices in that uclass. The uclass
 | 
			
		||||
ID is shown (e.g. uclass 7) and its name.
 | 
			
		||||
 | 
			
		||||
For each device, the format is::
 | 
			
		||||
 | 
			
		||||
    n    name @ a, seq s
 | 
			
		||||
 | 
			
		||||
where `n` is the index within the uclass, `a` is the address of the device in
 | 
			
		||||
memory and `s` is the sequence number of the device.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Examples
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
dm compat
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows an abridged version of the sandbox output::
 | 
			
		||||
 | 
			
		||||
    => dm compat
 | 
			
		||||
    Driver                Compatible
 | 
			
		||||
    --------------------------------
 | 
			
		||||
    act8846_reg
 | 
			
		||||
    sandbox_adder         sandbox,adder
 | 
			
		||||
    axi_sandbox_bus       sandbox,axi
 | 
			
		||||
    blk_partition
 | 
			
		||||
    bootcount-rtc         u-boot,bootcount-rtc
 | 
			
		||||
    ...
 | 
			
		||||
    rockchip_rk805        rockchip,rk805
 | 
			
		||||
                          rockchip,rk808
 | 
			
		||||
                          rockchip,rk809
 | 
			
		||||
                          rockchip,rk816
 | 
			
		||||
                          rockchip,rk817
 | 
			
		||||
                          rockchip,rk818
 | 
			
		||||
    root_driver
 | 
			
		||||
    rtc-rv8803            microcrystal,rv8803
 | 
			
		||||
                          epson,rx8803
 | 
			
		||||
                          epson,rx8900
 | 
			
		||||
    ...
 | 
			
		||||
    wdt_gpio              linux,wdt-gpio
 | 
			
		||||
    wdt_sandbox           sandbox,wdt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm devres
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows an abridged version of the sandbox test output (running
 | 
			
		||||
U-Boot with the -T flag)::
 | 
			
		||||
 | 
			
		||||
    => dm devres
 | 
			
		||||
    - root_driver
 | 
			
		||||
    - demo_shape_drv
 | 
			
		||||
    - demo_simple_drv
 | 
			
		||||
    - demo_shape_drv
 | 
			
		||||
    ...
 | 
			
		||||
    - h-test
 | 
			
		||||
    - devres-test
 | 
			
		||||
        00000000130194e0 (100 byte) devm_kmalloc_release  BIND
 | 
			
		||||
    - another-test
 | 
			
		||||
    ...
 | 
			
		||||
    - syscon@3
 | 
			
		||||
    - a-mux-controller
 | 
			
		||||
        0000000013025e60 (96 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013025f00 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013026010 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013026070 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        00000000130260d0 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
    - syscon@3
 | 
			
		||||
    - a-mux-controller
 | 
			
		||||
        0000000013026150 (96 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        00000000130261f0 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013026300 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013026360 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        00000000130263c0 (24 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
    - emul-mux-controller
 | 
			
		||||
        0000000013025fa0 (32 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
    - testfdtm0
 | 
			
		||||
    - testfdtm1
 | 
			
		||||
    ...
 | 
			
		||||
    - pinmux_spi0_pins
 | 
			
		||||
    - pinmux_uart0_pins
 | 
			
		||||
    - pinctrl-single-bits
 | 
			
		||||
        0000000013229180 (320 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013229300 (40 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        0000000013229370 (160 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        000000001322c190 (40 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
        000000001322c200 (32 byte) devm_kmalloc_release  PROBE
 | 
			
		||||
    - pinmux_i2c0_pins
 | 
			
		||||
    ...
 | 
			
		||||
    - reg@0
 | 
			
		||||
    - reg@1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm drivers
 | 
			
		||||
~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows an abridged version of the sandbox output::
 | 
			
		||||
 | 
			
		||||
    => dm drivers
 | 
			
		||||
    Driver                    uid uclass               Devices
 | 
			
		||||
    ----------------------------------------------------------
 | 
			
		||||
    act8846_reg               087 regulator            <none>
 | 
			
		||||
    sandbox_adder             021 axi                  adder
 | 
			
		||||
                                                    adder
 | 
			
		||||
    axi_sandbox_bus           021 axi                  axi@0
 | 
			
		||||
    ...
 | 
			
		||||
    da7219                    061 misc                 <none>
 | 
			
		||||
    demo_shape_drv            001 demo                 demo_shape_drv
 | 
			
		||||
                                                    demo_shape_drv
 | 
			
		||||
                                                    demo_shape_drv
 | 
			
		||||
    demo_simple_drv           001 demo                 demo_simple_drv
 | 
			
		||||
                                                    demo_simple_drv
 | 
			
		||||
    testfdt_drv               003 testfdt              a-test
 | 
			
		||||
                                                    b-test
 | 
			
		||||
                                                    d-test
 | 
			
		||||
                                                    e-test
 | 
			
		||||
                                                    f-test
 | 
			
		||||
                                                    g-test
 | 
			
		||||
                                                    another-test
 | 
			
		||||
                                                    chosen-test
 | 
			
		||||
    testbus_drv               005 testbus              some-bus
 | 
			
		||||
                                                    mmio-bus@0
 | 
			
		||||
                                                    mmio-bus@1
 | 
			
		||||
    dsa-port                  039 ethernet             lan0
 | 
			
		||||
                                                    lan1
 | 
			
		||||
    dsa_sandbox               035 dsa                  dsa-test
 | 
			
		||||
    eep_sandbox               121 w1_eeprom            <none>
 | 
			
		||||
    ...
 | 
			
		||||
    pfuze100_regulator        087 regulator            <none>
 | 
			
		||||
    phy_sandbox               077 phy                  bind-test-child1
 | 
			
		||||
                                                    gen_phy@0
 | 
			
		||||
                                                    gen_phy@1
 | 
			
		||||
                                                    gen_phy@2
 | 
			
		||||
    pinconfig                 078 pinconfig            gpios
 | 
			
		||||
                                                    gpio0
 | 
			
		||||
                                                    gpio1
 | 
			
		||||
                                                    gpio2
 | 
			
		||||
                                                    gpio3
 | 
			
		||||
                                                    i2c
 | 
			
		||||
                                                    groups
 | 
			
		||||
                                                    pins
 | 
			
		||||
                                                    i2s
 | 
			
		||||
                                                    spi
 | 
			
		||||
                                                    cs
 | 
			
		||||
                                                    pinmux_pwm_pins
 | 
			
		||||
                                                    pinmux_spi0_pins
 | 
			
		||||
                                                    pinmux_uart0_pins
 | 
			
		||||
                                                    pinmux_i2c0_pins
 | 
			
		||||
                                                    pinmux_lcd_pins
 | 
			
		||||
    pmc_sandbox               017 power-mgr            pci@1e,0
 | 
			
		||||
    act8846 pmic              080 pmic                 <none>
 | 
			
		||||
    max77686_pmic             080 pmic                 <none>
 | 
			
		||||
    mc34708_pmic              080 pmic                 pmic@41
 | 
			
		||||
    ...
 | 
			
		||||
    wdt_gpio                  122 watchdog             gpio-wdt
 | 
			
		||||
    wdt_sandbox               122 watchdog             wdt@0
 | 
			
		||||
    =>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm mem
 | 
			
		||||
~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows the sandbox output::
 | 
			
		||||
 | 
			
		||||
    > dm mem
 | 
			
		||||
    Struct sizes: udevice b0, driver 80, uclass 30, uc_driver 78
 | 
			
		||||
    Memory: device fe:aea0, device names a16, uclass 5e:11a0
 | 
			
		||||
 | 
			
		||||
    Attached type    Count   Size    Cur   Tags   Save
 | 
			
		||||
    ---------------  -----  -----  -----  -----  -----
 | 
			
		||||
    plat                45    a8f   aea0   a7c4    6dc (1756)
 | 
			
		||||
    parent_plat         1a    3b8   aea0   a718    788 (1928)
 | 
			
		||||
    uclass_plat         3d    6b4   aea0   a7a4    6fc (1788)
 | 
			
		||||
    priv                8a   68f3   aea0   a8d8    5c8 (1480)
 | 
			
		||||
    parent_priv          8   38a0   aea0   a6d0    7d0 (2000)
 | 
			
		||||
    uclass_priv         4e   14a6   aea0   a7e8    6b8 (1720)
 | 
			
		||||
    driver_data          f      0   aea0   a6ec    7b4 (1972)
 | 
			
		||||
    uclass               6     20
 | 
			
		||||
    Attached total     191   cb54                  3164 (12644)
 | 
			
		||||
    tags                 0      0
 | 
			
		||||
 | 
			
		||||
    Total size: 18b94 (101268)
 | 
			
		||||
 | 
			
		||||
    With tags:       15a30 (88624)
 | 
			
		||||
    - singly-linked: 14260 (82528)
 | 
			
		||||
    - driver index:  13b6e (80750)
 | 
			
		||||
    - uclass index:  1347c (78972)
 | 
			
		||||
    Drop device name (not SRAM): a16 (2582)
 | 
			
		||||
    =>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm static
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows the sandbox output::
 | 
			
		||||
 | 
			
		||||
    => dm static
 | 
			
		||||
    Driver                    Address
 | 
			
		||||
    ---------------------------------
 | 
			
		||||
    demo_shape_drv            0000562edab8dca0
 | 
			
		||||
    demo_simple_drv           0000562edab8dca0
 | 
			
		||||
    demo_shape_drv            0000562edab8dc90
 | 
			
		||||
    demo_simple_drv           0000562edab8dc80
 | 
			
		||||
    demo_shape_drv            0000562edab8dc80
 | 
			
		||||
    test_drv                  0000562edaae8840
 | 
			
		||||
    test_drv                  0000562edaae8848
 | 
			
		||||
    test_drv                  0000562edaae8850
 | 
			
		||||
    sandbox_gpio              0000000000000000
 | 
			
		||||
    mod_exp_sw                0000000000000000
 | 
			
		||||
    sandbox_test_proc         0000562edabb5330
 | 
			
		||||
    qfw_sandbox               0000000000000000
 | 
			
		||||
    sandbox_timer             0000000000000000
 | 
			
		||||
    sandbox_serial            0000562edaa8ed00
 | 
			
		||||
    sysreset_sandbox          0000000000000000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm tree
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
This example shows the abridged sandbox output::
 | 
			
		||||
 | 
			
		||||
    => dm tree
 | 
			
		||||
    Class     Index  Probed  Driver                Name
 | 
			
		||||
    -----------------------------------------------------------
 | 
			
		||||
    root          0  [ + ]   root_driver           root_driver
 | 
			
		||||
    demo          0  [   ]   demo_shape_drv        |-- demo_shape_drv
 | 
			
		||||
    demo          1  [   ]   demo_simple_drv       |-- demo_simple_drv
 | 
			
		||||
    demo          2  [   ]   demo_shape_drv        |-- demo_shape_drv
 | 
			
		||||
    demo          3  [   ]   demo_simple_drv       |-- demo_simple_drv
 | 
			
		||||
    demo          4  [   ]   demo_shape_drv        |-- demo_shape_drv
 | 
			
		||||
    test          0  [   ]   test_drv              |-- test_drv
 | 
			
		||||
    test          1  [   ]   test_drv              |-- test_drv
 | 
			
		||||
    test          2  [   ]   test_drv              |-- test_drv
 | 
			
		||||
    ..
 | 
			
		||||
    sysreset      0  [   ]   sysreset_sandbox      |-- sysreset_sandbox
 | 
			
		||||
    bootstd       0  [   ]   bootstd_drv           |-- bootstd
 | 
			
		||||
    bootmeth      0  [   ]   bootmeth_distro       |   |-- syslinux
 | 
			
		||||
    bootmeth      1  [   ]   bootmeth_efi          |   `-- efi
 | 
			
		||||
    reboot-mod    0  [   ]   reboot-mode-gpio      |-- reboot-mode0
 | 
			
		||||
    reboot-mod    1  [   ]   reboot-mode-rtc       |-- reboot-mode@14
 | 
			
		||||
    ...
 | 
			
		||||
    ethernet      7  [ + ]   dsa-port              |   `-- lan1
 | 
			
		||||
    pinctrl       0  [ + ]   sandbox_pinctrl_gpio  |-- pinctrl-gpio
 | 
			
		||||
    gpio          1  [ + ]   sandbox_gpio          |   |-- base-gpios
 | 
			
		||||
    nop           0  [ + ]   gpio_hog              |   |   |-- hog_input_active_low
 | 
			
		||||
    nop           1  [ + ]   gpio_hog              |   |   |-- hog_input_active_high
 | 
			
		||||
    nop           2  [ + ]   gpio_hog              |   |   |-- hog_output_low
 | 
			
		||||
    nop           3  [ + ]   gpio_hog              |   |   `-- hog_output_high
 | 
			
		||||
    gpio          2  [   ]   sandbox_gpio          |   |-- extra-gpios
 | 
			
		||||
    gpio          3  [   ]   sandbox_gpio          |   `-- pinmux-gpios
 | 
			
		||||
    i2c           0  [ + ]   sandbox_i2c           |-- i2c@0
 | 
			
		||||
    i2c_eeprom    0  [   ]   i2c_eeprom            |   |-- eeprom@2c
 | 
			
		||||
    i2c_eeprom    1  [   ]   i2c_eeprom_partition  |   |   `-- bootcount@10
 | 
			
		||||
    rtc           0  [   ]   sandbox_rtc           |   |-- rtc@43
 | 
			
		||||
    rtc           1  [ + ]   sandbox_rtc           |   |-- rtc@61
 | 
			
		||||
    i2c_emul_p    0  [ + ]   sandbox_i2c_emul_par  |   |-- emul
 | 
			
		||||
    i2c_emul      0  [   ]   sandbox_i2c_eeprom_e  |   |   |-- emul-eeprom
 | 
			
		||||
    i2c_emul      1  [   ]   sandbox_i2c_rtc_emul  |   |   |-- emul0
 | 
			
		||||
    i2c_emul      2  [ + ]   sandbox_i2c_rtc_emul  |   |   |-- emull
 | 
			
		||||
    i2c_emul      3  [   ]   sandbox_i2c_pmic_emu  |   |   |-- pmic-emul0
 | 
			
		||||
    i2c_emul      4  [   ]   sandbox_i2c_pmic_emu  |   |   `-- pmic-emul1
 | 
			
		||||
    pmic          0  [   ]   sandbox_pmic          |   |-- sandbox_pmic
 | 
			
		||||
    regulator     0  [   ]   sandbox_buck          |   |   |-- buck1
 | 
			
		||||
    regulator     1  [   ]   sandbox_buck          |   |   |-- buck2
 | 
			
		||||
    regulator     2  [   ]   sandbox_ldo           |   |   |-- ldo1
 | 
			
		||||
    regulator     3  [   ]   sandbox_ldo           |   |   |-- ldo2
 | 
			
		||||
    regulator     4  [   ]   sandbox_buck          |   |   `-- no_match_by_nodename
 | 
			
		||||
    pmic          1  [   ]   mc34708_pmic          |   `-- pmic@41
 | 
			
		||||
    bootcount     0  [ + ]   bootcount-rtc         |-- bootcount@0
 | 
			
		||||
    bootcount     1  [   ]   bootcount-i2c-eeprom  |-- bootcount
 | 
			
		||||
    ...
 | 
			
		||||
    clk           4  [   ]   fixed_clock           |-- osc
 | 
			
		||||
    firmware      0  [   ]   sandbox_firmware      |-- sandbox-firmware
 | 
			
		||||
    scmi_agent    0  [   ]   sandbox-scmi_agent    `-- scmi
 | 
			
		||||
    clk           5  [   ]   scmi_clk                  |-- protocol@14
 | 
			
		||||
    reset         2  [   ]   scmi_reset_domain         |-- protocol@16
 | 
			
		||||
    nop           8  [   ]   scmi_voltage_domain       `-- regulators
 | 
			
		||||
    regulator     5  [   ]   scmi_regulator                |-- reg@0
 | 
			
		||||
    regulator     6  [   ]   scmi_regulator                `-- reg@1
 | 
			
		||||
    =>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dm uclass
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This example shows the abridged sandbox output::
 | 
			
		||||
 | 
			
		||||
    => dm uclass
 | 
			
		||||
    uclass 0: root
 | 
			
		||||
    0   * root_driver @ 03015460, seq 0
 | 
			
		||||
 | 
			
		||||
    uclass 1: demo
 | 
			
		||||
    0     demo_shape_drv @ 03015560, seq 0
 | 
			
		||||
    1     demo_simple_drv @ 03015620, seq 1
 | 
			
		||||
    2     demo_shape_drv @ 030156e0, seq 2
 | 
			
		||||
    3     demo_simple_drv @ 030157a0, seq 3
 | 
			
		||||
    4     demo_shape_drv @ 03015860, seq 4
 | 
			
		||||
 | 
			
		||||
    uclass 2: test
 | 
			
		||||
    0     test_drv @ 03015980, seq 0
 | 
			
		||||
    1     test_drv @ 03015a60, seq 1
 | 
			
		||||
    2     test_drv @ 03015b40, seq 2
 | 
			
		||||
    ...
 | 
			
		||||
    uclass 20: audio-codec
 | 
			
		||||
    0     audio-codec @ 030168e0, seq 0
 | 
			
		||||
 | 
			
		||||
    uclass 21: axi
 | 
			
		||||
    0     adder @ 0301db60, seq 1
 | 
			
		||||
    1     adder @ 0301dc40, seq 2
 | 
			
		||||
    2     axi@0 @ 030217d0, seq 0
 | 
			
		||||
 | 
			
		||||
    uclass 22: blk
 | 
			
		||||
    0     mmc2.blk @ 0301ca00, seq 0
 | 
			
		||||
    1     mmc1.blk @ 0301cee0, seq 1
 | 
			
		||||
    2     mmc0.blk @ 0301d380, seq 2
 | 
			
		||||
 | 
			
		||||
    uclass 23: bootcount
 | 
			
		||||
    0   * bootcount@0 @ 0301b3f0, seq 0
 | 
			
		||||
    1     bootcount @ 0301b4b0, seq 1
 | 
			
		||||
    2     bootcount_4@0 @ 0301b570, seq 2
 | 
			
		||||
    3     bootcount_2@0 @ 0301b630, seq 3
 | 
			
		||||
 | 
			
		||||
    uclass 24: bootdev
 | 
			
		||||
    0     mmc2.bootdev @ 0301cbb0, seq 0
 | 
			
		||||
    1     mmc1.bootdev @ 0301d050, seq 1
 | 
			
		||||
    2     mmc0.bootdev @ 0301d4f0, seq 2
 | 
			
		||||
 | 
			
		||||
    ...
 | 
			
		||||
    uclass 78: pinconfig
 | 
			
		||||
    0     gpios @ 03022410, seq 0
 | 
			
		||||
    1     gpio0 @ 030224d0, seq 1
 | 
			
		||||
    2     gpio1 @ 03022590, seq 2
 | 
			
		||||
    3     gpio2 @ 03022650, seq 3
 | 
			
		||||
    4     gpio3 @ 03022710, seq 4
 | 
			
		||||
    5     i2c @ 030227d0, seq 5
 | 
			
		||||
    6     groups @ 03022890, seq 6
 | 
			
		||||
    7     pins @ 03022950, seq 7
 | 
			
		||||
    8     i2s @ 03022a10, seq 8
 | 
			
		||||
    9     spi @ 03022ad0, seq 9
 | 
			
		||||
    10    cs @ 03022b90, seq 10
 | 
			
		||||
    11    pinmux_pwm_pins @ 03022e10, seq 11
 | 
			
		||||
    12    pinmux_spi0_pins @ 03022ed0, seq 12
 | 
			
		||||
    13    pinmux_uart0_pins @ 03022f90, seq 13
 | 
			
		||||
    14  * pinmux_i2c0_pins @ 03023130, seq 14
 | 
			
		||||
    15  * pinmux_lcd_pins @ 030231f0, seq 15
 | 
			
		||||
 | 
			
		||||
    ...
 | 
			
		||||
    uclass 119: virtio
 | 
			
		||||
    0     sandbox_virtio1 @ 030220d0, seq 0
 | 
			
		||||
    1     sandbox_virtio2 @ 03022190, seq 1
 | 
			
		||||
 | 
			
		||||
    uclass 120: w1
 | 
			
		||||
    uclass 121: w1_eeprom
 | 
			
		||||
    uclass 122: watchdog
 | 
			
		||||
    0   * gpio-wdt @ 0301c070, seq 0
 | 
			
		||||
    1   * wdt@0 @ 03021710, seq 1
 | 
			
		||||
 | 
			
		||||
    =>
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ Shell commands
 | 
			
		|||
   cmd/bootz
 | 
			
		||||
   cmd/cbsysinfo
 | 
			
		||||
   cmd/conitrace
 | 
			
		||||
   cmd/dm
 | 
			
		||||
   cmd/echo
 | 
			
		||||
   cmd/env
 | 
			
		||||
   cmd/event
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,27 @@ config DM_DEBUG
 | 
			
		|||
	help
 | 
			
		||||
	  Say Y here if you want to compile in debug messages in DM core.
 | 
			
		||||
 | 
			
		||||
config DM_STATS
 | 
			
		||||
	bool "Collect and show driver model stats"
 | 
			
		||||
	depends on DM
 | 
			
		||||
	default y if SANDBOX
 | 
			
		||||
	help
 | 
			
		||||
	  Enable this to collect and display memory statistics about driver
 | 
			
		||||
	  model. This can help to figure out where all the memory is going and
 | 
			
		||||
	  to find optimisations.
 | 
			
		||||
 | 
			
		||||
	  To display the memory stats, use the 'dm mem' command.
 | 
			
		||||
 | 
			
		||||
config SPL_DM_STATS
 | 
			
		||||
	bool "Collect and show driver model stats in SPL"
 | 
			
		||||
	depends on DM_SPL
 | 
			
		||||
	help
 | 
			
		||||
	  Enable this to collect and display memory statistics about driver
 | 
			
		||||
	  model. This can help to figure out where all the memory is going and
 | 
			
		||||
	  to find optimisations.
 | 
			
		||||
 | 
			
		||||
	  The stats are displayed just before SPL boots to the next phase.
 | 
			
		||||
 | 
			
		||||
config DM_DEVICE_REMOVE
 | 
			
		||||
	bool "Support device removal"
 | 
			
		||||
	depends on DM
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ int device_chld_unbind(struct udevice *dev, struct driver *drv)
 | 
			
		|||
 | 
			
		||||
	assert(dev);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child_safe(pos, n, dev) {
 | 
			
		||||
		if (drv && (pos->driver != drv))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ int device_chld_remove(struct udevice *dev, struct driver *drv,
 | 
			
		|||
 | 
			
		||||
	assert(dev);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child_safe(pos, n, dev) {
 | 
			
		||||
		int ret;
 | 
			
		||||
 | 
			
		||||
		if (drv && (pos->driver != drv))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -284,8 +284,7 @@ int device_reparent(struct udevice *dev, struct udevice *new_parent)
 | 
			
		|||
	assert(dev);
 | 
			
		||||
	assert(new_parent);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(pos, n, &dev->parent->child_head,
 | 
			
		||||
				 sibling_node) {
 | 
			
		||||
	device_foreach_child_safe(pos, n, dev->parent) {
 | 
			
		||||
		if (pos->driver != dev->driver)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -675,6 +674,71 @@ void *dev_get_parent_priv(const struct udevice *dev)
 | 
			
		|||
	return dm_priv_to_rw(dev->parent_priv_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *dev_get_attach_ptr(const struct udevice *dev, enum dm_tag_t tag)
 | 
			
		||||
{
 | 
			
		||||
	switch (tag) {
 | 
			
		||||
	case DM_TAG_PLAT:
 | 
			
		||||
		return dev_get_plat(dev);
 | 
			
		||||
	case DM_TAG_PARENT_PLAT:
 | 
			
		||||
		return dev_get_parent_plat(dev);
 | 
			
		||||
	case DM_TAG_UC_PLAT:
 | 
			
		||||
		return dev_get_uclass_plat(dev);
 | 
			
		||||
	case DM_TAG_PRIV:
 | 
			
		||||
		return dev_get_priv(dev);
 | 
			
		||||
	case DM_TAG_PARENT_PRIV:
 | 
			
		||||
		return dev_get_parent_priv(dev);
 | 
			
		||||
	case DM_TAG_UC_PRIV:
 | 
			
		||||
		return dev_get_uclass_priv(dev);
 | 
			
		||||
	default:
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_get_attach_size(const struct udevice *dev, enum dm_tag_t tag)
 | 
			
		||||
{
 | 
			
		||||
	const struct udevice *parent = dev_get_parent(dev);
 | 
			
		||||
	const struct uclass *uc = dev->uclass;
 | 
			
		||||
	const struct uclass_driver *uc_drv = uc->uc_drv;
 | 
			
		||||
	const struct driver *parent_drv = NULL;
 | 
			
		||||
	int size = 0;
 | 
			
		||||
 | 
			
		||||
	if (parent)
 | 
			
		||||
		parent_drv = parent->driver;
 | 
			
		||||
 | 
			
		||||
	switch (tag) {
 | 
			
		||||
	case DM_TAG_PLAT:
 | 
			
		||||
		size = dev->driver->plat_auto;
 | 
			
		||||
		break;
 | 
			
		||||
	case DM_TAG_PARENT_PLAT:
 | 
			
		||||
		if (parent) {
 | 
			
		||||
			size = parent_drv->per_child_plat_auto;
 | 
			
		||||
			if (!size)
 | 
			
		||||
				size = parent->uclass->uc_drv->per_child_plat_auto;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case DM_TAG_UC_PLAT:
 | 
			
		||||
		size = uc_drv->per_device_plat_auto;
 | 
			
		||||
		break;
 | 
			
		||||
	case DM_TAG_PRIV:
 | 
			
		||||
		size = dev->driver->priv_auto;
 | 
			
		||||
		break;
 | 
			
		||||
	case DM_TAG_PARENT_PRIV:
 | 
			
		||||
		if (parent) {
 | 
			
		||||
			size = parent_drv->per_child_auto;
 | 
			
		||||
			if (!size)
 | 
			
		||||
				size = parent->uclass->uc_drv->per_child_auto;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case DM_TAG_UC_PRIV:
 | 
			
		||||
		size = uc_drv->per_device_auto;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int device_get_device_tail(struct udevice *dev, int ret,
 | 
			
		||||
				  struct udevice **devp)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -724,7 +788,7 @@ int device_get_child(const struct udevice *parent, int index,
 | 
			
		|||
{
 | 
			
		||||
	struct udevice *dev;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (!index--)
 | 
			
		||||
			return device_get_device_tail(dev, 0, devp);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -737,7 +801,7 @@ int device_get_child_count(const struct udevice *parent)
 | 
			
		|||
	struct udevice *dev;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node)
 | 
			
		||||
	device_foreach_child(dev, parent)
 | 
			
		||||
		count++;
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
| 
						 | 
				
			
			@ -748,7 +812,7 @@ int device_get_decendent_count(const struct udevice *parent)
 | 
			
		|||
	const struct udevice *dev;
 | 
			
		||||
	int count = 1;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node)
 | 
			
		||||
	device_foreach_child(dev, parent)
 | 
			
		||||
		count += device_get_decendent_count(dev);
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
| 
						 | 
				
			
			@ -761,7 +825,7 @@ int device_find_child_by_seq(const struct udevice *parent, int seq,
 | 
			
		|||
 | 
			
		||||
	*devp = NULL;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (dev->seq_ == seq) {
 | 
			
		||||
			*devp = dev;
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -790,7 +854,7 @@ int device_find_child_by_of_offset(const struct udevice *parent, int of_offset,
 | 
			
		|||
 | 
			
		||||
	*devp = NULL;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (dev_of_offset(dev) == of_offset) {
 | 
			
		||||
			*devp = dev;
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -819,7 +883,7 @@ static struct udevice *_device_find_global_by_ofnode(struct udevice *parent,
 | 
			
		|||
	if (ofnode_equal(dev_ofnode(parent), ofnode))
 | 
			
		||||
		return parent;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		found = _device_find_global_by_ofnode(dev, ofnode);
 | 
			
		||||
		if (found)
 | 
			
		||||
			return found;
 | 
			
		||||
| 
						 | 
				
			
			@ -897,7 +961,7 @@ int device_find_first_inactive_child(const struct udevice *parent,
 | 
			
		|||
	struct udevice *dev;
 | 
			
		||||
 | 
			
		||||
	*devp = NULL;
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (!device_active(dev) &&
 | 
			
		||||
		    device_get_uclass_id(dev) == uclass_id) {
 | 
			
		||||
			*devp = dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -915,7 +979,7 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
 | 
			
		|||
	struct udevice *dev;
 | 
			
		||||
 | 
			
		||||
	*devp = NULL;
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (device_get_uclass_id(dev) == uclass_id) {
 | 
			
		||||
			*devp = dev;
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -932,7 +996,7 @@ int device_find_child_by_namelen(const struct udevice *parent, const char *name,
 | 
			
		|||
 | 
			
		||||
	*devp = NULL;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node) {
 | 
			
		||||
	device_foreach_child(dev, parent) {
 | 
			
		||||
		if (!strncmp(dev->name, name, len) &&
 | 
			
		||||
		    strlen(dev->name) == len) {
 | 
			
		||||
			*devp = dev;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,7 +232,7 @@ static void dump_resources(struct udevice *dev, int depth)
 | 
			
		|||
		       (unsigned long)dr->size, dr->name,
 | 
			
		||||
		       devres_phase_name[dr->phase]);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(child, &dev->child_head, sibling_node)
 | 
			
		||||
	device_foreach_child(child, dev)
 | 
			
		||||
		dump_resources(child, depth + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,13 +39,13 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
 | 
			
		|||
 | 
			
		||||
	printf("%s\n", dev->name);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(child, &dev->child_head, sibling_node) {
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_dump_all(void)
 | 
			
		||||
void dm_dump_tree(void)
 | 
			
		||||
{
 | 
			
		||||
	struct udevice *root;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +89,6 @@ void dm_dump_uclass(void)
 | 
			
		|||
			continue;
 | 
			
		||||
 | 
			
		||||
		printf("uclass %d: %s\n", id, uc->uc_drv->name);
 | 
			
		||||
		if (list_empty(&uc->dev_head))
 | 
			
		||||
			continue;
 | 
			
		||||
		uclass_foreach_dev(dev, uc) {
 | 
			
		||||
			dm_display_line(dev, i);
 | 
			
		||||
			i++;
 | 
			
		||||
| 
						 | 
				
			
			@ -171,8 +169,79 @@ void dm_dump_static_driver_info(void)
 | 
			
		|||
 | 
			
		||||
	puts("Driver                    Address\n");
 | 
			
		||||
	puts("---------------------------------\n");
 | 
			
		||||
	for (entry = drv; entry != drv + n_ents; entry++) {
 | 
			
		||||
		printf("%-25.25s @%08lx\n", entry->name,
 | 
			
		||||
		       (ulong)map_to_sysmem(entry->plat));
 | 
			
		||||
	}
 | 
			
		||||
	for (entry = drv; entry != drv + n_ents; entry++)
 | 
			
		||||
		printf("%-25.25s %p\n", entry->name, entry->plat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_dump_mem(struct dm_stats *stats)
 | 
			
		||||
{
 | 
			
		||||
	int total, total_delta;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* Support SPL printf() */
 | 
			
		||||
	printf("Struct sizes: udevice %x, driver %x, uclass %x, uc_driver %x\n",
 | 
			
		||||
	       (int)sizeof(struct udevice), (int)sizeof(struct driver),
 | 
			
		||||
	       (int)sizeof(struct uclass), (int)sizeof(struct uclass_driver));
 | 
			
		||||
	printf("Memory: device %x:%x, device names %x, uclass %x:%x\n",
 | 
			
		||||
	       stats->dev_count, stats->dev_size, stats->dev_name_size,
 | 
			
		||||
	       stats->uc_count, stats->uc_size);
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("%-15s  %5s  %5s  %5s  %5s  %5s\n", "Attached type", "Count",
 | 
			
		||||
	       "Size", "Cur", "Tags", "Save");
 | 
			
		||||
	printf("%-15s  %5s  %5s  %5s  %5s  %5s\n", "---------------", "-----",
 | 
			
		||||
	       "-----", "-----", "-----", "-----");
 | 
			
		||||
	total_delta = 0;
 | 
			
		||||
	for (i = 0; i < DM_TAG_ATTACH_COUNT; i++) {
 | 
			
		||||
		int cur_size, new_size, delta;
 | 
			
		||||
 | 
			
		||||
		cur_size = stats->dev_count * sizeof(struct udevice);
 | 
			
		||||
		new_size = stats->dev_count * (sizeof(struct udevice) -
 | 
			
		||||
			sizeof(void *));
 | 
			
		||||
		/*
 | 
			
		||||
		 * Let's assume we can fit each dmtag_node into 32 bits. We can
 | 
			
		||||
		 * limit the 'tiny tags' feature to SPL with
 | 
			
		||||
		 * CONFIG_SPL_SYS_MALLOC_F_LEN <= 64KB, so needing 14 bits to
 | 
			
		||||
		 * point to anything in that region (with 4-byte alignment).
 | 
			
		||||
		 * So:
 | 
			
		||||
		 *    4 bits for tag
 | 
			
		||||
		 *    14 bits for offset of dev
 | 
			
		||||
		 *    14 bits for offset of data
 | 
			
		||||
		 */
 | 
			
		||||
		new_size += stats->attach_count[i] * sizeof(u32);
 | 
			
		||||
		delta = cur_size - new_size;
 | 
			
		||||
		total_delta += delta;
 | 
			
		||||
		printf("%-16s %5x %6x %6x %6x %6x (%d)\n", tag_get_name(i),
 | 
			
		||||
		       stats->attach_count[i], stats->attach_size[i],
 | 
			
		||||
		       cur_size, new_size, delta > 0 ? delta : 0, delta);
 | 
			
		||||
	}
 | 
			
		||||
	printf("%-16s %5x %6x\n", "uclass", stats->uc_attach_count,
 | 
			
		||||
	       stats->uc_attach_size);
 | 
			
		||||
	printf("%-16s %5x %6x  %5s  %5s  %6x (%d)\n", "Attached total",
 | 
			
		||||
	       stats->attach_count_total + stats->uc_attach_count,
 | 
			
		||||
	       stats->attach_size_total + stats->uc_attach_size, "", "",
 | 
			
		||||
	       total_delta > 0 ? total_delta : 0, total_delta);
 | 
			
		||||
	printf("%-16s %5x %6x\n", "tags", stats->tag_count, stats->tag_size);
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("Total size: %x (%d)\n", stats->total_size, stats->total_size);
 | 
			
		||||
	printf("\n");
 | 
			
		||||
 | 
			
		||||
	total = stats->total_size;
 | 
			
		||||
	total -= total_delta;
 | 
			
		||||
	printf("With tags:       %x (%d)\n", total, total);
 | 
			
		||||
 | 
			
		||||
	/* Use singly linked lists in struct udevice (3 nodes in each) */
 | 
			
		||||
	total -= sizeof(void *) * 3 * stats->dev_count;
 | 
			
		||||
	printf("- singly-linked: %x (%d)\n", total, total);
 | 
			
		||||
 | 
			
		||||
	/* Use an index into the struct_driver list instead of a pointer */
 | 
			
		||||
	total = total + stats->dev_count * (1 - sizeof(void *));
 | 
			
		||||
	printf("- driver index:  %x (%d)\n", total, total);
 | 
			
		||||
 | 
			
		||||
	/* Same with the uclass */
 | 
			
		||||
	total = total + stats->dev_count * (1 - sizeof(void *));
 | 
			
		||||
	printf("- uclass index:  %x (%d)\n", total, total);
 | 
			
		||||
 | 
			
		||||
	/* Drop the device name */
 | 
			
		||||
	printf("Drop device name (not SRAM): %x (%d)\n", stats->dev_name_size,
 | 
			
		||||
	       stats->dev_name_size);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -449,6 +449,59 @@ void dm_get_stats(int *device_countp, int *uclass_countp)
 | 
			
		|||
	*uclass_countp = uclass_get_count();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dev_collect_stats(struct dm_stats *stats, const struct udevice *parent)
 | 
			
		||||
{
 | 
			
		||||
	const struct udevice *dev;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	stats->dev_count++;
 | 
			
		||||
	stats->dev_size += sizeof(struct udevice);
 | 
			
		||||
	stats->dev_name_size += strlen(parent->name) + 1;
 | 
			
		||||
	for (i = 0; i < DM_TAG_ATTACH_COUNT; i++) {
 | 
			
		||||
		int size = dev_get_attach_size(parent, i);
 | 
			
		||||
 | 
			
		||||
		if (size ||
 | 
			
		||||
		    (i == DM_TAG_DRIVER_DATA && parent->driver_data)) {
 | 
			
		||||
			stats->attach_count[i]++;
 | 
			
		||||
			stats->attach_size[i] += size;
 | 
			
		||||
			stats->attach_count_total++;
 | 
			
		||||
			stats->attach_size_total += size;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(dev, &parent->child_head, sibling_node)
 | 
			
		||||
		dev_collect_stats(stats, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uclass_collect_stats(struct dm_stats *stats)
 | 
			
		||||
{
 | 
			
		||||
	struct uclass *uc;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(uc, gd->uclass_root, sibling_node) {
 | 
			
		||||
		int size;
 | 
			
		||||
 | 
			
		||||
		stats->uc_count++;
 | 
			
		||||
		stats->uc_size += sizeof(struct uclass);
 | 
			
		||||
		size = uc->uc_drv->priv_auto;
 | 
			
		||||
		if (size) {
 | 
			
		||||
			stats->uc_attach_count++;
 | 
			
		||||
			stats->uc_attach_size += size;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_get_mem(struct dm_stats *stats)
 | 
			
		||||
{
 | 
			
		||||
	memset(stats, '\0', sizeof(*stats));
 | 
			
		||||
	dev_collect_stats(stats, gd->dm_root);
 | 
			
		||||
	uclass_collect_stats(stats);
 | 
			
		||||
	dev_tag_collect_stats(stats);
 | 
			
		||||
 | 
			
		||||
	stats->total_size = stats->dev_size + stats->uc_size +
 | 
			
		||||
		stats->attach_size_total + stats->uc_attach_size +
 | 
			
		||||
		stats->tag_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ACPIGEN
 | 
			
		||||
static int root_acpi_get_name(const struct udevice *dev, char *out_name)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#include <asm/global_data.h>
 | 
			
		||||
#include <dm/root.h>
 | 
			
		||||
#include <dm/tag.h>
 | 
			
		||||
#include <linux/err.h>
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +16,24 @@ struct udevice;
 | 
			
		|||
 | 
			
		||||
DECLARE_GLOBAL_DATA_PTR;
 | 
			
		||||
 | 
			
		||||
static const char *const tag_name[] = {
 | 
			
		||||
	[DM_TAG_PLAT]		= "plat",
 | 
			
		||||
	[DM_TAG_PARENT_PLAT]	= "parent_plat",
 | 
			
		||||
	[DM_TAG_UC_PLAT]	= "uclass_plat",
 | 
			
		||||
 | 
			
		||||
	[DM_TAG_PRIV]		= "priv",
 | 
			
		||||
	[DM_TAG_PARENT_PRIV]	= "parent_priv",
 | 
			
		||||
	[DM_TAG_UC_PRIV]	= "uclass_priv",
 | 
			
		||||
	[DM_TAG_DRIVER_DATA]	= "driver_data",
 | 
			
		||||
 | 
			
		||||
	[DM_TAG_EFI]		= "efi",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *tag_get_name(enum dm_tag_t tag)
 | 
			
		||||
{
 | 
			
		||||
	return tag_name[tag];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct dmtag_node *node;
 | 
			
		||||
| 
						 | 
				
			
			@ -137,3 +156,13 @@ int dev_tag_del_all(struct udevice *dev)
 | 
			
		|||
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dev_tag_collect_stats(struct dm_stats *stats)
 | 
			
		||||
{
 | 
			
		||||
	struct dmtag_node *node;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(node, &gd->dmtag_list, sibling) {
 | 
			
		||||
		stats->tag_count++;
 | 
			
		||||
		stats->tag_size += sizeof(struct dmtag_node);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
 | 
			
		|||
{
 | 
			
		||||
	u16 entry;
 | 
			
		||||
	u32 control = be32_to_cpu(dma->control);
 | 
			
		||||
	void *address = (void *)be64_to_cpu(dma->address);
 | 
			
		||||
	void *address = (void *)(uintptr_t)be64_to_cpu(dma->address);
 | 
			
		||||
	u32 length = be32_to_cpu(dma->length);
 | 
			
		||||
	struct qfw_sandbox_plat *plat = dev_get_plat(dev);
 | 
			
		||||
	struct fw_cfg_file *file;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,8 +108,10 @@ UCLASS_DRIVER(testbus) = {
 | 
			
		|||
	.child_pre_probe = testbus_child_pre_probe_uclass,
 | 
			
		||||
	.child_post_probe = testbus_child_post_probe_uclass,
 | 
			
		||||
 | 
			
		||||
	/* This is for dtoc testing only */
 | 
			
		||||
	.per_device_plat_auto   = sizeof(struct dm_test_uclass_priv),
 | 
			
		||||
	.per_device_auto   = sizeof(struct dm_test_uclass_priv),
 | 
			
		||||
 | 
			
		||||
	/* Note: this is for dtoc testing as well as tags*/
 | 
			
		||||
	.per_device_plat_auto   = sizeof(struct dm_test_uclass_plat),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,9 +228,9 @@ static void handle_read(struct sandbox_flash_priv *priv, ulong lba,
 | 
			
		|||
			ulong transfer_len)
 | 
			
		||||
{
 | 
			
		||||
	debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
 | 
			
		||||
	priv->read_len = transfer_len;
 | 
			
		||||
	if (priv->fd != -1) {
 | 
			
		||||
		os_lseek(priv->fd, lba * SANDBOX_FLASH_BLOCK_LEN, OS_SEEK_SET);
 | 
			
		||||
		priv->read_len = transfer_len;
 | 
			
		||||
		setup_response(priv, priv->buff,
 | 
			
		||||
			       transfer_len * SANDBOX_FLASH_BLOCK_LEN);
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -336,6 +336,9 @@ static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
 | 
			
		|||
			if (priv->read_len) {
 | 
			
		||||
				ulong bytes_read;
 | 
			
		||||
 | 
			
		||||
				if (priv->fd == -1)
 | 
			
		||||
					return -EIO;
 | 
			
		||||
 | 
			
		||||
				bytes_read = os_read(priv->fd, buff, len);
 | 
			
		||||
				if (bytes_read != len)
 | 
			
		||||
					return -EIO;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,9 +11,11 @@
 | 
			
		|||
#ifndef __BINMAN_SYM_H
 | 
			
		||||
#define __BINMAN_SYM_H
 | 
			
		||||
 | 
			
		||||
/* BSYM in little endian, keep in sync with tools/binman/elf.py */
 | 
			
		||||
#define BINMAN_SYM_MAGIC_VALUE	(0x4d595342UL)
 | 
			
		||||
#define BINMAN_SYM_MISSING	(-1UL)
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_BINMAN
 | 
			
		||||
#if CONFIG_IS_ENABLED(BINMAN_SYMBOLS)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * binman_symname() - Internal function to get a binman symbol name
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +64,37 @@
 | 
			
		|||
		__attribute__((aligned(4), weak, unused, \
 | 
			
		||||
		section(".binman_sym")))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * _binman_sym_magic - Internal magic symbol for validity checks
 | 
			
		||||
 *
 | 
			
		||||
 * When building images, binman fills in this symbol with the magic
 | 
			
		||||
 * value #defined above. This is used to check at runtime if the
 | 
			
		||||
 * symbol values were filled in and are OK to use.
 | 
			
		||||
 */
 | 
			
		||||
extern ulong _binman_sym_magic;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * DECLARE_BINMAN_MAGIC_SYM - Declare the internal magic symbol
 | 
			
		||||
 *
 | 
			
		||||
 * This macro declares the _binman_sym_magic symbol so that it exists.
 | 
			
		||||
 * Declaring it here would cause errors during linking due to multiple
 | 
			
		||||
 * definitions of the symbol.
 | 
			
		||||
 */
 | 
			
		||||
#define DECLARE_BINMAN_MAGIC_SYM \
 | 
			
		||||
	ulong _binman_sym_magic \
 | 
			
		||||
		__attribute__((aligned(4), section(".binman_sym")))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * BINMAN_SYMS_OK - Check if the symbol values are valid
 | 
			
		||||
 *
 | 
			
		||||
 * This macro checks if the magic symbol's value is filled properly,
 | 
			
		||||
 * which indicates that other symbols are OK to use as well.
 | 
			
		||||
 *
 | 
			
		||||
 * Return: 1 if binman symbol values are usable, 0 if not
 | 
			
		||||
 */
 | 
			
		||||
#define BINMAN_SYMS_OK \
 | 
			
		||||
	(*(ulong *)&_binman_sym_magic == BINMAN_SYM_MAGIC_VALUE)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * binman_sym() - Access a previously declared symbol
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -72,12 +105,16 @@
 | 
			
		|||
 * @_type: Type f the symbol (e.g. unsigned long)
 | 
			
		||||
 * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
 | 
			
		||||
 * @_prop_name: Property value to get from that entry (e.g. 'pos')
 | 
			
		||||
 * @returns value of that property (filled in by binman)
 | 
			
		||||
 *
 | 
			
		||||
 * Return: value of that property (filled in by binman), or
 | 
			
		||||
 *	   BINMAN_SYM_MISSING if the value is unavailable
 | 
			
		||||
 */
 | 
			
		||||
#define binman_sym(_type, _entry_name, _prop_name) \
 | 
			
		||||
	(*(_type *)&binman_symname(_entry_name, _prop_name))
 | 
			
		||||
	(BINMAN_SYMS_OK ? \
 | 
			
		||||
	 (*(_type *)&binman_symname(_entry_name, _prop_name)) : \
 | 
			
		||||
	 BINMAN_SYM_MISSING)
 | 
			
		||||
 | 
			
		||||
#else /* !BINMAN */
 | 
			
		||||
#else /* !CONFIG_IS_ENABLED(BINMAN_SYMBOLS) */
 | 
			
		||||
 | 
			
		||||
#define binman_sym_declare(_type, _entry_name, _prop_name)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -85,8 +122,12 @@
 | 
			
		|||
 | 
			
		||||
#define binman_sym_extern(_type, _entry_name, _prop_name)
 | 
			
		||||
 | 
			
		||||
#define DECLARE_BINMAN_MAGIC_SYM
 | 
			
		||||
 | 
			
		||||
#define BINMAN_SYMS_OK (0)
 | 
			
		||||
 | 
			
		||||
#define binman_sym(_type, _entry_name, _prop_name) BINMAN_SYM_MISSING
 | 
			
		||||
 | 
			
		||||
#endif /* BINMAN */
 | 
			
		||||
#endif /* CONFIG_IS_ENABLED(BINMAN_SYMBOLS) */
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,66 @@
 | 
			
		|||
 * This provides a standard way of passing information between boot phases
 | 
			
		||||
 * (TPL -> SPL -> U-Boot proper.)
 | 
			
		||||
 *
 | 
			
		||||
 * A list of blobs of data, tagged with their owner. The list resides in memory
 | 
			
		||||
 * and can be updated by SPL, U-Boot, etc.
 | 
			
		||||
 * It consists of a list of blobs of data, tagged with their owner / contents.
 | 
			
		||||
 * The list resides in memory and can be updated by SPL, U-Boot, etc.
 | 
			
		||||
 *
 | 
			
		||||
 * Design goals for bloblist:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Small and efficient structure. This avoids UUIDs or 16-byte name fields,
 | 
			
		||||
 * since a 32-bit tag provides enough space for all the tags we will even need.
 | 
			
		||||
 * If UUIDs are desired, they can be added inside a particular blob.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Avoids use of pointers, so the structure can be relocated in memory. The
 | 
			
		||||
 * data in each blob is inline, rather than using pointers.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Bloblist is designed to start small in TPL or SPL, when only a few things
 | 
			
		||||
 * are needed, like the memory size or whether console output should be enabled.
 | 
			
		||||
 * Then it can grow in U-Boot proper, e.g. to include space for ACPI tables.
 | 
			
		||||
 *
 | 
			
		||||
 * 4. The bloblist structure is simple enough that it can be implemented in a
 | 
			
		||||
 * small amount of C code. The API does not require use of strings or UUIDs,
 | 
			
		||||
 * which would add to code size. For Thumb-2 the code size needed in SPL is
 | 
			
		||||
 * approximately 940 bytes (e.g. for chromebook_bob).
 | 
			
		||||
 *
 | 
			
		||||
 * 5. Bloblist uses 16-byte alignment internally and is designed to start on a
 | 
			
		||||
 * 16-byte boundary. Its headers are multiples of 16 bytes. This makes it easier
 | 
			
		||||
 * to deal with data structures which need this level of alignment, such as ACPI
 | 
			
		||||
 * tables. For use in SPL and TPL the alignment can be relaxed, since it can be
 | 
			
		||||
 * relocated to an aligned address in U-Boot proper.
 | 
			
		||||
 *
 | 
			
		||||
 * 6. Bloblist is designed to be passed to Linux as reserved memory. While linux
 | 
			
		||||
 * doesn't understand the bloblist header, it can be passed the indivdual blobs.
 | 
			
		||||
 * For example, ACPI tables can reside in a blob and the address of those is
 | 
			
		||||
 * passed to Linux, without Linux ever being away of the existence of a
 | 
			
		||||
 * bloblist. Having all the blobs contiguous in memory simplifies the
 | 
			
		||||
 * reserved-memory space.
 | 
			
		||||
 *
 | 
			
		||||
 * 7. Bloblist tags are defined in the enum below. There is an area for
 | 
			
		||||
 * project-specific stuff (e.g. U-Boot, TF-A) and vendor-specific stuff, e.g.
 | 
			
		||||
 * something used only on a particular SoC. There is also a private area for
 | 
			
		||||
 * temporary, local use.
 | 
			
		||||
 *
 | 
			
		||||
 * 8. Bloblist includes a simple checksum, so that each boot phase can update
 | 
			
		||||
 * this and allow the next phase to check that all is well. While the bloblist
 | 
			
		||||
 * is small, this is quite cheap to calculate. When it grows (e.g. in U-Boot\
 | 
			
		||||
 * proper), the CPU is likely running faster, so it is not prohibitive. Having
 | 
			
		||||
 * said that, U-Boot is often the last phase that uses bloblist, so calculating
 | 
			
		||||
 * the checksum there may not be necessary.
 | 
			
		||||
 *
 | 
			
		||||
 * 9. It would be possible to extend bloblist to support a non-contiguous
 | 
			
		||||
 * structure, e.g. by creating a blob type that points to the next bloblist.
 | 
			
		||||
 * This does not seem necessary for now. It adds complexity and code. We can
 | 
			
		||||
 * always just copy it.
 | 
			
		||||
 *
 | 
			
		||||
 * 10. Bloblist is designed for simple structures, those that can be defined by
 | 
			
		||||
 * a single C struct. More complex structures should be passed in a device tree.
 | 
			
		||||
 * There are some exceptions, chiefly the various binary structures that Intel
 | 
			
		||||
 * is fond of creating. But device tree provides a dictionary-type format which
 | 
			
		||||
 * is fairly efficient (for use in U-Boot proper and Linux at least), along with
 | 
			
		||||
 * a schema and a good set of tools. New formats should be designed around
 | 
			
		||||
 * device tree rather than creating new binary formats, unless they are needed
 | 
			
		||||
 * early in boot (where libfdt's 3KB of overhead is too large) and are trival
 | 
			
		||||
 * enough to be described by a C struct.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2018 Google, Inc
 | 
			
		||||
 * Written by Simon Glass <sjg@chromium.org>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
#define _DM_DEVICE_H
 | 
			
		||||
 | 
			
		||||
#include <dm/ofnode.h>
 | 
			
		||||
#include <dm/tag.h>
 | 
			
		||||
#include <dm/uclass-id.h>
 | 
			
		||||
#include <fdtdec.h>
 | 
			
		||||
#include <linker_lists.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -546,6 +547,30 @@ void *dev_get_parent_priv(const struct udevice *dev);
 | 
			
		|||
 */
 | 
			
		||||
void *dev_get_uclass_priv(const struct udevice *dev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dev_get_attach_ptr() - Get the value of an attached pointed tag
 | 
			
		||||
 *
 | 
			
		||||
 * The tag is assumed to hold a pointer, if it exists
 | 
			
		||||
 *
 | 
			
		||||
 * @dev: Device to look at
 | 
			
		||||
 * @tag: Tag to access
 | 
			
		||||
 * @return value of tag, or NULL if there is no tag of this type
 | 
			
		||||
 */
 | 
			
		||||
void *dev_get_attach_ptr(const struct udevice *dev, enum dm_tag_t tag);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dev_get_attach_size() - Get the size of an attached tag
 | 
			
		||||
 *
 | 
			
		||||
 * Core tags have an automatic-allocation mechanism where the allocated size is
 | 
			
		||||
 * defined by the device, parent or uclass. This returns the size associated
 | 
			
		||||
 * with a particular tag
 | 
			
		||||
 *
 | 
			
		||||
 * @dev: Device to look at
 | 
			
		||||
 * @tag: Tag to access
 | 
			
		||||
 * @return size of auto-allocated data, 0 if none
 | 
			
		||||
 */
 | 
			
		||||
int dev_get_attach_size(const struct udevice *dev, enum dm_tag_t tag);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dev_get_parent() - Get the parent of a device
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1181,6 +1181,33 @@ int ofnode_write_string(ofnode node, const char *propname, const char *value);
 | 
			
		|||
 */
 | 
			
		||||
int ofnode_set_enabled(ofnode node, bool value);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ofnode_get_phy_node() - Get PHY node for a MAC (if not fixed-link)
 | 
			
		||||
 *
 | 
			
		||||
 * This function parses PHY handle from the Ethernet controller's ofnode
 | 
			
		||||
 * (trying all possible PHY handle property names), and returns the PHY ofnode.
 | 
			
		||||
 *
 | 
			
		||||
 * Before this is used, ofnode_phy_is_fixed_link() should be checked first, and
 | 
			
		||||
 * if the result to that is true, this function should not be called.
 | 
			
		||||
 *
 | 
			
		||||
 * @eth_node:	ofnode belonging to the Ethernet controller
 | 
			
		||||
 * Return: ofnode of the PHY, if it exists, otherwise an invalid ofnode
 | 
			
		||||
 */
 | 
			
		||||
ofnode ofnode_get_phy_node(ofnode eth_node);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ofnode_read_phy_mode() - Read PHY connection type from a MAC node
 | 
			
		||||
 *
 | 
			
		||||
 * This function parses the "phy-mode" / "phy-connection-type" property and
 | 
			
		||||
 * returns the corresponding PHY interface type.
 | 
			
		||||
 *
 | 
			
		||||
 * @mac_node:	ofnode containing the property
 | 
			
		||||
 * Return: one of PHY_INTERFACE_MODE_* constants, PHY_INTERFACE_MODE_NA on
 | 
			
		||||
 *	   error
 | 
			
		||||
 */
 | 
			
		||||
phy_interface_t ofnode_read_phy_mode(ofnode mac_node);
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(DM)
 | 
			
		||||
/**
 | 
			
		||||
 * ofnode_conf_read_bool() - Read a boolean value from the U-Boot config
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1218,30 +1245,21 @@ int ofnode_conf_read_int(const char *prop_name, int default_val);
 | 
			
		|||
 */
 | 
			
		||||
const char *ofnode_conf_read_str(const char *prop_name);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ofnode_get_phy_node() - Get PHY node for a MAC (if not fixed-link)
 | 
			
		||||
 *
 | 
			
		||||
 * This function parses PHY handle from the Ethernet controller's ofnode
 | 
			
		||||
 * (trying all possible PHY handle property names), and returns the PHY ofnode.
 | 
			
		||||
 *
 | 
			
		||||
 * Before this is used, ofnode_phy_is_fixed_link() should be checked first, and
 | 
			
		||||
 * if the result to that is true, this function should not be called.
 | 
			
		||||
 *
 | 
			
		||||
 * @eth_node:	ofnode belonging to the Ethernet controller
 | 
			
		||||
 * Return: ofnode of the PHY, if it exists, otherwise an invalid ofnode
 | 
			
		||||
 */
 | 
			
		||||
ofnode ofnode_get_phy_node(ofnode eth_node);
 | 
			
		||||
#else /* CONFIG_DM */
 | 
			
		||||
static inline bool ofnode_conf_read_bool(const char *prop_name)
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ofnode_read_phy_mode() - Read PHY connection type from a MAC node
 | 
			
		||||
 *
 | 
			
		||||
 * This function parses the "phy-mode" / "phy-connection-type" property and
 | 
			
		||||
 * returns the corresponding PHY interface type.
 | 
			
		||||
 *
 | 
			
		||||
 * @mac_node:	ofnode containing the property
 | 
			
		||||
 * Return: one of PHY_INTERFACE_MODE_* constants, PHY_INTERFACE_MODE_NA on
 | 
			
		||||
 *	   error
 | 
			
		||||
 */
 | 
			
		||||
phy_interface_t ofnode_read_phy_mode(ofnode mac_node);
 | 
			
		||||
static inline int ofnode_conf_read_int(const char *prop_name, int default_val)
 | 
			
		||||
{
 | 
			
		||||
	return default_val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline const char *ofnode_conf_read_str(const char *prop_name)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_DM */
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,11 +9,49 @@
 | 
			
		|||
#ifndef _DM_ROOT_H_
 | 
			
		||||
#define _DM_ROOT_H_
 | 
			
		||||
 | 
			
		||||
#include <dm/tag.h>
 | 
			
		||||
 | 
			
		||||
struct udevice;
 | 
			
		||||
 | 
			
		||||
/* Head of the uclass list if CONFIG_OF_PLATDATA_INST is enabled */
 | 
			
		||||
extern struct list_head uclass_head;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct dm_stats - Information about driver model memory usage
 | 
			
		||||
 *
 | 
			
		||||
 * @total_size: All data
 | 
			
		||||
 * @dev_count: Number of devices
 | 
			
		||||
 * @dev_size: Size of all devices (just the struct udevice)
 | 
			
		||||
 * @dev_name_size: Bytes used by device names
 | 
			
		||||
 * @uc_count: Number of uclasses
 | 
			
		||||
 * @uc_size: Size of all uclasses (just the struct uclass)
 | 
			
		||||
 * @tag_count: Number of tags
 | 
			
		||||
 * @tag_size: Bytes used by all tags
 | 
			
		||||
 * @uc_attach_count: Number of uclasses with attached data (priv)
 | 
			
		||||
 * @uc_attach_size: Total size of that attached data
 | 
			
		||||
 * @attach_count_total: Total number of attached data items for all udevices and
 | 
			
		||||
 *	uclasses
 | 
			
		||||
 * @attach_size_total: Total number of bytes of attached data
 | 
			
		||||
 * @attach_count: Number of devices with attached, for each type
 | 
			
		||||
 * @attach_size: Total number of bytes of attached data, for each type
 | 
			
		||||
 */
 | 
			
		||||
struct dm_stats {
 | 
			
		||||
	int total_size;
 | 
			
		||||
	int dev_count;
 | 
			
		||||
	int dev_size;
 | 
			
		||||
	int dev_name_size;
 | 
			
		||||
	int uc_count;
 | 
			
		||||
	int uc_size;
 | 
			
		||||
	int tag_count;
 | 
			
		||||
	int tag_size;
 | 
			
		||||
	int uc_attach_count;
 | 
			
		||||
	int uc_attach_size;
 | 
			
		||||
	int attach_count_total;
 | 
			
		||||
	int attach_size_total;
 | 
			
		||||
	int attach_count[DM_TAG_ATTACH_COUNT];
 | 
			
		||||
	int attach_size[DM_TAG_ATTACH_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dm_root() - Return pointer to the top of the driver tree
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -141,4 +179,11 @@ static inline int dm_remove_devices_flags(uint flags) { return 0; }
 | 
			
		|||
 */
 | 
			
		||||
void dm_get_stats(int *device_countp, int *uclass_countp);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dm_get_mem() - Get stats on memory usage in driver model
 | 
			
		||||
 *
 | 
			
		||||
 * @stats: Place to put the information
 | 
			
		||||
 */
 | 
			
		||||
void dm_get_mem(struct dm_stats *stats);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,11 +10,23 @@
 | 
			
		|||
#include <linux/list.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
struct dm_stats;
 | 
			
		||||
struct udevice;
 | 
			
		||||
 | 
			
		||||
enum dm_tag_t {
 | 
			
		||||
	/* Types of core tags that can be attached to devices */
 | 
			
		||||
	DM_TAG_PLAT,
 | 
			
		||||
	DM_TAG_PARENT_PLAT,
 | 
			
		||||
	DM_TAG_UC_PLAT,
 | 
			
		||||
 | 
			
		||||
	DM_TAG_PRIV,
 | 
			
		||||
	DM_TAG_PARENT_PRIV,
 | 
			
		||||
	DM_TAG_UC_PRIV,
 | 
			
		||||
	DM_TAG_DRIVER_DATA,
 | 
			
		||||
	DM_TAG_ATTACH_COUNT,
 | 
			
		||||
 | 
			
		||||
	/* EFI_LOADER */
 | 
			
		||||
	DM_TAG_EFI = 0,
 | 
			
		||||
	DM_TAG_EFI = DM_TAG_ATTACH_COUNT,
 | 
			
		||||
 | 
			
		||||
	DM_TAG_COUNT,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -107,4 +119,22 @@ int dev_tag_del(struct udevice *dev, enum dm_tag_t tag);
 | 
			
		|||
 */
 | 
			
		||||
int dev_tag_del_all(struct udevice *dev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dev_tag_collect_stats() - Collect information on driver model performance
 | 
			
		||||
 *
 | 
			
		||||
 * This collects information on how driver model is performing. For now it only
 | 
			
		||||
 * includes memory usage
 | 
			
		||||
 *
 | 
			
		||||
 * @stats: Place to put the collected information
 | 
			
		||||
 */
 | 
			
		||||
void dev_tag_collect_stats(struct dm_stats *stats);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * tag_get_name() - Get the name of a tag
 | 
			
		||||
 *
 | 
			
		||||
 * @tag: Tag to look up, which must be valid
 | 
			
		||||
 * Returns: Name of tag
 | 
			
		||||
 */
 | 
			
		||||
const char *tag_get_name(enum dm_tag_t tag);
 | 
			
		||||
 | 
			
		||||
#endif /* _DM_TAG_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,6 +92,13 @@ struct dm_test_uclass_priv {
 | 
			
		|||
	int total_add;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct dm_test_uclass_plat - private plat data for test uclass
 | 
			
		||||
 */
 | 
			
		||||
struct dm_test_uclass_plat {
 | 
			
		||||
	char dummy[32];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct dm_test_parent_data - parent's information on each child
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@
 | 
			
		|||
#ifndef __DM_UTIL_H
 | 
			
		||||
#define __DM_UTIL_H
 | 
			
		||||
 | 
			
		||||
struct dm_stats;
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(DM_WARN)
 | 
			
		||||
#define dm_warn(fmt...) log(LOGC_DM, LOGL_WARNING, ##fmt)
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +27,7 @@ struct list_head;
 | 
			
		|||
int list_count_items(struct list_head *head);
 | 
			
		||||
 | 
			
		||||
/* Dump out a tree of all devices */
 | 
			
		||||
void dm_dump_all(void);
 | 
			
		||||
void dm_dump_tree(void);
 | 
			
		||||
 | 
			
		||||
/* Dump out a list of uclasses and their devices */
 | 
			
		||||
void dm_dump_uclass(void);
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +50,13 @@ void dm_dump_driver_compat(void);
 | 
			
		|||
/* Dump out a list of drivers with static platform data */
 | 
			
		||||
void dm_dump_static_driver_info(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dm_dump_mem() - Dump stats on memory usage in driver model
 | 
			
		||||
 *
 | 
			
		||||
 * @mem: Stats to dump
 | 
			
		||||
 */
 | 
			
		||||
void dm_dump_mem(struct dm_stats *stats);
 | 
			
		||||
 | 
			
		||||
#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
 | 
			
		||||
void *dm_priv_to_rw(void *priv);
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,13 @@
 | 
			
		|||
struct rtc_time;
 | 
			
		||||
struct sandbox_state;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * os_printf() - print directly to OS console
 | 
			
		||||
 *
 | 
			
		||||
 * @format: format string
 | 
			
		||||
 */
 | 
			
		||||
int os_printf(const char *format, ...);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Access to the OS read() system call
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -288,6 +288,8 @@ binman_sym_extern(ulong, u_boot_any, image_pos);
 | 
			
		|||
binman_sym_extern(ulong, u_boot_any, size);
 | 
			
		||||
binman_sym_extern(ulong, u_boot_spl, image_pos);
 | 
			
		||||
binman_sym_extern(ulong, u_boot_spl, size);
 | 
			
		||||
binman_sym_extern(ulong, u_boot_vpl, image_pos);
 | 
			
		||||
binman_sym_extern(ulong, u_boot_vpl, size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * spl_get_image_pos() - get the image position of the next phase
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1275,3 +1275,94 @@ static int dm_test_uclass_find_device(struct unit_test_state *uts)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
DM_TEST(dm_test_uclass_find_device, UT_TESTF_SCAN_FDT);
 | 
			
		||||
 | 
			
		||||
/* Test getting information about tags attached to devices */
 | 
			
		||||
static int dm_test_dev_get_attach(struct unit_test_state *uts)
 | 
			
		||||
{
 | 
			
		||||
	struct udevice *dev;
 | 
			
		||||
 | 
			
		||||
	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
 | 
			
		||||
	ut_asserteq_str("a-test", dev->name);
 | 
			
		||||
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_PLAT));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_PRIV));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_pdata),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_PLAT));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_priv),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_PRIV));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
DM_TEST(dm_test_dev_get_attach, UT_TESTF_SCAN_FDT);
 | 
			
		||||
 | 
			
		||||
/* Test getting information about tags attached to bus devices */
 | 
			
		||||
static int dm_test_dev_get_attach_bus(struct unit_test_state *uts)
 | 
			
		||||
{
 | 
			
		||||
	struct udevice *dev, *child;
 | 
			
		||||
 | 
			
		||||
	ut_assertok(uclass_first_device_err(UCLASS_TEST_BUS, &dev));
 | 
			
		||||
	ut_asserteq_str("some-bus", dev->name);
 | 
			
		||||
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_PLAT));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_PRIV));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(dev, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(dev, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_pdata),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_PLAT));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_priv),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_PRIV));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_uclass_priv),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_uclass_plat),
 | 
			
		||||
		    dev_get_attach_size(dev, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(dev, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	/* Now try the child of the bus */
 | 
			
		||||
	ut_assertok(device_first_child_err(dev, &child));
 | 
			
		||||
	ut_asserteq_str("c-test@5", child->name);
 | 
			
		||||
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(child, DM_TAG_PLAT));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(child, DM_TAG_PRIV));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(child, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_assertnull(dev_get_attach_ptr(child, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(child, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_assertnonnull(dev_get_attach_ptr(child, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_pdata),
 | 
			
		||||
		    dev_get_attach_size(child, DM_TAG_PLAT));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_priv),
 | 
			
		||||
		    dev_get_attach_size(child, DM_TAG_PRIV));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(child, DM_TAG_UC_PRIV));
 | 
			
		||||
	ut_asserteq(0, dev_get_attach_size(child, DM_TAG_UC_PLAT));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_parent_plat),
 | 
			
		||||
		    dev_get_attach_size(child, DM_TAG_PARENT_PLAT));
 | 
			
		||||
	ut_asserteq(sizeof(struct dm_test_parent_data),
 | 
			
		||||
		    dev_get_attach_size(child, DM_TAG_PARENT_PRIV));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
DM_TEST(dm_test_dev_get_attach_bus, UT_TESTF_SCAN_FDT);
 | 
			
		||||
 | 
			
		||||
/* Test getting information about tags attached to bus devices */
 | 
			
		||||
static int dm_test_dev_get_mem(struct unit_test_state *uts)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_stats stats;
 | 
			
		||||
 | 
			
		||||
	dm_get_mem(&stats);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
DM_TEST(dm_test_dev_get_mem, UT_TESTF_SCAN_FDT);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,186 +1,191 @@
 | 
			
		|||
# SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
 | 
			
		||||
 | 
			
		||||
import os.path
 | 
			
		||||
import pytest
 | 
			
		||||
""" Test for bind command """
 | 
			
		||||
 | 
			
		||||
import re
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
def in_tree(response, name, uclass, drv, depth, last_child):
 | 
			
		||||
	lines = [x.strip() for x in response.splitlines()]
 | 
			
		||||
	leaf = ''
 | 
			
		||||
	if depth != 0:
 | 
			
		||||
		leaf = '   ' + '    ' * (depth - 1) ;
 | 
			
		||||
		if not last_child:
 | 
			
		||||
			leaf = leaf + r'\|'
 | 
			
		||||
		else:
 | 
			
		||||
                        leaf = leaf + '`'
 | 
			
		||||
    lines = [x.strip() for x in response.splitlines()]
 | 
			
		||||
    leaf = ''
 | 
			
		||||
    if depth != 0:
 | 
			
		||||
        leaf = '   ' + '    ' * (depth - 1)
 | 
			
		||||
        if not last_child:
 | 
			
		||||
            leaf = leaf + r'\|'
 | 
			
		||||
        else:
 | 
			
		||||
            leaf = leaf + '`'
 | 
			
		||||
 | 
			
		||||
	leaf = leaf + '-- ' + name
 | 
			
		||||
	line = (r' *{:10.10} *[0-9]*  \[ [ +] \]   {:20.20}  [` |]{}$'
 | 
			
		||||
	        .format(uclass, drv, leaf))
 | 
			
		||||
	prog = re.compile(line)
 | 
			
		||||
	for l in lines:
 | 
			
		||||
		if prog.match(l):
 | 
			
		||||
			return True
 | 
			
		||||
	return False
 | 
			
		||||
    leaf = leaf + '-- ' + name
 | 
			
		||||
    line = (r' *{:10.10} *[0-9]*  \[ [ +] \]   {:20.20}  [` |]{}$'
 | 
			
		||||
            .format(uclass, drv, leaf))
 | 
			
		||||
    prog = re.compile(line)
 | 
			
		||||
    for l in lines:
 | 
			
		||||
        if prog.match(l):
 | 
			
		||||
            return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.buildconfigspec('cmd_bind')
 | 
			
		||||
def test_bind_unbind_with_node(u_boot_console):
 | 
			
		||||
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
 | 
			
		||||
	#bind usb_ether driver (which has no compatible) to usb@1 node.
 | 
			
		||||
	##New entry usb_ether should appear in the dm tree
 | 
			
		||||
	response = u_boot_console.run_command('bind  /usb@1 usb_ether')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'usb@1', 'ethernet', 'usb_ether', 1, True)
 | 
			
		||||
    #bind usb_ether driver (which has no compatible) to usb@1 node.
 | 
			
		||||
    ##New entry usb_ether should appear in the dm tree
 | 
			
		||||
    response = u_boot_console.run_command('bind  /usb@1 usb_ether')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'usb@1', 'ethernet', 'usb_ether', 1, True)
 | 
			
		||||
 | 
			
		||||
	#Unbind child #1. No error expected and all devices should be there except for bind-test-child1
 | 
			
		||||
	response = u_boot_console.run_command('unbind  /bind-test/bind-test-child1')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert 'bind-test-child1' not in tree
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    #Unbind child #1. No error expected and all devices should be there except for bind-test-child1
 | 
			
		||||
    response = u_boot_console.run_command('unbind  /bind-test/bind-test-child1')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert 'bind-test-child1' not in tree
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
 | 
			
		||||
	#bind child #1. No error expected and all devices should be there
 | 
			
		||||
	response = u_boot_console.run_command('bind  /bind-test/bind-test-child1 phy_sandbox')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, False)
 | 
			
		||||
    #bind child #1. No error expected and all devices should be there
 | 
			
		||||
    response = u_boot_console.run_command('bind  /bind-test/bind-test-child1 phy_sandbox')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, False)
 | 
			
		||||
 | 
			
		||||
	#Unbind child #2. No error expected and all devices should be there except for bind-test-child2
 | 
			
		||||
	response = u_boot_console.run_command('unbind  /bind-test/bind-test-child2')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
 | 
			
		||||
	assert 'bind-test-child2' not in tree
 | 
			
		||||
    #Unbind child #2. No error expected and all devices should be there except for bind-test-child2
 | 
			
		||||
    response = u_boot_console.run_command('unbind  /bind-test/bind-test-child2')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
 | 
			
		||||
    assert 'bind-test-child2' not in tree
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	#Bind child #2. No error expected and all devices should be there
 | 
			
		||||
	response = u_boot_console.run_command('bind /bind-test/bind-test-child2 simple_bus')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    #Bind child #2. No error expected and all devices should be there
 | 
			
		||||
    response = u_boot_console.run_command('bind /bind-test/bind-test-child2 simple_bus')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
 | 
			
		||||
	#Unbind parent. No error expected. All devices should be removed and unbound
 | 
			
		||||
	response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert 'bind-test' not in tree
 | 
			
		||||
	assert 'bind-test-child1' not in tree
 | 
			
		||||
	assert 'bind-test-child2' not in tree
 | 
			
		||||
    #Unbind parent. No error expected. All devices should be removed and unbound
 | 
			
		||||
    response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert 'bind-test' not in tree
 | 
			
		||||
    assert 'bind-test-child1' not in tree
 | 
			
		||||
    assert 'bind-test-child2' not in tree
 | 
			
		||||
 | 
			
		||||
	#try binding invalid node with valid driver
 | 
			
		||||
	response = u_boot_console.run_command('bind  /not-a-valid-node simple_bus')
 | 
			
		||||
	assert response != ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert 'not-a-valid-node' not in tree
 | 
			
		||||
    #try binding invalid node with valid driver
 | 
			
		||||
    response = u_boot_console.run_command('bind  /not-a-valid-node simple_bus')
 | 
			
		||||
    assert response != ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert 'not-a-valid-node' not in tree
 | 
			
		||||
 | 
			
		||||
	#try binding valid node with invalid driver
 | 
			
		||||
	response = u_boot_console.run_command('bind  /bind-test not_a_driver')
 | 
			
		||||
	assert response != ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert 'bind-test' not in tree
 | 
			
		||||
    #try binding valid node with invalid driver
 | 
			
		||||
    response = u_boot_console.run_command('bind  /bind-test not_a_driver')
 | 
			
		||||
    assert response != ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert 'bind-test' not in tree
 | 
			
		||||
 | 
			
		||||
	#bind /bind-test. Device should come up as well as its children
 | 
			
		||||
	response = u_boot_console.run_command('bind  /bind-test simple_bus')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    #bind /bind-test. Device should come up as well as its children
 | 
			
		||||
    response = u_boot_console.run_command('bind  /bind-test simple_bus')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
 | 
			
		||||
	response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
    response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
 | 
			
		||||
def get_next_line(tree, name):
 | 
			
		||||
	treelines = [x.strip() for x in tree.splitlines() if x.strip()]
 | 
			
		||||
	child_line = ''
 | 
			
		||||
	for idx, line in enumerate(treelines):
 | 
			
		||||
		if ('-- ' + name) in line:
 | 
			
		||||
			try:
 | 
			
		||||
				child_line = treelines[idx+1]
 | 
			
		||||
			except:
 | 
			
		||||
				pass
 | 
			
		||||
			break
 | 
			
		||||
	return child_line
 | 
			
		||||
    treelines = [x.strip() for x in tree.splitlines() if x.strip()]
 | 
			
		||||
    child_line = ''
 | 
			
		||||
    for idx, line in enumerate(treelines):
 | 
			
		||||
        if '-- ' + name in line:
 | 
			
		||||
            try:
 | 
			
		||||
                child_line = treelines[idx+1]
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
            break
 | 
			
		||||
    return child_line
 | 
			
		||||
 | 
			
		||||
@pytest.mark.buildconfigspec('cmd_bind')
 | 
			
		||||
def test_bind_unbind_with_uclass(u_boot_console):
 | 
			
		||||
	#bind /bind-test
 | 
			
		||||
	response = u_boot_console.run_command('bind  /bind-test simple_bus')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
    #bind /bind-test
 | 
			
		||||
    response = u_boot_console.run_command('bind  /bind-test simple_bus')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
 | 
			
		||||
	#make sure bind-test-child2 is there and get its uclass/index pair
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	child2_line = [x.strip() for x in tree.splitlines() if '-- bind-test-child2' in x]
 | 
			
		||||
	assert len(child2_line) == 1
 | 
			
		||||
    #make sure bind-test-child2 is there and get its uclass/index pair
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    child2_line = [x.strip() for x in tree.splitlines() if '-- bind-test-child2' in x]
 | 
			
		||||
    assert len(child2_line) == 1
 | 
			
		||||
 | 
			
		||||
	child2_uclass = child2_line[0].split()[0]
 | 
			
		||||
	child2_index = int(child2_line[0].split()[1])
 | 
			
		||||
    child2_uclass = child2_line[0].split()[0]
 | 
			
		||||
    child2_index = int(child2_line[0].split()[1])
 | 
			
		||||
 | 
			
		||||
	#bind simple_bus as a child of bind-test-child2
 | 
			
		||||
	response = u_boot_console.run_command('bind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
    #bind simple_bus as a child of bind-test-child2
 | 
			
		||||
    response = u_boot_console.run_command(
 | 
			
		||||
                    'bind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
 | 
			
		||||
	#check that the child is there and its uclass/index pair is right
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    #check that the child is there and its uclass/index pair is right
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
 | 
			
		||||
	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
	assert child_of_child2_line
 | 
			
		||||
	child_of_child2_index = int(child_of_child2_line.split()[1])
 | 
			
		||||
	assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
	assert child_of_child2_index == child2_index + 1
 | 
			
		||||
    child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
    assert child_of_child2_line
 | 
			
		||||
    child_of_child2_index = int(child_of_child2_line.split()[1])
 | 
			
		||||
    assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
    assert child_of_child2_index == child2_index + 1
 | 
			
		||||
 | 
			
		||||
	#unbind the child and check it has been removed
 | 
			
		||||
	response = u_boot_console.run_command('unbind  simple_bus {}'.format(child_of_child2_index))
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
	assert not in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
	assert child_of_child2_line == ''
 | 
			
		||||
    #unbind the child and check it has been removed
 | 
			
		||||
    response = u_boot_console.run_command('unbind  simple_bus {}'.format(child_of_child2_index))
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    assert not in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
    child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
    assert child_of_child2_line == ''
 | 
			
		||||
 | 
			
		||||
	#bind simple_bus as a child of bind-test-child2
 | 
			
		||||
	response = u_boot_console.run_command('bind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
    #bind simple_bus as a child of bind-test-child2
 | 
			
		||||
    response = u_boot_console.run_command(
 | 
			
		||||
                    'bind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
 | 
			
		||||
	#check that the child is there and its uclass/index pair is right
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	treelines = [x.strip() for x in tree.splitlines() if x.strip()]
 | 
			
		||||
    #check that the child is there and its uclass/index pair is right
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    treelines = [x.strip() for x in tree.splitlines() if x.strip()]
 | 
			
		||||
 | 
			
		||||
	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
	assert child_of_child2_line
 | 
			
		||||
	child_of_child2_index = int(child_of_child2_line.split()[1])
 | 
			
		||||
	assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
	assert child_of_child2_index == child2_index + 1
 | 
			
		||||
    child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
    assert child_of_child2_line
 | 
			
		||||
    child_of_child2_index = int(child_of_child2_line.split()[1])
 | 
			
		||||
    assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
 | 
			
		||||
    assert child_of_child2_index == child2_index + 1
 | 
			
		||||
 | 
			
		||||
	#unbind the child and check it has been removed
 | 
			
		||||
	response = u_boot_console.run_command('unbind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
	assert response == ''
 | 
			
		||||
    #unbind the child and check it has been removed
 | 
			
		||||
    response = u_boot_console.run_command(
 | 
			
		||||
                    'unbind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
    assert response == ''
 | 
			
		||||
 | 
			
		||||
	tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
    tree = u_boot_console.run_command('dm tree')
 | 
			
		||||
    assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
 | 
			
		||||
 | 
			
		||||
	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
	assert child_of_child2_line == ''
 | 
			
		||||
    child_of_child2_line = get_next_line(tree, 'bind-test-child2')
 | 
			
		||||
    assert child_of_child2_line == ''
 | 
			
		||||
 | 
			
		||||
	#unbind the child again and check it doesn't change the tree
 | 
			
		||||
	tree_old = u_boot_console.run_command('dm tree')
 | 
			
		||||
	response = u_boot_console.run_command('unbind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
	tree_new = u_boot_console.run_command('dm tree')
 | 
			
		||||
    #unbind the child again and check it doesn't change the tree
 | 
			
		||||
    tree_old = u_boot_console.run_command('dm tree')
 | 
			
		||||
    response = u_boot_console.run_command(
 | 
			
		||||
                    'unbind  {} {} simple_bus'.format(child2_uclass, child2_index))
 | 
			
		||||
    tree_new = u_boot_console.run_command('dm tree')
 | 
			
		||||
 | 
			
		||||
	assert response == ''
 | 
			
		||||
	assert tree_old == tree_new
 | 
			
		||||
    assert response == ''
 | 
			
		||||
    assert tree_old == tree_new
 | 
			
		||||
 | 
			
		||||
	response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
	assert response == ''
 | 
			
		||||
    response = u_boot_console.run_command('unbind  /bind-test')
 | 
			
		||||
    assert response == ''
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,9 @@ try:
 | 
			
		|||
except:  # pragma: no cover
 | 
			
		||||
    ELF_TOOLS = False
 | 
			
		||||
 | 
			
		||||
# BSYM in little endian, keep in sync with include/binman_sym.h
 | 
			
		||||
BINMAN_SYM_MAGIC_VALUE = 0x4d595342
 | 
			
		||||
 | 
			
		||||
# Information about an EFL symbol:
 | 
			
		||||
# section (str): Name of the section containing this symbol
 | 
			
		||||
# address (int): Address of the symbol (its value)
 | 
			
		||||
| 
						 | 
				
			
			@ -223,9 +226,12 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
 | 
			
		|||
                raise ValueError('%s has size %d: only 4 and 8 are supported' %
 | 
			
		||||
                                 (msg, sym.size))
 | 
			
		||||
 | 
			
		||||
            # Look up the symbol in our entry tables.
 | 
			
		||||
            value = section.GetImage().LookupImageSymbol(name, sym.weak, msg,
 | 
			
		||||
                                                         base.address)
 | 
			
		||||
            if name == '_binman_sym_magic':
 | 
			
		||||
                value = BINMAN_SYM_MAGIC_VALUE
 | 
			
		||||
            else:
 | 
			
		||||
                # Look up the symbol in our entry tables.
 | 
			
		||||
                value = section.GetImage().LookupImageSymbol(name, sym.weak,
 | 
			
		||||
                                                             msg, base.address)
 | 
			
		||||
            if value is None:
 | 
			
		||||
                value = -1
 | 
			
		||||
                pack_string = pack_string.lower()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ class TestElf(unittest.TestCase):
 | 
			
		|||
        elf_fname = self.ElfTestFile('u_boot_binman_syms')
 | 
			
		||||
        with self.assertRaises(ValueError) as e:
 | 
			
		||||
            elf.LookupAndWriteSymbols(elf_fname, entry, section)
 | 
			
		||||
        self.assertIn('entry_path has offset 4 (size 8) but the contents size '
 | 
			
		||||
        self.assertIn('entry_path has offset 8 (size 8) but the contents size '
 | 
			
		||||
                      'is a', str(e.exception))
 | 
			
		||||
 | 
			
		||||
    def testMissingImageStart(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -161,18 +161,20 @@ class TestElf(unittest.TestCase):
 | 
			
		|||
        This should produce -1 values for all thress symbols, taking up the
 | 
			
		||||
        first 16 bytes of the image.
 | 
			
		||||
        """
 | 
			
		||||
        entry = FakeEntry(24)
 | 
			
		||||
        entry = FakeEntry(28)
 | 
			
		||||
        section = FakeSection(sym_value=None)
 | 
			
		||||
        elf_fname = self.ElfTestFile('u_boot_binman_syms')
 | 
			
		||||
        elf.LookupAndWriteSymbols(elf_fname, entry, section)
 | 
			
		||||
        self.assertEqual(tools.get_bytes(255, 20) + tools.get_bytes(ord('a'), 4),
 | 
			
		||||
                                                                  entry.data)
 | 
			
		||||
        expected = (struct.pack('<L', elf.BINMAN_SYM_MAGIC_VALUE) +
 | 
			
		||||
                    tools.get_bytes(255, 20) +
 | 
			
		||||
                    tools.get_bytes(ord('a'), 4))
 | 
			
		||||
        self.assertEqual(expected, entry.data)
 | 
			
		||||
 | 
			
		||||
    def testDebug(self):
 | 
			
		||||
        """Check that enabling debug in the elf module produced debug output"""
 | 
			
		||||
        try:
 | 
			
		||||
            tout.init(tout.DEBUG)
 | 
			
		||||
            entry = FakeEntry(20)
 | 
			
		||||
            entry = FakeEntry(24)
 | 
			
		||||
            section = FakeSection()
 | 
			
		||||
            elf_fname = self.ElfTestFile('u_boot_binman_syms')
 | 
			
		||||
            with test_util.capture_sys_output() as (stdout, stderr):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,8 +43,8 @@ from patman import tout
 | 
			
		|||
# Contents of test files, corresponding to different entry types
 | 
			
		||||
U_BOOT_DATA           = b'1234'
 | 
			
		||||
U_BOOT_IMG_DATA       = b'img'
 | 
			
		||||
U_BOOT_SPL_DATA       = b'56780123456789abcdefghi'
 | 
			
		||||
U_BOOT_TPL_DATA       = b'tpl9876543210fedcbazyw'
 | 
			
		||||
U_BOOT_SPL_DATA       = b'56780123456789abcdefghijklm'
 | 
			
		||||
U_BOOT_TPL_DATA       = b'tpl9876543210fedcbazywvuts'
 | 
			
		||||
BLOB_DATA             = b'89'
 | 
			
		||||
ME_DATA               = b'0abcd'
 | 
			
		||||
VGA_DATA              = b'vga'
 | 
			
		||||
| 
						 | 
				
			
			@ -1406,8 +1406,9 @@ class TestFunctional(unittest.TestCase):
 | 
			
		|||
        elf_fname = self.ElfTestFile('u_boot_binman_syms')
 | 
			
		||||
        syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
 | 
			
		||||
        addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
 | 
			
		||||
        self.assertEqual(syms['_binman_sym_magic'].address, addr)
 | 
			
		||||
        self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
 | 
			
		||||
                         addr)
 | 
			
		||||
                         addr + 4)
 | 
			
		||||
 | 
			
		||||
        self._SetupSplElf('u_boot_binman_syms')
 | 
			
		||||
        data = self._DoReadFileDtb(dts, entry_args=entry_args,
 | 
			
		||||
| 
						 | 
				
			
			@ -1415,17 +1416,17 @@ class TestFunctional(unittest.TestCase):
 | 
			
		|||
        # The image should contain the symbols from u_boot_binman_syms.c
 | 
			
		||||
        # Note that image_pos is adjusted by the base address of the image,
 | 
			
		||||
        # which is 0x10 in our test image
 | 
			
		||||
        sym_values = struct.pack('<LQLL', 0x00,
 | 
			
		||||
                                 u_boot_offset + len(U_BOOT_DATA),
 | 
			
		||||
        sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
 | 
			
		||||
                                 0x00, u_boot_offset + len(U_BOOT_DATA),
 | 
			
		||||
                                 0x10 + u_boot_offset, 0x04)
 | 
			
		||||
        expected = (sym_values + base_data[20:] +
 | 
			
		||||
        expected = (sym_values + base_data[24:] +
 | 
			
		||||
                    tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
 | 
			
		||||
                    base_data[20:])
 | 
			
		||||
                    base_data[24:])
 | 
			
		||||
        self.assertEqual(expected, data)
 | 
			
		||||
 | 
			
		||||
    def testSymbols(self):
 | 
			
		||||
        """Test binman can assign symbols embedded in U-Boot"""
 | 
			
		||||
        self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
 | 
			
		||||
        self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
 | 
			
		||||
 | 
			
		||||
    def testSymbolsNoDtb(self):
 | 
			
		||||
        """Test binman can assign symbols embedded in U-Boot SPL"""
 | 
			
		||||
| 
						 | 
				
			
			@ -3610,20 +3611,20 @@ class TestFunctional(unittest.TestCase):
 | 
			
		|||
 | 
			
		||||
    def _CheckSymbolsTplSection(self, dts, expected_vals):
 | 
			
		||||
        data = self._DoReadFile(dts)
 | 
			
		||||
        sym_values = struct.pack('<LQLL', *expected_vals)
 | 
			
		||||
        sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
 | 
			
		||||
        upto1 = 4 + len(U_BOOT_SPL_DATA)
 | 
			
		||||
        expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
 | 
			
		||||
        expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
 | 
			
		||||
        self.assertEqual(expected1, data[:upto1])
 | 
			
		||||
 | 
			
		||||
        upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
 | 
			
		||||
        expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
 | 
			
		||||
        expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
 | 
			
		||||
        self.assertEqual(expected2, data[upto1:upto2])
 | 
			
		||||
 | 
			
		||||
        upto3 = 0x34 + len(U_BOOT_DATA)
 | 
			
		||||
        upto3 = 0x3c + len(U_BOOT_DATA)
 | 
			
		||||
        expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
 | 
			
		||||
        self.assertEqual(expected3, data[upto2:upto3])
 | 
			
		||||
 | 
			
		||||
        expected4 = sym_values + U_BOOT_TPL_DATA[20:]
 | 
			
		||||
        expected4 = sym_values + U_BOOT_TPL_DATA[24:]
 | 
			
		||||
        self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
 | 
			
		||||
 | 
			
		||||
    def testSymbolsTplSection(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -3631,14 +3632,14 @@ class TestFunctional(unittest.TestCase):
 | 
			
		|||
        self._SetupSplElf('u_boot_binman_syms')
 | 
			
		||||
        self._SetupTplElf('u_boot_binman_syms')
 | 
			
		||||
        self._CheckSymbolsTplSection('149_symbols_tpl.dts',
 | 
			
		||||
                                     [0x04, 0x1c, 0x10 + 0x34, 0x04])
 | 
			
		||||
                                     [0x04, 0x20, 0x10 + 0x3c, 0x04])
 | 
			
		||||
 | 
			
		||||
    def testSymbolsTplSectionX86(self):
 | 
			
		||||
        """Test binman can assign symbols in a section with end-at-4gb"""
 | 
			
		||||
        self._SetupSplElf('u_boot_binman_syms_x86')
 | 
			
		||||
        self._SetupTplElf('u_boot_binman_syms_x86')
 | 
			
		||||
        self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
 | 
			
		||||
                                     [0xffffff04, 0xffffff1c, 0xffffff34,
 | 
			
		||||
                                     [0xffffff04, 0xffffff20, 0xffffff3c,
 | 
			
		||||
                                      0x04])
 | 
			
		||||
 | 
			
		||||
    def testPackX86RomIfwiSectiom(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -4488,7 +4489,7 @@ class TestFunctional(unittest.TestCase):
 | 
			
		|||
 | 
			
		||||
    def testSymbolsSubsection(self):
 | 
			
		||||
        """Test binman can assign symbols from a subsection"""
 | 
			
		||||
        self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
 | 
			
		||||
        self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
 | 
			
		||||
 | 
			
		||||
    def testReadImageEntryArg(self):
 | 
			
		||||
        """Test reading an image that would need an entry arg to generate"""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,6 @@ import os
 | 
			
		|||
import site
 | 
			
		||||
import sys
 | 
			
		||||
import traceback
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
# Get the absolute path to this file at run-time
 | 
			
		||||
our_path = os.path.dirname(os.path.realpath(__file__))
 | 
			
		||||
| 
						 | 
				
			
			@ -73,19 +72,18 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
 | 
			
		|||
    from binman import image_test
 | 
			
		||||
    import doctest
 | 
			
		||||
 | 
			
		||||
    result = unittest.TestResult()
 | 
			
		||||
    test_name = args and args[0] or None
 | 
			
		||||
 | 
			
		||||
    # Run the entry tests first ,since these need to be the first to import the
 | 
			
		||||
    # 'entry' module.
 | 
			
		||||
    test_util.run_test_suites(
 | 
			
		||||
        result, debug, verbosity, test_preserve_dirs, processes, test_name,
 | 
			
		||||
    result = test_util.run_test_suites(
 | 
			
		||||
        'binman', debug, verbosity, test_preserve_dirs, processes, test_name,
 | 
			
		||||
        toolpath,
 | 
			
		||||
        [bintool_test.TestBintool, entry_test.TestEntry, ftest.TestFunctional,
 | 
			
		||||
         fdt_test.TestFdt, elf_test.TestElf, image_test.TestImage,
 | 
			
		||||
         cbfs_util_test.TestCbfs, fip_util_test.TestFip])
 | 
			
		||||
 | 
			
		||||
    return test_util.report_result('binman', test_name, result)
 | 
			
		||||
    return (0 if result.wasSuccessful() else 1)
 | 
			
		||||
 | 
			
		||||
def RunTestCoverage(toolpath):
 | 
			
		||||
    """Run the tests and check that we get 100% coverage"""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <24>;
 | 
			
		||||
			offset = <28>;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
	binman {
 | 
			
		||||
		sort-by-offset;
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <26>;
 | 
			
		||||
			offset = <30>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@
 | 
			
		|||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl {
 | 
			
		||||
			offset = <0xffffffe7>;
 | 
			
		||||
			offset = <0xffffffe3>;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,13 +7,13 @@
 | 
			
		|||
	binman {
 | 
			
		||||
		sort-by-offset;
 | 
			
		||||
		end-at-4gb;
 | 
			
		||||
		size = <32>;
 | 
			
		||||
		size = <36>;
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <0xffffffe0>;
 | 
			
		||||
			offset = <0xffffffdc>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl {
 | 
			
		||||
			offset = <0xffffffe7>;
 | 
			
		||||
			offset = <0xffffffe3>;
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <0x18>;
 | 
			
		||||
			offset = <0x1c>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl2 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,12 +11,12 @@
 | 
			
		|||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl2 {
 | 
			
		||||
			offset = <0x1c>;
 | 
			
		||||
			offset = <0x20>;
 | 
			
		||||
			type = "u-boot-spl";
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <0x34>;
 | 
			
		||||
			offset = <0x3c>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		section {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,12 +14,12 @@
 | 
			
		|||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot-spl2 {
 | 
			
		||||
			offset = <0xffffff1c>;
 | 
			
		||||
			offset = <0xffffff20>;
 | 
			
		||||
			type = "u-boot-spl";
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		u-boot {
 | 
			
		||||
			offset = <0xffffff34>;
 | 
			
		||||
			offset = <0xffffff3c>;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		section {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
			};
 | 
			
		||||
 | 
			
		||||
			u-boot {
 | 
			
		||||
				offset = <24>;
 | 
			
		||||
				offset = <28>;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ CC		= $(CROSS_COMPILE)gcc
 | 
			
		|||
OBJCOPY		= $(CROSS_COMPILE)objcopy
 | 
			
		||||
 | 
			
		||||
VPATH := $(SRC)
 | 
			
		||||
CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include \
 | 
			
		||||
CFLAGS := -march=i386 -m32 -nostdlib -I $(SRC)../../../include -I $(SRC) \
 | 
			
		||||
	-Wl,--no-dynamic-linker
 | 
			
		||||
 | 
			
		||||
LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#define CONFIG_BINMAN 1
 | 
			
		||||
#define CONFIG_SPL_BUILD 1
 | 
			
		||||
#define CONFIG_SPL_BINMAN_SYMBOLS 1
 | 
			
		||||
| 
						 | 
				
			
			@ -5,9 +5,13 @@
 | 
			
		|||
 * Simple program to create some binman symbols. This is used by binman tests.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CONFIG_BINMAN
 | 
			
		||||
typedef unsigned long ulong;
 | 
			
		||||
 | 
			
		||||
#include <linux/kconfig.h>
 | 
			
		||||
#include <binman_sym.h>
 | 
			
		||||
 | 
			
		||||
DECLARE_BINMAN_MAGIC_SYM;
 | 
			
		||||
 | 
			
		||||
binman_sym_declare(unsigned long, u_boot_spl_any, offset);
 | 
			
		||||
binman_sym_declare(unsigned long long, u_boot_spl2, offset);
 | 
			
		||||
binman_sym_declare(unsigned long, u_boot_any, image_pos);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,11 @@
 | 
			
		|||
 * Simple program to create some binman symbols. This is used by binman tests.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CONFIG_BINMAN
 | 
			
		||||
typedef unsigned long ulong;
 | 
			
		||||
 | 
			
		||||
#include <linux/kconfig.h>
 | 
			
		||||
#include <binman_sym.h>
 | 
			
		||||
 | 
			
		||||
DECLARE_BINMAN_MAGIC_SYM;
 | 
			
		||||
 | 
			
		||||
binman_sym_declare(char, u_boot_spl, pos);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,6 @@ import multiprocessing
 | 
			
		|||
import os
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
# Bring in the patman libraries
 | 
			
		||||
our_path = os.path.dirname(os.path.realpath(__file__))
 | 
			
		||||
| 
						 | 
				
			
			@ -34,19 +33,18 @@ def RunTests(skip_net_tests, verboose, args):
 | 
			
		|||
    from buildman import test
 | 
			
		||||
    import doctest
 | 
			
		||||
 | 
			
		||||
    result = unittest.TestResult()
 | 
			
		||||
    test_name = args and args[0] or None
 | 
			
		||||
    if skip_net_tests:
 | 
			
		||||
        test.use_network = False
 | 
			
		||||
 | 
			
		||||
    # Run the entry tests first ,since these need to be the first to import the
 | 
			
		||||
    # 'entry' module.
 | 
			
		||||
    test_util.run_test_suites(
 | 
			
		||||
        result, False, verboose, False, None, test_name, [],
 | 
			
		||||
    result = test_util.run_test_suites(
 | 
			
		||||
        'buildman', False, verboose, False, None, test_name, [],
 | 
			
		||||
        [test.TestBuild, func_test.TestFunctional,
 | 
			
		||||
         'buildman.toolchain', 'patman.gitutil'])
 | 
			
		||||
 | 
			
		||||
    return test_util.report_result('buildman', test_name, result)
 | 
			
		||||
    return (0 if result.wasSuccessful() else 1)
 | 
			
		||||
 | 
			
		||||
options, args = cmdline.ParseArgs()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ from subunit import ProtocolTestCase, TestProtocolClient
 | 
			
		|||
from subunit.test_results import AutoTimingTestResultDecorator
 | 
			
		||||
 | 
			
		||||
from testtools import ConcurrentTestSuite, iterate_tests
 | 
			
		||||
from testtools.content import TracebackContent, text_content
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_all__ = [
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +44,81 @@ _all__ = [
 | 
			
		|||
CPU_COUNT = cpu_count()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fork_for_tests(concurrency_num=CPU_COUNT):
 | 
			
		||||
class BufferingTestProtocolClient(TestProtocolClient):
 | 
			
		||||
    """A TestProtocolClient which can buffer the test outputs
 | 
			
		||||
 | 
			
		||||
    This class captures the stdout and stderr output streams of the
 | 
			
		||||
    tests as it runs them, and includes the output texts in the subunit
 | 
			
		||||
    stream as additional details.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        stream: A file-like object to write a subunit stream to
 | 
			
		||||
        buffer (bool): True to capture test stdout/stderr outputs and
 | 
			
		||||
            include them in the test details
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, stream, buffer=True):
 | 
			
		||||
        super().__init__(stream)
 | 
			
		||||
        self.buffer = buffer
 | 
			
		||||
 | 
			
		||||
    def _addOutcome(self, outcome, test, error=None, details=None,
 | 
			
		||||
            error_permitted=True):
 | 
			
		||||
        """Report a test outcome to the subunit stream
 | 
			
		||||
 | 
			
		||||
        The parent class uses this function as a common implementation
 | 
			
		||||
        for various methods that report successes, errors, failures, etc.
 | 
			
		||||
 | 
			
		||||
        This version automatically upgrades the error tracebacks to the
 | 
			
		||||
        new 'details' format by wrapping them in a Content object, so
 | 
			
		||||
        that we can include the captured test output in the test result
 | 
			
		||||
        details.
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            outcome: A string describing the outcome - used as the
 | 
			
		||||
                event name in the subunit stream.
 | 
			
		||||
            test: The test case whose outcome is to be reported
 | 
			
		||||
            error: Standard unittest positional argument form - an
 | 
			
		||||
                exc_info tuple.
 | 
			
		||||
            details: New Testing-in-python drafted API; a dict from
 | 
			
		||||
                string to subunit.Content objects.
 | 
			
		||||
            error_permitted: If True then one and only one of error or
 | 
			
		||||
                details must be supplied. If False then error must not
 | 
			
		||||
                be supplied and details is still optional.
 | 
			
		||||
        """
 | 
			
		||||
        if details is None:
 | 
			
		||||
            details = {}
 | 
			
		||||
 | 
			
		||||
        # Parent will raise an exception if error_permitted is False but
 | 
			
		||||
        # error is not None. We want that exception in that case, so
 | 
			
		||||
        # don't touch error when error_permitted is explicitly False.
 | 
			
		||||
        if error_permitted and error is not None:
 | 
			
		||||
            # Parent class prefers error over details
 | 
			
		||||
            details['traceback'] = TracebackContent(error, test)
 | 
			
		||||
            error_permitted = False
 | 
			
		||||
            error = None
 | 
			
		||||
 | 
			
		||||
        if self.buffer:
 | 
			
		||||
            stdout = sys.stdout.getvalue()
 | 
			
		||||
            if stdout:
 | 
			
		||||
                details['stdout'] = text_content(stdout)
 | 
			
		||||
 | 
			
		||||
            stderr = sys.stderr.getvalue()
 | 
			
		||||
            if stderr:
 | 
			
		||||
                details['stderr'] = text_content(stderr)
 | 
			
		||||
 | 
			
		||||
        return super()._addOutcome(outcome, test, error=error,
 | 
			
		||||
                details=details, error_permitted=error_permitted)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fork_for_tests(concurrency_num=CPU_COUNT, buffer=False):
 | 
			
		||||
    """Implementation of `make_tests` used to construct `ConcurrentTestSuite`.
 | 
			
		||||
 | 
			
		||||
    :param concurrency_num: number of processes to use.
 | 
			
		||||
    """
 | 
			
		||||
    if buffer:
 | 
			
		||||
        test_protocol_client_class = BufferingTestProtocolClient
 | 
			
		||||
    else:
 | 
			
		||||
        test_protocol_client_class = TestProtocolClient
 | 
			
		||||
 | 
			
		||||
    def do_fork(suite):
 | 
			
		||||
        """Take suite and start up multiple runners by forking (Unix only).
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +147,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
 | 
			
		|||
                    # child actually gets keystrokes for pdb etc).
 | 
			
		||||
                    sys.stdin.close()
 | 
			
		||||
                    subunit_result = AutoTimingTestResultDecorator(
 | 
			
		||||
                        TestProtocolClient(stream)
 | 
			
		||||
                        test_protocol_client_class(stream)
 | 
			
		||||
                    )
 | 
			
		||||
                    process_suite.run(subunit_result)
 | 
			
		||||
                except:
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +164,13 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
 | 
			
		|||
            else:
 | 
			
		||||
                os.close(c2pwrite)
 | 
			
		||||
                stream = os.fdopen(c2pread, 'rb')
 | 
			
		||||
                test = ProtocolTestCase(stream)
 | 
			
		||||
                # If we don't pass the second argument here, it defaults
 | 
			
		||||
                # to sys.stdout.buffer down the line. But if we don't
 | 
			
		||||
                # pass it *now*, it may be resolved after sys.stdout is
 | 
			
		||||
                # replaced with a StringIO (to capture tests' outputs)
 | 
			
		||||
                # which doesn't have a buffer attribute and can end up
 | 
			
		||||
                # occasionally causing a 'broken-runner' error.
 | 
			
		||||
                test = ProtocolTestCase(stream, sys.stdout.buffer)
 | 
			
		||||
                result.append(test)
 | 
			
		||||
        return result
 | 
			
		||||
    return do_fork
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,6 @@ see doc/driver-model/of-plat.rst
 | 
			
		|||
from argparse import ArgumentParser
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
# Bring in the patman libraries
 | 
			
		||||
our_path = os.path.dirname(os.path.realpath(__file__))
 | 
			
		||||
| 
						 | 
				
			
			@ -49,18 +48,18 @@ def run_tests(processes, args):
 | 
			
		|||
    from dtoc import test_src_scan
 | 
			
		||||
    from dtoc import test_dtoc
 | 
			
		||||
 | 
			
		||||
    result = unittest.TestResult()
 | 
			
		||||
    sys.argv = [sys.argv[0]]
 | 
			
		||||
    test_name = args.files and args.files[0] or None
 | 
			
		||||
 | 
			
		||||
    test_dtoc.setup()
 | 
			
		||||
 | 
			
		||||
    test_util.run_test_suites(
 | 
			
		||||
        result, debug=True, verbosity=1, test_preserve_dirs=False,
 | 
			
		||||
    result = test_util.run_test_suites(
 | 
			
		||||
        toolname='dtoc', debug=True, verbosity=1, test_preserve_dirs=False,
 | 
			
		||||
        processes=processes, test_name=test_name, toolpath=[],
 | 
			
		||||
        class_and_module_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan])
 | 
			
		||||
 | 
			
		||||
    return test_util.report_result('binman', test_name, result)
 | 
			
		||||
    return (0 if result.wasSuccessful() else 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def RunTestCoverage():
 | 
			
		||||
    """Run the tests and check that we get 100% coverage"""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -616,8 +616,11 @@ struct dm_test_pdata __attribute__ ((section (".priv_data")))
 | 
			
		|||
u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
 | 
			
		||||
\t__attribute__ ((section (".priv_data")));
 | 
			
		||||
#include <dm/test.h>
 | 
			
		||||
u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)]
 | 
			
		||||
u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_plat)]
 | 
			
		||||
\t__attribute__ ((section (".priv_data")));
 | 
			
		||||
#include <dm/test.h>
 | 
			
		||||
u8 _denx_u_boot_test_bus_uc_priv_some_bus[sizeof(struct dm_test_uclass_priv)]
 | 
			
		||||
	__attribute__ ((section (".priv_data")));
 | 
			
		||||
#include <test.h>
 | 
			
		||||
 | 
			
		||||
DM_DEVICE_INST(some_bus) = {
 | 
			
		||||
| 
						 | 
				
			
			@ -628,6 +631,7 @@ DM_DEVICE_INST(some_bus) = {
 | 
			
		|||
\t.driver_data\t= DM_TEST_TYPE_FIRST,
 | 
			
		||||
\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
 | 
			
		||||
\t.uclass\t\t= DM_UCLASS_REF(testbus),
 | 
			
		||||
\t.uclass_priv_ = _denx_u_boot_test_bus_uc_priv_some_bus,
 | 
			
		||||
\t.uclass_node\t= {
 | 
			
		||||
\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
 | 
			
		||||
\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -780,25 +780,17 @@ def RunTests(args):
 | 
			
		|||
    Args:
 | 
			
		||||
        args: List of positional args provided to fdt. This can hold a test
 | 
			
		||||
            name to execute (as in 'fdt -t testFdt', for example)
 | 
			
		||||
    """
 | 
			
		||||
    result = unittest.TestResult()
 | 
			
		||||
    sys.argv = [sys.argv[0]]
 | 
			
		||||
    test_name = args and args[0] or None
 | 
			
		||||
    for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
 | 
			
		||||
        if test_name:
 | 
			
		||||
            try:
 | 
			
		||||
                suite = unittest.TestLoader().loadTestsFromName(test_name, module)
 | 
			
		||||
            except AttributeError:
 | 
			
		||||
                continue
 | 
			
		||||
        else:
 | 
			
		||||
            suite = unittest.TestLoader().loadTestsFromTestCase(module)
 | 
			
		||||
        suite.run(result)
 | 
			
		||||
 | 
			
		||||
    print(result)
 | 
			
		||||
    for _, err in result.errors:
 | 
			
		||||
        print(err)
 | 
			
		||||
    for _, err in result.failures:
 | 
			
		||||
        print(err)
 | 
			
		||||
    Returns:
 | 
			
		||||
        Return code, 0 on success
 | 
			
		||||
    """
 | 
			
		||||
    test_name = args and args[0] or None
 | 
			
		||||
    result = test_util.run_test_suites(
 | 
			
		||||
        'test_fdt', False, False, False, None, test_name, None,
 | 
			
		||||
        [TestFdt, TestNode, TestProp, TestFdtUtil])
 | 
			
		||||
 | 
			
		||||
    return (0 if result.wasSuccessful() else 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ != '__main__':
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
| 
						 | 
				
			
			@ -816,6 +808,7 @@ parser.add_option('-T', '--test-coverage', action='store_true',
 | 
			
		|||
 | 
			
		||||
# Run our meagre tests
 | 
			
		||||
if options.test:
 | 
			
		||||
    RunTests(args)
 | 
			
		||||
    ret_code = RunTests(args)
 | 
			
		||||
    sys.exit(ret_code)
 | 
			
		||||
elif options.test_coverage:
 | 
			
		||||
    RunTestCoverage()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,6 @@ import re
 | 
			
		|||
import shutil
 | 
			
		||||
import sys
 | 
			
		||||
import traceback
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    # Allow 'from patman import xxx to work'
 | 
			
		||||
| 
						 | 
				
			
			@ -134,13 +133,12 @@ if args.cmd == 'test':
 | 
			
		|||
    import doctest
 | 
			
		||||
    from patman import func_test
 | 
			
		||||
 | 
			
		||||
    result = unittest.TestResult()
 | 
			
		||||
    test_util.run_test_suites(
 | 
			
		||||
        result, False, False, False, None, None, None,
 | 
			
		||||
    result = test_util.run_test_suites(
 | 
			
		||||
        'patman', False, False, False, None, None, None,
 | 
			
		||||
        [test_checkpatch.TestPatch, func_test.TestFunctional,
 | 
			
		||||
         'gitutil', 'settings', 'terminal'])
 | 
			
		||||
 | 
			
		||||
    sys.exit(test_util.report_result('patman', args.testname, result))
 | 
			
		||||
    sys.exit(0 if result.wasSuccessful() else 1)
 | 
			
		||||
 | 
			
		||||
# Process commits, produce patches files, check them, email them
 | 
			
		||||
elif args.cmd == 'send':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -246,8 +246,10 @@ def _UpdateDefaults(main_parser, config):
 | 
			
		|||
 | 
			
		||||
    # Collect the defaults from each parser
 | 
			
		||||
    defaults = {}
 | 
			
		||||
    parser_defaults = []
 | 
			
		||||
    for parser in parsers:
 | 
			
		||||
        pdefs = parser.parse_known_args()[0]
 | 
			
		||||
        parser_defaults.append(pdefs)
 | 
			
		||||
        defaults.update(vars(pdefs))
 | 
			
		||||
 | 
			
		||||
    # Go through the settings and collect defaults
 | 
			
		||||
| 
						 | 
				
			
			@ -264,8 +266,11 @@ def _UpdateDefaults(main_parser, config):
 | 
			
		|||
        else:
 | 
			
		||||
            print("WARNING: Unknown setting %s" % name)
 | 
			
		||||
 | 
			
		||||
    # Set all the defaults (this propagates through all subparsers)
 | 
			
		||||
    # Set all the defaults and manually propagate them to subparsers
 | 
			
		||||
    main_parser.set_defaults(**defaults)
 | 
			
		||||
    for parser, pdefs in zip(parsers, parser_defaults):
 | 
			
		||||
        parser.set_defaults(**{ k: v for k, v in defaults.items()
 | 
			
		||||
                                    if k in pdefs })
 | 
			
		||||
 | 
			
		||||
def _ReadAliasFile(fname):
 | 
			
		||||
    """Read in the U-Boot git alias file if it exists.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ from patman import command
 | 
			
		|||
 | 
			
		||||
from io import StringIO
 | 
			
		||||
 | 
			
		||||
buffer_outputs = True
 | 
			
		||||
use_concurrent = True
 | 
			
		||||
try:
 | 
			
		||||
    from concurrencytest.concurrencytest import ConcurrentTestSuite
 | 
			
		||||
| 
						 | 
				
			
			@ -102,49 +103,85 @@ def capture_sys_output():
 | 
			
		|||
        sys.stdout, sys.stderr = old_out, old_err
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def report_result(toolname:str, test_name: str, result: unittest.TestResult):
 | 
			
		||||
    """Report the results from a suite of tests
 | 
			
		||||
class FullTextTestResult(unittest.TextTestResult):
 | 
			
		||||
    """A test result class that can print extended text results to a stream
 | 
			
		||||
 | 
			
		||||
    This is meant to be used by a TestRunner as a result class. Like
 | 
			
		||||
    TextTestResult, this prints out the names of tests as they are run,
 | 
			
		||||
    errors as they occur, and a summary of the results at the end of the
 | 
			
		||||
    test run. Beyond those, this prints information about skipped tests,
 | 
			
		||||
    expected failures and unexpected successes.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        toolname: Name of the tool that ran the tests
 | 
			
		||||
        test_name: Name of test that was run, or None for all
 | 
			
		||||
        result: A unittest.TestResult object containing the results
 | 
			
		||||
        stream: A file-like object to write results to
 | 
			
		||||
        descriptions (bool): True to print descriptions with test names
 | 
			
		||||
        verbosity (int): Detail of printed output per test as they run
 | 
			
		||||
            Test stdout and stderr always get printed when buffering
 | 
			
		||||
            them is disabled by the test runner. In addition to that,
 | 
			
		||||
            0: Print nothing
 | 
			
		||||
            1: Print a dot per test
 | 
			
		||||
            2: Print test names
 | 
			
		||||
            3: Print test names, and buffered outputs for failing tests
 | 
			
		||||
    """
 | 
			
		||||
    # Remove errors which just indicate a missing test. Since Python v3.5 If an
 | 
			
		||||
    # ImportError or AttributeError occurs while traversing name then a
 | 
			
		||||
    # synthetic test that raises that error when run will be returned. These
 | 
			
		||||
    # errors are included in the errors accumulated by result.errors.
 | 
			
		||||
    if test_name:
 | 
			
		||||
        errors = []
 | 
			
		||||
    def __init__(self, stream, descriptions, verbosity):
 | 
			
		||||
        self.verbosity = verbosity
 | 
			
		||||
        super().__init__(stream, descriptions, verbosity)
 | 
			
		||||
 | 
			
		||||
        for test, err in result.errors:
 | 
			
		||||
            if ("has no attribute '%s'" % test_name) not in err:
 | 
			
		||||
                errors.append((test, err))
 | 
			
		||||
            result.testsRun -= 1
 | 
			
		||||
        result.errors = errors
 | 
			
		||||
    def printErrors(self):
 | 
			
		||||
        "Called by TestRunner after test run to summarize the tests"
 | 
			
		||||
        # The parent class doesn't keep unexpected successes in the same
 | 
			
		||||
        # format as the rest. Adapt it to what printErrorList expects.
 | 
			
		||||
        unexpected_successes = [
 | 
			
		||||
            (test, 'Test was expected to fail, but succeeded.\n')
 | 
			
		||||
            for test in self.unexpectedSuccesses
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    print(result)
 | 
			
		||||
    for test, err in result.errors:
 | 
			
		||||
        print(test.id(), err)
 | 
			
		||||
    for test, err in result.failures:
 | 
			
		||||
        print(err, result.failures)
 | 
			
		||||
    if result.skipped:
 | 
			
		||||
        print('%d %s test%s SKIPPED:' % (len(result.skipped), toolname,
 | 
			
		||||
            's' if len(result.skipped) > 1 else ''))
 | 
			
		||||
        for skip_info in result.skipped:
 | 
			
		||||
            print('%s: %s' % (skip_info[0], skip_info[1]))
 | 
			
		||||
    if result.errors or result.failures:
 | 
			
		||||
        print('%s tests FAILED' % toolname)
 | 
			
		||||
        return 1
 | 
			
		||||
    return 0
 | 
			
		||||
        super().printErrors()  # FAIL and ERROR
 | 
			
		||||
        self.printErrorList('SKIP', self.skipped)
 | 
			
		||||
        self.printErrorList('XFAIL', self.expectedFailures)
 | 
			
		||||
        self.printErrorList('XPASS', unexpected_successes)
 | 
			
		||||
 | 
			
		||||
    def addError(self, test, err):
 | 
			
		||||
        """Called when an error has occurred."""
 | 
			
		||||
        super().addError(test, err)
 | 
			
		||||
        self._mirrorOutput &= self.verbosity >= 3
 | 
			
		||||
 | 
			
		||||
    def addFailure(self, test, err):
 | 
			
		||||
        """Called when a test has failed."""
 | 
			
		||||
        super().addFailure(test, err)
 | 
			
		||||
        self._mirrorOutput &= self.verbosity >= 3
 | 
			
		||||
 | 
			
		||||
    def addSubTest(self, test, subtest, err):
 | 
			
		||||
        """Called at the end of a subtest."""
 | 
			
		||||
        super().addSubTest(test, subtest, err)
 | 
			
		||||
        self._mirrorOutput &= self.verbosity >= 3
 | 
			
		||||
 | 
			
		||||
    def addSuccess(self, test):
 | 
			
		||||
        """Called when a test has completed successfully"""
 | 
			
		||||
        super().addSuccess(test)
 | 
			
		||||
        # Don't print stdout/stderr for successful tests
 | 
			
		||||
        self._mirrorOutput = False
 | 
			
		||||
 | 
			
		||||
    def addSkip(self, test, reason):
 | 
			
		||||
        """Called when a test is skipped."""
 | 
			
		||||
        # Add empty line to keep spacing consistent with other results
 | 
			
		||||
        if not reason.endswith('\n'):
 | 
			
		||||
            reason += '\n'
 | 
			
		||||
        super().addSkip(test, reason)
 | 
			
		||||
        self._mirrorOutput &= self.verbosity >= 3
 | 
			
		||||
 | 
			
		||||
    def addExpectedFailure(self, test, err):
 | 
			
		||||
        """Called when an expected failure/error occurred."""
 | 
			
		||||
        super().addExpectedFailure(test, err)
 | 
			
		||||
        self._mirrorOutput &= self.verbosity >= 3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
 | 
			
		||||
def run_test_suites(toolname, debug, verbosity, test_preserve_dirs, processes,
 | 
			
		||||
                    test_name, toolpath, class_and_module_list):
 | 
			
		||||
    """Run a series of test suites and collect the results
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        result: A unittest.TestResult object to add the results to
 | 
			
		||||
        toolname: Name of the tool that ran the tests
 | 
			
		||||
        debug: True to enable debugging, which shows a full stack trace on error
 | 
			
		||||
        verbosity: Verbosity level to use (0-4)
 | 
			
		||||
        test_preserve_dirs: True to preserve the input directory used by tests
 | 
			
		||||
| 
						 | 
				
			
			@ -158,11 +195,6 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
 | 
			
		|||
        class_and_module_list: List of test classes (type class) and module
 | 
			
		||||
           names (type str) to run
 | 
			
		||||
    """
 | 
			
		||||
    for module in class_and_module_list:
 | 
			
		||||
        if isinstance(module, str) and (not test_name or test_name == module):
 | 
			
		||||
            suite = doctest.DocTestSuite(module)
 | 
			
		||||
            suite.run(result)
 | 
			
		||||
 | 
			
		||||
    sys.argv = [sys.argv[0]]
 | 
			
		||||
    if debug:
 | 
			
		||||
        sys.argv.append('-D')
 | 
			
		||||
| 
						 | 
				
			
			@ -174,6 +206,22 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
 | 
			
		|||
 | 
			
		||||
    suite = unittest.TestSuite()
 | 
			
		||||
    loader = unittest.TestLoader()
 | 
			
		||||
    runner = unittest.TextTestRunner(
 | 
			
		||||
        stream=sys.stdout,
 | 
			
		||||
        verbosity=(1 if verbosity is None else verbosity),
 | 
			
		||||
        buffer=buffer_outputs,
 | 
			
		||||
        resultclass=FullTextTestResult,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if use_concurrent and processes != 1:
 | 
			
		||||
        suite = ConcurrentTestSuite(suite,
 | 
			
		||||
                fork_for_tests(processes or multiprocessing.cpu_count(),
 | 
			
		||||
                               buffer=buffer_outputs))
 | 
			
		||||
 | 
			
		||||
    for module in class_and_module_list:
 | 
			
		||||
        if isinstance(module, str) and (not test_name or test_name == module):
 | 
			
		||||
            suite.addTests(doctest.DocTestSuite(module))
 | 
			
		||||
 | 
			
		||||
    for module in class_and_module_list:
 | 
			
		||||
        if isinstance(module, str):
 | 
			
		||||
            continue
 | 
			
		||||
| 
						 | 
				
			
			@ -184,15 +232,17 @@ def run_test_suites(result, debug, verbosity, test_preserve_dirs, processes,
 | 
			
		|||
                preserve_outdirs=test_preserve_dirs and test_name is not None,
 | 
			
		||||
                toolpath=toolpath, verbosity=verbosity)
 | 
			
		||||
        if test_name:
 | 
			
		||||
            try:
 | 
			
		||||
            # Since Python v3.5 If an ImportError or AttributeError occurs
 | 
			
		||||
            # while traversing a name then a synthetic test that raises that
 | 
			
		||||
            # error when run will be returned. Check that the requested test
 | 
			
		||||
            # exists, otherwise these errors are included in the results.
 | 
			
		||||
            if test_name in loader.getTestCaseNames(module):
 | 
			
		||||
                suite.addTests(loader.loadTestsFromName(test_name, module))
 | 
			
		||||
            except AttributeError:
 | 
			
		||||
                continue
 | 
			
		||||
        else:
 | 
			
		||||
            suite.addTests(loader.loadTestsFromTestCase(module))
 | 
			
		||||
    if use_concurrent and processes != 1:
 | 
			
		||||
        concurrent_suite = ConcurrentTestSuite(suite,
 | 
			
		||||
                fork_for_tests(processes or multiprocessing.cpu_count()))
 | 
			
		||||
        concurrent_suite.run(result)
 | 
			
		||||
    else:
 | 
			
		||||
        suite.run(result)
 | 
			
		||||
 | 
			
		||||
    print(f" Running {toolname} tests ".center(70, "="))
 | 
			
		||||
    result = runner.run(suite)
 | 
			
		||||
    print()
 | 
			
		||||
 | 
			
		||||
    return result
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue