Commit 518039bc authored by Robin Getz's avatar Robin Getz Committed by Bryan Wu
Browse files

Blackfin arch: Add ability to expend the hardware trace buffer



Add ability to expend the hardware trace buffer via a configurable
software buffer - so you can have lots of history when a crash occurs.

The interesting way we do printk in the traps.c confusese the checking
script

Signed-off-by: default avatarRobin Getz <robin.getz@analog.com>
Signed-off-by: default avatarBryan Wu <bryan.wu@analog.com>
parent f16295e7
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -1024,8 +1024,89 @@ config DEBUG_HUNT_FOR_ZERO
	  Enabling this option will take up an extra entry in CPLB table.
	  Otherwise, there is no extra overhead.

config DEBUG_BFIN_HWTRACE_ON
	bool "Turn on Blackfin's Hardware Trace"
	default y
	help
	  All Blackfins include a Trace Unit which stores a history of the last
	  16 changes in program flow taken by the program sequencer. The history
	  allows the user to recreate the program sequencer’s recent path. This
	  can be handy when an application dies - we print out the execution
	  path of how it got to the offending instruction.

	  By turning this off, you may save a tiny amount of power.

choice
	prompt "Omit loop Tracing"
	default DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
	depends on DEBUG_BFIN_HWTRACE_ON
	help
	  The trace buffer can be configured to omit recording of changes in
	  program flow that match either the last entry or one of the last
	  two entries. Omitting one of these entries from the record prevents
	  the trace buffer from overflowing because of any sort of loop (for, do
	  while, etc) in the program.

	  Because zero-overhead Hardware loops are not recorded in the trace buffer,
	  this feature can be used to prevent trace overflow from loops that
	  are nested four deep.

config DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
	bool "Trace all Loops"
	help
	  The trace buffer records all changes of flow 

config DEBUG_BFIN_HWTRACE_COMPRESSION_ONE
	bool "Compress single-level loops"
	help
	  The trace buffer does not record single loops - helpful if trace 
	  is spinning on a while or do loop.

config DEBUG_BFIN_HWTRACE_COMPRESSION_TWO
	bool "Compress two-level loops"
	help
	  The trace buffer does not record loops two levels deep. Helpful if
	  the trace is spinning in a nested loop

endchoice

config DEBUG_BFIN_HWTRACE_COMPRESSION
	int
	depends on DEBUG_BFIN_HWTRACE_ON
	default 0 if DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
	default 1 if DEBUG_BFIN_HWTRACE_COMPRESSION_ONE
	default 2 if DEBUG_BFIN_HWTRACE_COMPRESSION_TWO


config DEBUG_BFIN_HWTRACE_EXPAND
	bool "Expand Trace Buffer greater than 16 entries"
	depends on DEBUG_BFIN_HWTRACE_ON
	default n
	help
	  By selecting this option, every time the 16 hardware entries in
	  the Blackfin's HW Trace buffer are full, the kernel will move them
	  into a software buffer, for dumping when there is an issue. This 
	  has a great impact on performance, (an interrupt every 16 change of 
	  flows) and should normally be turned off, except in those nasty
	  debugging sessions

config DEBUG_BFIN_HWTRACE_EXPAND_LEN
	int "Size of Trace buffer (in power of 2k)"
	range 0 4
	depends on DEBUG_BFIN_HWTRACE_EXPAND
	default 1
	help
	  This sets the size of the software buffer that the trace information
	  is kept in.
	  0 for (2^0)  1k, or 256 entries,
	  1 for (2^1)  2k, or 512 entries,
	  2 for (2^2)  4k, or 1024 entries,
	  3 for (2^3)  8k, or 2048 entries,
	  4 for (2^4) 16k, or 4096 entries

config DEBUG_BFIN_NO_KERN_HWTRACE
	bool "Trace user apps (turn off hwtrace in kernel)"
	depends on DEBUG_BFIN_HWTRACE_ON
	default n
	help
	  Some pieces of the kernel contain a lot of flow changes which can
+9 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/trace.h>

static unsigned long irq_err_count;
static spinlock_t irq_controller_lock;
@@ -144,4 +145,12 @@ void __init init_IRQ(void)
	}

	init_arch_irq();

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	/* Now that evt_ivhw is set up, turn this on */
	trace_buff_offset = 0;
	bfin_write_TBUFCTL(BFIN_TRACE_ON);
	printk(KERN_INFO "Hardware Trace expanded to %ik\n",
	  1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
#endif
}
+46 −7
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ asmlinkage void trap_c(struct pt_regs *fp);

int kstack_depth_to_print = 48;

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
static int printk_address(unsigned long address)
{
	struct vm_list_struct *vml;
@@ -131,10 +132,14 @@ static int printk_address(unsigned long address)
	/* we were unable to find this address anywhere */
	return printk("[<0x%p>]", (void *)address);
}
#endif

asmlinkage void trap_c(struct pt_regs *fp)
{
	int j, sig = 0;
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
	int j;
#endif
	int sig = 0;
	siginfo_t info;
	unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;

@@ -429,16 +434,23 @@ asmlinkage void trap_c(struct pt_regs *fp)

/* Typical exception handling routines	*/

#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)

void dump_bfin_trace_buffer(void)
{
	int tflags;
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
	int tflags, i = 0;
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	int j, index;
#endif

	trace_buffer_save(tflags);

	if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
		int i;
	printk(KERN_EMERG "Hardware Trace:\n");
		for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
			printk(KERN_EMERG "%2i Target : ", i);

	if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
		for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
			printk(KERN_EMERG "%4i Target : ", i);
			printk_address((unsigned long)bfin_read_TBUF());
			printk("\n" KERN_EMERG "     Source : ");
			printk_address((unsigned long)bfin_read_TBUF());
@@ -446,7 +458,32 @@ void dump_bfin_trace_buffer(void)
		}
	}

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
	if (trace_buff_offset)
		index = trace_buff_offset/4 - 1;
	else
		index = EXPAND_LEN;

	j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
	while (j) {
		printk(KERN_EMERG "%4i Target : ", i);
		printk_address(software_trace_buff[index]);
		index -= 1;
		if (index < 0 )
			index = EXPAND_LEN;
		printk("\n" KERN_EMERG "     Source : ");
		printk_address(software_trace_buff[index]);
		index -= 1;
		if (index < 0)
			index = EXPAND_LEN;
		printk("\n");
		j--;
		i++;
	}
#endif

	trace_buffer_restore(tflags);
#endif
}
EXPORT_SYMBOL(dump_bfin_trace_buffer);

@@ -510,7 +547,9 @@ void show_stack(struct task_struct *task, unsigned long *stack)
void dump_stack(void)
{
	unsigned long stack;
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
	int tflags;
#endif
	trace_buffer_save(tflags);
	dump_bfin_trace_buffer();
	show_stack(current, &stack);
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ ENTRY(__start)
	M2 = r0;
	M3 = r0;

	trace_buffer_start(p0,r0);
	trace_buffer_init(p0,r0);
	P0 = R1;
	R0 = R1;

+1 −1
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ ENTRY(__start)
	M2 = r0;
	M3 = r0;

	trace_buffer_start(p0,r0);
	trace_buffer_init(p0,r0);
	P0 = R1;
	R0 = R1;

Loading