Merge branch 'agust@denx.de-next' of git://git.denx.de/u-boot-staging
This commit is contained in:
commit
bd23b22bad
25
README
25
README
@ -2391,6 +2391,31 @@ The following options need to be configured:
|
||||
29,916,167 26,005,792 bootm_start
|
||||
30,361,327 445,160 start_kernel
|
||||
|
||||
CONFIG_CMD_BOOTSTAGE
|
||||
Add a 'bootstage' command which supports printing a report
|
||||
and un/stashing of bootstage data.
|
||||
|
||||
CONFIG_BOOTSTAGE_FDT
|
||||
Stash the bootstage information in the FDT. A root 'bootstage'
|
||||
node is created with each bootstage id as a child. Each child
|
||||
has a 'name' property and either 'mark' containing the
|
||||
mark time in microsecond, or 'accum' containing the
|
||||
accumulated time for that bootstage id in microseconds.
|
||||
For example:
|
||||
|
||||
bootstage {
|
||||
154 {
|
||||
name = "board_init_f";
|
||||
mark = <3575678>;
|
||||
};
|
||||
170 {
|
||||
name = "lcd";
|
||||
accum = <33482>;
|
||||
};
|
||||
};
|
||||
|
||||
Code in the Linux kernel can find this in /proc/devicetree.
|
||||
|
||||
Legacy uImage format:
|
||||
|
||||
Arg Where When
|
||||
|
@ -96,6 +96,9 @@ static void announce_and_cleanup(void)
|
||||
{
|
||||
printf("\nStarting kernel ...\n\n");
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
#ifdef CONFIG_BOOTSTAGE_FDT
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
@ -68,6 +68,7 @@ COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
|
||||
COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
|
||||
COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o
|
||||
COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
|
||||
COBJS-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o
|
||||
COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o
|
||||
COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o
|
||||
COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o
|
||||
|
@ -33,13 +33,9 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum bootstage_flags {
|
||||
BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
|
||||
BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
|
||||
};
|
||||
|
||||
struct bootstage_record {
|
||||
ulong time_us;
|
||||
uint32_t start_us;
|
||||
const char *name;
|
||||
int flags; /* see enum bootstage_flags */
|
||||
enum bootstage_id id;
|
||||
@ -48,11 +44,22 @@ struct bootstage_record {
|
||||
static struct bootstage_record record[BOOTSTAGE_ID_COUNT] = { {1} };
|
||||
static int next_id = BOOTSTAGE_ID_USER;
|
||||
|
||||
enum {
|
||||
BOOTSTAGE_VERSION = 0,
|
||||
BOOTSTAGE_MAGIC = 0xb00757a3,
|
||||
};
|
||||
|
||||
struct bootstage_hdr {
|
||||
uint32_t version; /* BOOTSTAGE_VERSION */
|
||||
uint32_t count; /* Number of records */
|
||||
uint32_t size; /* Total data size (non-zero if valid) */
|
||||
uint32_t magic; /* Unused */
|
||||
};
|
||||
|
||||
ulong bootstage_add_record(enum bootstage_id id, const char *name,
|
||||
int flags)
|
||||
int flags, ulong mark)
|
||||
{
|
||||
struct bootstage_record *rec;
|
||||
ulong mark = timer_get_boot_us();
|
||||
|
||||
if (flags & BOOTSTAGEF_ALLOC)
|
||||
id = next_id++;
|
||||
@ -77,12 +84,13 @@ ulong bootstage_add_record(enum bootstage_id id, const char *name,
|
||||
|
||||
ulong bootstage_mark(enum bootstage_id id)
|
||||
{
|
||||
return bootstage_add_record(id, NULL, 0);
|
||||
return bootstage_add_record(id, NULL, 0, timer_get_boot_us());
|
||||
}
|
||||
|
||||
ulong bootstage_error(enum bootstage_id id)
|
||||
{
|
||||
return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR);
|
||||
return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR,
|
||||
timer_get_boot_us());
|
||||
}
|
||||
|
||||
ulong bootstage_mark_name(enum bootstage_id id, const char *name)
|
||||
@ -91,7 +99,26 @@ ulong bootstage_mark_name(enum bootstage_id id, const char *name)
|
||||
|
||||
if (id == BOOTSTAGE_ID_ALLOC)
|
||||
flags = BOOTSTAGEF_ALLOC;
|
||||
return bootstage_add_record(id, name, flags);
|
||||
return bootstage_add_record(id, name, flags, timer_get_boot_us());
|
||||
}
|
||||
|
||||
uint32_t bootstage_start(enum bootstage_id id, const char *name)
|
||||
{
|
||||
struct bootstage_record *rec = &record[id];
|
||||
|
||||
rec->start_us = timer_get_boot_us();
|
||||
rec->name = name;
|
||||
return rec->start_us;
|
||||
}
|
||||
|
||||
uint32_t bootstage_accum(enum bootstage_id id)
|
||||
{
|
||||
struct bootstage_record *rec = &record[id];
|
||||
uint32_t duration;
|
||||
|
||||
duration = (uint32_t)timer_get_boot_us() - rec->start_us;
|
||||
rec->time_us += duration;
|
||||
return duration;
|
||||
}
|
||||
|
||||
static void print_time(unsigned long us_time)
|
||||
@ -109,17 +136,41 @@ static void print_time(unsigned long us_time)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a record name as a printable string
|
||||
*
|
||||
* @param buf Buffer to put name if needed
|
||||
* @param len Length of buffer
|
||||
* @param rec Boot stage record to get the name from
|
||||
* @return pointer to name, either from the record or pointing to buf.
|
||||
*/
|
||||
static const char *get_record_name(char *buf, int len,
|
||||
struct bootstage_record *rec)
|
||||
{
|
||||
if (rec->name)
|
||||
return rec->name;
|
||||
else if (rec->id >= BOOTSTAGE_ID_USER)
|
||||
snprintf(buf, len, "user_%d", rec->id - BOOTSTAGE_ID_USER);
|
||||
else
|
||||
snprintf(buf, len, "id=%d", rec->id);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static uint32_t print_time_record(enum bootstage_id id,
|
||||
struct bootstage_record *rec, uint32_t prev)
|
||||
{
|
||||
print_time(rec->time_us);
|
||||
print_time(rec->time_us - prev);
|
||||
if (rec->name)
|
||||
printf(" %s\n", rec->name);
|
||||
else if (id >= BOOTSTAGE_ID_USER)
|
||||
printf(" user_%d\n", id - BOOTSTAGE_ID_USER);
|
||||
else
|
||||
printf(" id=%d\n", id);
|
||||
char buf[20];
|
||||
|
||||
if (prev == -1U) {
|
||||
printf("%11s", "");
|
||||
print_time(rec->time_us);
|
||||
} else {
|
||||
print_time(rec->time_us);
|
||||
print_time(rec->time_us - prev);
|
||||
}
|
||||
printf(" %s\n", get_record_name(buf, sizeof(buf), rec));
|
||||
|
||||
return rec->time_us;
|
||||
}
|
||||
|
||||
@ -130,6 +181,70 @@ static int h_compare_record(const void *r1, const void *r2)
|
||||
return rec1->time_us > rec2->time_us ? 1 : -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
/**
|
||||
* Add all bootstage timings to a device tree.
|
||||
*
|
||||
* @param blob Device tree blob
|
||||
* @return 0 on success, != 0 on failure.
|
||||
*/
|
||||
static int add_bootstages_devicetree(struct fdt_header *blob)
|
||||
{
|
||||
int bootstage;
|
||||
char buf[20];
|
||||
int id;
|
||||
int i;
|
||||
|
||||
if (!blob)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Create the node for bootstage.
|
||||
* The address of flat device tree is set up by the command bootm.
|
||||
*/
|
||||
bootstage = fdt_add_subnode(blob, 0, "bootstage");
|
||||
if (bootstage < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Insert the timings to the device tree in the reverse order so
|
||||
* that they can be printed in the Linux kernel in the right order.
|
||||
*/
|
||||
for (id = BOOTSTAGE_ID_COUNT - 1, i = 0; id >= 0; id--, i++) {
|
||||
struct bootstage_record *rec = &record[id];
|
||||
int node;
|
||||
|
||||
if (id != BOOTSTAGE_ID_AWAKE && rec->time_us == 0)
|
||||
continue;
|
||||
|
||||
node = fdt_add_subnode(blob, bootstage, simple_itoa(i));
|
||||
if (node < 0)
|
||||
break;
|
||||
|
||||
/* add properties to the node. */
|
||||
if (fdt_setprop_string(blob, node, "name",
|
||||
get_record_name(buf, sizeof(buf), rec)))
|
||||
return -1;
|
||||
|
||||
/* Check if this is a 'mark' or 'accum' record */
|
||||
if (fdt_setprop_cell(blob, node,
|
||||
rec->start_us ? "accum" : "mark",
|
||||
rec->time_us))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bootstage_fdt_add_report(void)
|
||||
{
|
||||
if (add_bootstages_devicetree(working_fdt))
|
||||
puts("bootstage: Failed to add to device tree\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void bootstage_report(void)
|
||||
{
|
||||
struct bootstage_record *rec = record;
|
||||
@ -148,13 +263,19 @@ void bootstage_report(void)
|
||||
qsort(record, ARRAY_SIZE(record), sizeof(*rec), h_compare_record);
|
||||
|
||||
for (id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
|
||||
if (rec->time_us != 0)
|
||||
if (rec->time_us != 0 && !rec->start_us)
|
||||
prev = print_time_record(rec->id, rec, prev);
|
||||
}
|
||||
if (next_id > BOOTSTAGE_ID_COUNT)
|
||||
printf("(Overflowed internal boot id table by %d entries\n"
|
||||
"- please increase CONFIG_BOOTSTAGE_USER_COUNT\n",
|
||||
next_id - BOOTSTAGE_ID_COUNT);
|
||||
|
||||
puts("\nAccumulated time:\n");
|
||||
for (id = 0, rec = record; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
|
||||
if (rec->start_us)
|
||||
prev = print_time_record(id, rec, -1);
|
||||
}
|
||||
}
|
||||
|
||||
ulong __timer_get_boot_us(void)
|
||||
@ -173,3 +294,150 @@ ulong __timer_get_boot_us(void)
|
||||
|
||||
ulong timer_get_boot_us(void)
|
||||
__attribute__((weak, alias("__timer_get_boot_us")));
|
||||
|
||||
/**
|
||||
* Append data to a memory buffer
|
||||
*
|
||||
* Write data to the buffer if there is space. Whether there is space or not,
|
||||
* the buffer pointer is incremented.
|
||||
*
|
||||
* @param ptrp Pointer to buffer, updated by this function
|
||||
* @param end Pointer to end of buffer
|
||||
* @param data Data to write to buffer
|
||||
* @param size Size of data
|
||||
*/
|
||||
static void append_data(char **ptrp, char *end, const void *data, int size)
|
||||
{
|
||||
char *ptr = *ptrp;
|
||||
|
||||
*ptrp += size;
|
||||
if (*ptrp > end)
|
||||
return;
|
||||
|
||||
memcpy(ptr, data, size);
|
||||
}
|
||||
|
||||
int bootstage_stash(void *base, int size)
|
||||
{
|
||||
struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
|
||||
struct bootstage_record *rec;
|
||||
char buf[20];
|
||||
char *ptr = base, *end = ptr + size;
|
||||
uint32_t count;
|
||||
int id;
|
||||
|
||||
if (hdr + 1 > (struct bootstage_hdr *)end) {
|
||||
debug("%s: Not enough space for bootstage hdr\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write an arbitrary version number */
|
||||
hdr->version = BOOTSTAGE_VERSION;
|
||||
|
||||
/* Count the number of records, and write that value first */
|
||||
for (rec = record, id = count = 0; id < BOOTSTAGE_ID_COUNT;
|
||||
id++, rec++) {
|
||||
if (rec->time_us != 0)
|
||||
count++;
|
||||
}
|
||||
hdr->count = count;
|
||||
hdr->size = 0;
|
||||
hdr->magic = BOOTSTAGE_MAGIC;
|
||||
ptr += sizeof(*hdr);
|
||||
|
||||
/* Write the records, silently stopping when we run out of space */
|
||||
for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
|
||||
if (rec->time_us != 0)
|
||||
append_data(&ptr, end, rec, sizeof(*rec));
|
||||
}
|
||||
|
||||
/* Write the name strings */
|
||||
for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
|
||||
if (rec->time_us != 0) {
|
||||
const char *name;
|
||||
|
||||
name = get_record_name(buf, sizeof(buf), rec);
|
||||
append_data(&ptr, end, name, strlen(name) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for buffer overflow */
|
||||
if (ptr > end) {
|
||||
debug("%s: Not enough space for bootstage stash\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update total data size */
|
||||
hdr->size = ptr - (char *)base;
|
||||
printf("Stashed %d records\n", hdr->count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bootstage_unstash(void *base, int size)
|
||||
{
|
||||
struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
|
||||
struct bootstage_record *rec;
|
||||
char *ptr = base, *end = ptr + size;
|
||||
uint rec_size;
|
||||
int id;
|
||||
|
||||
if (size == -1)
|
||||
end = (char *)(~(uintptr_t)0);
|
||||
|
||||
if (hdr + 1 > (struct bootstage_hdr *)end) {
|
||||
debug("%s: Not enough space for bootstage hdr\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->magic != BOOTSTAGE_MAGIC) {
|
||||
debug("%s: Invalid bootstage magic\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ptr + hdr->size > end) {
|
||||
debug("%s: Bootstage data runs past buffer end\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->count * sizeof(*rec) > hdr->size) {
|
||||
debug("%s: Bootstage has %d records needing %d bytes, but "
|
||||
"only %d bytes is available\n", __func__, hdr->count,
|
||||
hdr->count * sizeof(*rec), hdr->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->version != BOOTSTAGE_VERSION) {
|
||||
debug("%s: Bootstage data version %#0x unrecognised\n",
|
||||
__func__, hdr->version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (next_id + hdr->count > BOOTSTAGE_ID_COUNT) {
|
||||
debug("%s: Bootstage has %d records, we have space for %d\n"
|
||||
"- please increase CONFIG_BOOTSTAGE_USER_COUNT\n",
|
||||
__func__, hdr->count, BOOTSTAGE_ID_COUNT - next_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr += sizeof(*hdr);
|
||||
|
||||
/* Read the records */
|
||||
rec_size = hdr->count * sizeof(*record);
|
||||
memcpy(record + next_id, ptr, rec_size);
|
||||
|
||||
/* Read the name strings */
|
||||
ptr += rec_size;
|
||||
for (rec = record + next_id, id = 0; id < hdr->count; id++, rec++) {
|
||||
rec->name = ptr;
|
||||
|
||||
/* Assume no data corruption here */
|
||||
ptr += strlen(ptr) + 1;
|
||||
}
|
||||
|
||||
/* Mark the records as read */
|
||||
next_id += hdr->count;
|
||||
printf("Unstashed %d records\n", hdr->count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
116
common/cmd_bootstage.c
Normal file
116
common/cmd_bootstage.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Google Inc. All rights reserved.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifndef CONFIG_BOOTSTAGE_STASH
|
||||
#define CONFIG_BOOTSTAGE_STASH -1UL
|
||||
#define CONFIG_BOOTSTAGE_STASH_SIZE -1
|
||||
#endif
|
||||
|
||||
static int do_bootstage_report(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
bootstage_report();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_base_size(int argc, char * const argv[], ulong *basep,
|
||||
ulong *sizep)
|
||||
{
|
||||
char *endp;
|
||||
|
||||
*basep = CONFIG_BOOTSTAGE_STASH;
|
||||
*sizep = CONFIG_BOOTSTAGE_STASH_SIZE;
|
||||
if (argc < 2)
|
||||
return 0;
|
||||
*basep = simple_strtoul(argv[1], &endp, 16);
|
||||
if (*argv[1] == 0 || *endp != 0)
|
||||
return -1;
|
||||
if (argc == 2)
|
||||
return 0;
|
||||
*sizep = simple_strtoul(argv[2], &endp, 16);
|
||||
if (*argv[2] == 0 || *endp != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_bootstage_stash(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
ulong base, size;
|
||||
int ret;
|
||||
|
||||
if (get_base_size(argc, argv, &base, &size))
|
||||
return CMD_RET_USAGE;
|
||||
if (base == -1UL) {
|
||||
printf("No bootstage stash area defined\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 == strcmp(argv[0], "stash"))
|
||||
ret = bootstage_stash((void *)base, size);
|
||||
else
|
||||
ret = bootstage_unstash((void *)base, size);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t cmd_bootstage_sub[] = {
|
||||
U_BOOT_CMD_MKENT(report, 2, 1, do_bootstage_report, "", ""),
|
||||
U_BOOT_CMD_MKENT(stash, 4, 0, do_bootstage_stash, "", ""),
|
||||
U_BOOT_CMD_MKENT(unstash, 4, 0, do_bootstage_stash, "", ""),
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a bootstage sub-command
|
||||
*/
|
||||
static int do_boostage(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *c;
|
||||
|
||||
/* Strip off leading 'bootstage' command argument */
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
c = find_cmd_tbl(argv[0], cmd_bootstage_sub,
|
||||
ARRAY_SIZE(cmd_bootstage_sub));
|
||||
|
||||
if (c)
|
||||
return c->cmd(cmdtp, flag, argc, argv);
|
||||
else
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
||||
|
||||
U_BOOT_CMD(bootstage, 4, 1, do_boostage,
|
||||
"Boot stage command",
|
||||
" - check boot progress and timing\n"
|
||||
"report - Print a report\n"
|
||||
"stash [<start> [<size>]] - Stash data into memory\n"
|
||||
"unstash [<start> [<size>]] - Unstash data from memory"
|
||||
);
|
@ -31,6 +31,12 @@
|
||||
#define CONFIG_BOOTSTAGE_USER_COUNT 20
|
||||
#endif
|
||||
|
||||
/* Flags for each bootstage record */
|
||||
enum bootstage_flags {
|
||||
BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
|
||||
BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
|
||||
};
|
||||
|
||||
/*
|
||||
* A list of boot stages that we know about. Each of these indicates the
|
||||
* state that we are at, and the action that we are about to perform. For
|
||||
@ -181,6 +187,7 @@ enum bootstage_id {
|
||||
* rough boot timing information.
|
||||
*/
|
||||
BOOTSTAGE_ID_AWAKE,
|
||||
BOOTSTAGE_ID_START_SPL,
|
||||
BOOTSTAGE_ID_START_UBOOT_F,
|
||||
BOOTSTAGE_ID_START_UBOOT_R,
|
||||
BOOTSTAGE_ID_USB_START,
|
||||
@ -192,11 +199,15 @@ enum bootstage_id {
|
||||
BOOTSTAGE_ID_MAIN_LOOP,
|
||||
BOOTSTAGE_KERNELREAD_START,
|
||||
BOOTSTAGE_KERNELREAD_STOP,
|
||||
BOOTSTAGE_ID_BOARD_INIT,
|
||||
BOOTSTAGE_ID_BOARD_INIT_DONE,
|
||||
|
||||
BOOTSTAGE_ID_CPU_AWAKE,
|
||||
BOOTSTAGE_ID_MAIN_CPU_AWAKE,
|
||||
BOOTSTAGE_ID_MAIN_CPU_READY,
|
||||
|
||||
BOOTSTAGE_ID_ACCUM_LCD,
|
||||
|
||||
/* a few spare for the user, from here */
|
||||
BOOTSTAGE_ID_USER,
|
||||
BOOTSTAGE_ID_COUNT = BOOTSTAGE_ID_USER + CONFIG_BOOTSTAGE_USER_COUNT,
|
||||
@ -225,6 +236,17 @@ void show_boot_progress(int val);
|
||||
#if defined(CONFIG_BOOTSTAGE) && !defined(CONFIG_SPL_BUILD)
|
||||
/* This is the full bootstage implementation */
|
||||
|
||||
/**
|
||||
* Add a new bootstage record
|
||||
*
|
||||
* @param id Bootstage ID to use (ignored if flags & BOOTSTAGEF_ALLOC)
|
||||
* @param name Name of record, or NULL for none
|
||||
* @param flags Flags (BOOTSTAGEF_...)
|
||||
* @param mark Time to record in this record, in microseconds
|
||||
*/
|
||||
ulong bootstage_add_record(enum bootstage_id id, const char *name,
|
||||
int flags, ulong mark);
|
||||
|
||||
/*
|
||||
* Mark a time stamp for the current boot stage.
|
||||
*/
|
||||
@ -234,9 +256,64 @@ ulong bootstage_error(enum bootstage_id id);
|
||||
|
||||
ulong bootstage_mark_name(enum bootstage_id id, const char *name);
|
||||
|
||||
/**
|
||||
* Mark the start of a bootstage activity. The end will be marked later with
|
||||
* bootstage_accum() and at that point we accumulate the time taken. Calling
|
||||
* this function turns the given id into a accumulator rather than and
|
||||
* absolute mark in time. Accumulators record the total amount of time spent
|
||||
* in an activty during boot.
|
||||
*
|
||||
* @param id Bootstage id to record this timestamp against
|
||||
* @param name Textual name to display for this id in the report (maybe NULL)
|
||||
* @return start timestamp in microseconds
|
||||
*/
|
||||
uint32_t bootstage_start(enum bootstage_id id, const char *name);
|
||||
|
||||
/**
|
||||
* Mark the end of a bootstage activity
|
||||
*
|
||||
* After previously marking the start of an activity with bootstage_start(),
|
||||
* call this function to mark the end. You can call these functions in pairs
|
||||
* as many times as you like.
|
||||
*
|
||||
* @param id Bootstage id to record this timestamp against
|
||||
* @return time spent in this iteration of the activity (i.e. the time now
|
||||
* less the start time recorded in the last bootstage_start() call
|
||||
* with this id.
|
||||
*/
|
||||
uint32_t bootstage_accum(enum bootstage_id id);
|
||||
|
||||
/* Print a report about boot time */
|
||||
void bootstage_report(void);
|
||||
|
||||
/**
|
||||
* Add bootstage information to the device tree
|
||||
*
|
||||
* @return 0 if ok, -ve on error
|
||||
*/
|
||||
int bootstage_fdt_add_report(void);
|
||||
|
||||
/*
|
||||
* Stash bootstage data into memory
|
||||
*
|
||||
* @param base Base address of memory buffer
|
||||
* @param size Size of memory buffer
|
||||
* @return 0 if stashed ok, -1 if out of space
|
||||
*/
|
||||
int bootstage_stash(void *base, int size);
|
||||
|
||||
/**
|
||||
* Read bootstage data from memory
|
||||
*
|
||||
* Bootstage data is read from memory and placed in the bootstage table
|
||||
* in the user records.
|
||||
*
|
||||
* @param base Base address of memory buffer
|
||||
* @param size Size of memory buffer (-1 if unknown)
|
||||
* @return 0 if unstashed ok, -1 if bootstage info not found, or out of space
|
||||
*/
|
||||
int bootstage_unstash(void *base, int size);
|
||||
|
||||
#else
|
||||
/*
|
||||
* This is a dummy implementation which just calls show_boot_progress(),
|
||||
@ -260,7 +337,15 @@ static inline ulong bootstage_mark_name(enum bootstage_id id, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bootstage_stash(void *base, int size)
|
||||
{
|
||||
return 0; /* Pretend to succeed */
|
||||
}
|
||||
|
||||
static inline int bootstage_unstash(void *base, int size)
|
||||
{
|
||||
return 0; /* Pretend to succeed */
|
||||
}
|
||||
#endif /* CONFIG_BOOTSTAGE */
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user