diff options
author | Robin Getz <robin.getz@analog.com> | 2007-07-24 23:03:28 -0400 |
---|---|---|
committer | Bryan Wu <bryan.wu@analog.com> | 2007-07-24 23:03:28 -0400 |
commit | 518039bc24cbb9ce34665814fe120eac50bedd9a (patch) | |
tree | 6b089a05025ae224d6636b6dc9d95e7c9e4677eb /arch/blackfin | |
parent | f16295e7e7f2a2a15876f570f10d6dc8f1f36ab8 (diff) |
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: Robin Getz <robin.getz@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Diffstat (limited to 'arch/blackfin')
-rw-r--r-- | arch/blackfin/Kconfig | 81 | ||||
-rw-r--r-- | arch/blackfin/kernel/irqchip.c | 9 | ||||
-rw-r--r-- | arch/blackfin/kernel/traps.c | 53 | ||||
-rw-r--r-- | arch/blackfin/mach-bf533/head.S | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-bf537/head.S | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-bf548/head.S | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-bf561/head.S | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 73 |
8 files changed, 213 insertions, 11 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 | ||
1027 | config 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 | |||
1039 | choice | ||
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 | |||
1054 | config DEBUG_BFIN_HWTRACE_COMPRESSION_OFF | ||
1055 | bool "Trace all Loops" | ||
1056 | help | ||
1057 | The trace buffer records all changes of flow | ||
1058 | |||
1059 | config 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 | |||
1065 | config 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 | |||
1071 | endchoice | ||
1072 | |||
1073 | config 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 | |||
1081 | config 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 | |||
1093 | config 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 | |||
1027 | config DEBUG_BFIN_NO_KERN_HWTRACE | 1107 | config 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 | ||
38 | static unsigned long irq_err_count; | 39 | static unsigned long irq_err_count; |
39 | static spinlock_t irq_controller_lock; | 40 | static 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 | ||
56 | int kstack_depth_to_print = 48; | 56 | int kstack_depth_to_print = 48; |
57 | 57 | ||
58 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
58 | static int printk_address(unsigned long address) | 59 | static 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 | ||
135 | asmlinkage void trap_c(struct pt_regs *fp) | 137 | asmlinkage 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 | |||
432 | void dump_bfin_trace_buffer(void) | 439 | void 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 | } |
451 | EXPORT_SYMBOL(dump_bfin_trace_buffer); | 488 | EXPORT_SYMBOL(dump_bfin_trace_buffer); |
452 | 489 | ||
@@ -510,7 +547,9 @@ void show_stack(struct task_struct *task, unsigned long *stack) | |||
510 | void dump_stack(void) | 547 | void 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; |
732 | ENDPROC(_init_exception_buff) | 732 | ENDPROC(_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 | ||
739 | ENTRY(_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 | ||
794 | ENTRY(_trace_buff_offset) | ||
795 | .long 0; | ||
796 | ALIGN | ||
797 | ENTRY(_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 */ |