]> Git Repo - J-u-boot.git/blobdiff - lib/trace.c
arm: cpu: Add ACPI parking protocol support
[J-u-boot.git] / lib / trace.c
index f2402b93593b3d84525f67b668ab05731acacde5..cabbe47b58a3f5f494182e4b6145b1da311e921a 100644 (file)
@@ -3,16 +3,18 @@
  * Copyright (c) 2012 The Chromium OS Authors.
  */
 
-#include <common.h>
 #include <mapmem.h>
+#include <time.h>
 #include <trace.h>
+#include <linux/errno.h>
+#include <asm/global_data.h>
 #include <asm/io.h>
 #include <asm/sections.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static char trace_enabled __attribute__((section(".data")));
-static char trace_inited __attribute__((section(".data")));
+static char trace_enabled __section(".data");
+static char trace_inited __section(".data");
 
 /* The header block at the start of the trace memory area */
 struct trace_hdr {
@@ -33,12 +35,15 @@ struct trace_hdr {
        ulong ftrace_count;     /* Num. of ftrace records written */
        ulong ftrace_too_deep_count;    /* Functions that were too deep */
 
-       int depth;
-       int depth_limit;
-       int max_depth;
+       int depth;              /* Depth of function calls */
+       int depth_limit;        /* Depth limit to trace to */
+       int max_depth;          /* Maximum depth seen so far */
+       int min_depth;          /* Minimum depth seen so far */
+       bool trace_locked;      /* Used to detect recursive tracing */
 };
 
-static struct trace_hdr *hdr;  /* Pointer to start of trace buffer */
+/* Pointer to start of trace buffer */
+static struct trace_hdr *hdr __section(".data");
 
 static inline uintptr_t __attribute__((no_instrument_function))
                func_ptr_to_num(void *func_ptr)
@@ -46,27 +51,27 @@ static inline uintptr_t __attribute__((no_instrument_function))
        uintptr_t offset = (uintptr_t)func_ptr;
 
 #ifdef CONFIG_SANDBOX
-       offset -= (uintptr_t)&_init;
+       offset -= (uintptr_t)_init;
 #else
        if (gd->flags & GD_FLG_RELOC)
                offset -= gd->relocaddr;
        else
-               offset -= CONFIG_SYS_TEXT_BASE;
+               offset -= CONFIG_TEXT_BASE;
 #endif
        return offset / FUNC_SITE_SIZE;
 }
 
-#ifdef CONFIG_EFI_LOADER
+#if defined(CONFIG_EFI_LOADER) && (defined(CONFIG_ARM) || defined(CONFIG_RISCV))
 
 /**
  * trace_gd - the value of the gd register
  */
-static volatile void *trace_gd;
+static volatile gd_t *trace_gd;
 
 /**
  * trace_save_gd() - save the value of the gd register
  */
-static void __attribute__((no_instrument_function)) trace_save_gd(void)
+static void notrace trace_save_gd(void)
 {
        trace_gd = gd;
 }
@@ -79,28 +84,27 @@ static void __attribute__((no_instrument_function)) trace_save_gd(void)
  * have to set the gd register to the U-Boot value when entering a trace
  * point and set it back to the application value when exiting the trace point.
  */
-static void __attribute__((no_instrument_function)) trace_swap_gd(void)
+static void notrace trace_swap_gd(void)
 {
-       volatile void *temp_gd = trace_gd;
+       volatile gd_t *temp_gd = trace_gd;
 
        trace_gd = gd;
-       gd = temp_gd;
+       set_gd(temp_gd);
 }
 
 #else
 
-static void __attribute__((no_instrument_function)) trace_save_gd(void)
+static void notrace trace_save_gd(void)
 {
 }
 
-static void __attribute__((no_instrument_function)) trace_swap_gd(void)
+static void notrace trace_swap_gd(void)
 {
 }
 
 #endif
 
-static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
-                               void *caller, ulong flags)
+static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags)
 {
        if (hdr->depth > hdr->depth_limit) {
                hdr->ftrace_too_deep_count++;
@@ -116,33 +120,28 @@ static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
        hdr->ftrace_count++;
 }
 
-static void __attribute__((no_instrument_function)) add_textbase(void)
-{
-       if (hdr->ftrace_count < hdr->ftrace_size) {
-               struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
-
-               rec->func = CONFIG_SYS_TEXT_BASE;
-               rec->caller = 0;
-               rec->flags = FUNCF_TEXTBASE;
-       }
-       hdr->ftrace_count++;
-}
-
 /**
- * This is called on every function entry
+ * __cyg_profile_func_enter() - record function entry
  *
  * We add to our tally for this function and add to the list of called
  * functions.
  *
- * @param func_ptr     Pointer to function being entered
- * @param caller       Pointer to function which called this function
+ * @func_ptr:  pointer to function being entered
+ * @caller:    pointer to function which called this function
  */
-void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
-               void *func_ptr, void *caller)
+void notrace __cyg_profile_func_enter(void *func_ptr, void *caller)
 {
        if (trace_enabled) {
                int func;
 
+               if (hdr->trace_locked) {
+                       trace_enabled = 0;
+                       puts("trace: recursion detected, disabling\n");
+                       hdr->trace_locked = false;
+                       return;
+               }
+
+               hdr->trace_locked = true;
                trace_swap_gd();
                add_ftrace(func_ptr, caller, FUNCF_ENTRY);
                func = func_ptr_to_num(func_ptr);
@@ -153,42 +152,42 @@ void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
                        hdr->untracked_count++;
                }
                hdr->depth++;
-               if (hdr->depth > hdr->depth_limit)
+               if (hdr->depth > hdr->max_depth)
                        hdr->max_depth = hdr->depth;
                trace_swap_gd();
+               hdr->trace_locked = false;
        }
 }
 
 /**
- * This is called on every function exit
- *
- * We do nothing here.
+ * __cyg_profile_func_exit() - record function exit
  *
- * @param func_ptr     Pointer to function being entered
- * @param caller       Pointer to function which called this function
+ * @func_ptr:  pointer to function being entered
+ * @caller:    pointer to function which called this function
  */
-void __attribute__((no_instrument_function)) __cyg_profile_func_exit(
-               void *func_ptr, void *caller)
+void notrace __cyg_profile_func_exit(void *func_ptr, void *caller)
 {
        if (trace_enabled) {
                trace_swap_gd();
-               add_ftrace(func_ptr, caller, FUNCF_EXIT);
                hdr->depth--;
+               add_ftrace(func_ptr, caller, FUNCF_EXIT);
+               if (hdr->depth < hdr->min_depth)
+                       hdr->min_depth = hdr->depth;
                trace_swap_gd();
        }
 }
 
 /**
- * Produce a list of called functions
+ * trace_list_functions() - produce a list of called functions
  *
  * The information is written into the supplied buffer - a header followed
  * by a list of function records.
  *
- * @param buff         Buffer to place list into
- * @param buff_size    Size of buffer
- * @param needed       Returns size of buffer needed, which may be
- *                     greater than buff_size if we ran out of space.
- * @return 0 if ok, -1 if space was exhausted
+ * @buff:      buffer to place list into
+ * @buff_size: size of buffer
+ * @needed:    returns size of buffer needed, which may be
+ *             greater than buff_size if we ran out of space.
+ * Return:     0 if ok, -ENOSPC if space was exhausted
  */
 int trace_list_functions(void *buff, size_t buff_size, size_t *needed)
 {
@@ -235,6 +234,18 @@ int trace_list_functions(void *buff, size_t buff_size, size_t *needed)
        return 0;
 }
 
+/**
+ * trace_list_functions() - produce a list of function calls
+ *
+ * The information is written into the supplied buffer - a header followed
+ * by a list of function records.
+ *
+ * @buff:      buffer to place list into
+ * @buff_size: size of buffer
+ * @needed:    returns size of buffer needed, which may be
+ *             greater than buff_size if we ran out of space.
+ * Return:     0 if ok, -ENOSPC if space was exhausted
+ */
 int trace_list_calls(void *buff, size_t buff_size, size_t *needed)
 {
        struct trace_output_hdr *output_hdr = NULL;
@@ -268,8 +279,11 @@ int trace_list_calls(void *buff, size_t buff_size, size_t *needed)
 
        /* Update the header */
        if (output_hdr) {
+               memset(output_hdr, '\0', sizeof(*output_hdr));
                output_hdr->rec_count = upto;
                output_hdr->type = TRACE_CHUNK_CALLS;
+               output_hdr->version = TRACE_VERSION;
+               output_hdr->text_base = CONFIG_TEXT_BASE;
        }
 
        /* Work out how must of the buffer we used */
@@ -280,7 +294,9 @@ int trace_list_calls(void *buff, size_t buff_size, size_t *needed)
        return 0;
 }
 
-/* Print basic information about tracing */
+/**
+ * trace_print_stats() - print basic information about tracing
+ */
 void trace_print_stats(void)
 {
        ulong count;
@@ -306,37 +322,56 @@ void trace_print_stats(void)
                printf(" (%lu dropped due to overflow)",
                       hdr->ftrace_count - hdr->ftrace_size);
        }
-       puts("\n");
-       printf("%15d maximum observed call depth\n", hdr->max_depth);
+
+       /* Add in minimum depth since the trace did not start at top level */
+       printf("\n%15d maximum observed call depth\n",
+              hdr->max_depth - hdr->min_depth);
        printf("%15d call depth limit\n", hdr->depth_limit);
        print_grouped_ull(hdr->ftrace_too_deep_count, 10);
        puts(" calls not traced due to depth\n");
+       print_grouped_ull(hdr->ftrace_size, 10);
+       puts(" max function calls\n");
+       printf("\ntrace buffer %lx call records %lx\n",
+              (ulong)map_to_sysmem(hdr), (ulong)map_to_sysmem(hdr->ftrace));
 }
 
-void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
+void notrace trace_set_enabled(int enabled)
 {
        trace_enabled = enabled != 0;
 }
 
+static int get_func_count(void)
+{
+       /* Detect no support for mon_len since this means tracing cannot work */
+       if (IS_ENABLED(CONFIG_SANDBOX) && !gd->mon_len) {
+               puts("Tracing is not supported on this board\n");
+               return -ENOTSUPP;
+       }
+
+       return gd->mon_len / FUNC_SITE_SIZE;
+}
+
 /**
- * Init the tracing system ready for used, and enable it
+ * trace_init() - initialize the tracing system and enable it
  *
- * @param buff         Pointer to trace buffer
- * @param buff_size    Size of trace buffer
+ * @buff:      Pointer to trace buffer
+ * @buff_size: Size of trace buffer
+ * Return:     0 if ok
  */
-int __attribute__((no_instrument_function)) trace_init(void *buff,
-               size_t buff_size)
+int notrace trace_init(void *buff, size_t buff_size)
 {
-       ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
+       int func_count = get_func_count();
        size_t needed;
        int was_disabled = !trace_enabled;
 
+       if (func_count < 0)
+               return func_count;
        trace_save_gd();
 
        if (!was_disabled) {
 #ifdef CONFIG_TRACE_EARLY
+               ulong used, count;
                char *end;
-               ulong used;
 
                /*
                 * Copy over the early trace data if we have it. Disable
@@ -345,12 +380,19 @@ int __attribute__((no_instrument_function)) trace_init(void *buff,
                trace_enabled = 0;
                hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR,
                                 CONFIG_TRACE_EARLY_SIZE);
-               end = (char *)&hdr->ftrace[min(hdr->ftrace_count,
-                                              hdr->ftrace_size)];
+               count = min(hdr->ftrace_count, hdr->ftrace_size);
+               end = (char *)&hdr->ftrace[count];
                used = end - (char *)hdr;
                printf("trace: copying %08lx bytes of early data from %x to %08lx\n",
                       used, CONFIG_TRACE_EARLY_ADDR,
                       (ulong)map_to_sysmem(buff));
+               printf("%lu traced function calls", count);
+               if (hdr->ftrace_count > hdr->ftrace_size) {
+                       printf(" (%lu dropped due to overflow)",
+                              hdr->ftrace_count - hdr->ftrace_size);
+                       hdr->ftrace_count = hdr->ftrace_size;
+               }
+               puts("\n");
                memcpy(buff, hdr, used);
 #else
                puts("trace: already enabled\n");
@@ -360,23 +402,24 @@ int __attribute__((no_instrument_function)) trace_init(void *buff,
        hdr = (struct trace_hdr *)buff;
        needed = sizeof(*hdr) + func_count * sizeof(uintptr_t);
        if (needed > buff_size) {
-               printf("trace: buffer size %zd bytes: at least %zd needed\n",
+               printf("trace: buffer size %zx bytes: at least %zx needed\n",
                       buff_size, needed);
                return -ENOSPC;
        }
 
-       if (was_disabled)
+       if (was_disabled) {
                memset(hdr, '\0', needed);
+               hdr->min_depth = INT_MAX;
+       }
        hdr->func_count = func_count;
        hdr->call_accum = (uintptr_t *)(hdr + 1);
 
        /* Use any remaining space for the timed function trace */
        hdr->ftrace = (struct trace_call *)(buff + needed);
        hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace);
-       add_textbase();
+       hdr->depth_limit = CONFIG_TRACE_CALL_DEPTH_LIMIT;
 
        puts("trace: enabled\n");
-       hdr->depth_limit = CONFIG_TRACE_CALL_DEPTH_LIMIT;
        trace_enabled = 1;
        trace_inited = 1;
 
@@ -384,12 +427,19 @@ int __attribute__((no_instrument_function)) trace_init(void *buff,
 }
 
 #ifdef CONFIG_TRACE_EARLY
-int __attribute__((no_instrument_function)) trace_early_init(void)
+/**
+ * trace_early_init() - initialize the tracing system for early tracing
+ *
+ * Return:     0 if ok, -ENOSPC if not enough memory is available
+ */
+int notrace trace_early_init(void)
 {
-       ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
+       int func_count = get_func_count();
        size_t buff_size = CONFIG_TRACE_EARLY_SIZE;
        size_t needed;
 
+       if (func_count < 0)
+               return func_count;
        /* We can ignore additional calls to this function */
        if (trace_enabled)
                return 0;
@@ -397,7 +447,7 @@ int __attribute__((no_instrument_function)) trace_early_init(void)
        hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE);
        needed = sizeof(*hdr) + func_count * sizeof(uintptr_t);
        if (needed > buff_size) {
-               printf("trace: buffer size is %zd bytes, at least %zd needed\n",
+               printf("trace: buffer size is %zx bytes, at least %zx needed\n",
                       buff_size, needed);
                return -ENOSPC;
        }
@@ -405,11 +455,11 @@ int __attribute__((no_instrument_function)) trace_early_init(void)
        memset(hdr, '\0', needed);
        hdr->call_accum = (uintptr_t *)(hdr + 1);
        hdr->func_count = func_count;
+       hdr->min_depth = INT_MAX;
 
        /* Use any remaining space for the timed function trace */
        hdr->ftrace = (struct trace_call *)((char *)hdr + needed);
        hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace);
-       add_textbase();
        hdr->depth_limit = CONFIG_TRACE_EARLY_CALL_DEPTH_LIMIT;
        printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR);
 
This page took 0.040929 seconds and 4 git commands to generate.