aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r--arch/blackfin/kernel/traps.c86
1 files changed, 44 insertions, 42 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index bef025b07443..5b0667da8d05 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -32,6 +32,7 @@
32#include <linux/module.h> 32#include <linux/module.h>
33#include <linux/kallsyms.h> 33#include <linux/kallsyms.h>
34#include <linux/fs.h> 34#include <linux/fs.h>
35#include <linux/rbtree.h>
35#include <asm/traps.h> 36#include <asm/traps.h>
36#include <asm/cacheflush.h> 37#include <asm/cacheflush.h>
37#include <asm/cplb.h> 38#include <asm/cplb.h>
@@ -75,16 +76,6 @@ void __init trap_init(void)
75 CSYNC(); 76 CSYNC();
76} 77}
77 78
78/*
79 * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
80 * values across the transition from exception to IRQ5.
81 * We put these in L1, so they are going to be in a valid
82 * location during exception context
83 */
84__attribute__((l1_data))
85unsigned long saved_retx, saved_seqstat,
86 saved_icplb_fault_addr, saved_dcplb_fault_addr;
87
88static void decode_address(char *buf, unsigned long address) 79static void decode_address(char *buf, unsigned long address)
89{ 80{
90#ifdef CONFIG_DEBUG_VERBOSE 81#ifdef CONFIG_DEBUG_VERBOSE
@@ -93,6 +84,7 @@ static void decode_address(char *buf, unsigned long address)
93 struct mm_struct *mm; 84 struct mm_struct *mm;
94 unsigned long flags, offset; 85 unsigned long flags, offset;
95 unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); 86 unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
87 struct rb_node *n;
96 88
97#ifdef CONFIG_KALLSYMS 89#ifdef CONFIG_KALLSYMS
98 unsigned long symsize; 90 unsigned long symsize;
@@ -138,9 +130,10 @@ static void decode_address(char *buf, unsigned long address)
138 if (!mm) 130 if (!mm)
139 continue; 131 continue;
140 132
141 vml = mm->context.vmlist; 133 for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
142 while (vml) { 134 struct vm_area_struct *vma;
143 struct vm_area_struct *vma = vml->vma; 135
136 vma = rb_entry(n, struct vm_area_struct, vm_rb);
144 137
145 if (address >= vma->vm_start && address < vma->vm_end) { 138 if (address >= vma->vm_start && address < vma->vm_end) {
146 char _tmpbuf[256]; 139 char _tmpbuf[256];
@@ -186,8 +179,6 @@ static void decode_address(char *buf, unsigned long address)
186 179
187 goto done; 180 goto done;
188 } 181 }
189
190 vml = vml->next;
191 } 182 }
192 if (!in_atomic) 183 if (!in_atomic)
193 mmput(mm); 184 mmput(mm);
@@ -211,18 +202,18 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
211 printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); 202 printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
212#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT 203#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
213 if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { 204 if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) {
205 unsigned int cpu = smp_processor_id();
214 char buf[150]; 206 char buf[150];
215 decode_address(buf, saved_retx); 207 decode_address(buf, cpu_pda[cpu].retx);
216 printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", 208 printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
217 (int)saved_seqstat & SEQSTAT_EXCAUSE, buf); 209 (unsigned int)cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE, buf);
218 decode_address(buf, saved_dcplb_fault_addr); 210 decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
219 printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); 211 printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf);
220 decode_address(buf, saved_icplb_fault_addr); 212 decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
221 printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); 213 printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf);
222 214
223 decode_address(buf, fp->retx); 215 decode_address(buf, fp->retx);
224 printk(KERN_NOTICE "The instruction at %s caused a double exception\n", 216 printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf);
225 buf);
226 } else 217 } else
227#endif 218#endif
228 { 219 {
@@ -240,6 +231,9 @@ asmlinkage void trap_c(struct pt_regs *fp)
240#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON 231#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
241 int j; 232 int j;
242#endif 233#endif
234#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
235 unsigned int cpu = smp_processor_id();
236#endif
243 int sig = 0; 237 int sig = 0;
244 siginfo_t info; 238 siginfo_t info;
245 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; 239 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
@@ -417,7 +411,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
417 info.si_code = ILL_CPLB_MULHIT; 411 info.si_code = ILL_CPLB_MULHIT;
418 sig = SIGSEGV; 412 sig = SIGSEGV;
419#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO 413#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
420 if (saved_dcplb_fault_addr < FIXED_CODE_START) 414 if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
421 verbose_printk(KERN_NOTICE "NULL pointer access\n"); 415 verbose_printk(KERN_NOTICE "NULL pointer access\n");
422 else 416 else
423#endif 417#endif
@@ -471,7 +465,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
471 info.si_code = ILL_CPLB_MULHIT; 465 info.si_code = ILL_CPLB_MULHIT;
472 sig = SIGSEGV; 466 sig = SIGSEGV;
473#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO 467#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
474 if (saved_icplb_fault_addr < FIXED_CODE_START) 468 if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
475 verbose_printk(KERN_NOTICE "Jump to NULL address\n"); 469 verbose_printk(KERN_NOTICE "Jump to NULL address\n");
476 else 470 else
477#endif 471#endif
@@ -584,10 +578,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
584 } 578 }
585 } 579 }
586 580
587 info.si_signo = sig; 581#ifdef CONFIG_IPIPE
588 info.si_errno = 0; 582 if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp))
589 info.si_addr = (void __user *)fp->pc; 583#endif
590 force_sig_info(sig, &info, current); 584 {
585 info.si_signo = sig;
586 info.si_errno = 0;
587 info.si_addr = (void __user *)fp->pc;
588 force_sig_info(sig, &info, current);
589 }
591 590
592 trace_buffer_restore(j); 591 trace_buffer_restore(j);
593 return; 592 return;
@@ -656,13 +655,13 @@ static bool get_instruction(unsigned short *val, unsigned short *address)
656 return false; 655 return false;
657} 656}
658 657
659/* 658/*
660 * decode the instruction if we are printing out the trace, as it 659 * decode the instruction if we are printing out the trace, as it
661 * makes things easier to follow, without running it through objdump 660 * makes things easier to follow, without running it through objdump
662 * These are the normal instructions which cause change of flow, which 661 * These are the normal instructions which cause change of flow, which
663 * would be at the source of the trace buffer 662 * would be at the source of the trace buffer
664 */ 663 */
665#ifdef CONFIG_DEBUG_VERBOSE 664#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BFIN_HWTRACE_ON)
666static void decode_instruction(unsigned short *address) 665static void decode_instruction(unsigned short *address)
667{ 666{
668 unsigned short opcode; 667 unsigned short opcode;
@@ -846,7 +845,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
846 } 845 }
847 if (fp) { 846 if (fp) {
848 frame = fp; 847 frame = fp;
849 printk(" FP: (0x%p)\n", fp); 848 printk(KERN_NOTICE " FP: (0x%p)\n", fp);
850 } else 849 } else
851 frame = 0; 850 frame = 0;
852 851
@@ -960,6 +959,7 @@ void dump_bfin_process(struct pt_regs *fp)
960 else 959 else
961 verbose_printk(KERN_NOTICE "COMM= invalid\n"); 960 verbose_printk(KERN_NOTICE "COMM= invalid\n");
962 961
962 printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu);
963 if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) 963 if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
964 verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" 964 verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
965 KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n" 965 KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n"
@@ -1053,6 +1053,7 @@ void show_regs(struct pt_regs *fp)
1053 struct irqaction *action; 1053 struct irqaction *action;
1054 unsigned int i; 1054 unsigned int i;
1055 unsigned long flags; 1055 unsigned long flags;
1056 unsigned int cpu = smp_processor_id();
1056 1057
1057 verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); 1058 verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
1058 verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", 1059 verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
@@ -1112,9 +1113,9 @@ unlock:
1112 1113
1113 if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && 1114 if (((long)fp->seqstat & SEQSTAT_EXCAUSE) &&
1114 (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { 1115 (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
1115 decode_address(buf, saved_dcplb_fault_addr); 1116 decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
1116 verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); 1117 verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
1117 decode_address(buf, saved_icplb_fault_addr); 1118 decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
1118 verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); 1119 verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
1119 } 1120 }
1120 1121
@@ -1153,20 +1154,21 @@ unlock:
1153asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); 1154asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
1154#endif 1155#endif
1155 1156
1156asmlinkage int sys_bfin_spinlock(int *spinlock) 1157static DEFINE_SPINLOCK(bfin_spinlock_lock);
1158
1159asmlinkage int sys_bfin_spinlock(int *p)
1157{ 1160{
1158 int ret = 0; 1161 int ret, tmp = 0;
1159 int tmp = 0;
1160 1162
1161 local_irq_disable(); 1163 spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */
1162 ret = get_user(tmp, spinlock); 1164 ret = get_user(tmp, p);
1163 if (ret == 0) { 1165 if (likely(ret == 0)) {
1164 if (tmp) 1166 if (unlikely(tmp))
1165 ret = 1; 1167 ret = 1;
1166 tmp = 1; 1168 else
1167 put_user(tmp, spinlock); 1169 put_user(1, p);
1168 } 1170 }
1169 local_irq_enable(); 1171 spin_unlock(&bfin_spinlock_lock);
1170 return ret; 1172 return ret;
1171} 1173}
1172 1174