diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index bef025b07443..ffe7fb53eccb 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/fs.h> +#include <linux/rbtree.h> #include <asm/traps.h> #include <asm/cacheflush.h> #include <asm/cplb.h> @@ -75,16 +76,6 @@ void __init trap_init(void) CSYNC(); } -/* - * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR - * values across the transition from exception to IRQ5. - * We put these in L1, so they are going to be in a valid - * location during exception context - */ -__attribute__((l1_data)) -unsigned long saved_retx, saved_seqstat, - saved_icplb_fault_addr, saved_dcplb_fault_addr; - static void decode_address(char *buf, unsigned long address) { #ifdef CONFIG_DEBUG_VERBOSE @@ -93,6 +84,7 @@ static void decode_address(char *buf, unsigned long address) struct mm_struct *mm; unsigned long flags, offset; unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); + struct rb_node *n; #ifdef CONFIG_KALLSYMS unsigned long symsize; @@ -138,9 +130,10 @@ static void decode_address(char *buf, unsigned long address) if (!mm) continue; - vml = mm->context.vmlist; - while (vml) { - struct vm_area_struct *vma = vml->vma; + for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { + struct vm_area_struct *vma; + + vma = rb_entry(n, struct vm_area_struct, vm_rb); if (address >= vma->vm_start && address < vma->vm_end) { char _tmpbuf[256]; @@ -186,8 +179,6 @@ static void decode_address(char *buf, unsigned long address) goto done; } - - vml = vml->next; } if (!in_atomic) mmput(mm); @@ -211,18 +202,18 @@ asmlinkage void double_fault_c(struct pt_regs *fp) printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { + unsigned int cpu = smp_processor_id(); char buf[150]; - decode_address(buf, saved_retx); + decode_address(buf, cpu_pda[cpu].retx); printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", - (int)saved_seqstat & SEQSTAT_EXCAUSE, buf); - decode_address(buf, saved_dcplb_fault_addr); + (unsigned int)cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE, buf); + decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); - decode_address(buf, saved_icplb_fault_addr); + decode_address(buf, cpu_pda[cpu].icplb_fault_addr); printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); decode_address(buf, fp->retx); - printk(KERN_NOTICE "The instruction at %s caused a double exception\n", - buf); + printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf); } else #endif { @@ -240,6 +231,9 @@ asmlinkage void trap_c(struct pt_regs *fp) #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON int j; #endif +#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO + unsigned int cpu = smp_processor_id(); +#endif int sig = 0; siginfo_t info; unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; @@ -417,7 +411,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = ILL_CPLB_MULHIT; sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO - if (saved_dcplb_fault_addr < FIXED_CODE_START) + if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) verbose_printk(KERN_NOTICE "NULL pointer access\n"); else #endif @@ -471,7 +465,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = ILL_CPLB_MULHIT; sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO - if (saved_icplb_fault_addr < FIXED_CODE_START) + if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) verbose_printk(KERN_NOTICE "Jump to NULL address\n"); else #endif @@ -584,10 +578,15 @@ asmlinkage void trap_c(struct pt_regs *fp) } } - info.si_signo = sig; - info.si_errno = 0; - info.si_addr = (void __user *)fp->pc; - force_sig_info(sig, &info, current); +#ifdef CONFIG_IPIPE + if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp)) +#endif + { + info.si_signo = sig; + info.si_errno = 0; + info.si_addr = (void __user *)fp->pc; + force_sig_info(sig, &info, current); + } trace_buffer_restore(j); return; @@ -656,13 +655,13 @@ static bool get_instruction(unsigned short *val, unsigned short *address) return false; } -/* +/* * decode the instruction if we are printing out the trace, as it * makes things easier to follow, without running it through objdump * These are the normal instructions which cause change of flow, which * would be at the source of the trace buffer */ -#ifdef CONFIG_DEBUG_VERBOSE +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BFIN_HWTRACE_ON) static void decode_instruction(unsigned short *address) { unsigned short opcode; @@ -674,6 +673,14 @@ static void decode_instruction(unsigned short *address) verbose_printk("RTI"); else if (opcode == 0x0012) verbose_printk("RTX"); + else if (opcode == 0x0013) + verbose_printk("RTN"); + else if (opcode == 0x0014) + verbose_printk("RTE"); + else if (opcode == 0x0025) + verbose_printk("EMUEXCPT"); + else if (opcode == 0x0040 && opcode <= 0x0047) + verbose_printk("STI R%i", opcode & 7); else if (opcode >= 0x0050 && opcode <= 0x0057) verbose_printk("JUMP (P%i)", opcode & 7); else if (opcode >= 0x0060 && opcode <= 0x0067) @@ -682,6 +689,10 @@ static void decode_instruction(unsigned short *address) verbose_printk("CALL (PC+P%i)", opcode & 7); else if (opcode >= 0x0080 && opcode <= 0x0087) verbose_printk("JUMP (PC+P%i)", opcode & 7); + else if (opcode >= 0x0090 && opcode <= 0x009F) + verbose_printk("RAISE 0x%x", opcode & 0xF); + else if (opcode >= 0x00A0 && opcode <= 0x00AF) + verbose_printk("EXCPT 0x%x", opcode & 0xF); else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF)) verbose_printk("IF !CC JUMP"); else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff)) @@ -821,11 +832,8 @@ void show_stack(struct task_struct *task, unsigned long *stack) decode_address(buf, (unsigned int)stack); printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); - addr = (unsigned int *)((unsigned int)stack & ~0x3F); - /* First thing is to look for a frame pointer */ - for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; - addr < endstack; addr++, i++) { + for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { if (*addr & 0x1) continue; ins_addr = (unsigned short *)*addr; @@ -835,7 +843,8 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (fp) { /* Let's check to see if it is a frame pointer */ - while (fp >= (addr - 1) && fp < endstack && fp) + while (fp >= (addr - 1) && fp < endstack + && fp && ((unsigned int) fp & 0x3) == 0) fp = (unsigned int *)*fp; if (fp == 0 || fp == endstack) { fp = addr - 1; @@ -846,7 +855,7 @@ void show_stack(struct task_struct *task, unsigned long *stack) } if (fp) { frame = fp; - printk(" FP: (0x%p)\n", fp); + printk(KERN_NOTICE " FP: (0x%p)\n", fp); } else frame = 0; @@ -960,6 +969,7 @@ void dump_bfin_process(struct pt_regs *fp) else verbose_printk(KERN_NOTICE "COMM= invalid\n"); + printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu); if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n" @@ -1052,7 +1062,9 @@ void show_regs(struct pt_regs *fp) char buf [150]; struct irqaction *action; unsigned int i; - unsigned long flags; + unsigned long flags = 0; + unsigned int cpu = smp_processor_id(); + unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", @@ -1072,17 +1084,22 @@ void show_regs(struct pt_regs *fp) } verbose_printk(KERN_NOTICE " EXCAUSE : 0x%lx\n", fp->seqstat & SEQSTAT_EXCAUSE); - for (i = 6; i <= 15 ; i++) { + for (i = 2; i <= 15 ; i++) { if (fp->ipend & (1 << i)) { - decode_address(buf, bfin_read32(EVT0 + 4*i)); - verbose_printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf); + if (i != 4) { + decode_address(buf, bfin_read32(EVT0 + 4*i)); + verbose_printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf); + } else + verbose_printk(KERN_NOTICE " interrupts disabled\n"); } } /* if no interrupts are going off, don't print this out */ if (fp->ipend & ~0x3F) { for (i = 0; i < (NR_IRQS - 1); i++) { - spin_lock_irqsave(&irq_desc[i].lock, flags); + if (!in_atomic) + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; if (!action) goto unlock; @@ -1095,7 +1112,8 @@ void show_regs(struct pt_regs *fp) } verbose_printk("\n"); unlock: - spin_unlock_irqrestore(&irq_desc[i].lock, flags); + if (!in_atomic) + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } } @@ -1112,9 +1130,9 @@ unlock: if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { - decode_address(buf, saved_dcplb_fault_addr); + decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); - decode_address(buf, saved_icplb_fault_addr); + decode_address(buf, cpu_pda[cpu].icplb_fault_addr); verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); } @@ -1153,20 +1171,21 @@ unlock: asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); #endif -asmlinkage int sys_bfin_spinlock(int *spinlock) +static DEFINE_SPINLOCK(bfin_spinlock_lock); + +asmlinkage int sys_bfin_spinlock(int *p) { - int ret = 0; - int tmp = 0; + int ret, tmp = 0; - local_irq_disable(); - ret = get_user(tmp, spinlock); - if (ret == 0) { - if (tmp) + spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */ + ret = get_user(tmp, p); + if (likely(ret == 0)) { + if (unlikely(tmp)) ret = 1; - tmp = 1; - put_user(tmp, spinlock); + else + put_user(1, p); } - local_irq_enable(); + spin_unlock(&bfin_spinlock_lock); return ret; } |