dtoc improvements to show better warnings
minor test build fixes sandbox fixes for SDL2 and running TPL bloblist resize feature binman multithreading -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmD41JkRHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIrea8+wgArpcRqyC2nCYtdDl1q/8mWQabct2rUJVt rzIYzgyPgkRBLQjlE8xgEchzAPOuw0YzQnEz3T80wepBPIy53+QYXaqumd9iuhtm B1x4r/GumqS4qgn9Pfqxabw2eP8DNbxClc14ExDx3zR1pUwp0DRvnYQV/w+W2RQp nWFKDdhdnkxuXApiVc01RF/9I+IygstVl1TUklxlw9EGkdpirczIX5cP2lhW9rsV Cm4fPz4V6AphiUQ4RpllossBNVHHlbVyKOtdGWe4CrERH8Zv8tIVRVeHCr0GydPr ORhIZTk7hmwTav3Zi4XAQ434UZcRVrJFRkZvv8TpmMhMTVb8+gyZaQ== =F/gP -----END PGP SIGNATURE----- Merge tag 'dm-pull-21jul21' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm dtoc improvements to show better warnings minor test build fixes sandbox fixes for SDL2 and running TPL bloblist resize feature binman multithreading
This commit is contained in:
commit
a15fa1ba67
@ -226,7 +226,7 @@ int os_setup_signal_handlers(void)
|
||||
|
||||
act.sa_sigaction = os_signal_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGILL, &act, NULL) ||
|
||||
sigaction(SIGBUS, &act, NULL) ||
|
||||
sigaction(SIGSEGV, &act, NULL))
|
||||
@ -783,12 +783,14 @@ int os_jump_to_image(const void *dest, int size)
|
||||
return os_jump_to_file(fname, true);
|
||||
}
|
||||
|
||||
int os_find_u_boot(char *fname, int maxlen, bool use_img)
|
||||
int os_find_u_boot(char *fname, int maxlen, bool use_img,
|
||||
const char *cur_prefix, const char *next_prefix)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
const char *progname = state->argv[0];
|
||||
int len = strlen(progname);
|
||||
const char *suffix;
|
||||
char subdir[10];
|
||||
char *suffix;
|
||||
char *p;
|
||||
int fd;
|
||||
|
||||
@ -798,45 +800,36 @@ int os_find_u_boot(char *fname, int maxlen, bool use_img)
|
||||
strcpy(fname, progname);
|
||||
suffix = fname + len - 4;
|
||||
|
||||
/* If we are TPL, boot to SPL */
|
||||
if (!strcmp(suffix, "-tpl")) {
|
||||
fname[len - 3] = 's';
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
/* Change the existing suffix to the new one */
|
||||
if (*suffix != '-')
|
||||
return -EINVAL;
|
||||
|
||||
/* Look for 'u-boot-spl' in the spl/ directory */
|
||||
p = strstr(fname, "/spl/");
|
||||
if (p) {
|
||||
p[1] = 's';
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
if (*next_prefix)
|
||||
strcpy(suffix + 1, next_prefix); /* e.g. "-tpl" to "-spl" */
|
||||
else
|
||||
*suffix = '\0'; /* e.g. "-spl" to "" */
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look for 'u-boot' in the same directory as 'u-boot-spl' */
|
||||
if (!strcmp(suffix, "-spl")) {
|
||||
fname[len - 4] = '\0';
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for 'u-boot' in the parent directory of spl/ */
|
||||
p = strstr(fname, "spl/");
|
||||
/*
|
||||
* We didn't find it, so try looking for 'u-boot-xxx' in the xxx/
|
||||
* directory. Replace the old dirname with the new one.
|
||||
*/
|
||||
snprintf(subdir, sizeof(subdir), "/%s/", cur_prefix);
|
||||
p = strstr(fname, subdir);
|
||||
if (p) {
|
||||
/* Remove the "spl" characters */
|
||||
memmove(p, p + 4, strlen(p + 4) + 1);
|
||||
if (*next_prefix)
|
||||
/* e.g. ".../tpl/u-boot-spl" to "../spl/u-boot-spl" */
|
||||
memcpy(p + 1, next_prefix, strlen(next_prefix));
|
||||
else
|
||||
/* e.g. ".../spl/u-boot" to ".../u-boot" */
|
||||
strcpy(p, p + 1 + strlen(cur_prefix));
|
||||
if (use_img)
|
||||
strcat(p, ".img");
|
||||
|
||||
fd = os_open(fname, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
|
@ -123,6 +123,9 @@ int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
||||
sdl.vis_height = sdl.height;
|
||||
}
|
||||
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
|
||||
printf("Unable to init hinting: %s", SDL_GetError());
|
||||
|
||||
sdl.depth = 1 << log2_bpp;
|
||||
sdl.pitch = sdl.width * sdl.depth / 8;
|
||||
SDL_Window *screen = SDL_CreateWindow("U-Boot", SDL_WINDOWPOS_UNDEFINED,
|
||||
@ -164,8 +167,29 @@ int sandbox_sdl_init_display(int width, int height, int log2_bpp,
|
||||
|
||||
int sandbox_sdl_sync(void *lcd_base)
|
||||
{
|
||||
struct SDL_Rect rect;
|
||||
int ret;
|
||||
|
||||
if (!sdl.texture)
|
||||
return 0;
|
||||
SDL_RenderClear(sdl.renderer);
|
||||
SDL_UpdateTexture(sdl.texture, NULL, lcd_base, sdl.pitch);
|
||||
SDL_RenderCopy(sdl.renderer, sdl.texture, NULL, NULL);
|
||||
ret = SDL_RenderCopy(sdl.renderer, sdl.texture, NULL, NULL);
|
||||
if (ret) {
|
||||
printf("SDL copy %d: %s\n", ret, SDL_GetError());
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* On some machines this does not appear. Draw an empty rectangle which
|
||||
* seems to fix that.
|
||||
*/
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = 0;
|
||||
rect.h = 0;
|
||||
SDL_RenderDrawRect(sdl.renderer, &rect);
|
||||
|
||||
SDL_RenderPresent(sdl.renderer);
|
||||
sandbox_sdl_poll_events();
|
||||
|
||||
|
@ -17,6 +17,20 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int sandbox_find_next_phase(char *fname, int maxlen, bool use_img)
|
||||
{
|
||||
const char *cur_prefix, *next_prefix;
|
||||
int ret;
|
||||
|
||||
cur_prefix = spl_phase_prefix(spl_phase());
|
||||
next_prefix = spl_phase_prefix(spl_next_phase());
|
||||
ret = os_find_u_boot(fname, maxlen, use_img, cur_prefix, next_prefix);
|
||||
if (ret)
|
||||
return log_msg_ret("find", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SPL / TPL init function */
|
||||
void board_init_f(ulong flag)
|
||||
{
|
||||
@ -37,7 +51,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image,
|
||||
char fname[256];
|
||||
int ret;
|
||||
|
||||
ret = os_find_u_boot(fname, sizeof(fname), false);
|
||||
ret = sandbox_find_next_phase(fname, sizeof(fname), false);
|
||||
if (ret) {
|
||||
printf("(%s not found, error %d)\n", fname, ret);
|
||||
return ret;
|
||||
|
@ -819,6 +819,7 @@
|
||||
|
||||
mmc2 {
|
||||
compatible = "sandbox,mmc";
|
||||
non-removable;
|
||||
};
|
||||
|
||||
mmc1 {
|
||||
|
@ -12,4 +12,17 @@ enum {
|
||||
BOOT_DEVICE_BOARD,
|
||||
};
|
||||
|
||||
/**
|
||||
* sandbox_find_next_phase() - Find the next phase of U-Boot
|
||||
*
|
||||
* This function is intended to be called from within sandbox SPL. It uses
|
||||
* a few rules to find the filename of the next U-Boot phase. See also
|
||||
* os_find_u_boot().
|
||||
*
|
||||
* @fname: place to put full path to U-Boot
|
||||
* @maxlen: maximum size of @fname
|
||||
* @use_img: select the 'u-boot.img' file instead of the 'u-boot' ELF file
|
||||
*/
|
||||
int sandbox_find_next_phase(char *fname, int maxlen, bool use_img);
|
||||
|
||||
#endif
|
||||
|
@ -322,6 +322,14 @@ config LOGF_FUNC
|
||||
Show the function name in log messages by default. This value can
|
||||
be overridden using the 'log format' command.
|
||||
|
||||
config LOGF_FUNC_PAD
|
||||
int "Number of characters to use for function"
|
||||
default 20
|
||||
help
|
||||
Sets the field width to use when showing the function. Set this to
|
||||
a larger value if you have lots of long function names, and want
|
||||
things to line up.
|
||||
|
||||
config LOG_SYSLOG
|
||||
bool "Log output to syslog server"
|
||||
depends on NET
|
||||
@ -724,7 +732,7 @@ config BLOBLIST_SIZE
|
||||
config BLOBLIST_ADDR
|
||||
hex "Address of bloblist"
|
||||
depends on BLOBLIST
|
||||
default 0xe000 if SANDBOX
|
||||
default 0xc000 if SANDBOX
|
||||
help
|
||||
Sets the address of the bloblist, set up by the first part of U-Boot
|
||||
which runs. Subsequent U-Boot stages typically use the same address.
|
||||
|
@ -57,13 +57,22 @@ static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
|
||||
return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
|
||||
}
|
||||
|
||||
static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
|
||||
struct bloblist_rec *rec)
|
||||
static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr,
|
||||
struct bloblist_rec *rec)
|
||||
{
|
||||
ulong offset;
|
||||
|
||||
offset = (void *)rec - (void *)hdr;
|
||||
offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
|
||||
struct bloblist_rec *rec)
|
||||
{
|
||||
ulong offset = bloblist_blob_end_ofs(hdr, rec);
|
||||
|
||||
if (offset >= hdr->alloced)
|
||||
return NULL;
|
||||
return (struct bloblist_rec *)((void *)hdr + offset);
|
||||
@ -109,7 +118,7 @@ static int bloblist_addrec(uint tag, int size, int align,
|
||||
/* Calculate the new allocated total */
|
||||
new_alloced = data_start + ALIGN(size, align);
|
||||
|
||||
if (new_alloced >= hdr->size) {
|
||||
if (new_alloced > hdr->size) {
|
||||
log(LOGC_BLOBLIST, LOGL_ERR,
|
||||
"Failed to allocate %x bytes size=%x, need size=%x\n",
|
||||
size, hdr->size, new_alloced);
|
||||
@ -215,6 +224,64 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bloblist_resize_rec(struct bloblist_hdr *hdr,
|
||||
struct bloblist_rec *rec,
|
||||
int new_size)
|
||||
{
|
||||
int expand_by; /* Number of bytes to expand by (-ve to contract) */
|
||||
int new_alloced; /* New value for @hdr->alloced */
|
||||
ulong next_ofs; /* Offset of the record after @rec */
|
||||
|
||||
expand_by = ALIGN(new_size - rec->size, BLOBLIST_ALIGN);
|
||||
new_alloced = ALIGN(hdr->alloced + expand_by, BLOBLIST_ALIGN);
|
||||
if (new_size < 0) {
|
||||
log(LOGC_BLOBLIST, LOGL_DEBUG,
|
||||
"Attempt to shrink blob size below 0 (%x)\n", new_size);
|
||||
return log_msg_ret("size", -EINVAL);
|
||||
}
|
||||
if (new_alloced > hdr->size) {
|
||||
log(LOGC_BLOBLIST, LOGL_ERR,
|
||||
"Failed to allocate %x bytes size=%x, need size=%x\n",
|
||||
new_size, hdr->size, new_alloced);
|
||||
return log_msg_ret("alloc", -ENOSPC);
|
||||
}
|
||||
|
||||
/* Move the following blobs up or down, if this is not the last */
|
||||
next_ofs = bloblist_blob_end_ofs(hdr, rec);
|
||||
if (next_ofs != hdr->alloced) {
|
||||
memmove((void *)hdr + next_ofs + expand_by,
|
||||
(void *)hdr + next_ofs, new_alloced - next_ofs);
|
||||
}
|
||||
hdr->alloced = new_alloced;
|
||||
|
||||
/* Zero the new part of the blob */
|
||||
if (expand_by > 0) {
|
||||
memset((void *)rec + rec->hdr_size + rec->size, '\0',
|
||||
new_size - rec->size);
|
||||
}
|
||||
|
||||
/* Update the size of this blob */
|
||||
rec->size = new_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bloblist_resize(uint tag, int new_size)
|
||||
{
|
||||
struct bloblist_hdr *hdr = gd->bloblist;
|
||||
struct bloblist_rec *rec;
|
||||
int ret;
|
||||
|
||||
rec = bloblist_findrec(tag);
|
||||
if (!rec)
|
||||
return log_msg_ret("find", -ENOENT);
|
||||
ret = bloblist_resize_rec(hdr, rec, new_size);
|
||||
if (ret)
|
||||
return log_msg_ret("resize", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
|
||||
{
|
||||
struct bloblist_rec *rec;
|
||||
|
@ -1377,7 +1377,7 @@ int fit_image_verify(const void *fit, int image_noffset)
|
||||
size_t size;
|
||||
char *err_msg = "";
|
||||
|
||||
if (strchr(name, '@')) {
|
||||
if (IS_ENABLED(CONFIG_FIT_SIGNATURE) && strchr(name, '@')) {
|
||||
/*
|
||||
* We don't support this since libfdt considers names with the
|
||||
* name root but different @ suffix to be equal
|
||||
|
@ -38,7 +38,7 @@ static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
|
||||
if (fmt & BIT(LOGF_LINE))
|
||||
printf("%d-", rec->line);
|
||||
if (fmt & BIT(LOGF_FUNC))
|
||||
printf("%s()", rec->func);
|
||||
printf("%*s()", CONFIG_LOGF_FUNC_PAD, rec->func);
|
||||
}
|
||||
if (fmt & BIT(LOGF_MSG))
|
||||
printf("%s%s", add_space ? " " : "", rec->msg);
|
||||
|
@ -91,6 +91,16 @@ config SPL_SYS_REPORT_STACK_F_USAGE
|
||||
occurrence of non 0xaa bytes.
|
||||
This default implementation works for stacks growing down only.
|
||||
|
||||
config SPL_SHOW_ERRORS
|
||||
bool "Show more information when something goes wrong"
|
||||
help
|
||||
This enabled more verbose error messages and checking when something
|
||||
goes wrong in SPL. For example, it shows the error code when U-Boot
|
||||
cannot be located. This can help to diagnose the problem and figure
|
||||
out a fix, particularly during development.
|
||||
|
||||
This adds a small amount to SPL code size, perhaps 100 bytes.
|
||||
|
||||
menu "PowerPC and LayerScape SPL Boot options"
|
||||
|
||||
config SPL_NAND_BOOT
|
||||
|
@ -593,32 +593,42 @@ static int spl_load_image(struct spl_image_info *spl_image,
|
||||
* @spl_image: Place to put the image details if successful
|
||||
* @spl_boot_list: List of boot devices to try
|
||||
* @count: Number of elements in spl_boot_list
|
||||
* @return 0 if OK, -ve on error
|
||||
* @return 0 if OK, -ENODEV if there were no boot devices
|
||||
* if CONFIG_SHOW_ERRORS is enabled, returns -ENXIO if there were
|
||||
* devices but none worked
|
||||
*/
|
||||
static int boot_from_devices(struct spl_image_info *spl_image,
|
||||
u32 spl_boot_list[], int count)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) {
|
||||
struct spl_image_loader *loader;
|
||||
int bootdev = spl_boot_list[i];
|
||||
|
||||
loader = spl_ll_find_loader(spl_boot_list[i]);
|
||||
#if defined(CONFIG_SPL_SERIAL_SUPPORT) \
|
||||
&& defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \
|
||||
&& !defined(CONFIG_SILENT_CONSOLE)
|
||||
if (loader)
|
||||
printf("Trying to boot from %s\n", loader->name);
|
||||
else
|
||||
puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
|
||||
#endif
|
||||
if (CONFIG_IS_ENABLED(SHOW_ERRORS))
|
||||
ret = -ENXIO;
|
||||
loader = spl_ll_find_loader(bootdev);
|
||||
if (CONFIG_IS_ENABLED(SERIAL_SUPPORT) &&
|
||||
CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT) &&
|
||||
!IS_ENABLED(CONFIG_SILENT_CONSOLE)) {
|
||||
if (loader)
|
||||
printf("Trying to boot from %s\n",
|
||||
spl_loader_name(loader));
|
||||
else if (CONFIG_IS_ENABLED(SHOW_ERRORS))
|
||||
printf(SPL_TPL_PROMPT
|
||||
"Unsupported Boot Device %d\n", bootdev);
|
||||
else
|
||||
puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
|
||||
}
|
||||
if (loader && !spl_load_image(spl_image, loader)) {
|
||||
spl_image->boot_device = spl_boot_list[i];
|
||||
spl_image->boot_device = bootdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPL_FRAMEWORK_BOARD_INIT_F)
|
||||
@ -710,9 +720,15 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
||||
spl_image.boot_device = BOOT_DEVICE_NONE;
|
||||
board_boot_order(spl_boot_list);
|
||||
|
||||
if (boot_from_devices(&spl_image, spl_boot_list,
|
||||
ARRAY_SIZE(spl_boot_list))) {
|
||||
puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n");
|
||||
ret = boot_from_devices(&spl_image, spl_boot_list,
|
||||
ARRAY_SIZE(spl_boot_list));
|
||||
if (ret) {
|
||||
if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
|
||||
CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT))
|
||||
printf(SPL_TPL_PROMPT "failed to boot from all boot devices (err=%d)\n",
|
||||
ret);
|
||||
else
|
||||
puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
|
@ -510,7 +510,7 @@ that are mapped into that memory:
|
||||
Addr Config Usage
|
||||
======= ======================== ===============================
|
||||
0 CONFIG_SYS_FDT_LOAD_ADDR Device tree
|
||||
e000 CONFIG_BLOBLIST_ADDR Blob list
|
||||
c000 CONFIG_BLOBLIST_ADDR Blob list
|
||||
10000 CONFIG_MALLOC_F_ADDR Early memory allocation
|
||||
f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer
|
||||
100000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used
|
||||
|
@ -597,6 +597,59 @@ as a macro included in the driver definition::
|
||||
|
||||
|
||||
|
||||
Problems
|
||||
--------
|
||||
|
||||
In some cases you will you see something like this::
|
||||
|
||||
WARNING: the driver rockchip_rk3188_grf was not found in the driver list
|
||||
|
||||
The driver list is a list of drivers, each with a name. The name is in the
|
||||
U_BOOT_DRIVER() declaration, repeated twice, one in brackets and once as the
|
||||
.name member. For example, in the following declaration the driver name is
|
||||
`rockchip_rk3188_grf`::
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3188_grf) = {
|
||||
.name = "rockchip_rk3188_grf",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = rk3188_syscon_ids + 1,
|
||||
.bind = rk3188_syscon_bind_of_plat,
|
||||
};
|
||||
|
||||
The first name U_BOOT_DRIVER(xx) is used to create a linker symbol so that the
|
||||
driver can be accessed at build-time without any overhead. The second one
|
||||
(.name = "xx") is used at runtime when something wants to print out the driver
|
||||
name.
|
||||
|
||||
The dtoc tool expects to be able to find a driver for each compatible string in
|
||||
the devicetree. For example, if the devicetree has::
|
||||
|
||||
grf: grf@20008000 {
|
||||
compatible = "rockchip,rk3188-grf", "syscon";
|
||||
reg = <0x20008000 0x200>;
|
||||
u-boot,dm-spl;
|
||||
};
|
||||
|
||||
then dtoc looks at the first compatible string ("rockchip,rk3188-grf"),
|
||||
converts that to a C identifier (rockchip_rk3188_grf) and then looks for that.
|
||||
|
||||
Various things can cause dtoc to fail to find the driver and it tries to
|
||||
warn about these. For example:
|
||||
|
||||
rockchip_rk3188_uart: Missing .compatible in drivers/serial/serial_rockchip.c
|
||||
: WARNING: the driver rockchip_rk3188_uart was not found in the driver list
|
||||
|
||||
Without a compatible string a driver cannot be used by dtoc, even if the
|
||||
compatible string is not actually needed at runtime.
|
||||
|
||||
If the problem is simply that there are multiple compatible strings, the
|
||||
DM_DRIVER_ALIAS() macro can be used to tell dtoc about this and avoid a problem.
|
||||
|
||||
Checks are also made to confirm that the referenced driver has a .compatible
|
||||
member and a .id member. The first provides the array of compatible strings and
|
||||
the second provides the uclass ID.
|
||||
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
|
@ -540,6 +540,55 @@ int blk_next_free_devnum(enum if_type if_type)
|
||||
return ret + 1;
|
||||
}
|
||||
|
||||
static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
|
||||
{
|
||||
const struct blk_desc *desc = dev_get_uclass_plat(dev);
|
||||
enum blk_flag_t flags;
|
||||
|
||||
flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
|
||||
|
||||
return flags & req_flags ? 0 : 1;
|
||||
}
|
||||
|
||||
int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (ret = uclass_first_device_err(UCLASS_BLK, devp);
|
||||
!ret;
|
||||
ret = uclass_next_device_err(devp)) {
|
||||
if (!blk_flags_check(*devp, flags))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (ret = uclass_next_device_err(devp);
|
||||
!ret;
|
||||
ret = uclass_next_device_err(devp)) {
|
||||
if (!blk_flags_check(*devp, flags))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int blk_count_devices(enum blk_flag_t flag)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int count = 0;
|
||||
|
||||
blk_foreach_probe(flag, dev)
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int blk_claim_devnum(enum if_type if_type, int devnum)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
@ -87,8 +87,10 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL) &&
|
||||
!CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
if (uc->uc_drv->name && ofnode_valid(node)) {
|
||||
if (!dev_read_alias_seq(dev, &dev->seq_))
|
||||
if (!dev_read_alias_seq(dev, &dev->seq_)) {
|
||||
auto_seq = false;
|
||||
log_debug(" - seq=%d\n", dev->seq_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
|
||||
if (prop) {
|
||||
if (!strcmp(prop, "lz4"))
|
||||
entry->compress_algo = FMAP_COMPRESS_LZ4;
|
||||
else if (!strcmp(prop, "lzma"))
|
||||
entry->compress_algo = FMAP_COMPRESS_LZMA;
|
||||
else
|
||||
return log_msg_ret("compression algo", -EINVAL);
|
||||
} else {
|
||||
|
@ -329,7 +329,8 @@ static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
|
||||
{
|
||||
int na, ns;
|
||||
|
||||
*size = FDT_SIZE_T_NONE;
|
||||
if (size)
|
||||
*size = FDT_SIZE_T_NONE;
|
||||
|
||||
if (ofnode_is_np(node)) {
|
||||
const __be32 *prop_val;
|
||||
@ -340,6 +341,7 @@ static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
|
||||
&flags);
|
||||
if (!prop_val)
|
||||
return FDT_ADDR_T_NONE;
|
||||
|
||||
if (size)
|
||||
*size = size64;
|
||||
|
||||
@ -359,8 +361,6 @@ static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
|
||||
index, na, ns, size,
|
||||
translate);
|
||||
}
|
||||
|
||||
return FDT_ADDR_T_NONE;
|
||||
}
|
||||
|
||||
fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
|
||||
|
@ -754,17 +754,6 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cros_ec_entering_mode(struct udevice *dev, int mode)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ec_command(dev, EC_CMD_ENTERING_MODE, 0, &mode, sizeof(mode),
|
||||
NULL, 0);
|
||||
if (rc)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_check_version(struct udevice *dev)
|
||||
{
|
||||
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
|
||||
@ -1661,6 +1650,23 @@ int cros_ec_get_switches(struct udevice *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cros_ec_read_batt_charge(struct udevice *dev, uint *chargep)
|
||||
{
|
||||
struct ec_params_charge_state req;
|
||||
struct ec_response_charge_state resp;
|
||||
int ret;
|
||||
|
||||
req.cmd = CHARGE_STATE_CMD_GET_STATE;
|
||||
ret = ec_command(dev, EC_CMD_CHARGE_STATE, 0, &req, sizeof(req),
|
||||
&resp, sizeof(resp));
|
||||
if (ret)
|
||||
return log_msg_ret("read", ret);
|
||||
|
||||
*chargep = resp.get_state.batt_state_of_charge;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(cros_ec) = {
|
||||
.id = UCLASS_CROS_EC,
|
||||
.name = "cros-ec",
|
||||
|
@ -343,15 +343,13 @@ static int process_cmd(struct ec_state *ec,
|
||||
|
||||
switch (req->op) {
|
||||
case EC_VBNV_CONTEXT_OP_READ:
|
||||
/* TODO(sjg@chromium.org): Support full-size context */
|
||||
memcpy(resp->block, ec->vbnv_context,
|
||||
EC_VBNV_BLOCK_SIZE);
|
||||
len = 16;
|
||||
EC_VBNV_BLOCK_SIZE_V2);
|
||||
len = EC_VBNV_BLOCK_SIZE_V2;
|
||||
break;
|
||||
case EC_VBNV_CONTEXT_OP_WRITE:
|
||||
/* TODO(sjg@chromium.org): Support full-size context */
|
||||
memcpy(ec->vbnv_context, req->block,
|
||||
EC_VBNV_BLOCK_SIZE);
|
||||
EC_VBNV_BLOCK_SIZE_V2);
|
||||
len = 0;
|
||||
break;
|
||||
default:
|
||||
@ -496,9 +494,6 @@ static int process_cmd(struct ec_state *ec,
|
||||
case EC_CMD_MKBP_STATE:
|
||||
len = cros_ec_keyscan(ec, resp_data);
|
||||
break;
|
||||
case EC_CMD_ENTERING_MODE:
|
||||
len = 0;
|
||||
break;
|
||||
case EC_CMD_GET_NEXT_EVENT: {
|
||||
struct ec_response_get_next_event *resp = resp_data;
|
||||
|
||||
@ -629,15 +624,19 @@ void cros_ec_check_keyboard(struct udevice *dev)
|
||||
struct ec_state *ec = dev_get_priv(dev);
|
||||
ulong start;
|
||||
|
||||
printf("Press keys for EC to detect on reset (ESC=recovery)...");
|
||||
printf("\nPress keys for EC to detect on reset (ESC=recovery)...");
|
||||
start = get_timer(0);
|
||||
while (get_timer(start) < 1000)
|
||||
;
|
||||
putc('\n');
|
||||
if (!sandbox_sdl_key_pressed(KEY_ESC)) {
|
||||
ec->recovery_req = true;
|
||||
printf(" - EC requests recovery\n");
|
||||
while (get_timer(start) < 2000) {
|
||||
if (tstc()) {
|
||||
int ch = getchar();
|
||||
|
||||
if (ch == 0x1b) {
|
||||
ec->recovery_req = true;
|
||||
printf("EC requests recovery");
|
||||
}
|
||||
}
|
||||
}
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
/* Return the byte of EC switch states */
|
||||
|
@ -136,14 +136,31 @@ static const struct dm_mmc_ops sandbox_mmc_ops = {
|
||||
.get_cd = sandbox_mmc_get_cd,
|
||||
};
|
||||
|
||||
int sandbox_mmc_probe(struct udevice *dev)
|
||||
static int sandbox_mmc_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
|
||||
struct mmc_config *cfg = &plat->cfg;
|
||||
struct blk_desc *blk;
|
||||
int ret;
|
||||
|
||||
ret = mmc_of_parse(dev, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
blk = mmc_get_blk_desc(&plat->mmc);
|
||||
if (blk)
|
||||
blk->removable = !(cfg->host_caps & MMC_CAP_NONREMOVABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_mmc_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
|
||||
|
||||
return mmc_init(&plat->mmc);
|
||||
}
|
||||
|
||||
int sandbox_mmc_bind(struct udevice *dev)
|
||||
static int sandbox_mmc_bind(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
|
||||
struct mmc_config *cfg = &plat->cfg;
|
||||
@ -158,7 +175,7 @@ int sandbox_mmc_bind(struct udevice *dev)
|
||||
return mmc_bind(dev, &plat->mmc, cfg);
|
||||
}
|
||||
|
||||
int sandbox_mmc_unbind(struct udevice *dev)
|
||||
static int sandbox_mmc_unbind(struct udevice *dev)
|
||||
{
|
||||
mmc_unbind(dev);
|
||||
|
||||
@ -177,6 +194,7 @@ U_BOOT_DRIVER(mmc_sandbox) = {
|
||||
.ops = &sandbox_mmc_ops,
|
||||
.bind = sandbox_mmc_bind,
|
||||
.unbind = sandbox_mmc_unbind,
|
||||
.of_to_plat = sandbox_mmc_of_to_plat,
|
||||
.probe = sandbox_mmc_probe,
|
||||
.priv_auto = sizeof(struct sandbox_mmc_priv),
|
||||
.plat_auto = sizeof(struct sandbox_mmc_plat),
|
||||
|
@ -19,6 +19,8 @@ typedef ulong lbaint_t;
|
||||
#define LBAF "%" LBAFlength "x"
|
||||
#define LBAFU "%" LBAFlength "u"
|
||||
|
||||
struct udevice;
|
||||
|
||||
/* Interface types: */
|
||||
enum if_type {
|
||||
IF_TYPE_UNKNOWN = 0,
|
||||
@ -683,4 +685,58 @@ const char *blk_get_if_type_name(enum if_type if_type);
|
||||
int blk_common_cmd(int argc, char *const argv[], enum if_type if_type,
|
||||
int *cur_devnump);
|
||||
|
||||
enum blk_flag_t {
|
||||
BLKF_FIXED = 1 << 0,
|
||||
BLKF_REMOVABLE = 1 << 1,
|
||||
BLKF_BOTH = BLKF_FIXED | BLKF_REMOVABLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* blk_first_device_err() - Get the first block device
|
||||
*
|
||||
* The device returned is probed if necessary, and ready for use
|
||||
*
|
||||
* @flags: Indicates type of device to return
|
||||
* @devp: Returns pointer to the first device in that uclass, or NULL if none
|
||||
* @return 0 if found, -ENODEV if not found, other -ve on error
|
||||
*/
|
||||
int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* blk_next_device_err() - Get the next block device
|
||||
*
|
||||
* The device returned is probed if necessary, and ready for use
|
||||
*
|
||||
* @flags: Indicates type of device to return
|
||||
* @devp: On entry, pointer to device to lookup. On exit, returns pointer
|
||||
* to the next device in the uclass if no error occurred, or -ENODEV if
|
||||
* there is no next device.
|
||||
* @return 0 if found, -ENODEV if not found, other -ve on error
|
||||
*/
|
||||
int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* blk_foreach_probe() - Helper function to iteration through block devices
|
||||
*
|
||||
* This creates a for() loop which works through the available devices in
|
||||
* a uclass in order from start to end. Devices are probed if necessary,
|
||||
* and ready for use.
|
||||
*
|
||||
* @flags: Indicates type of device to return
|
||||
* @dev: struct udevice * to hold the current device. Set to NULL when there
|
||||
* are no more devices.
|
||||
*/
|
||||
#define blk_foreach_probe(flags, pos) \
|
||||
for (int _ret = blk_first_device_err(flags, &(pos)); \
|
||||
!_ret && pos; \
|
||||
_ret = blk_next_device_err(flags, &(pos)))
|
||||
|
||||
/**
|
||||
* blk_count_devices() - count the number of devices of a particular type
|
||||
*
|
||||
* @flags: Indicates type of device to find
|
||||
* @return number of devices matching those flags
|
||||
*/
|
||||
int blk_count_devices(enum blk_flag_t flag);
|
||||
|
||||
#endif
|
||||
|
@ -64,10 +64,10 @@ enum bloblist_tag_t {
|
||||
* first bloblist_rec starts at this offset from the start of the header
|
||||
* @flags: Space for BLOBLISTF_... flags (none yet)
|
||||
* @magic: BLOBLIST_MAGIC
|
||||
* @size: Total size of all records (non-zero if valid) including this header.
|
||||
* @size: Total size of the bloblist (non-zero if valid) including this header.
|
||||
* The bloblist extends for this many bytes from the start of this header.
|
||||
* @alloced: Total size allocated for this bloblist. When adding new records,
|
||||
* the bloblist can grow up to this size. This starts out as
|
||||
* When adding new records, the bloblist can grow up to this size.
|
||||
* @alloced: Total size allocated so far for this bloblist. This starts out as
|
||||
* sizeof(bloblist_hdr) since we need at least that much space to store a
|
||||
* valid bloblist
|
||||
* @spare: Spare space (for future use)
|
||||
@ -179,6 +179,19 @@ void *bloblist_ensure(uint tag, int size);
|
||||
*/
|
||||
int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp);
|
||||
|
||||
/**
|
||||
* bloblist_resize() - resize a blob
|
||||
*
|
||||
* Any blobs above this one are relocated up or down. The resized blob remains
|
||||
* in the same place.
|
||||
*
|
||||
* @tag: Tag to add (enum bloblist_tag_t)
|
||||
* @new_size: New size of the blob (>0 to expand, <0 to contract)
|
||||
* @return 0 if OK, -ENOSPC if the bloblist does not have enough space, -ENOENT
|
||||
* if the tag is not found
|
||||
*/
|
||||
int bloblist_resize(uint tag, int new_size);
|
||||
|
||||
/**
|
||||
* bloblist_new() - Create a new, empty bloblist of a given size
|
||||
*
|
||||
@ -217,6 +230,10 @@ int bloblist_finish(void);
|
||||
* bloblist_get_stats() - Get information about the bloblist
|
||||
*
|
||||
* This returns useful information about the bloblist
|
||||
*
|
||||
* @basep: Returns base address of bloblist
|
||||
* @sizep: Returns the number of bytes used in the bloblist
|
||||
* @allocedp: Returns the total space allocated to the bloblist
|
||||
*/
|
||||
void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp);
|
||||
|
||||
|
@ -198,15 +198,6 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask,
|
||||
uint32_t set_flags,
|
||||
struct ec_response_flash_protect *resp);
|
||||
|
||||
/**
|
||||
* Notify EC of current boot mode
|
||||
*
|
||||
* @param dev CROS-EC device
|
||||
* @param vboot_mode Verified boot mode
|
||||
* @return 0 if ok, <0 on error
|
||||
*/
|
||||
int cros_ec_entering_mode(struct udevice *dev, int mode);
|
||||
|
||||
/**
|
||||
* Run internal tests on the cros_ec interface.
|
||||
*
|
||||
@ -652,4 +643,12 @@ int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data);
|
||||
int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* cros_ec_read_batt_charge() - Read the battery-charge state
|
||||
*
|
||||
* @dev: CROS-EC device
|
||||
* @chargep: Return battery-charge state as a percentage
|
||||
*/
|
||||
int cros_ec_read_batt_charge(struct udevice *dev, uint *chargep);
|
||||
|
||||
#endif
|
||||
|
@ -327,9 +327,12 @@ int os_jump_to_image(const void *dest, int size);
|
||||
* @fname: place to put full path to U-Boot
|
||||
* @maxlen: maximum size of @fname
|
||||
* @use_img: select the 'u-boot.img' file instead of the 'u-boot' ELF file
|
||||
* @cur_prefix: prefix of current executable, e.g. "spl" or "tpl"
|
||||
* @next_prefix: prefix of executable to find, e.g. "spl" or ""
|
||||
* Return: 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found
|
||||
*/
|
||||
int os_find_u_boot(char *fname, int maxlen, bool use_img);
|
||||
int os_find_u_boot(char *fname, int maxlen, bool use_img,
|
||||
const char *cur_prefix, const char *next_prefix);
|
||||
|
||||
/**
|
||||
* os_spl_to_uboot() - Run U-Boot proper
|
||||
|
@ -176,6 +176,27 @@ static inline const char *spl_phase_name(enum u_boot_phase phase)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spl_phase_prefix() - Get the prefix of the current phase
|
||||
*
|
||||
* @phase: Phase to look up
|
||||
* @return phase prefix ("spl", "tpl", etc.)
|
||||
*/
|
||||
static inline const char *spl_phase_prefix(enum u_boot_phase phase)
|
||||
{
|
||||
switch (phase) {
|
||||
case PHASE_TPL:
|
||||
return "tpl";
|
||||
case PHASE_SPL:
|
||||
return "spl";
|
||||
case PHASE_BOARD_F:
|
||||
case PHASE_BOARD_R:
|
||||
return "";
|
||||
default:
|
||||
return "phase?";
|
||||
}
|
||||
}
|
||||
|
||||
/* A string name for SPL or TPL */
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
# ifdef CONFIG_TPL_BUILD
|
||||
@ -484,6 +505,16 @@ struct spl_image_loader {
|
||||
struct spl_boot_device *bootdev);
|
||||
};
|
||||
|
||||
/* Helper function for accessing the name */
|
||||
static inline const char *spl_loader_name(const struct spl_image_loader *loader)
|
||||
{
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
return loader->name;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Declare an SPL image loader */
|
||||
#define SPL_LOAD_IMAGE(__name) \
|
||||
ll_entry_declare(struct spl_image_loader, __name, spl_image_loader)
|
||||
|
@ -3,7 +3,9 @@
|
||||
# (C) Copyright 2012 The Chromium Authors
|
||||
|
||||
obj-y += test-main.o
|
||||
ifdef CONFIG_SPL_LOAD_FIT
|
||||
obj-$(CONFIG_SANDBOX) += image/
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_$(SPL_)BLOBLIST),)
|
||||
obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o
|
||||
|
215
test/bloblist.c
215
test/bloblist.c
@ -33,6 +33,9 @@ enum {
|
||||
ERASE_BYTE = '\xff',
|
||||
};
|
||||
|
||||
static const char test1_str[] = "the eyes are open";
|
||||
static const char test2_str[] = "the mouth moves";
|
||||
|
||||
static struct bloblist_hdr *clear_bloblist(void)
|
||||
{
|
||||
struct bloblist_hdr *hdr;
|
||||
@ -384,6 +387,218 @@ static int bloblist_test_reloc(struct unit_test_state *uts)
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_reloc, 0);
|
||||
|
||||
/* Test expansion of a blob */
|
||||
static int bloblist_test_grow(struct unit_test_state *uts)
|
||||
{
|
||||
const uint small_size = 0x20;
|
||||
void *blob1, *blob2, *blob1_new;
|
||||
struct bloblist_hdr *hdr;
|
||||
void *ptr;
|
||||
|
||||
ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
|
||||
hdr = ptr;
|
||||
memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
|
||||
|
||||
/* Create two blobs */
|
||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
|
||||
blob1 = bloblist_add(TEST_TAG, small_size, 0);
|
||||
ut_assertnonnull(blob1);
|
||||
ut_assertok(check_zero(blob1, small_size));
|
||||
strcpy(blob1, test1_str);
|
||||
|
||||
blob2 = bloblist_add(TEST_TAG2, small_size, 0);
|
||||
ut_assertnonnull(blob2);
|
||||
strcpy(blob2, test2_str);
|
||||
|
||||
ut_asserteq(sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2,
|
||||
hdr->alloced);
|
||||
|
||||
/* Resize the first one */
|
||||
ut_assertok(bloblist_resize(TEST_TAG, small_size + 4));
|
||||
|
||||
/* The first one should not have moved, just got larger */
|
||||
blob1_new = bloblist_find(TEST_TAG, small_size + 4);
|
||||
ut_asserteq_ptr(blob1, blob1_new);
|
||||
|
||||
/* The new space should be zeroed */
|
||||
ut_assertok(check_zero(blob1 + small_size, 4));
|
||||
|
||||
/* The second one should have moved */
|
||||
blob2 = bloblist_find(TEST_TAG2, small_size);
|
||||
ut_assertnonnull(blob2);
|
||||
ut_asserteq_str(test2_str, blob2);
|
||||
|
||||
/* The header should have more bytes in use */
|
||||
hdr = ptr;
|
||||
ut_asserteq(sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2 +
|
||||
BLOBLIST_ALIGN,
|
||||
hdr->alloced);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_grow, 0);
|
||||
|
||||
/* Test shrinking of a blob */
|
||||
static int bloblist_test_shrink(struct unit_test_state *uts)
|
||||
{
|
||||
const uint small_size = 0x20;
|
||||
void *blob1, *blob2, *blob1_new;
|
||||
struct bloblist_hdr *hdr;
|
||||
int new_size;
|
||||
void *ptr;
|
||||
|
||||
ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
|
||||
|
||||
/* Create two blobs */
|
||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
|
||||
blob1 = bloblist_add(TEST_TAG, small_size, 0);
|
||||
ut_assertnonnull(blob1);
|
||||
strcpy(blob1, test1_str);
|
||||
|
||||
blob2 = bloblist_add(TEST_TAG2, small_size, 0);
|
||||
ut_assertnonnull(blob2);
|
||||
strcpy(blob2, test2_str);
|
||||
|
||||
hdr = ptr;
|
||||
ut_asserteq(sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2,
|
||||
hdr->alloced);
|
||||
|
||||
/* Resize the first one */
|
||||
new_size = small_size - BLOBLIST_ALIGN - 4;
|
||||
ut_assertok(bloblist_resize(TEST_TAG, new_size));
|
||||
|
||||
/* The first one should not have moved, just got smaller */
|
||||
blob1_new = bloblist_find(TEST_TAG, new_size);
|
||||
ut_asserteq_ptr(blob1, blob1_new);
|
||||
|
||||
/* The second one should have moved */
|
||||
blob2 = bloblist_find(TEST_TAG2, small_size);
|
||||
ut_assertnonnull(blob2);
|
||||
ut_asserteq_str(test2_str, blob2);
|
||||
|
||||
/* The header should have fewer bytes in use */
|
||||
hdr = ptr;
|
||||
ut_asserteq(sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2 -
|
||||
BLOBLIST_ALIGN,
|
||||
hdr->alloced);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_shrink, 0);
|
||||
|
||||
/* Test failing to adjust a blob size */
|
||||
static int bloblist_test_resize_fail(struct unit_test_state *uts)
|
||||
{
|
||||
const uint small_size = 0x20;
|
||||
struct bloblist_hdr *hdr;
|
||||
void *blob1, *blob2;
|
||||
int new_size;
|
||||
void *ptr;
|
||||
|
||||
ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
|
||||
|
||||
/* Create two blobs */
|
||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
|
||||
blob1 = bloblist_add(TEST_TAG, small_size, 0);
|
||||
ut_assertnonnull(blob1);
|
||||
|
||||
blob2 = bloblist_add(TEST_TAG2, small_size, 0);
|
||||
ut_assertnonnull(blob2);
|
||||
|
||||
hdr = ptr;
|
||||
ut_asserteq(sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2,
|
||||
hdr->alloced);
|
||||
|
||||
/* Resize the first one, to check the boundary conditions */
|
||||
ut_asserteq(-EINVAL, bloblist_resize(TEST_TAG, -1));
|
||||
|
||||
new_size = small_size + (hdr->size - hdr->alloced);
|
||||
ut_asserteq(-ENOSPC, bloblist_resize(TEST_TAG, new_size + 1));
|
||||
ut_assertok(bloblist_resize(TEST_TAG, new_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_resize_fail, 0);
|
||||
|
||||
/* Test expanding the last blob in a bloblist */
|
||||
static int bloblist_test_resize_last(struct unit_test_state *uts)
|
||||
{
|
||||
const uint small_size = 0x20;
|
||||
struct bloblist_hdr *hdr;
|
||||
void *blob1, *blob2, *blob2_new;
|
||||
int alloced_val;
|
||||
void *ptr;
|
||||
|
||||
ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
|
||||
memset(ptr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
|
||||
hdr = ptr;
|
||||
|
||||
/* Create two blobs */
|
||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
|
||||
blob1 = bloblist_add(TEST_TAG, small_size, 0);
|
||||
ut_assertnonnull(blob1);
|
||||
|
||||
blob2 = bloblist_add(TEST_TAG2, small_size, 0);
|
||||
ut_assertnonnull(blob2);
|
||||
|
||||
/* Check the byte after the last blob */
|
||||
alloced_val = sizeof(struct bloblist_hdr) +
|
||||
sizeof(struct bloblist_rec) * 2 + small_size * 2;
|
||||
ut_asserteq(alloced_val, hdr->alloced);
|
||||
ut_asserteq_ptr((void *)hdr + alloced_val, blob2 + small_size);
|
||||
ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced));
|
||||
|
||||
/* Resize the second one, checking nothing changes */
|
||||
ut_asserteq(0, bloblist_resize(TEST_TAG2, small_size + 4));
|
||||
|
||||
blob2_new = bloblist_find(TEST_TAG2, small_size + 4);
|
||||
ut_asserteq_ptr(blob2, blob2_new);
|
||||
|
||||
/*
|
||||
* the new blob should encompass the byte we checked now, so it should
|
||||
* be zeroed. This zeroing should affect only the four new bytes added
|
||||
* to the blob.
|
||||
*/
|
||||
ut_asserteq(0, *((u8 *)hdr + alloced_val));
|
||||
ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + alloced_val + 4));
|
||||
|
||||
/* Check that the new top of the allocated blobs has not been touched */
|
||||
alloced_val += BLOBLIST_ALIGN;
|
||||
ut_asserteq(alloced_val, hdr->alloced);
|
||||
ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced));
|
||||
|
||||
return 0;
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_resize_last, 0);
|
||||
|
||||
/* Check a completely full bloblist */
|
||||
static int bloblist_test_blob_maxsize(struct unit_test_state *uts)
|
||||
{
|
||||
void *ptr;
|
||||
int size;
|
||||
|
||||
/* At the start there should be no records */
|
||||
clear_bloblist();
|
||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
|
||||
|
||||
/* Add a blob that takes up all space */
|
||||
size = TEST_BLOBLIST_SIZE - sizeof(struct bloblist_hdr) -
|
||||
sizeof(struct bloblist_rec);
|
||||
ptr = bloblist_add(TEST_TAG, size, 0);
|
||||
ut_assertnonnull(ptr);
|
||||
|
||||
ptr = bloblist_add(TEST_TAG, size + 1, 0);
|
||||
ut_assertnull(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BLOBLIST_TEST(bloblist_test_blob_maxsize, 0);
|
||||
|
||||
int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
|
@ -162,3 +162,58 @@ static int dm_test_blk_get_from_parent(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_blk_get_from_parent, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
||||
/* Test iteration through block devices */
|
||||
static int dm_test_blk_iter(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* See sandbox test.dts - it has:
|
||||
*
|
||||
* mmc0 - removable
|
||||
* mmc1 - removable
|
||||
* mmc2 - fixed
|
||||
*/
|
||||
ut_assertok(blk_first_device_err(BLKF_FIXED, &dev));
|
||||
ut_asserteq_str("mmc2.blk", dev->name);
|
||||
ut_asserteq(-ENODEV, blk_next_device_err(BLKF_FIXED, &dev));
|
||||
|
||||
ut_assertok(blk_first_device_err(BLKF_REMOVABLE, &dev));
|
||||
ut_asserteq_str("mmc1.blk", dev->name);
|
||||
ut_assertok(blk_next_device_err(BLKF_REMOVABLE, &dev));
|
||||
ut_asserteq_str("mmc0.blk", dev->name);
|
||||
ut_asserteq(-ENODEV, blk_next_device_err(BLKF_REMOVABLE, &dev));
|
||||
|
||||
ut_assertok(blk_first_device_err(BLKF_BOTH, &dev));
|
||||
ut_asserteq_str("mmc2.blk", dev->name);
|
||||
ut_assertok(blk_next_device_err(BLKF_BOTH, &dev));
|
||||
ut_asserteq_str("mmc1.blk", dev->name);
|
||||
ut_assertok(blk_next_device_err(BLKF_BOTH, &dev));
|
||||
ut_asserteq_str("mmc0.blk", dev->name);
|
||||
ut_asserteq(-ENODEV, blk_next_device_err(BLKF_FIXED, &dev));
|
||||
|
||||
ut_asserteq(1, blk_count_devices(BLKF_FIXED));
|
||||
ut_asserteq(2, blk_count_devices(BLKF_REMOVABLE));
|
||||
ut_asserteq(3, blk_count_devices(BLKF_BOTH));
|
||||
|
||||
i = 0;
|
||||
blk_foreach_probe(BLKF_FIXED, dev)
|
||||
ut_asserteq_str((i++, "mmc2.blk"), dev->name);
|
||||
ut_asserteq(1, i);
|
||||
|
||||
i = 0;
|
||||
blk_foreach_probe(BLKF_REMOVABLE, dev)
|
||||
ut_asserteq_str(i++ ? "mmc0.blk" : "mmc1.blk", dev->name);
|
||||
ut_asserteq(2, i);
|
||||
|
||||
i = 0;
|
||||
blk_foreach_probe(BLKF_BOTH, dev)
|
||||
ut_asserteq_str((++i == 1 ? "mmc2.blk" : i == 2 ?
|
||||
"mmc1.blk" : "mmc0.blk"), dev->name);
|
||||
ut_asserteq(3, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_blk_iter, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
@ -1171,6 +1171,7 @@ static int dm_test_all_have_seq(struct unit_test_state *uts)
|
||||
}
|
||||
DM_TEST(dm_test_all_have_seq, UT_TESTF_SCAN_PDATA);
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_DMA)
|
||||
static int dm_test_dma_offset(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
@ -1200,3 +1201,4 @@ static int dm_test_dma_offset(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_dma_offset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
#endif
|
||||
|
@ -56,6 +56,7 @@ struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
|
||||
|
||||
static int spl_test_load(struct unit_test_state *uts)
|
||||
{
|
||||
const char *cur_prefix, *next_prefix;
|
||||
struct spl_image_info image;
|
||||
struct image_header *header;
|
||||
struct text_ctx text_ctx;
|
||||
@ -68,7 +69,10 @@ static int spl_test_load(struct unit_test_state *uts)
|
||||
load.bl_len = 512;
|
||||
load.read = read_fit_image;
|
||||
|
||||
ret = os_find_u_boot(fname, sizeof(fname), true);
|
||||
cur_prefix = spl_phase_prefix(spl_phase());
|
||||
next_prefix = spl_phase_prefix(spl_next_phase());
|
||||
ret = os_find_u_boot(fname, sizeof(fname), true, cur_prefix,
|
||||
next_prefix);
|
||||
if (ret) {
|
||||
printf("(%s not found, error %d)\n", fname, ret);
|
||||
return ret;
|
||||
|
@ -62,9 +62,9 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min,
|
||||
|
||||
for (i = min; i <= max; i++) {
|
||||
if (flags & EXPECT_LOG)
|
||||
ut_assert_nextline("do_log_run() log %d", i);
|
||||
ut_assert_nextline(" do_log_run() log %d", i);
|
||||
if (flags & EXPECT_DIRECT)
|
||||
ut_assert_nextline("func() _log %d", i);
|
||||
ut_assert_nextline(" func() _log %d", i);
|
||||
if (flags & EXPECT_DEBUG) {
|
||||
ut_assert_nextline("log %d", i);
|
||||
ut_assert_nextline("_log %d", i);
|
||||
@ -72,11 +72,12 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min,
|
||||
}
|
||||
if (flags & EXPECT_EXTRA)
|
||||
for (; i <= LOGL_MAX ; i++)
|
||||
ut_assert_nextline("func() _log %d", i);
|
||||
ut_assert_nextline(" func() _log %d", i);
|
||||
|
||||
for (i = LOGL_FIRST; i < LOGL_COUNT; i++) {
|
||||
if (flags & EXPECT_FORCE)
|
||||
ut_assert_nextline("func() _log force %d", i);
|
||||
ut_assert_nextline(" func() _log force %d",
|
||||
i);
|
||||
if (flags & EXPECT_DEBUG)
|
||||
ut_assert_nextline("_log force %d", i);
|
||||
}
|
||||
@ -277,7 +278,8 @@ int do_log_test_helpers(struct unit_test_state *uts)
|
||||
log_io("level %d\n", LOGL_DEBUG_IO);
|
||||
|
||||
for (i = LOGL_EMERG; i <= _LOG_MAX_LEVEL; i++)
|
||||
ut_assert_nextline("%s() level %d", __func__, i);
|
||||
ut_assert_nextline("%*s() level %d", CONFIG_LOGF_FUNC_PAD,
|
||||
__func__, i);
|
||||
ut_assert_console_end();
|
||||
return 0;
|
||||
}
|
||||
@ -297,14 +299,14 @@ int do_log_test_disable(struct unit_test_state *uts)
|
||||
{
|
||||
ut_assertok(console_record_reset_enable());
|
||||
log_err("default\n");
|
||||
ut_assert_nextline("%s() default", __func__);
|
||||
ut_assert_nextline("%*s() default", CONFIG_LOGF_FUNC_PAD, __func__);
|
||||
|
||||
ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), false));
|
||||
log_err("disabled\n");
|
||||
|
||||
ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), true));
|
||||
log_err("enabled\n");
|
||||
ut_assert_nextline("%s() enabled", __func__);
|
||||
ut_assert_nextline("%*s() enabled", CONFIG_LOGF_FUNC_PAD, __func__);
|
||||
ut_assert_console_end();
|
||||
return 0;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ static int dm_test_pre_run(struct unit_test_state *uts)
|
||||
uts->force_fail_alloc = false;
|
||||
uts->skip_post_probe = false;
|
||||
gd->dm_root = NULL;
|
||||
if (IS_ENABLED(CONFIG_UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
if (CONFIG_IS_ENABLED(UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count));
|
||||
arch_reset_for_test();
|
||||
|
||||
|
@ -1142,6 +1142,22 @@ adds a -v<level> option to the call to binman::
|
||||
make BINMAN_VERBOSE=5
|
||||
|
||||
|
||||
Building sections in parallel
|
||||
-----------------------------
|
||||
|
||||
By default binman uses multiprocessing to speed up compilation of large images.
|
||||
This works at a section level, with one thread for each entry in the section.
|
||||
This can speed things up if the entries are large and use compression.
|
||||
|
||||
This feature can be disabled with the '-T' flag, which defaults to a suitable
|
||||
value for your machine. This depends on the Python version, e.g on v3.8 it uses
|
||||
12 threads on an 8-core machine. See ConcurrentFutures_ for more details.
|
||||
|
||||
The special value -T0 selects single-threaded mode, useful for debugging during
|
||||
development, since dealing with exceptions and problems in threads is more
|
||||
difficult. This avoids any use of ThreadPoolExecutor.
|
||||
|
||||
|
||||
History / Credits
|
||||
-----------------
|
||||
|
||||
@ -1190,3 +1206,5 @@ Some ideas:
|
||||
--
|
||||
Simon Glass <sjg@chromium.org>
|
||||
7/7/2016
|
||||
|
||||
.. _ConcurrentFutures: https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor
|
||||
|
@ -32,6 +32,10 @@ controlled by a description in the board device tree.'''
|
||||
default=False, help='Display the README file')
|
||||
parser.add_argument('--toolpath', type=str, action='append',
|
||||
help='Add a path to the directories containing tools')
|
||||
parser.add_argument('-T', '--threads', type=int,
|
||||
default=None, help='Number of threads to use (0=single-thread)')
|
||||
parser.add_argument('--test-section-timeout', action='store_true',
|
||||
help='Use a zero timeout for section multi-threading (for testing)')
|
||||
parser.add_argument('-v', '--verbosity', default=1,
|
||||
type=int, help='Control verbosity: 0=silent, 1=warnings, 2=notices, '
|
||||
'3=info, 4=detail, 5=debug')
|
||||
|
@ -628,9 +628,13 @@ def Binman(args):
|
||||
tools.PrepareOutputDir(args.outdir, args.preserve)
|
||||
tools.SetToolPaths(args.toolpath)
|
||||
state.SetEntryArgs(args.entry_arg)
|
||||
state.SetThreads(args.threads)
|
||||
|
||||
images = PrepareImagesAndDtbs(dtb_fname, args.image,
|
||||
args.update_fdt, use_expanded)
|
||||
if args.test_section_timeout:
|
||||
# Set the first image to timeout, used in testThreadTimeout()
|
||||
images[list(images.keys())[0]].test_section_timeout = True
|
||||
missing = False
|
||||
for image in images.values():
|
||||
missing |= ProcessImage(image, args.update_fdt, args.map,
|
||||
@ -642,6 +646,9 @@ def Binman(args):
|
||||
|
||||
if missing:
|
||||
tout.Warning("\nSome images are invalid")
|
||||
|
||||
# Use this to debug the time take to pack the image
|
||||
#state.TimingShow()
|
||||
finally:
|
||||
tools.FinaliseOutputDir()
|
||||
finally:
|
||||
|
@ -6,6 +6,7 @@
|
||||
#
|
||||
|
||||
from binman.entry import Entry
|
||||
from binman import state
|
||||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
from patman import tout
|
||||
@ -59,8 +60,12 @@ class Entry_blob(Entry):
|
||||
the data in chunks and avoid reading it all at once. For now
|
||||
this seems like an unnecessary complication.
|
||||
"""
|
||||
state.TimingStart('read')
|
||||
indata = tools.ReadFile(self._pathname)
|
||||
state.TimingAccum('read')
|
||||
state.TimingStart('compress')
|
||||
data = self.CompressData(indata)
|
||||
state.TimingAccum('compress')
|
||||
self.SetContents(data)
|
||||
return True
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Entry_collection(Entry):
|
||||
"""
|
||||
# Join up all the data
|
||||
self.Info('Getting contents, required=%s' % required)
|
||||
data = b''
|
||||
data = bytearray()
|
||||
for entry_phandle in self.content:
|
||||
entry_data = self.section.GetContentsByPhandle(entry_phandle, self,
|
||||
required)
|
||||
|
@ -34,6 +34,9 @@ class Entry_files(Entry_section):
|
||||
from binman import state
|
||||
|
||||
super().__init__(section, etype, node)
|
||||
|
||||
def ReadNode(self):
|
||||
super().ReadNode()
|
||||
self._pattern = fdt_util.GetString(self._node, 'pattern')
|
||||
if not self._pattern:
|
||||
self.Raise("Missing 'pattern' property")
|
||||
|
@ -9,10 +9,12 @@ images to be created.
|
||||
"""
|
||||
|
||||
from collections import OrderedDict
|
||||
import concurrent.futures
|
||||
import re
|
||||
import sys
|
||||
|
||||
from binman.entry import Entry
|
||||
from binman import state
|
||||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
from patman import tout
|
||||
@ -164,7 +166,7 @@ class Entry_section(Entry):
|
||||
pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
|
||||
else self._pad_byte)
|
||||
|
||||
data = b''
|
||||
data = bytearray()
|
||||
# Handle padding before the entry
|
||||
if entry.pad_before:
|
||||
data += tools.GetBytes(self._pad_byte, entry.pad_before)
|
||||
@ -198,7 +200,7 @@ class Entry_section(Entry):
|
||||
Returns:
|
||||
Contents of the section (bytes)
|
||||
"""
|
||||
section_data = b''
|
||||
section_data = bytearray()
|
||||
|
||||
for entry in self._entries.values():
|
||||
entry_data = entry.GetData(required)
|
||||
@ -525,15 +527,43 @@ class Entry_section(Entry):
|
||||
def GetEntryContents(self):
|
||||
"""Call ObtainContents() for each entry in the section
|
||||
"""
|
||||
def _CheckDone(entry):
|
||||
if not entry.ObtainContents():
|
||||
next_todo.append(entry)
|
||||
return entry
|
||||
|
||||
todo = self._entries.values()
|
||||
for passnum in range(3):
|
||||
threads = state.GetThreads()
|
||||
next_todo = []
|
||||
for entry in todo:
|
||||
if not entry.ObtainContents():
|
||||
next_todo.append(entry)
|
||||
|
||||
if threads == 0:
|
||||
for entry in todo:
|
||||
_CheckDone(entry)
|
||||
else:
|
||||
with concurrent.futures.ThreadPoolExecutor(
|
||||
max_workers=threads) as executor:
|
||||
future_to_data = {
|
||||
entry: executor.submit(_CheckDone, entry)
|
||||
for entry in todo}
|
||||
timeout = 60
|
||||
if self.GetImage().test_section_timeout:
|
||||
timeout = 0
|
||||
done, not_done = concurrent.futures.wait(
|
||||
future_to_data.values(), timeout=timeout)
|
||||
# Make sure we check the result, so any exceptions are
|
||||
# generated. Check the results in entry order, since tests
|
||||
# may expect earlier entries to fail first.
|
||||
for entry in todo:
|
||||
job = future_to_data[entry]
|
||||
job.result()
|
||||
if not_done:
|
||||
self.Raise('Timed out obtaining contents')
|
||||
|
||||
todo = next_todo
|
||||
if not todo:
|
||||
break
|
||||
|
||||
if todo:
|
||||
self.Raise('Internal error: Could not complete processing of contents: remaining %s' %
|
||||
todo)
|
||||
|
@ -308,7 +308,8 @@ class TestFunctional(unittest.TestCase):
|
||||
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
|
||||
entry_args=None, images=None, use_real_dtb=False,
|
||||
use_expanded=False, verbosity=None, allow_missing=False,
|
||||
extra_indirs=None):
|
||||
extra_indirs=None, threads=None,
|
||||
test_section_timeout=False):
|
||||
"""Run binman with a given test file
|
||||
|
||||
Args:
|
||||
@ -331,6 +332,8 @@ class TestFunctional(unittest.TestCase):
|
||||
allow_missing: Set the '--allow-missing' flag so that missing
|
||||
external binaries just produce a warning instead of an error
|
||||
extra_indirs: Extra input directories to add using -I
|
||||
threads: Number of threads to use (None for default, 0 for
|
||||
single-threaded)
|
||||
"""
|
||||
args = []
|
||||
if debug:
|
||||
@ -342,6 +345,10 @@ class TestFunctional(unittest.TestCase):
|
||||
if self.toolpath:
|
||||
for path in self.toolpath:
|
||||
args += ['--toolpath', path]
|
||||
if threads is not None:
|
||||
args.append('-T%d' % threads)
|
||||
if test_section_timeout:
|
||||
args.append('--test-section-timeout')
|
||||
args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
||||
if map:
|
||||
args.append('-m')
|
||||
@ -412,7 +419,7 @@ class TestFunctional(unittest.TestCase):
|
||||
|
||||
def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
|
||||
map=False, update_dtb=False, entry_args=None,
|
||||
reset_dtbs=True, extra_indirs=None):
|
||||
reset_dtbs=True, extra_indirs=None, threads=None):
|
||||
"""Run binman and return the resulting image
|
||||
|
||||
This runs binman with a given test file and then reads the resulting
|
||||
@ -439,6 +446,8 @@ class TestFunctional(unittest.TestCase):
|
||||
function. If reset_dtbs is True, then the original test dtb
|
||||
is written back before this function finishes
|
||||
extra_indirs: Extra input directories to add using -I
|
||||
threads: Number of threads to use (None for default, 0 for
|
||||
single-threaded)
|
||||
|
||||
Returns:
|
||||
Tuple:
|
||||
@ -463,7 +472,8 @@ class TestFunctional(unittest.TestCase):
|
||||
try:
|
||||
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
|
||||
entry_args=entry_args, use_real_dtb=use_real_dtb,
|
||||
use_expanded=use_expanded, extra_indirs=extra_indirs)
|
||||
use_expanded=use_expanded, extra_indirs=extra_indirs,
|
||||
threads=threads)
|
||||
self.assertEqual(0, retcode)
|
||||
out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
|
||||
|
||||
@ -4542,5 +4552,30 @@ class TestFunctional(unittest.TestCase):
|
||||
data = self._DoReadFile('201_opensbi.dts')
|
||||
self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
|
||||
|
||||
def testSectionsSingleThread(self):
|
||||
"""Test sections without multithreading"""
|
||||
data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
|
||||
expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
|
||||
U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
|
||||
U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testThreadTimeout(self):
|
||||
"""Test handling a thread that takes too long"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('202_section_timeout.dts',
|
||||
test_section_timeout=True)
|
||||
self.assertIn("Node '/binman/section@0': Timed out obtaining contents",
|
||||
str(e.exception))
|
||||
|
||||
def testTiming(self):
|
||||
"""Test output of timing information"""
|
||||
data = self._DoReadFile('055_sections.dts')
|
||||
with test_util.capture_sys_output() as (stdout, stderr):
|
||||
state.TimingShow()
|
||||
self.assertIn('read:', stdout.getvalue())
|
||||
self.assertIn('compress:', stdout.getvalue())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
@ -36,6 +36,8 @@ class Image(section.Entry_section):
|
||||
fdtmap_data: Contents of the fdtmap when loading from a file
|
||||
allow_repack: True to add properties to allow the image to be safely
|
||||
repacked later
|
||||
test_section_timeout: Use a zero timeout for section multi-threading
|
||||
(for testing)
|
||||
|
||||
Args:
|
||||
copy_to_orig: Copy offset/size to orig_offset/orig_size after reading
|
||||
@ -74,6 +76,7 @@ class Image(section.Entry_section):
|
||||
self.allow_repack = False
|
||||
self._ignore_missing = ignore_missing
|
||||
self.use_expanded = use_expanded
|
||||
self.test_section_timeout = False
|
||||
if not test:
|
||||
self.ReadNode()
|
||||
|
||||
|
@ -5,8 +5,11 @@
|
||||
# Holds and modifies the state information held by binman
|
||||
#
|
||||
|
||||
from collections import defaultdict
|
||||
import hashlib
|
||||
import re
|
||||
import time
|
||||
import threading
|
||||
|
||||
from dtoc import fdt
|
||||
import os
|
||||
@ -55,6 +58,30 @@ allow_entry_expansion = True
|
||||
# to the new ones, the compressed size increases, etc.
|
||||
allow_entry_contraction = False
|
||||
|
||||
# Number of threads to use for binman (None means machine-dependent)
|
||||
num_threads = None
|
||||
|
||||
|
||||
class Timing:
|
||||
"""Holds information about an operation that is being timed
|
||||
|
||||
Properties:
|
||||
name: Operation name (only one of each name is stored)
|
||||
start: Start time of operation in seconds (None if not start)
|
||||
accum:: Amount of time spent on this operation so far, in seconds
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.start = None # cause an error if TimingStart() is not called
|
||||
self.accum = 0.0
|
||||
|
||||
|
||||
# Holds timing info for each name:
|
||||
# key: name of Timing info (Timing.name)
|
||||
# value: Timing object
|
||||
timing_info = {}
|
||||
|
||||
|
||||
def GetFdtForEtype(etype):
|
||||
"""Get the Fdt object for a particular device-tree entry
|
||||
|
||||
@ -420,3 +447,71 @@ def AllowEntryContraction():
|
||||
raised
|
||||
"""
|
||||
return allow_entry_contraction
|
||||
|
||||
def SetThreads(threads):
|
||||
"""Set the number of threads to use when building sections
|
||||
|
||||
Args:
|
||||
threads: Number of threads to use (None for default, 0 for
|
||||
single-threaded)
|
||||
"""
|
||||
global num_threads
|
||||
|
||||
num_threads = threads
|
||||
|
||||
def GetThreads():
|
||||
"""Get the number of threads to use when building sections
|
||||
|
||||
Returns:
|
||||
Number of threads to use (None for default, 0 for single-threaded)
|
||||
"""
|
||||
return num_threads
|
||||
|
||||
def GetTiming(name):
|
||||
"""Get the timing info for a particular operation
|
||||
|
||||
The object is created if it does not already exist.
|
||||
|
||||
Args:
|
||||
name: Operation name to get
|
||||
|
||||
Returns:
|
||||
Timing object for the current thread
|
||||
"""
|
||||
threaded_name = '%s:%d' % (name, threading.get_ident())
|
||||
timing = timing_info.get(threaded_name)
|
||||
if not timing:
|
||||
timing = Timing(threaded_name)
|
||||
timing_info[threaded_name] = timing
|
||||
return timing
|
||||
|
||||
def TimingStart(name):
|
||||
"""Start the timer for an operation
|
||||
|
||||
Args:
|
||||
name: Operation name to start
|
||||
"""
|
||||
timing = GetTiming(name)
|
||||
timing.start = time.monotonic()
|
||||
|
||||
def TimingAccum(name):
|
||||
"""Stop and accumlate the time for an operation
|
||||
|
||||
This measures the time since the last TimingStart() and adds that to the
|
||||
accumulated time.
|
||||
|
||||
Args:
|
||||
name: Operation name to start
|
||||
"""
|
||||
timing = GetTiming(name)
|
||||
timing.accum += time.monotonic() - timing.start
|
||||
|
||||
def TimingShow():
|
||||
"""Show all timing information"""
|
||||
duration = defaultdict(float)
|
||||
for threaded_name, timing in timing_info.items():
|
||||
name = threaded_name.split(':')[0]
|
||||
duration[name] += timing.accum
|
||||
|
||||
for name, seconds in duration.items():
|
||||
print('%10s: %10.1fms' % (name, seconds * 1000))
|
||||
|
21
tools/binman/test/202_section_timeout.dts
Normal file
21
tools/binman/test/202_section_timeout.dts
Normal file
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pad-byte = <0x26>;
|
||||
size = <0x28>;
|
||||
section@0 {
|
||||
read-only;
|
||||
size = <0x10>;
|
||||
pad-byte = <0x21>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -21,7 +21,7 @@ options. For more information about the use of this options and tool please
|
||||
see doc/driver-model/of-plat.rst
|
||||
"""
|
||||
|
||||
from optparse import OptionParser
|
||||
from argparse import ArgumentParser
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
@ -51,7 +51,7 @@ def run_tests(processes, args):
|
||||
|
||||
result = unittest.TestResult()
|
||||
sys.argv = [sys.argv[0]]
|
||||
test_name = args and args[0] or None
|
||||
test_name = args.files and args.files[0] or None
|
||||
|
||||
test_dtoc.setup()
|
||||
|
||||
@ -66,47 +66,50 @@ def RunTestCoverage():
|
||||
"""Run the tests and check that we get 100% coverage"""
|
||||
sys.argv = [sys.argv[0]]
|
||||
test_util.RunTestCoverage('tools/dtoc/dtoc', '/main.py',
|
||||
['tools/patman/*.py', '*/fdt*', '*test*'], options.build_dir)
|
||||
['tools/patman/*.py', '*/fdt*', '*test*'], args.build_dir)
|
||||
|
||||
|
||||
if __name__ != '__main__':
|
||||
sys.exit(1)
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('-B', '--build-dir', type='string', default='b',
|
||||
epilog = '''Generate C code from devicetree files. See of-plat.rst for details'''
|
||||
|
||||
parser = ArgumentParser(epilog=epilog)
|
||||
parser.add_argument('-B', '--build-dir', type=str, default='b',
|
||||
help='Directory containing the build output')
|
||||
parser.add_option('-c', '--c-output-dir', action='store',
|
||||
parser.add_argument('-c', '--c-output-dir', action='store',
|
||||
help='Select output directory for C files')
|
||||
parser.add_option('-C', '--h-output-dir', action='store',
|
||||
parser.add_argument('-C', '--h-output-dir', action='store',
|
||||
help='Select output directory for H files (defaults to --c-output-di)')
|
||||
parser.add_option('-d', '--dtb-file', action='store',
|
||||
parser.add_argument('-d', '--dtb-file', action='store',
|
||||
help='Specify the .dtb input file')
|
||||
parser.add_option('-i', '--instantiate', action='store_true', default=False,
|
||||
parser.add_argument('-i', '--instantiate', action='store_true', default=False,
|
||||
help='Instantiate devices to avoid needing device_bind()')
|
||||
parser.add_option('--include-disabled', action='store_true',
|
||||
parser.add_argument('--include-disabled', action='store_true',
|
||||
help='Include disabled nodes')
|
||||
parser.add_option('-o', '--output', action='store',
|
||||
parser.add_argument('-o', '--output', action='store',
|
||||
help='Select output filename')
|
||||
parser.add_option('-p', '--phase', type=str,
|
||||
parser.add_argument('-p', '--phase', type=str,
|
||||
help='set phase of U-Boot this invocation is for (spl/tpl)')
|
||||
parser.add_option('-P', '--processes', type=int,
|
||||
parser.add_argument('-P', '--processes', type=int,
|
||||
help='set number of processes to use for running tests')
|
||||
parser.add_option('-t', '--test', action='store_true', dest='test',
|
||||
parser.add_argument('-t', '--test', action='store_true', dest='test',
|
||||
default=False, help='run tests')
|
||||
parser.add_option('-T', '--test-coverage', action='store_true',
|
||||
default=False, help='run tests and check for 100% coverage')
|
||||
(options, args) = parser.parse_args()
|
||||
parser.add_argument('-T', '--test-coverage', action='store_true',
|
||||
default=False, help='run tests and check for 100%% coverage')
|
||||
parser.add_argument('files', nargs='*')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Run our meagre tests
|
||||
if options.test:
|
||||
ret_code = run_tests(options.processes, args)
|
||||
if args.test:
|
||||
ret_code = run_tests(args.processes, args)
|
||||
sys.exit(ret_code)
|
||||
|
||||
elif options.test_coverage:
|
||||
elif args.test_coverage:
|
||||
RunTestCoverage()
|
||||
|
||||
else:
|
||||
dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
|
||||
options.output,
|
||||
[options.c_output_dir, options.h_output_dir],
|
||||
options.phase, instantiate=options.instantiate)
|
||||
dtb_platdata.run_steps(args.files, args.dtb_file, args.include_disabled,
|
||||
args.output,
|
||||
[args.c_output_dir, args.h_output_dir],
|
||||
args.phase, instantiate=args.instantiate)
|
||||
|
@ -13,6 +13,7 @@ U_BOOT_DRIVER(), UCLASS_DRIVER and all struct declarations in header files.
|
||||
See doc/driver-model/of-plat.rst for more informaiton
|
||||
"""
|
||||
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@ -190,6 +191,9 @@ class Scanner:
|
||||
value: Driver name declared with U_BOOT_DRIVER(driver_name)
|
||||
_drivers_additional (list or str): List of additional drivers to use
|
||||
during scanning
|
||||
_warnings: Dict of warnings found:
|
||||
key: Driver name
|
||||
value: Set of warnings
|
||||
_of_match: Dict holding information about compatible strings
|
||||
key: Name of struct udevice_id variable
|
||||
value: Dict of compatible info in that variable:
|
||||
@ -217,6 +221,7 @@ class Scanner:
|
||||
self._driver_aliases = {}
|
||||
self._drivers_additional = drivers_additional or []
|
||||
self._missing_drivers = set()
|
||||
self._warnings = collections.defaultdict(set)
|
||||
self._of_match = {}
|
||||
self._compat_to_driver = {}
|
||||
self._uclass = {}
|
||||
@ -267,7 +272,10 @@ class Scanner:
|
||||
aliases_c.remove(compat_c)
|
||||
return compat_c, aliases_c
|
||||
|
||||
self._missing_drivers.add(compat_list_c[0])
|
||||
name = compat_list_c[0]
|
||||
self._missing_drivers.add(name)
|
||||
self._warnings[name].add(
|
||||
'WARNING: the driver %s was not found in the driver list' % name)
|
||||
|
||||
return compat_list_c[0], compat_list_c[1:]
|
||||
|
||||
@ -444,8 +452,8 @@ class Scanner:
|
||||
|
||||
# Collect the compatible string, e.g. 'rockchip,rk3288-grf'
|
||||
compat = None
|
||||
re_compat = re.compile(r'{\s*.compatible\s*=\s*"(.*)"\s*'
|
||||
r'(,\s*.data\s*=\s*(\S*))?\s*},')
|
||||
re_compat = re.compile(r'{\s*\.compatible\s*=\s*"(.*)"\s*'
|
||||
r'(,\s*\.data\s*=\s*(\S*))?\s*},')
|
||||
|
||||
# This is a dict of compatible strings that were found:
|
||||
# key: Compatible string, e.g. 'rockchip,rk3288-grf'
|
||||
@ -460,7 +468,7 @@ class Scanner:
|
||||
|
||||
# Matches the references to the udevice_id list
|
||||
re_of_match = re.compile(
|
||||
r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
|
||||
r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)([^,]*),')
|
||||
|
||||
re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
|
||||
re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
|
||||
@ -506,6 +514,11 @@ class Scanner:
|
||||
driver.uclass_id = m_id.group(1)
|
||||
elif m_of_match:
|
||||
compat = m_of_match.group(2)
|
||||
suffix = m_of_match.group(3)
|
||||
if suffix and suffix != ')':
|
||||
self._warnings[driver.name].add(
|
||||
"%s: Warning: unexpected suffix '%s' on .of_match line for compat '%s'" %
|
||||
(fname, suffix, compat))
|
||||
elif m_phase:
|
||||
driver.phase = m_phase.group(1)
|
||||
elif m_hdr:
|
||||
@ -533,7 +546,12 @@ class Scanner:
|
||||
# The driver does not have a uclass or compat string.
|
||||
# The first is required but the second is not, so just
|
||||
# ignore this.
|
||||
pass
|
||||
if not driver.uclass_id:
|
||||
warn = 'Missing .uclass'
|
||||
else:
|
||||
warn = 'Missing .compatible'
|
||||
self._warnings[driver.name].add('%s in %s' %
|
||||
(warn, fname))
|
||||
driver = None
|
||||
ids_name = None
|
||||
compat = None
|
||||
@ -555,7 +573,7 @@ class Scanner:
|
||||
if ids_m:
|
||||
ids_name = ids_m.group(1)
|
||||
elif m_alias:
|
||||
self._driver_aliases[m_alias[2]] = m_alias[1]
|
||||
self._driver_aliases[m_alias.group(2)] = m_alias.group(1)
|
||||
|
||||
# Make the updates based on what we found
|
||||
for driver in drivers.values():
|
||||
@ -577,9 +595,18 @@ class Scanner:
|
||||
|
||||
def show_warnings(self):
|
||||
"""Show any warnings that have been collected"""
|
||||
for name in sorted(list(self._missing_drivers)):
|
||||
print('WARNING: the driver %s was not found in the driver list'
|
||||
% name)
|
||||
used_drivers = [drv.name for drv in self._drivers.values() if drv.used]
|
||||
missing = self._missing_drivers.copy()
|
||||
for name in sorted(self._warnings.keys()):
|
||||
if name in missing or name in used_drivers:
|
||||
warns = sorted(list(self._warnings[name]))
|
||||
print('%s: %s' % (name, warns[0]))
|
||||
indent = ' ' * len(name)
|
||||
for warn in warns[1:]:
|
||||
print('%-s: %s' % (indent, warn))
|
||||
if name in missing:
|
||||
missing.remove(name)
|
||||
print()
|
||||
|
||||
def scan_driver(self, fname):
|
||||
"""Scan a driver file to build a list of driver names and aliases
|
||||
|
@ -20,6 +20,9 @@ from patman import tools
|
||||
|
||||
OUR_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
EXPECT_WARN = {'rockchip_rk3288_grf':
|
||||
{'WARNING: the driver rockchip_rk3288_grf was not found in the driver list'}}
|
||||
|
||||
class FakeNode:
|
||||
"""Fake Node object for testing"""
|
||||
def __init__(self):
|
||||
@ -152,6 +155,7 @@ class TestSrcScan(unittest.TestCase):
|
||||
'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
|
||||
self.assertEqual('i2c_bus', drv.priv)
|
||||
self.assertEqual(1, len(scan._drivers))
|
||||
self.assertEqual({}, scan._warnings)
|
||||
|
||||
def test_normalized_name(self):
|
||||
"""Test operation of get_normalized_compat_name()"""
|
||||
@ -171,8 +175,8 @@ class TestSrcScan(unittest.TestCase):
|
||||
self.assertEqual([], aliases)
|
||||
self.assertEqual(1, len(scan._missing_drivers))
|
||||
self.assertEqual({'rockchip_rk3288_grf'}, scan._missing_drivers)
|
||||
#'WARNING: the driver rockchip_rk3288_grf was not found in the driver list',
|
||||
#stdout.getvalue().strip())
|
||||
self.assertEqual('', stdout.getvalue().strip())
|
||||
self.assertEqual(EXPECT_WARN, scan._warnings)
|
||||
|
||||
i2c = 'I2C_UCLASS'
|
||||
compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
|
||||
@ -189,6 +193,7 @@ class TestSrcScan(unittest.TestCase):
|
||||
self.assertEqual('', stdout.getvalue().strip())
|
||||
self.assertEqual('rockchip_rk3288_grf', name)
|
||||
self.assertEqual([], aliases)
|
||||
self.assertEqual(EXPECT_WARN, scan._warnings)
|
||||
|
||||
prop.value = 'rockchip,rk3288-srf'
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
@ -196,6 +201,7 @@ class TestSrcScan(unittest.TestCase):
|
||||
self.assertEqual('', stdout.getvalue().strip())
|
||||
self.assertEqual('rockchip_rk3288_grf', name)
|
||||
self.assertEqual(['rockchip_rk3288_srf'], aliases)
|
||||
self.assertEqual(EXPECT_WARN, scan._warnings)
|
||||
|
||||
def test_scan_errors(self):
|
||||
"""Test detection of scanning errors"""
|
||||
@ -490,3 +496,126 @@ U_BOOT_DRIVER(%s) = {
|
||||
self.assertEqual(3, seq)
|
||||
self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
|
||||
self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)
|
||||
|
||||
def test_scan_warnings(self):
|
||||
"""Test detection of scanning warnings"""
|
||||
buff = '''
|
||||
static const struct udevice_id tegra_i2c_ids[] = {
|
||||
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(i2c_tegra) = {
|
||||
.name = "i2c_tegra",
|
||||
.id = UCLASS_I2C,
|
||||
.of_match = tegra_i2c_ids + 1,
|
||||
};
|
||||
'''
|
||||
# The '+ 1' above should generate a warning
|
||||
|
||||
prop = FakeProp()
|
||||
prop.name = 'compatible'
|
||||
prop.value = 'rockchip,rk3288-grf'
|
||||
node = FakeNode()
|
||||
node.props = {'compatible': prop}
|
||||
|
||||
# get_normalized_compat_name() uses this to check for root node
|
||||
node.parent = FakeNode()
|
||||
|
||||
scan = src_scan.Scanner(None, None)
|
||||
scan._parse_driver('file.c', buff)
|
||||
self.assertEqual(
|
||||
{'i2c_tegra':
|
||||
{"file.c: Warning: unexpected suffix ' + 1' on .of_match line for compat 'tegra_i2c_ids'"}},
|
||||
scan._warnings)
|
||||
|
||||
tprop = FakeProp()
|
||||
tprop.name = 'compatible'
|
||||
tprop.value = 'nvidia,tegra114-i2c'
|
||||
tnode = FakeNode()
|
||||
tnode.props = {'compatible': tprop}
|
||||
|
||||
# get_normalized_compat_name() uses this to check for root node
|
||||
tnode.parent = FakeNode()
|
||||
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
scan.get_normalized_compat_name(node)
|
||||
scan.get_normalized_compat_name(tnode)
|
||||
self.assertEqual('', stdout.getvalue().strip())
|
||||
|
||||
self.assertEqual(2, len(scan._missing_drivers))
|
||||
self.assertEqual({'rockchip_rk3288_grf', 'nvidia_tegra114_i2c'},
|
||||
scan._missing_drivers)
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
scan.show_warnings()
|
||||
self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
|
||||
|
||||
# This should show just the rockchip warning, since the tegra driver
|
||||
# is not in self._missing_drivers
|
||||
scan._missing_drivers.remove('nvidia_tegra114_i2c')
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
scan.show_warnings()
|
||||
self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
|
||||
self.assertNotIn('tegra_i2c_ids', stdout.getvalue())
|
||||
|
||||
# Do a similar thing with used drivers. By marking the tegra driver as
|
||||
# used, the warning related to that driver will be shown
|
||||
drv = scan._drivers['i2c_tegra']
|
||||
drv.used = True
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
scan.show_warnings()
|
||||
self.assertIn('rockchip_rk3288_grf', stdout.getvalue())
|
||||
self.assertIn('tegra_i2c_ids', stdout.getvalue())
|
||||
|
||||
# Add a warning to make sure multiple warnings are shown
|
||||
scan._warnings['i2c_tegra'].update(
|
||||
scan._warnings['nvidia_tegra114_i2c'])
|
||||
del scan._warnings['nvidia_tegra114_i2c']
|
||||
with test_util.capture_sys_output() as (stdout, _):
|
||||
scan.show_warnings()
|
||||
self.assertEqual('''i2c_tegra: WARNING: the driver nvidia_tegra114_i2c was not found in the driver list
|
||||
: file.c: Warning: unexpected suffix ' + 1' on .of_match line for compat 'tegra_i2c_ids'
|
||||
|
||||
rockchip_rk3288_grf: WARNING: the driver rockchip_rk3288_grf was not found in the driver list
|
||||
|
||||
''',
|
||||
stdout.getvalue())
|
||||
self.assertIn('tegra_i2c_ids', stdout.getvalue())
|
||||
|
||||
def scan_uclass_warning(self):
|
||||
"""Test a missing .uclass in the driver"""
|
||||
buff = '''
|
||||
static const struct udevice_id tegra_i2c_ids[] = {
|
||||
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(i2c_tegra) = {
|
||||
.name = "i2c_tegra",
|
||||
.of_match = tegra_i2c_ids,
|
||||
};
|
||||
'''
|
||||
scan = src_scan.Scanner(None, None)
|
||||
scan._parse_driver('file.c', buff)
|
||||
self.assertEqual(
|
||||
{'i2c_tegra': {'Missing .uclass in file.c'}},
|
||||
scan._warnings)
|
||||
|
||||
def scan_compat_warning(self):
|
||||
"""Test a missing .compatible in the driver"""
|
||||
buff = '''
|
||||
static const struct udevice_id tegra_i2c_ids[] = {
|
||||
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(i2c_tegra) = {
|
||||
.name = "i2c_tegra",
|
||||
.id = UCLASS_I2C,
|
||||
};
|
||||
'''
|
||||
scan = src_scan.Scanner(None, None)
|
||||
scan._parse_driver('file.c', buff)
|
||||
self.assertEqual(
|
||||
{'i2c_tegra': {'Missing .compatible in file.c'}},
|
||||
scan._warnings)
|
||||
|
@ -169,11 +169,11 @@ class Popen(subprocess.Popen):
|
||||
self.stdin.close()
|
||||
if self.stdout:
|
||||
read_set.append(self.stdout)
|
||||
stdout = b''
|
||||
stdout = bytearray()
|
||||
if self.stderr and self.stderr != self.stdout:
|
||||
read_set.append(self.stderr)
|
||||
stderr = b''
|
||||
combined = b''
|
||||
stderr = bytearray()
|
||||
combined = bytearray()
|
||||
|
||||
input_offset = 0
|
||||
while read_set or write_set:
|
||||
|
@ -466,6 +466,9 @@ def Compress(indata, algo, with_header=True):
|
||||
This requires 'lz4' and 'lzma_alone' tools. It also requires an output
|
||||
directory to be previously set up, by calling PrepareOutputDir().
|
||||
|
||||
Care is taken to use unique temporary files so that this function can be
|
||||
called from multiple threads.
|
||||
|
||||
Args:
|
||||
indata: Input data to compress
|
||||
algo: Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
|
||||
@ -475,14 +478,16 @@ def Compress(indata, algo, with_header=True):
|
||||
"""
|
||||
if algo == 'none':
|
||||
return indata
|
||||
fname = GetOutputFilename('%s.comp.tmp' % algo)
|
||||
fname = tempfile.NamedTemporaryFile(prefix='%s.comp.tmp' % algo,
|
||||
dir=outdir).name
|
||||
WriteFile(fname, indata)
|
||||
if algo == 'lz4':
|
||||
data = Run('lz4', '--no-frame-crc', '-B4', '-5', '-c', fname,
|
||||
binary=True)
|
||||
# cbfstool uses a very old version of lzma
|
||||
elif algo == 'lzma':
|
||||
outfname = GetOutputFilename('%s.comp.otmp' % algo)
|
||||
outfname = tempfile.NamedTemporaryFile(prefix='%s.comp.otmp' % algo,
|
||||
dir=outdir).name
|
||||
Run('lzma_alone', 'e', fname, outfname, '-lc1', '-lp0', '-pb0', '-d8')
|
||||
data = ReadFile(outfname)
|
||||
elif algo == 'gzip':
|
||||
|
Loading…
Reference in New Issue
Block a user