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:
Tom Rini 2021-07-22 11:15:52 -04:00
commit a15fa1ba67
48 changed files with 1210 additions and 164 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -819,6 +819,7 @@
mmc2 {
compatible = "sandbox,mmc";
non-removable;
};
mmc1 {

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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
-------

View File

@ -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;

View File

@ -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_);
}
}
}
}

View File

@ -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 {

View File

@ -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)

View File

@ -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",

View File

@ -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 */

View File

@ -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),

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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[])
{

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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')

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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))

View 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 {
};
};
};
};

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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':