Commit bd23b22badadcdc414a900828253961fc5ec6c39

Authored by Tom Rini

Merge branch 'agust@denx.de-next' of git://git.denx.de/u-boot-staging

Showing 6 changed files Side-by-side Diff

... ... @@ -2391,6 +2391,31 @@
2391 2391 29,916,167 26,005,792 bootm_start
2392 2392 30,361,327 445,160 start_kernel
2393 2393  
  2394 + CONFIG_CMD_BOOTSTAGE
  2395 + Add a 'bootstage' command which supports printing a report
  2396 + and un/stashing of bootstage data.
  2397 +
  2398 + CONFIG_BOOTSTAGE_FDT
  2399 + Stash the bootstage information in the FDT. A root 'bootstage'
  2400 + node is created with each bootstage id as a child. Each child
  2401 + has a 'name' property and either 'mark' containing the
  2402 + mark time in microsecond, or 'accum' containing the
  2403 + accumulated time for that bootstage id in microseconds.
  2404 + For example:
  2405 +
  2406 + bootstage {
  2407 + 154 {
  2408 + name = "board_init_f";
  2409 + mark = <3575678>;
  2410 + };
  2411 + 170 {
  2412 + name = "lcd";
  2413 + accum = <33482>;
  2414 + };
  2415 + };
  2416 +
  2417 + Code in the Linux kernel can find this in /proc/devicetree.
  2418 +
2394 2419 Legacy uImage format:
2395 2420  
2396 2421 Arg Where When
arch/arm/lib/bootm.c
... ... @@ -96,6 +96,9 @@
96 96 {
97 97 printf("\nStarting kernel ...\n\n");
98 98 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
  99 +#ifdef CONFIG_BOOTSTAGE_FDT
  100 + bootstage_fdt_add_report();
  101 +#endif
99 102 #ifdef CONFIG_BOOTSTAGE_REPORT
100 103 bootstage_report();
101 104 #endif
... ... @@ -68,6 +68,7 @@
68 68 COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
69 69 COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o
70 70 COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
  71 +COBJS-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o
71 72 COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o
72 73 COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o
73 74 COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o
... ... @@ -33,13 +33,9 @@
33 33  
34 34 DECLARE_GLOBAL_DATA_PTR;
35 35  
36   -enum bootstage_flags {
37   - BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
38   - BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
39   -};
40   -
41 36 struct bootstage_record {
42 37 ulong time_us;
  38 + uint32_t start_us;
43 39 const char *name;
44 40 int flags; /* see enum bootstage_flags */
45 41 enum bootstage_id id;
46 42  
47 43  
... ... @@ -48,11 +44,22 @@
48 44 static struct bootstage_record record[BOOTSTAGE_ID_COUNT] = { {1} };
49 45 static int next_id = BOOTSTAGE_ID_USER;
50 46  
  47 +enum {
  48 + BOOTSTAGE_VERSION = 0,
  49 + BOOTSTAGE_MAGIC = 0xb00757a3,
  50 +};
  51 +
  52 +struct bootstage_hdr {
  53 + uint32_t version; /* BOOTSTAGE_VERSION */
  54 + uint32_t count; /* Number of records */
  55 + uint32_t size; /* Total data size (non-zero if valid) */
  56 + uint32_t magic; /* Unused */
  57 +};
  58 +
51 59 ulong bootstage_add_record(enum bootstage_id id, const char *name,
52   - int flags)
  60 + int flags, ulong mark)
53 61 {
54 62 struct bootstage_record *rec;
55   - ulong mark = timer_get_boot_us();
56 63  
57 64 if (flags & BOOTSTAGEF_ALLOC)
58 65 id = next_id++;
59 66  
... ... @@ -77,12 +84,13 @@
77 84  
78 85 ulong bootstage_mark(enum bootstage_id id)
79 86 {
80   - return bootstage_add_record(id, NULL, 0);
  87 + return bootstage_add_record(id, NULL, 0, timer_get_boot_us());
81 88 }
82 89  
83 90 ulong bootstage_error(enum bootstage_id id)
84 91 {
85   - return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR);
  92 + return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR,
  93 + timer_get_boot_us());
86 94 }
87 95  
88 96 ulong bootstage_mark_name(enum bootstage_id id, const char *name)
89 97  
... ... @@ -91,9 +99,28 @@
91 99  
92 100 if (id == BOOTSTAGE_ID_ALLOC)
93 101 flags = BOOTSTAGEF_ALLOC;
94   - return bootstage_add_record(id, name, flags);
  102 + return bootstage_add_record(id, name, flags, timer_get_boot_us());
95 103 }
96 104  
  105 +uint32_t bootstage_start(enum bootstage_id id, const char *name)
  106 +{
  107 + struct bootstage_record *rec = &record[id];
  108 +
  109 + rec->start_us = timer_get_boot_us();
  110 + rec->name = name;
  111 + return rec->start_us;
  112 +}
  113 +
  114 +uint32_t bootstage_accum(enum bootstage_id id)
  115 +{
  116 + struct bootstage_record *rec = &record[id];
  117 + uint32_t duration;
  118 +
  119 + duration = (uint32_t)timer_get_boot_us() - rec->start_us;
  120 + rec->time_us += duration;
  121 + return duration;
  122 +}
  123 +
97 124 static void print_time(unsigned long us_time)
98 125 {
99 126 char str[15], *s;
100 127  
101 128  
102 129  
... ... @@ -109,17 +136,41 @@
109 136 }
110 137 }
111 138  
112   -static uint32_t print_time_record(enum bootstage_id id,
113   - struct bootstage_record *rec, uint32_t prev)
  139 +/**
  140 + * Get a record name as a printable string
  141 + *
  142 + * @param buf Buffer to put name if needed
  143 + * @param len Length of buffer
  144 + * @param rec Boot stage record to get the name from
  145 + * @return pointer to name, either from the record or pointing to buf.
  146 + */
  147 +static const char *get_record_name(char *buf, int len,
  148 + struct bootstage_record *rec)
114 149 {
115   - print_time(rec->time_us);
116   - print_time(rec->time_us - prev);
117 150 if (rec->name)
118   - printf(" %s\n", rec->name);
119   - else if (id >= BOOTSTAGE_ID_USER)
120   - printf(" user_%d\n", id - BOOTSTAGE_ID_USER);
  151 + return rec->name;
  152 + else if (rec->id >= BOOTSTAGE_ID_USER)
  153 + snprintf(buf, len, "user_%d", rec->id - BOOTSTAGE_ID_USER);
121 154 else
122   - printf(" id=%d\n", id);
  155 + snprintf(buf, len, "id=%d", rec->id);
  156 +
  157 + return buf;
  158 +}
  159 +
  160 +static uint32_t print_time_record(enum bootstage_id id,
  161 + struct bootstage_record *rec, uint32_t prev)
  162 +{
  163 + char buf[20];
  164 +
  165 + if (prev == -1U) {
  166 + printf("%11s", "");
  167 + print_time(rec->time_us);
  168 + } else {
  169 + print_time(rec->time_us);
  170 + print_time(rec->time_us - prev);
  171 + }
  172 + printf(" %s\n", get_record_name(buf, sizeof(buf), rec));
  173 +
123 174 return rec->time_us;
124 175 }
125 176  
... ... @@ -130,6 +181,70 @@
130 181 return rec1->time_us > rec2->time_us ? 1 : -1;
131 182 }
132 183  
  184 +#ifdef CONFIG_OF_LIBFDT
  185 +/**
  186 + * Add all bootstage timings to a device tree.
  187 + *
  188 + * @param blob Device tree blob
  189 + * @return 0 on success, != 0 on failure.
  190 + */
  191 +static int add_bootstages_devicetree(struct fdt_header *blob)
  192 +{
  193 + int bootstage;
  194 + char buf[20];
  195 + int id;
  196 + int i;
  197 +
  198 + if (!blob)
  199 + return 0;
  200 +
  201 + /*
  202 + * Create the node for bootstage.
  203 + * The address of flat device tree is set up by the command bootm.
  204 + */
  205 + bootstage = fdt_add_subnode(blob, 0, "bootstage");
  206 + if (bootstage < 0)
  207 + return -1;
  208 +
  209 + /*
  210 + * Insert the timings to the device tree in the reverse order so
  211 + * that they can be printed in the Linux kernel in the right order.
  212 + */
  213 + for (id = BOOTSTAGE_ID_COUNT - 1, i = 0; id >= 0; id--, i++) {
  214 + struct bootstage_record *rec = &record[id];
  215 + int node;
  216 +
  217 + if (id != BOOTSTAGE_ID_AWAKE && rec->time_us == 0)
  218 + continue;
  219 +
  220 + node = fdt_add_subnode(blob, bootstage, simple_itoa(i));
  221 + if (node < 0)
  222 + break;
  223 +
  224 + /* add properties to the node. */
  225 + if (fdt_setprop_string(blob, node, "name",
  226 + get_record_name(buf, sizeof(buf), rec)))
  227 + return -1;
  228 +
  229 + /* Check if this is a 'mark' or 'accum' record */
  230 + if (fdt_setprop_cell(blob, node,
  231 + rec->start_us ? "accum" : "mark",
  232 + rec->time_us))
  233 + return -1;
  234 + }
  235 +
  236 + return 0;
  237 +}
  238 +
  239 +int bootstage_fdt_add_report(void)
  240 +{
  241 + if (add_bootstages_devicetree(working_fdt))
  242 + puts("bootstage: Failed to add to device tree\n");
  243 +
  244 + return 0;
  245 +}
  246 +#endif
  247 +
133 248 void bootstage_report(void)
134 249 {
135 250 struct bootstage_record *rec = record;
136 251  
... ... @@ -148,13 +263,19 @@
148 263 qsort(record, ARRAY_SIZE(record), sizeof(*rec), h_compare_record);
149 264  
150 265 for (id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
151   - if (rec->time_us != 0)
  266 + if (rec->time_us != 0 && !rec->start_us)
152 267 prev = print_time_record(rec->id, rec, prev);
153 268 }
154 269 if (next_id > BOOTSTAGE_ID_COUNT)
155 270 printf("(Overflowed internal boot id table by %d entries\n"
156 271 "- please increase CONFIG_BOOTSTAGE_USER_COUNT\n",
157 272 next_id - BOOTSTAGE_ID_COUNT);
  273 +
  274 + puts("\nAccumulated time:\n");
  275 + for (id = 0, rec = record; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
  276 + if (rec->start_us)
  277 + prev = print_time_record(id, rec, -1);
  278 + }
158 279 }
159 280  
160 281 ulong __timer_get_boot_us(void)
... ... @@ -173,4 +294,151 @@
173 294  
174 295 ulong timer_get_boot_us(void)
175 296 __attribute__((weak, alias("__timer_get_boot_us")));
  297 +
  298 +/**
  299 + * Append data to a memory buffer
  300 + *
  301 + * Write data to the buffer if there is space. Whether there is space or not,
  302 + * the buffer pointer is incremented.
  303 + *
  304 + * @param ptrp Pointer to buffer, updated by this function
  305 + * @param end Pointer to end of buffer
  306 + * @param data Data to write to buffer
  307 + * @param size Size of data
  308 + */
  309 +static void append_data(char **ptrp, char *end, const void *data, int size)
  310 +{
  311 + char *ptr = *ptrp;
  312 +
  313 + *ptrp += size;
  314 + if (*ptrp > end)
  315 + return;
  316 +
  317 + memcpy(ptr, data, size);
  318 +}
  319 +
  320 +int bootstage_stash(void *base, int size)
  321 +{
  322 + struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
  323 + struct bootstage_record *rec;
  324 + char buf[20];
  325 + char *ptr = base, *end = ptr + size;
  326 + uint32_t count;
  327 + int id;
  328 +
  329 + if (hdr + 1 > (struct bootstage_hdr *)end) {
  330 + debug("%s: Not enough space for bootstage hdr\n", __func__);
  331 + return -1;
  332 + }
  333 +
  334 + /* Write an arbitrary version number */
  335 + hdr->version = BOOTSTAGE_VERSION;
  336 +
  337 + /* Count the number of records, and write that value first */
  338 + for (rec = record, id = count = 0; id < BOOTSTAGE_ID_COUNT;
  339 + id++, rec++) {
  340 + if (rec->time_us != 0)
  341 + count++;
  342 + }
  343 + hdr->count = count;
  344 + hdr->size = 0;
  345 + hdr->magic = BOOTSTAGE_MAGIC;
  346 + ptr += sizeof(*hdr);
  347 +
  348 + /* Write the records, silently stopping when we run out of space */
  349 + for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
  350 + if (rec->time_us != 0)
  351 + append_data(&ptr, end, rec, sizeof(*rec));
  352 + }
  353 +
  354 + /* Write the name strings */
  355 + for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
  356 + if (rec->time_us != 0) {
  357 + const char *name;
  358 +
  359 + name = get_record_name(buf, sizeof(buf), rec);
  360 + append_data(&ptr, end, name, strlen(name) + 1);
  361 + }
  362 + }
  363 +
  364 + /* Check for buffer overflow */
  365 + if (ptr > end) {
  366 + debug("%s: Not enough space for bootstage stash\n", __func__);
  367 + return -1;
  368 + }
  369 +
  370 + /* Update total data size */
  371 + hdr->size = ptr - (char *)base;
  372 + printf("Stashed %d records\n", hdr->count);
  373 +
  374 + return 0;
  375 +}
  376 +
  377 +int bootstage_unstash(void *base, int size)
  378 +{
  379 + struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
  380 + struct bootstage_record *rec;
  381 + char *ptr = base, *end = ptr + size;
  382 + uint rec_size;
  383 + int id;
  384 +
  385 + if (size == -1)
  386 + end = (char *)(~(uintptr_t)0);
  387 +
  388 + if (hdr + 1 > (struct bootstage_hdr *)end) {
  389 + debug("%s: Not enough space for bootstage hdr\n", __func__);
  390 + return -1;
  391 + }
  392 +
  393 + if (hdr->magic != BOOTSTAGE_MAGIC) {
  394 + debug("%s: Invalid bootstage magic\n", __func__);
  395 + return -1;
  396 + }
  397 +
  398 + if (ptr + hdr->size > end) {
  399 + debug("%s: Bootstage data runs past buffer end\n", __func__);
  400 + return -1;
  401 + }
  402 +
  403 + if (hdr->count * sizeof(*rec) > hdr->size) {
  404 + debug("%s: Bootstage has %d records needing %d bytes, but "
  405 + "only %d bytes is available\n", __func__, hdr->count,
  406 + hdr->count * sizeof(*rec), hdr->size);
  407 + return -1;
  408 + }
  409 +
  410 + if (hdr->version != BOOTSTAGE_VERSION) {
  411 + debug("%s: Bootstage data version %#0x unrecognised\n",
  412 + __func__, hdr->version);
  413 + return -1;
  414 + }
  415 +
  416 + if (next_id + hdr->count > BOOTSTAGE_ID_COUNT) {
  417 + debug("%s: Bootstage has %d records, we have space for %d\n"
  418 + "- please increase CONFIG_BOOTSTAGE_USER_COUNT\n",
  419 + __func__, hdr->count, BOOTSTAGE_ID_COUNT - next_id);
  420 + return -1;
  421 + }
  422 +
  423 + ptr += sizeof(*hdr);
  424 +
  425 + /* Read the records */
  426 + rec_size = hdr->count * sizeof(*record);
  427 + memcpy(record + next_id, ptr, rec_size);
  428 +
  429 + /* Read the name strings */
  430 + ptr += rec_size;
  431 + for (rec = record + next_id, id = 0; id < hdr->count; id++, rec++) {
  432 + rec->name = ptr;
  433 +
  434 + /* Assume no data corruption here */
  435 + ptr += strlen(ptr) + 1;
  436 + }
  437 +
  438 + /* Mark the records as read */
  439 + next_id += hdr->count;
  440 + printf("Unstashed %d records\n", hdr->count);
  441 +
  442 + return 0;
  443 +}
common/cmd_bootstage.c
  1 +/*
  2 + * Copyright (c) 2012, Google Inc. All rights reserved.
  3 + *
  4 + * See file CREDITS for list of people who contributed to this
  5 + * project.
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 of
  10 + * the License, or (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include <common.h>
  24 +
  25 +#ifndef CONFIG_BOOTSTAGE_STASH
  26 +#define CONFIG_BOOTSTAGE_STASH -1UL
  27 +#define CONFIG_BOOTSTAGE_STASH_SIZE -1
  28 +#endif
  29 +
  30 +static int do_bootstage_report(cmd_tbl_t *cmdtp, int flag, int argc,
  31 + char * const argv[])
  32 +{
  33 + bootstage_report();
  34 +
  35 + return 0;
  36 +}
  37 +
  38 +static int get_base_size(int argc, char * const argv[], ulong *basep,
  39 + ulong *sizep)
  40 +{
  41 + char *endp;
  42 +
  43 + *basep = CONFIG_BOOTSTAGE_STASH;
  44 + *sizep = CONFIG_BOOTSTAGE_STASH_SIZE;
  45 + if (argc < 2)
  46 + return 0;
  47 + *basep = simple_strtoul(argv[1], &endp, 16);
  48 + if (*argv[1] == 0 || *endp != 0)
  49 + return -1;
  50 + if (argc == 2)
  51 + return 0;
  52 + *sizep = simple_strtoul(argv[2], &endp, 16);
  53 + if (*argv[2] == 0 || *endp != 0)
  54 + return -1;
  55 +
  56 + return 0;
  57 +}
  58 +
  59 +static int do_bootstage_stash(cmd_tbl_t *cmdtp, int flag, int argc,
  60 + char * const argv[])
  61 +{
  62 + ulong base, size;
  63 + int ret;
  64 +
  65 + if (get_base_size(argc, argv, &base, &size))
  66 + return CMD_RET_USAGE;
  67 + if (base == -1UL) {
  68 + printf("No bootstage stash area defined\n");
  69 + return 1;
  70 + }
  71 +
  72 + if (0 == strcmp(argv[0], "stash"))
  73 + ret = bootstage_stash((void *)base, size);
  74 + else
  75 + ret = bootstage_unstash((void *)base, size);
  76 + if (ret)
  77 + return 1;
  78 +
  79 + return 0;
  80 +}
  81 +
  82 +static cmd_tbl_t cmd_bootstage_sub[] = {
  83 + U_BOOT_CMD_MKENT(report, 2, 1, do_bootstage_report, "", ""),
  84 + U_BOOT_CMD_MKENT(stash, 4, 0, do_bootstage_stash, "", ""),
  85 + U_BOOT_CMD_MKENT(unstash, 4, 0, do_bootstage_stash, "", ""),
  86 +};
  87 +
  88 +/*
  89 + * Process a bootstage sub-command
  90 + */
  91 +static int do_boostage(cmd_tbl_t *cmdtp, int flag, int argc,
  92 + char * const argv[])
  93 +{
  94 + cmd_tbl_t *c;
  95 +
  96 + /* Strip off leading 'bootstage' command argument */
  97 + argc--;
  98 + argv++;
  99 +
  100 + c = find_cmd_tbl(argv[0], cmd_bootstage_sub,
  101 + ARRAY_SIZE(cmd_bootstage_sub));
  102 +
  103 + if (c)
  104 + return c->cmd(cmdtp, flag, argc, argv);
  105 + else
  106 + return CMD_RET_USAGE;
  107 +}
  108 +
  109 +
  110 +U_BOOT_CMD(bootstage, 4, 1, do_boostage,
  111 + "Boot stage command",
  112 + " - check boot progress and timing\n"
  113 + "report - Print a report\n"
  114 + "stash [<start> [<size>]] - Stash data into memory\n"
  115 + "unstash [<start> [<size>]] - Unstash data from memory"
  116 +);
... ... @@ -31,6 +31,12 @@
31 31 #define CONFIG_BOOTSTAGE_USER_COUNT 20
32 32 #endif
33 33  
  34 +/* Flags for each bootstage record */
  35 +enum bootstage_flags {
  36 + BOOTSTAGEF_ERROR = 1 << 0, /* Error record */
  37 + BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */
  38 +};
  39 +
34 40 /*
35 41 * A list of boot stages that we know about. Each of these indicates the
36 42 * state that we are at, and the action that we are about to perform. For
... ... @@ -181,6 +187,7 @@
181 187 * rough boot timing information.
182 188 */
183 189 BOOTSTAGE_ID_AWAKE,
  190 + BOOTSTAGE_ID_START_SPL,
184 191 BOOTSTAGE_ID_START_UBOOT_F,
185 192 BOOTSTAGE_ID_START_UBOOT_R,
186 193 BOOTSTAGE_ID_USB_START,
187 194  
... ... @@ -192,11 +199,15 @@
192 199 BOOTSTAGE_ID_MAIN_LOOP,
193 200 BOOTSTAGE_KERNELREAD_START,
194 201 BOOTSTAGE_KERNELREAD_STOP,
  202 + BOOTSTAGE_ID_BOARD_INIT,
  203 + BOOTSTAGE_ID_BOARD_INIT_DONE,
195 204  
196 205 BOOTSTAGE_ID_CPU_AWAKE,
197 206 BOOTSTAGE_ID_MAIN_CPU_AWAKE,
198 207 BOOTSTAGE_ID_MAIN_CPU_READY,
199 208  
  209 + BOOTSTAGE_ID_ACCUM_LCD,
  210 +
200 211 /* a few spare for the user, from here */
201 212 BOOTSTAGE_ID_USER,
202 213 BOOTSTAGE_ID_COUNT = BOOTSTAGE_ID_USER + CONFIG_BOOTSTAGE_USER_COUNT,
... ... @@ -225,6 +236,17 @@
225 236 #if defined(CONFIG_BOOTSTAGE) && !defined(CONFIG_SPL_BUILD)
226 237 /* This is the full bootstage implementation */
227 238  
  239 +/**
  240 + * Add a new bootstage record
  241 + *
  242 + * @param id Bootstage ID to use (ignored if flags & BOOTSTAGEF_ALLOC)
  243 + * @param name Name of record, or NULL for none
  244 + * @param flags Flags (BOOTSTAGEF_...)
  245 + * @param mark Time to record in this record, in microseconds
  246 + */
  247 +ulong bootstage_add_record(enum bootstage_id id, const char *name,
  248 + int flags, ulong mark);
  249 +
228 250 /*
229 251 * Mark a time stamp for the current boot stage.
230 252 */
231 253  
... ... @@ -234,9 +256,64 @@
234 256  
235 257 ulong bootstage_mark_name(enum bootstage_id id, const char *name);
236 258  
  259 +/**
  260 + * Mark the start of a bootstage activity. The end will be marked later with
  261 + * bootstage_accum() and at that point we accumulate the time taken. Calling
  262 + * this function turns the given id into a accumulator rather than and
  263 + * absolute mark in time. Accumulators record the total amount of time spent
  264 + * in an activty during boot.
  265 + *
  266 + * @param id Bootstage id to record this timestamp against
  267 + * @param name Textual name to display for this id in the report (maybe NULL)
  268 + * @return start timestamp in microseconds
  269 + */
  270 +uint32_t bootstage_start(enum bootstage_id id, const char *name);
  271 +
  272 +/**
  273 + * Mark the end of a bootstage activity
  274 + *
  275 + * After previously marking the start of an activity with bootstage_start(),
  276 + * call this function to mark the end. You can call these functions in pairs
  277 + * as many times as you like.
  278 + *
  279 + * @param id Bootstage id to record this timestamp against
  280 + * @return time spent in this iteration of the activity (i.e. the time now
  281 + * less the start time recorded in the last bootstage_start() call
  282 + * with this id.
  283 + */
  284 +uint32_t bootstage_accum(enum bootstage_id id);
  285 +
237 286 /* Print a report about boot time */
238 287 void bootstage_report(void);
239 288  
  289 +/**
  290 + * Add bootstage information to the device tree
  291 + *
  292 + * @return 0 if ok, -ve on error
  293 + */
  294 +int bootstage_fdt_add_report(void);
  295 +
  296 +/*
  297 + * Stash bootstage data into memory
  298 + *
  299 + * @param base Base address of memory buffer
  300 + * @param size Size of memory buffer
  301 + * @return 0 if stashed ok, -1 if out of space
  302 + */
  303 +int bootstage_stash(void *base, int size);
  304 +
  305 +/**
  306 + * Read bootstage data from memory
  307 + *
  308 + * Bootstage data is read from memory and placed in the bootstage table
  309 + * in the user records.
  310 + *
  311 + * @param base Base address of memory buffer
  312 + * @param size Size of memory buffer (-1 if unknown)
  313 + * @return 0 if unstashed ok, -1 if bootstage info not found, or out of space
  314 + */
  315 +int bootstage_unstash(void *base, int size);
  316 +
240 317 #else
241 318 /*
242 319 * This is a dummy implementation which just calls show_boot_progress(),
243 320  
... ... @@ -260,7 +337,15 @@
260 337 return 0;
261 338 }
262 339  
  340 +static inline int bootstage_stash(void *base, int size)
  341 +{
  342 + return 0; /* Pretend to succeed */
  343 +}
263 344  
  345 +static inline int bootstage_unstash(void *base, int size)
  346 +{
  347 + return 0; /* Pretend to succeed */
  348 +}
264 349 #endif /* CONFIG_BOOTSTAGE */
265 350  
266 351 #endif