1*b2e16a85SSimon Glass /* 2*b2e16a85SSimon Glass * Copyright (c) 2012 The Chromium OS Authors. 3*b2e16a85SSimon Glass * 4*b2e16a85SSimon Glass * This program is free software; you can redistribute it and/or 5*b2e16a85SSimon Glass * modify it under the terms of the GNU General Public License as 6*b2e16a85SSimon Glass * published by the Free Software Foundation; either version 2 of 7*b2e16a85SSimon Glass * the License, or (at your option) any later version. 8*b2e16a85SSimon Glass * 9*b2e16a85SSimon Glass * This program is distributed in the hope that it will be useful, 10*b2e16a85SSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*b2e16a85SSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*b2e16a85SSimon Glass * GNU General Public License for more details. 13*b2e16a85SSimon Glass * 14*b2e16a85SSimon Glass * You should have received a copy of the GNU General Public License 15*b2e16a85SSimon Glass * along with this program; if not, write to the Free Software 16*b2e16a85SSimon Glass * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17*b2e16a85SSimon Glass * MA 02111-1307 USA 18*b2e16a85SSimon Glass */ 19*b2e16a85SSimon Glass 20*b2e16a85SSimon Glass #include <common.h> 21*b2e16a85SSimon Glass #include <trace.h> 22*b2e16a85SSimon Glass #include <asm/io.h> 23*b2e16a85SSimon Glass #include <asm/sections.h> 24*b2e16a85SSimon Glass 25*b2e16a85SSimon Glass DECLARE_GLOBAL_DATA_PTR; 26*b2e16a85SSimon Glass 27*b2e16a85SSimon Glass static char trace_enabled __attribute__((section(".data"))); 28*b2e16a85SSimon Glass static char trace_inited __attribute__((section(".data"))); 29*b2e16a85SSimon Glass 30*b2e16a85SSimon Glass /* The header block at the start of the trace memory area */ 31*b2e16a85SSimon Glass struct trace_hdr { 32*b2e16a85SSimon Glass int func_count; /* Total number of function call sites */ 33*b2e16a85SSimon Glass u64 call_count; /* Total number of tracked function calls */ 34*b2e16a85SSimon Glass u64 untracked_count; /* Total number of untracked function calls */ 35*b2e16a85SSimon Glass int funcs_used; /* Total number of functions used */ 36*b2e16a85SSimon Glass 37*b2e16a85SSimon Glass /* 38*b2e16a85SSimon Glass * Call count for each function. This is indexed by the word offset 39*b2e16a85SSimon Glass * of the function from gd->relocaddr 40*b2e16a85SSimon Glass */ 41*b2e16a85SSimon Glass uintptr_t *call_accum; 42*b2e16a85SSimon Glass 43*b2e16a85SSimon Glass /* Function trace list */ 44*b2e16a85SSimon Glass struct trace_call *ftrace; /* The function call records */ 45*b2e16a85SSimon Glass ulong ftrace_size; /* Num. of ftrace records we have space for */ 46*b2e16a85SSimon Glass ulong ftrace_count; /* Num. of ftrace records written */ 47*b2e16a85SSimon Glass ulong ftrace_too_deep_count; /* Functions that were too deep */ 48*b2e16a85SSimon Glass 49*b2e16a85SSimon Glass int depth; 50*b2e16a85SSimon Glass int depth_limit; 51*b2e16a85SSimon Glass int max_depth; 52*b2e16a85SSimon Glass }; 53*b2e16a85SSimon Glass 54*b2e16a85SSimon Glass static struct trace_hdr *hdr; /* Pointer to start of trace buffer */ 55*b2e16a85SSimon Glass 56*b2e16a85SSimon Glass static inline uintptr_t __attribute__((no_instrument_function)) 57*b2e16a85SSimon Glass func_ptr_to_num(void *func_ptr) 58*b2e16a85SSimon Glass { 59*b2e16a85SSimon Glass uintptr_t offset = (uintptr_t)func_ptr; 60*b2e16a85SSimon Glass 61*b2e16a85SSimon Glass #ifdef CONFIG_SANDBOX 62*b2e16a85SSimon Glass offset -= (uintptr_t)&_init; 63*b2e16a85SSimon Glass #else 64*b2e16a85SSimon Glass if (gd->flags & GD_FLG_RELOC) 65*b2e16a85SSimon Glass offset -= gd->relocaddr; 66*b2e16a85SSimon Glass else 67*b2e16a85SSimon Glass offset -= CONFIG_SYS_TEXT_BASE; 68*b2e16a85SSimon Glass #endif 69*b2e16a85SSimon Glass return offset / FUNC_SITE_SIZE; 70*b2e16a85SSimon Glass } 71*b2e16a85SSimon Glass 72*b2e16a85SSimon Glass static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr, 73*b2e16a85SSimon Glass void *caller, ulong flags) 74*b2e16a85SSimon Glass { 75*b2e16a85SSimon Glass if (hdr->depth > hdr->depth_limit) { 76*b2e16a85SSimon Glass hdr->ftrace_too_deep_count++; 77*b2e16a85SSimon Glass return; 78*b2e16a85SSimon Glass } 79*b2e16a85SSimon Glass if (hdr->ftrace_count < hdr->ftrace_size) { 80*b2e16a85SSimon Glass struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; 81*b2e16a85SSimon Glass 82*b2e16a85SSimon Glass rec->func = func_ptr_to_num(func_ptr); 83*b2e16a85SSimon Glass rec->caller = func_ptr_to_num(caller); 84*b2e16a85SSimon Glass rec->flags = flags | (timer_get_us() & FUNCF_TIMESTAMP_MASK); 85*b2e16a85SSimon Glass } 86*b2e16a85SSimon Glass hdr->ftrace_count++; 87*b2e16a85SSimon Glass } 88*b2e16a85SSimon Glass 89*b2e16a85SSimon Glass static void __attribute__((no_instrument_function)) add_textbase(void) 90*b2e16a85SSimon Glass { 91*b2e16a85SSimon Glass if (hdr->ftrace_count < hdr->ftrace_size) { 92*b2e16a85SSimon Glass struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; 93*b2e16a85SSimon Glass 94*b2e16a85SSimon Glass rec->func = CONFIG_SYS_TEXT_BASE; 95*b2e16a85SSimon Glass rec->caller = 0; 96*b2e16a85SSimon Glass rec->flags = FUNCF_TEXTBASE; 97*b2e16a85SSimon Glass } 98*b2e16a85SSimon Glass hdr->ftrace_count++; 99*b2e16a85SSimon Glass } 100*b2e16a85SSimon Glass 101*b2e16a85SSimon Glass /** 102*b2e16a85SSimon Glass * This is called on every function entry 103*b2e16a85SSimon Glass * 104*b2e16a85SSimon Glass * We add to our tally for this function and add to the list of called 105*b2e16a85SSimon Glass * functions. 106*b2e16a85SSimon Glass * 107*b2e16a85SSimon Glass * @param func_ptr Pointer to function being entered 108*b2e16a85SSimon Glass * @param caller Pointer to function which called this function 109*b2e16a85SSimon Glass */ 110*b2e16a85SSimon Glass void __attribute__((no_instrument_function)) __cyg_profile_func_enter( 111*b2e16a85SSimon Glass void *func_ptr, void *caller) 112*b2e16a85SSimon Glass { 113*b2e16a85SSimon Glass if (trace_enabled) { 114*b2e16a85SSimon Glass int func; 115*b2e16a85SSimon Glass 116*b2e16a85SSimon Glass add_ftrace(func_ptr, caller, FUNCF_ENTRY); 117*b2e16a85SSimon Glass func = func_ptr_to_num(func_ptr); 118*b2e16a85SSimon Glass if (func < hdr->func_count) { 119*b2e16a85SSimon Glass hdr->call_accum[func]++; 120*b2e16a85SSimon Glass hdr->call_count++; 121*b2e16a85SSimon Glass } else { 122*b2e16a85SSimon Glass hdr->untracked_count++; 123*b2e16a85SSimon Glass } 124*b2e16a85SSimon Glass hdr->depth++; 125*b2e16a85SSimon Glass if (hdr->depth > hdr->depth_limit) 126*b2e16a85SSimon Glass hdr->max_depth = hdr->depth; 127*b2e16a85SSimon Glass } 128*b2e16a85SSimon Glass } 129*b2e16a85SSimon Glass 130*b2e16a85SSimon Glass /** 131*b2e16a85SSimon Glass * This is called on every function exit 132*b2e16a85SSimon Glass * 133*b2e16a85SSimon Glass * We do nothing here. 134*b2e16a85SSimon Glass * 135*b2e16a85SSimon Glass * @param func_ptr Pointer to function being entered 136*b2e16a85SSimon Glass * @param caller Pointer to function which called this function 137*b2e16a85SSimon Glass */ 138*b2e16a85SSimon Glass void __attribute__((no_instrument_function)) __cyg_profile_func_exit( 139*b2e16a85SSimon Glass void *func_ptr, void *caller) 140*b2e16a85SSimon Glass { 141*b2e16a85SSimon Glass if (trace_enabled) { 142*b2e16a85SSimon Glass add_ftrace(func_ptr, caller, FUNCF_EXIT); 143*b2e16a85SSimon Glass hdr->depth--; 144*b2e16a85SSimon Glass } 145*b2e16a85SSimon Glass } 146*b2e16a85SSimon Glass 147*b2e16a85SSimon Glass /** 148*b2e16a85SSimon Glass * Produce a list of called functions 149*b2e16a85SSimon Glass * 150*b2e16a85SSimon Glass * The information is written into the supplied buffer - a header followed 151*b2e16a85SSimon Glass * by a list of function records. 152*b2e16a85SSimon Glass * 153*b2e16a85SSimon Glass * @param buff Buffer to place list into 154*b2e16a85SSimon Glass * @param buff_size Size of buffer 155*b2e16a85SSimon Glass * @param needed Returns size of buffer needed, which may be 156*b2e16a85SSimon Glass * greater than buff_size if we ran out of space. 157*b2e16a85SSimon Glass * @return 0 if ok, -1 if space was exhausted 158*b2e16a85SSimon Glass */ 159*b2e16a85SSimon Glass int trace_list_functions(void *buff, int buff_size, unsigned int *needed) 160*b2e16a85SSimon Glass { 161*b2e16a85SSimon Glass struct trace_output_hdr *output_hdr = NULL; 162*b2e16a85SSimon Glass void *end, *ptr = buff; 163*b2e16a85SSimon Glass int func; 164*b2e16a85SSimon Glass int upto; 165*b2e16a85SSimon Glass 166*b2e16a85SSimon Glass end = buff ? buff + buff_size : NULL; 167*b2e16a85SSimon Glass 168*b2e16a85SSimon Glass /* Place some header information */ 169*b2e16a85SSimon Glass if (ptr + sizeof(struct trace_output_hdr) < end) 170*b2e16a85SSimon Glass output_hdr = ptr; 171*b2e16a85SSimon Glass ptr += sizeof(struct trace_output_hdr); 172*b2e16a85SSimon Glass 173*b2e16a85SSimon Glass /* Add information about each function */ 174*b2e16a85SSimon Glass for (func = upto = 0; func < hdr->func_count; func++) { 175*b2e16a85SSimon Glass int calls = hdr->call_accum[func]; 176*b2e16a85SSimon Glass 177*b2e16a85SSimon Glass if (!calls) 178*b2e16a85SSimon Glass continue; 179*b2e16a85SSimon Glass 180*b2e16a85SSimon Glass if (ptr + sizeof(struct trace_output_func) < end) { 181*b2e16a85SSimon Glass struct trace_output_func *stats = ptr; 182*b2e16a85SSimon Glass 183*b2e16a85SSimon Glass stats->offset = func * FUNC_SITE_SIZE; 184*b2e16a85SSimon Glass stats->call_count = calls; 185*b2e16a85SSimon Glass upto++; 186*b2e16a85SSimon Glass } 187*b2e16a85SSimon Glass ptr += sizeof(struct trace_output_func); 188*b2e16a85SSimon Glass } 189*b2e16a85SSimon Glass 190*b2e16a85SSimon Glass /* Update the header */ 191*b2e16a85SSimon Glass if (output_hdr) { 192*b2e16a85SSimon Glass output_hdr->rec_count = upto; 193*b2e16a85SSimon Glass output_hdr->type = TRACE_CHUNK_FUNCS; 194*b2e16a85SSimon Glass } 195*b2e16a85SSimon Glass 196*b2e16a85SSimon Glass /* Work out how must of the buffer we used */ 197*b2e16a85SSimon Glass *needed = ptr - buff; 198*b2e16a85SSimon Glass if (ptr > end) 199*b2e16a85SSimon Glass return -1; 200*b2e16a85SSimon Glass return 0; 201*b2e16a85SSimon Glass } 202*b2e16a85SSimon Glass 203*b2e16a85SSimon Glass int trace_list_calls(void *buff, int buff_size, unsigned *needed) 204*b2e16a85SSimon Glass { 205*b2e16a85SSimon Glass struct trace_output_hdr *output_hdr = NULL; 206*b2e16a85SSimon Glass void *end, *ptr = buff; 207*b2e16a85SSimon Glass int rec, upto; 208*b2e16a85SSimon Glass int count; 209*b2e16a85SSimon Glass 210*b2e16a85SSimon Glass end = buff ? buff + buff_size : NULL; 211*b2e16a85SSimon Glass 212*b2e16a85SSimon Glass /* Place some header information */ 213*b2e16a85SSimon Glass if (ptr + sizeof(struct trace_output_hdr) < end) 214*b2e16a85SSimon Glass output_hdr = ptr; 215*b2e16a85SSimon Glass ptr += sizeof(struct trace_output_hdr); 216*b2e16a85SSimon Glass 217*b2e16a85SSimon Glass /* Add information about each call */ 218*b2e16a85SSimon Glass count = hdr->ftrace_count; 219*b2e16a85SSimon Glass if (count > hdr->ftrace_size) 220*b2e16a85SSimon Glass count = hdr->ftrace_size; 221*b2e16a85SSimon Glass for (rec = upto = 0; rec < count; rec++) { 222*b2e16a85SSimon Glass if (ptr + sizeof(struct trace_call) < end) { 223*b2e16a85SSimon Glass struct trace_call *call = &hdr->ftrace[rec]; 224*b2e16a85SSimon Glass struct trace_call *out = ptr; 225*b2e16a85SSimon Glass 226*b2e16a85SSimon Glass out->func = call->func * FUNC_SITE_SIZE; 227*b2e16a85SSimon Glass out->caller = call->caller * FUNC_SITE_SIZE; 228*b2e16a85SSimon Glass out->flags = call->flags; 229*b2e16a85SSimon Glass upto++; 230*b2e16a85SSimon Glass } 231*b2e16a85SSimon Glass ptr += sizeof(struct trace_call); 232*b2e16a85SSimon Glass } 233*b2e16a85SSimon Glass 234*b2e16a85SSimon Glass /* Update the header */ 235*b2e16a85SSimon Glass if (output_hdr) { 236*b2e16a85SSimon Glass output_hdr->rec_count = upto; 237*b2e16a85SSimon Glass output_hdr->type = TRACE_CHUNK_CALLS; 238*b2e16a85SSimon Glass } 239*b2e16a85SSimon Glass 240*b2e16a85SSimon Glass /* Work out how must of the buffer we used */ 241*b2e16a85SSimon Glass *needed = ptr - buff; 242*b2e16a85SSimon Glass if (ptr > end) 243*b2e16a85SSimon Glass return -1; 244*b2e16a85SSimon Glass return 0; 245*b2e16a85SSimon Glass } 246*b2e16a85SSimon Glass 247*b2e16a85SSimon Glass /* Print basic information about tracing */ 248*b2e16a85SSimon Glass void trace_print_stats(void) 249*b2e16a85SSimon Glass { 250*b2e16a85SSimon Glass ulong count; 251*b2e16a85SSimon Glass 252*b2e16a85SSimon Glass #ifndef FTRACE 253*b2e16a85SSimon Glass puts("Warning: make U-Boot with FTRACE to enable function instrumenting.\n"); 254*b2e16a85SSimon Glass puts("You will likely get zeroed data here\n"); 255*b2e16a85SSimon Glass #endif 256*b2e16a85SSimon Glass if (!trace_inited) { 257*b2e16a85SSimon Glass printf("Trace is disabled\n"); 258*b2e16a85SSimon Glass return; 259*b2e16a85SSimon Glass } 260*b2e16a85SSimon Glass print_grouped_ull(hdr->func_count, 10); 261*b2e16a85SSimon Glass puts(" function sites\n"); 262*b2e16a85SSimon Glass print_grouped_ull(hdr->call_count, 10); 263*b2e16a85SSimon Glass puts(" function calls\n"); 264*b2e16a85SSimon Glass print_grouped_ull(hdr->untracked_count, 10); 265*b2e16a85SSimon Glass puts(" untracked function calls\n"); 266*b2e16a85SSimon Glass count = min(hdr->ftrace_count, hdr->ftrace_size); 267*b2e16a85SSimon Glass print_grouped_ull(count, 10); 268*b2e16a85SSimon Glass puts(" traced function calls"); 269*b2e16a85SSimon Glass if (hdr->ftrace_count > hdr->ftrace_size) { 270*b2e16a85SSimon Glass printf(" (%lu dropped due to overflow)", 271*b2e16a85SSimon Glass hdr->ftrace_count - hdr->ftrace_size); 272*b2e16a85SSimon Glass } 273*b2e16a85SSimon Glass puts("\n"); 274*b2e16a85SSimon Glass printf("%15d maximum observed call depth\n", hdr->max_depth); 275*b2e16a85SSimon Glass printf("%15d call depth limit\n", hdr->depth_limit); 276*b2e16a85SSimon Glass print_grouped_ull(hdr->ftrace_too_deep_count, 10); 277*b2e16a85SSimon Glass puts(" calls not traced due to depth\n"); 278*b2e16a85SSimon Glass } 279*b2e16a85SSimon Glass 280*b2e16a85SSimon Glass void __attribute__((no_instrument_function)) trace_set_enabled(int enabled) 281*b2e16a85SSimon Glass { 282*b2e16a85SSimon Glass trace_enabled = enabled != 0; 283*b2e16a85SSimon Glass } 284*b2e16a85SSimon Glass 285*b2e16a85SSimon Glass /** 286*b2e16a85SSimon Glass * Init the tracing system ready for used, and enable it 287*b2e16a85SSimon Glass * 288*b2e16a85SSimon Glass * @param buff Pointer to trace buffer 289*b2e16a85SSimon Glass * @param buff_size Size of trace buffer 290*b2e16a85SSimon Glass */ 291*b2e16a85SSimon Glass int __attribute__((no_instrument_function)) trace_init(void *buff, 292*b2e16a85SSimon Glass size_t buff_size) 293*b2e16a85SSimon Glass { 294*b2e16a85SSimon Glass ulong func_count = gd->mon_len / FUNC_SITE_SIZE; 295*b2e16a85SSimon Glass size_t needed; 296*b2e16a85SSimon Glass int was_disabled = !trace_enabled; 297*b2e16a85SSimon Glass 298*b2e16a85SSimon Glass if (!was_disabled) { 299*b2e16a85SSimon Glass #ifdef CONFIG_TRACE_EARLY 300*b2e16a85SSimon Glass char *end; 301*b2e16a85SSimon Glass ulong used; 302*b2e16a85SSimon Glass 303*b2e16a85SSimon Glass /* 304*b2e16a85SSimon Glass * Copy over the early trace data if we have it. Disable 305*b2e16a85SSimon Glass * tracing while we are doing this. 306*b2e16a85SSimon Glass */ 307*b2e16a85SSimon Glass trace_enabled = 0; 308*b2e16a85SSimon Glass hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, 309*b2e16a85SSimon Glass CONFIG_TRACE_EARLY_SIZE); 310*b2e16a85SSimon Glass end = (char *)&hdr->ftrace[hdr->ftrace_count]; 311*b2e16a85SSimon Glass used = end - (char *)hdr; 312*b2e16a85SSimon Glass printf("trace: copying %08lx bytes of early data from %x to %08lx\n", 313*b2e16a85SSimon Glass used, CONFIG_TRACE_EARLY_ADDR, 314*b2e16a85SSimon Glass (ulong)map_to_sysmem(buff)); 315*b2e16a85SSimon Glass memcpy(buff, hdr, used); 316*b2e16a85SSimon Glass #else 317*b2e16a85SSimon Glass puts("trace: already enabled\n"); 318*b2e16a85SSimon Glass return -1; 319*b2e16a85SSimon Glass #endif 320*b2e16a85SSimon Glass } 321*b2e16a85SSimon Glass hdr = (struct trace_hdr *)buff; 322*b2e16a85SSimon Glass needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); 323*b2e16a85SSimon Glass if (needed > buff_size) { 324*b2e16a85SSimon Glass printf("trace: buffer size %zd bytes: at least %zd needed\n", 325*b2e16a85SSimon Glass buff_size, needed); 326*b2e16a85SSimon Glass return -1; 327*b2e16a85SSimon Glass } 328*b2e16a85SSimon Glass 329*b2e16a85SSimon Glass if (was_disabled) 330*b2e16a85SSimon Glass memset(hdr, '\0', needed); 331*b2e16a85SSimon Glass hdr->func_count = func_count; 332*b2e16a85SSimon Glass hdr->call_accum = (uintptr_t *)(hdr + 1); 333*b2e16a85SSimon Glass 334*b2e16a85SSimon Glass /* Use any remaining space for the timed function trace */ 335*b2e16a85SSimon Glass hdr->ftrace = (struct trace_call *)(buff + needed); 336*b2e16a85SSimon Glass hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); 337*b2e16a85SSimon Glass add_textbase(); 338*b2e16a85SSimon Glass 339*b2e16a85SSimon Glass puts("trace: enabled\n"); 340*b2e16a85SSimon Glass hdr->depth_limit = 15; 341*b2e16a85SSimon Glass trace_enabled = 1; 342*b2e16a85SSimon Glass trace_inited = 1; 343*b2e16a85SSimon Glass return 0; 344*b2e16a85SSimon Glass } 345*b2e16a85SSimon Glass 346*b2e16a85SSimon Glass #ifdef CONFIG_TRACE_EARLY 347*b2e16a85SSimon Glass int __attribute__((no_instrument_function)) trace_early_init(void) 348*b2e16a85SSimon Glass { 349*b2e16a85SSimon Glass ulong func_count = gd->mon_len / FUNC_SITE_SIZE; 350*b2e16a85SSimon Glass size_t buff_size = CONFIG_TRACE_EARLY_SIZE; 351*b2e16a85SSimon Glass size_t needed; 352*b2e16a85SSimon Glass 353*b2e16a85SSimon Glass /* We can ignore additional calls to this function */ 354*b2e16a85SSimon Glass if (trace_enabled) 355*b2e16a85SSimon Glass return 0; 356*b2e16a85SSimon Glass 357*b2e16a85SSimon Glass hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE); 358*b2e16a85SSimon Glass needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); 359*b2e16a85SSimon Glass if (needed > buff_size) { 360*b2e16a85SSimon Glass printf("trace: buffer size is %zd bytes, at least %zd needed\n", 361*b2e16a85SSimon Glass buff_size, needed); 362*b2e16a85SSimon Glass return -1; 363*b2e16a85SSimon Glass } 364*b2e16a85SSimon Glass 365*b2e16a85SSimon Glass memset(hdr, '\0', needed); 366*b2e16a85SSimon Glass hdr->call_accum = (uintptr_t *)(hdr + 1); 367*b2e16a85SSimon Glass hdr->func_count = func_count; 368*b2e16a85SSimon Glass 369*b2e16a85SSimon Glass /* Use any remaining space for the timed function trace */ 370*b2e16a85SSimon Glass hdr->ftrace = (struct trace_call *)((char *)hdr + needed); 371*b2e16a85SSimon Glass hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); 372*b2e16a85SSimon Glass add_textbase(); 373*b2e16a85SSimon Glass hdr->depth_limit = 200; 374*b2e16a85SSimon Glass printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR); 375*b2e16a85SSimon Glass 376*b2e16a85SSimon Glass trace_enabled = 1; 377*b2e16a85SSimon Glass return 0; 378*b2e16a85SSimon Glass } 379*b2e16a85SSimon Glass #endif 380