aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/blackfin/Kconfig81
-rw-r--r--arch/blackfin/kernel/irqchip.c9
-rw-r--r--arch/blackfin/kernel/traps.c53
-rw-r--r--arch/blackfin/mach-bf533/head.S2
-rw-r--r--arch/blackfin/mach-bf537/head.S2
-rw-r--r--arch/blackfin/mach-bf548/head.S2
-rw-r--r--arch/blackfin/mach-bf561/head.S2
-rw-r--r--arch/blackfin/mach-common/entry.S73
-rw-r--r--include/asm-blackfin/trace.h55
9 files changed, 259 insertions, 20 deletions
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 9ce675e80260..a7a6e0c5827d 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -1024,8 +1024,89 @@ config DEBUG_HUNT_FOR_ZERO
1024 Enabling this option will take up an extra entry in CPLB table. 1024 Enabling this option will take up an extra entry in CPLB table.
1025 Otherwise, there is no extra overhead. 1025 Otherwise, there is no extra overhead.
1026 1026
1027config DEBUG_BFIN_HWTRACE_ON
1028 bool "Turn on Blackfin's Hardware Trace"
1029 default y
1030 help
1031 All Blackfins include a Trace Unit which stores a history of the last
1032 16 changes in program flow taken by the program sequencer. The history
1033 allows the user to recreate the program sequencer’s recent path. This
1034 can be handy when an application dies - we print out the execution
1035 path of how it got to the offending instruction.
1036
1037 By turning this off, you may save a tiny amount of power.
1038
1039choice
1040 prompt "Omit loop Tracing"
1041 default DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
1042 depends on DEBUG_BFIN_HWTRACE_ON
1043 help
1044 The trace buffer can be configured to omit recording of changes in
1045 program flow that match either the last entry or one of the last
1046 two entries. Omitting one of these entries from the record prevents
1047 the trace buffer from overflowing because of any sort of loop (for, do
1048 while, etc) in the program.
1049
1050 Because zero-overhead Hardware loops are not recorded in the trace buffer,
1051 this feature can be used to prevent trace overflow from loops that
1052 are nested four deep.
1053
1054config DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
1055 bool "Trace all Loops"
1056 help
1057 The trace buffer records all changes of flow
1058
1059config DEBUG_BFIN_HWTRACE_COMPRESSION_ONE
1060 bool "Compress single-level loops"
1061 help
1062 The trace buffer does not record single loops - helpful if trace
1063 is spinning on a while or do loop.
1064
1065config DEBUG_BFIN_HWTRACE_COMPRESSION_TWO
1066 bool "Compress two-level loops"
1067 help
1068 The trace buffer does not record loops two levels deep. Helpful if
1069 the trace is spinning in a nested loop
1070
1071endchoice
1072
1073config DEBUG_BFIN_HWTRACE_COMPRESSION
1074 int
1075 depends on DEBUG_BFIN_HWTRACE_ON
1076 default 0 if DEBUG_BFIN_HWTRACE_COMPRESSION_OFF
1077 default 1 if DEBUG_BFIN_HWTRACE_COMPRESSION_ONE
1078 default 2 if DEBUG_BFIN_HWTRACE_COMPRESSION_TWO
1079
1080
1081config DEBUG_BFIN_HWTRACE_EXPAND
1082 bool "Expand Trace Buffer greater than 16 entries"
1083 depends on DEBUG_BFIN_HWTRACE_ON
1084 default n
1085 help
1086 By selecting this option, every time the 16 hardware entries in
1087 the Blackfin's HW Trace buffer are full, the kernel will move them
1088 into a software buffer, for dumping when there is an issue. This
1089 has a great impact on performance, (an interrupt every 16 change of
1090 flows) and should normally be turned off, except in those nasty
1091 debugging sessions
1092
1093config DEBUG_BFIN_HWTRACE_EXPAND_LEN
1094 int "Size of Trace buffer (in power of 2k)"
1095 range 0 4
1096 depends on DEBUG_BFIN_HWTRACE_EXPAND
1097 default 1
1098 help
1099 This sets the size of the software buffer that the trace information
1100 is kept in.
1101 0 for (2^0) 1k, or 256 entries,
1102 1 for (2^1) 2k, or 512 entries,
1103 2 for (2^2) 4k, or 1024 entries,
1104 3 for (2^3) 8k, or 2048 entries,
1105 4 for (2^4) 16k, or 4096 entries
1106
1027config DEBUG_BFIN_NO_KERN_HWTRACE 1107config DEBUG_BFIN_NO_KERN_HWTRACE
1028 bool "Trace user apps (turn off hwtrace in kernel)" 1108 bool "Trace user apps (turn off hwtrace in kernel)"
1109 depends on DEBUG_BFIN_HWTRACE_ON
1029 default n 1110 default n
1030 help 1111 help
1031 Some pieces of the kernel contain a lot of flow changes which can 1112 Some pieces of the kernel contain a lot of flow changes which can
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 1fc001c7abda..462ae41144c7 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -34,6 +34,7 @@
34#include <linux/kallsyms.h> 34#include <linux/kallsyms.h>
35#include <linux/interrupt.h> 35#include <linux/interrupt.h>
36#include <linux/irq.h> 36#include <linux/irq.h>
37#include <asm/trace.h>
37 38
38static unsigned long irq_err_count; 39static unsigned long irq_err_count;
39static spinlock_t irq_controller_lock; 40static spinlock_t irq_controller_lock;
@@ -144,4 +145,12 @@ void __init init_IRQ(void)
144 } 145 }
145 146
146 init_arch_irq(); 147 init_arch_irq();
148
149#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
150 /* Now that evt_ivhw is set up, turn this on */
151 trace_buff_offset = 0;
152 bfin_write_TBUFCTL(BFIN_TRACE_ON);
153 printk(KERN_INFO "Hardware Trace expanded to %ik\n",
154 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
155#endif
147} 156}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 792a8416fe10..0ec02fe663e9 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -55,6 +55,7 @@ asmlinkage void trap_c(struct pt_regs *fp);
55 55
56int kstack_depth_to_print = 48; 56int kstack_depth_to_print = 48;
57 57
58#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
58static int printk_address(unsigned long address) 59static int printk_address(unsigned long address)
59{ 60{
60 struct vm_list_struct *vml; 61 struct vm_list_struct *vml;
@@ -131,10 +132,14 @@ static int printk_address(unsigned long address)
131 /* we were unable to find this address anywhere */ 132 /* we were unable to find this address anywhere */
132 return printk("[<0x%p>]", (void *)address); 133 return printk("[<0x%p>]", (void *)address);
133} 134}
135#endif
134 136
135asmlinkage void trap_c(struct pt_regs *fp) 137asmlinkage void trap_c(struct pt_regs *fp)
136{ 138{
137 int j, sig = 0; 139#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
140 int j;
141#endif
142 int sig = 0;
138 siginfo_t info; 143 siginfo_t info;
139 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; 144 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
140 145
@@ -429,24 +434,56 @@ asmlinkage void trap_c(struct pt_regs *fp)
429 434
430/* Typical exception handling routines */ 435/* Typical exception handling routines */
431 436
437#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)
438
432void dump_bfin_trace_buffer(void) 439void dump_bfin_trace_buffer(void)
433{ 440{
434 int tflags; 441#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
442 int tflags, i = 0;
443#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
444 int j, index;
445#endif
446
435 trace_buffer_save(tflags); 447 trace_buffer_save(tflags);
436 448
449 printk(KERN_EMERG "Hardware Trace:\n");
450
437 if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { 451 if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
438 int i; 452 for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
439 printk(KERN_EMERG "Hardware Trace:\n"); 453 printk(KERN_EMERG "%4i Target : ", i);
440 for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
441 printk(KERN_EMERG "%2i Target : ", i);
442 printk_address((unsigned long)bfin_read_TBUF()); 454 printk_address((unsigned long)bfin_read_TBUF());
443 printk("\n" KERN_EMERG " Source : "); 455 printk("\n" KERN_EMERG " Source : ");
444 printk_address((unsigned long)bfin_read_TBUF()); 456 printk_address((unsigned long)bfin_read_TBUF());
445 printk("\n"); 457 printk("\n");
446 } 458 }
447 } 459 }
448 460
461#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
462 if (trace_buff_offset)
463 index = trace_buff_offset/4 - 1;
464 else
465 index = EXPAND_LEN;
466
467 j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
468 while (j) {
469 printk(KERN_EMERG "%4i Target : ", i);
470 printk_address(software_trace_buff[index]);
471 index -= 1;
472 if (index < 0 )
473 index = EXPAND_LEN;
474 printk("\n" KERN_EMERG " Source : ");
475 printk_address(software_trace_buff[index]);
476 index -= 1;
477 if (index < 0)
478 index = EXPAND_LEN;
479 printk("\n");
480 j--;
481 i++;
482 }
483#endif
484
449 trace_buffer_restore(tflags); 485 trace_buffer_restore(tflags);
486#endif
450} 487}
451EXPORT_SYMBOL(dump_bfin_trace_buffer); 488EXPORT_SYMBOL(dump_bfin_trace_buffer);
452 489
@@ -510,7 +547,9 @@ void show_stack(struct task_struct *task, unsigned long *stack)
510void dump_stack(void) 547void dump_stack(void)
511{ 548{
512 unsigned long stack; 549 unsigned long stack;
550#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
513 int tflags; 551 int tflags;
552#endif
514 trace_buffer_save(tflags); 553 trace_buffer_save(tflags);
515 dump_bfin_trace_buffer(); 554 dump_bfin_trace_buffer();
516 show_stack(current, &stack); 555 show_stack(current, &stack);
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
index 9c5378bb8a28..1d5b9dbbbaa7 100644
--- a/arch/blackfin/mach-bf533/head.S
+++ b/arch/blackfin/mach-bf533/head.S
@@ -98,7 +98,7 @@ ENTRY(__start)
98 M2 = r0; 98 M2 = r0;
99 M3 = r0; 99 M3 = r0;
100 100
101 trace_buffer_start(p0,r0); 101 trace_buffer_init(p0,r0);
102 P0 = R1; 102 P0 = R1;
103 R0 = R1; 103 R0 = R1;
104 104
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
index 82ea04705917..6dbcb77c8d36 100644
--- a/arch/blackfin/mach-bf537/head.S
+++ b/arch/blackfin/mach-bf537/head.S
@@ -96,7 +96,7 @@ ENTRY(__start)
96 M2 = r0; 96 M2 = r0;
97 M3 = r0; 97 M3 = r0;
98 98
99 trace_buffer_start(p0,r0); 99 trace_buffer_init(p0,r0);
100 P0 = R1; 100 P0 = R1;
101 R0 = R1; 101 R0 = R1;
102 102
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
index 72087c2e6a83..e53d74d4c0a2 100644
--- a/arch/blackfin/mach-bf548/head.S
+++ b/arch/blackfin/mach-bf548/head.S
@@ -93,7 +93,7 @@ ENTRY(__stext)
93 M2 = r0; 93 M2 = r0;
94 M3 = r0; 94 M3 = r0;
95 95
96 trace_buffer_start(p0,r0); 96 trace_buffer_init(p0,r0);
97 P0 = R1; 97 P0 = R1;
98 R0 = R1; 98 R0 = R1;
99 99
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
index 83cd3f9bbf2d..8c9f73b8e579 100644
--- a/arch/blackfin/mach-bf561/head.S
+++ b/arch/blackfin/mach-bf561/head.S
@@ -96,7 +96,7 @@ ENTRY(__start)
96 M2 = r0; 96 M2 = r0;
97 M3 = r0; 97 M3 = r0;
98 98
99 trace_buffer_start(p0,r0); 99 trace_buffer_init(p0,r0);
100 P0 = R1; 100 P0 = R1;
101 R0 = R1; 101 R0 = R1;
102 102
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 207e69786b40..ab278a72f282 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -731,6 +731,75 @@ ENTRY(_init_exception_buff)
731 rts; 731 rts;
732ENDPROC(_init_exception_buff) 732ENDPROC(_init_exception_buff)
733 733
734/* We handle this 100% in exception space - to reduce overhead
735 * Only potiential problem is if the software buffer gets swapped out of the
736 * CPLB table - then double fault. - so we don't let this happen in other places
737 */
738#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
739ENTRY(_ex_trace_buff_full)
740 [--sp] = P3;
741 [--sp] = P2;
742 [--sp] = LC0;
743 [--sp] = LT0;
744 [--sp] = LB0;
745 P5.L = _trace_buff_offset;
746 P5.H = _trace_buff_offset;
747 P3 = [P5]; /* trace_buff_offset */
748 P5.L = lo(TBUFSTAT);
749 P5.H = hi(TBUFSTAT);
750 R7 = [P5];
751 R7 <<= 1; /* double, since we need to read twice */
752 LC0 = R7;
753 R7 <<= 2; /* need to shift over again,
754 * to get the number of bytes */
755 P5.L = lo(TBUF);
756 P5.H = hi(TBUF);
757 R6 = ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*1024) - 1;
758
759 P2 = R7;
760 P3 = P3 + P2;
761 R7 = P3;
762 R7 = R7 & R6;
763 P3 = R7;
764 P2.L = _trace_buff_offset;
765 P2.H = _trace_buff_offset;
766 [P2] = P3;
767
768 P2.L = _software_trace_buff;
769 P2.H = _software_trace_buff;
770
771 LSETUP (.Lstart, .Lend) LC0;
772.Lstart:
773 R7 = [P5]; /* read TBUF */
774 P4 = P3 + P2;
775 [P4] = R7;
776 P3 += -4;
777 R7 = P3;
778 R7 = R7 & R6;
779.Lend:
780 P3 = R7;
781
782 LB0 = [sp++];
783 LT0 = [sp++];
784 LC0 = [sp++];
785 P2 = [sp++];
786 P3 = [sp++];
787 jump _return_from_exception;
788
789#if CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN == 4
790.data
791#else
792.section .l1.data.B
793#endif
794ENTRY(_trace_buff_offset)
795 .long 0;
796ALIGN
797ENTRY(_software_trace_buff)
798 .rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256);
799 .long 0
800 .endr
801#endif
802
734/* 803/*
735 * Put these in the kernel data section - that should always be covered by 804 * Put these in the kernel data section - that should always be covered by
736 * a CPLB. This is needed to ensure we don't get double fault conditions 805 * a CPLB. This is needed to ensure we don't get double fault conditions
@@ -764,7 +833,11 @@ _extable:
764 .long _ex_trap_c /* 0x0E - User Defined */ 833 .long _ex_trap_c /* 0x0E - User Defined */
765 .long _ex_trap_c /* 0x0F - User Defined */ 834 .long _ex_trap_c /* 0x0F - User Defined */
766 .long _ex_single_step /* 0x10 - HW Single step */ 835 .long _ex_single_step /* 0x10 - HW Single step */
836#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
837 .long _ex_trace_buff_full /* 0x11 - Trace Buffer Full */
838#else
767 .long _ex_trap_c /* 0x11 - Trace Buffer Full */ 839 .long _ex_trap_c /* 0x11 - Trace Buffer Full */
840#endif
768 .long _ex_trap_c /* 0x12 - Reserved */ 841 .long _ex_trap_c /* 0x12 - Reserved */
769 .long _ex_trap_c /* 0x13 - Reserved */ 842 .long _ex_trap_c /* 0x13 - Reserved */
770 .long _ex_trap_c /* 0x14 - Reserved */ 843 .long _ex_trap_c /* 0x14 - Reserved */
diff --git a/include/asm-blackfin/trace.h b/include/asm-blackfin/trace.h
index 9c2474c9a589..6313aace9d59 100644
--- a/include/asm-blackfin/trace.h
+++ b/include/asm-blackfin/trace.h
@@ -6,23 +6,46 @@
6#ifndef _BLACKFIN_TRACE_ 6#ifndef _BLACKFIN_TRACE_
7#define _BLACKFIN_TRACE_ 7#define _BLACKFIN_TRACE_
8 8
9/* Normally, we use ON, but you can't turn on software expansion until
10 * interrupts subsystem is ready
11 */
12
13#define BFIN_TRACE_INIT ((CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION << 4) | 0x03)
14#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
15#define BFIN_TRACE_ON (BFIN_TRACE_INIT | (CONFIG_DEBUG_BFIN_HWTRACE_EXPAND << 2))
16#else
17#define BFIN_TRACE_ON (BFIN_TRACE_INIT)
18#endif
19
9#ifndef __ASSEMBLY__ 20#ifndef __ASSEMBLY__
21extern unsigned long trace_buff_offset;
22extern unsigned long software_trace_buff[];
23
10/* Trace Macros for C files */ 24/* Trace Macros for C files */
11 25
26#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
27
12#define trace_buffer_save(x) \ 28#define trace_buffer_save(x) \
13 do { \ 29 do { \
14 (x) = bfin_read_TBUFCTL(); \ 30 (x) = bfin_read_TBUFCTL(); \
15 bfin_write_TBUFCTL((x) & ~TBUFEN); \ 31 bfin_write_TBUFCTL((x) & ~TBUFEN); \
16 } while (0) 32 } while (0)
17 33
18#define trace_buffer_restore(x) \ 34#define trace_buffer_restore(x) \
19 do { \ 35 do { \
20 bfin_write_TBUFCTL((x)); \ 36 bfin_write_TBUFCTL((x)); \
21 } while (0) 37 } while (0)
38#else /* DEBUG_BFIN_HWTRACE_ON */
39
40#define trace_buffer_save(x)
41#define trace_buffer_restore(x)
42#endif /* CONFIG_DEBUG_BFIN_HWTRACE_ON */
22 43
23#else 44#else
24/* Trace Macros for Assembly files */ 45/* Trace Macros for Assembly files */
25 46
47#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
48
26#define TRACE_BUFFER_START(preg, dreg) trace_buffer_start(preg, dreg) 49#define TRACE_BUFFER_START(preg, dreg) trace_buffer_start(preg, dreg)
27#define TRACE_BUFFER_STOP(preg, dreg) trace_buffer_stop(preg, dreg) 50#define TRACE_BUFFER_STOP(preg, dreg) trace_buffer_stop(preg, dreg)
28 51
@@ -32,12 +55,26 @@
32 dreg = 0x1; \ 55 dreg = 0x1; \
33 [preg] = dreg; 56 [preg] = dreg;
34 57
35#define trace_buffer_start(preg, dreg) \ 58#define trace_buffer_start(preg, dreg) \
36 preg.L = LO(TBUFCTL); \ 59 preg.L = LO(TBUFCTL); \
37 preg.H = HI(TBUFCTL); \ 60 preg.H = HI(TBUFCTL); \
38 dreg = 0x13; \ 61 dreg = BFIN_TRACE_ON; \
62 [preg] = dreg;
63
64#define trace_buffer_init(preg, dreg) \
65 preg.L = LO(TBUFCTL); \
66 preg.H = HI(TBUFCTL); \
67 dreg = BFIN_TRACE_INIT; \
39 [preg] = dreg; 68 [preg] = dreg;
40 69
70#else /* CONFIG_DEBUG_BFIN_HWTRACE_ON */
71
72#define trace_buffer_stop(preg, dreg)
73#define trace_buffer_start(preg, dreg)
74#define trace_buffer_init(preg, dreg)
75
76#endif /* CONFIG_DEBUG_BFIN_HWTRACE_ON */
77
41#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE 78#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
42# define DEBUG_START_HWTRACE(preg, dreg) trace_buffer_start(preg, dreg) 79# define DEBUG_START_HWTRACE(preg, dreg) trace_buffer_start(preg, dreg)
43# define DEBUG_STOP_HWTRACE(preg, dreg) trace_buffer_stop(preg, dreg) 80# define DEBUG_STOP_HWTRACE(preg, dreg) trace_buffer_stop(preg, dreg)