diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 86 |
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)) | ||
85 | unsigned long saved_retx, saved_seqstat, | ||
86 | saved_icplb_fault_addr, saved_dcplb_fault_addr; | ||
87 | |||
88 | static void decode_address(char *buf, unsigned long address) | 79 | static 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) |
666 | static void decode_instruction(unsigned short *address) | 665 | static 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: | |||
1153 | asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); | 1154 | asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); |
1154 | #endif | 1155 | #endif |
1155 | 1156 | ||
1156 | asmlinkage int sys_bfin_spinlock(int *spinlock) | 1157 | static DEFINE_SPINLOCK(bfin_spinlock_lock); |
1158 | |||
1159 | asmlinkage 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 | ||