SmartAudio/lichee/brandy/u-boot-2014.07/lib/aw_ff_trace.c

230 lines
6.7 KiB
C

#include <common.h>
#include <asm/global_data.h>
#include <spare_head.h>
/*
* About this defination, please refer to common/board_f.c
* Pointer to initial global data area
*
* Here we initialize it if needed.
*/
#ifdef XTRN_DECLARE_GLOBAL_DATA_PTR
#undef XTRN_DECLARE_GLOBAL_DATA_PTR
#define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */
DECLARE_GLOBAL_DATA_PTR = (gd_t *) (CONFIG_SYS_INIT_GD_ADDR);
#else
DECLARE_GLOBAL_DATA_PTR;
#endif
/*
* one element record one function event : enter or exit
* time [bit 31 ~ 3] : event time stamp, uint16_t about 32 seconds,
* which is enough for boot0 & uboot
* time [bit 2 ~ 0] : enter or exit flag
* funaddr : function address, using "unsigned long"
* (32-bits in arm, 64-bits in arm64)
* In 32-bit-ARCH : 8-bytes can record one event
* In 64-bit_ARCH : need 12-bytes
*/
struct ff_one_element {
uint32_t time;
unsigned long funaddr;
};
#define ELEMENT_FLAG_BITS (3)
#define ELEMENT_FLAG_MASK ((1<<ELEMENT_FLAG_BITS)-1)
struct aw_uboot_trace_buf_head {
unsigned long reloc_off;
uint32_t valid_data_size;
};
#define FF_BUF_HEAD_SIZE (sizeof(struct aw_uboot_trace_buf_head))
/* total memory size for recording, suggest use 1M bytes space */
#define FF_PRINT_BUF_SIZE (2*1024*1024)
/* memory size for recording events-info,reserve 128-bytes */
#define FF_MAX_PRINT_BUF (FF_PRINT_BUF_SIZE - FF_BUF_HEAD_SIZE)
/* the max number of events */
#define FF_MAX_ELEMENT_NUM (FF_MAX_PRINT_BUF/sizeof(struct ff_one_element))
#define FF_FUN_ENTER_FLAG (1)
#define FF_FUN_EXIT_FLAG (2)
#define FF_BUF_NOT_FULL (1)
#define FF_BUF_FULL (2)
/*
* Please note this array must:
* 1. locate in bss section
* 2. 16 bytes aligne
* 3. note the relocation issue
*/
char ff_print_buf[FF_PRINT_BUF_SIZE] __aligned(16);
/*
* because of the affect of bss 0-clear of relocation-code
* bellow variables can not be located at bss section
* so do not set 0 to them when initialization
*/
static char *ff_buf_cur = (char *)ff_print_buf + FF_BUF_HEAD_SIZE;
static int ff_buf_element_cnt = 1;
static int ff_buf_full_flag = FF_BUF_NOT_FULL;
/*
* 64bit arch timer.CNTPCT
* Freq = 24000000Hz
*/
u64 __attribute__((__no_instrument_function__)) fun_gcc_get_arch_counter(void)
{
u32 low = 0, high = 0;
asm volatile("mrrc p15, 0, %0, %1, c14"
: "=r" (low), "=r" (high)
:
: "memory");
return ((u64)high)<<32 | low;
}
int __attribute__((__no_instrument_function__))
ff_handle_one_event(void *this_func, uint32_t flag)
{
uint64_t time;
#define ARM64_HANDLE_LOW32BITS (32)
#define ARM64_HANDLE_LOW32BITS_MASK (0xffffffff)
/*
* Only enable trace funtion in BOOT mode
* In other modes, exit directly without error
*/
if (WORK_MODE_BOOT != uboot_spare_head.boot_data.work_mode)
return 0;
if (ff_buf_element_cnt > FF_MAX_ELEMENT_NUM) {
ff_buf_full_flag = FF_BUF_FULL;
return -1;
}
time = fun_gcc_get_arch_counter();
time = time / 24;
*((uint32_t *)ff_buf_cur) = ((uint32_t)(time<<ELEMENT_FLAG_BITS))
| ((uint32_t)(flag & ELEMENT_FLAG_MASK));
ff_buf_cur += sizeof(uint32_t);
/*
* this "if-else" is used for ARM64. In arm64
* unsigned long is 8-bytes, for saving space,
* current version use 12-bytes for on event-trace data.
* So fun-address may not be
* 8-byte-alligned.
* Here, all see it as little-endian ARCH to store data,
* if machine is big-endian in real board,
* please handle it by parser script.
* if it ARM64, must define Macro AW_FF_CONFIG_ARM64
* in the "include/configs/sunxxxxx.h"
*/
#ifndef CONFIG_AW_FF_CONFIG_ARM64
*((unsigned long *)ff_buf_cur) = (unsigned long)this_func;
#else
*((uint32_t *)ff_buf_cur) = (uint32_t)((unsigned long)this_func
& ARM64_HANDLE_LOW32BITS_MASK);
*((uint32_t *)(ff_buf_cur + sizeof(uint32_t))) =
(uint32_t)((unsigned long)this_func >> ARM64_HANDLE_LOW32BITS);
#endif
ff_buf_cur += sizeof(unsigned long);
ff_buf_element_cnt++;
return 0;
}
void __attribute__((__no_instrument_function__))
__cyg_profile_func_enter(void *this_func, void *call_site)
{
ff_handle_one_event(this_func, FF_FUN_ENTER_FLAG);
return;
}
void __attribute__((__no_instrument_function__))
__cyg_profile_func_exit(void *this_func, void *call_site)
{
ff_handle_one_event(this_func, FF_FUN_EXIT_FLAG);
return;
}
int __attribute__((__no_instrument_function__)) ff_ouput_print_buf(void)
{
return 0; /* only open this function when debug*/
int i;
struct ff_one_element *element;
char *buf_pointer = (char *)ff_print_buf + FF_BUF_HEAD_SIZE;
printf("Reloc_off : 0x%lx : element_cnt=%d, FF_MAX_ELEMENT_NUM=%d\n",
gd->reloc_off, ff_buf_element_cnt, FF_MAX_ELEMENT_NUM);
for (i = 0; i < (ff_buf_element_cnt-1); i++) {
element = (struct ff_one_element *)((char *)buf_pointer
+ i*sizeof(struct ff_one_element));
if (0 == element->time && 0 == element->funaddr) {
element = (struct ff_one_element *)((char *)buf_pointer
- gd->reloc_off + i*sizeof(struct ff_one_element));
}
printf("%9d:%c:0x%lx\n", (element->time)>>ELEMENT_FLAG_BITS,
((((element->time)
& ELEMENT_FLAG_MASK) == FF_FUN_ENTER_FLAG)?'G':'L'),
element->funaddr);
}
return 0;
}
extern int __attribute__((__no_instrument_function__))
ff_write_fun_trace_data2flash(void *data_buffer,
unsigned int data_size);
int __attribute__((__no_instrument_function__)) ff_move_reloc_data(void)
{
unsigned int i;
unsigned int data_size;
struct ff_one_element *element;
struct aw_uboot_trace_buf_head *buf_head;
char *buf_pointer = (char *)ff_print_buf + FF_BUF_HEAD_SIZE;
for (i = 0; i < (ff_buf_element_cnt-1); i++) {
element = (struct ff_one_element *)
((char *)buf_pointer
+ i*sizeof(struct ff_one_element));
if (0 == element->time && 0 == element->funaddr) {
*element = *((struct ff_one_element *)
((char *)buf_pointer - gd->reloc_off
+ i*sizeof(struct ff_one_element)));
} else {
break;
}
}
/*
* write the buf head size
*/
data_size = (ff_buf_element_cnt-1) * sizeof(struct ff_one_element);
buf_head = (struct aw_uboot_trace_buf_head *)ff_print_buf;
buf_head->reloc_off = gd->reloc_off;
buf_head->valid_data_size = data_size;
/* for debug */
#if 0
printf("buffer head info : reloc=0x%x, data_size=0x%x\n",
buf_head->reloc_off, buf_head->valid_data_size);
buf_pointer = (char *)ff_print_buf + FF_BUF_HEAD_SIZE;
for (i = 0; i < (ff_buf_element_cnt-1); i++) {
element = (struct ff_one_element *)
((char *)buf_pointer
+ i*sizeof(struct ff_one_element));
printf("* [%d, 0x%x] %9d:%c:0x%lux\n",
i, (unsigned int)element,
(element->time)>>ELEMENT_FLAG_BITS,
((((element->time) & ELEMENT_FLAG_MASK)
== FF_FUN_ENTER_FLAG)?'G':'L'), element->funaddr);
}
#endif
/* flush data to storage from ddr */
data_size += FF_BUF_HEAD_SIZE;
ff_write_fun_trace_data2flash(ff_print_buf, data_size);
return 0;
}