ARM: SPEAR6xx: remove duplicated #include
[safe/jmp/linux-2.6] / arch / blackfin / kernel / traps.c
index aa76dfb..ba70c4b 100644 (file)
@@ -1,32 +1,10 @@
 /*
- * File:         arch/blackfin/kernel/traps.c
- * Based on:
- * Author:       Hamish Macdonald
+ * Copyright 2004-2009 Analog Devices Inc.
  *
- * Created:
- * Description:  uses S/W interrupt 15 for the system calls
- *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later
  */
 
+#include <linux/bug.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -36,6 +14,7 @@
 #include <asm/traps.h>
 #include <asm/cacheflush.h>
 #include <asm/cplb.h>
+#include <asm/dma.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
 #include <linux/irq.h>
@@ -98,7 +77,11 @@ static void decode_address(char *buf, unsigned long address)
        char *modname;
        char *delim = ":";
        char namebuf[128];
+#endif
 
+       buf += sprintf(buf, "<0x%08lx> ", address);
+
+#ifdef CONFIG_KALLSYMS
        /* look up the address and see if we are in kernel space */
        symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
 
@@ -106,23 +89,42 @@ static void decode_address(char *buf, unsigned long address)
                /* yeah! kernel space! */
                if (!modname)
                        modname = delim = "";
-               sprintf(buf, "<0x%p> { %s%s%s%s + 0x%lx }",
-                             (void *)address, delim, modname, delim, symname,
-                             (unsigned long)offset);
+               sprintf(buf, "{ %s%s%s%s + 0x%lx }",
+                       delim, modname, delim, symname,
+                       (unsigned long)offset);
                return;
-
        }
 #endif
 
-       /* Problem in fixed code section? */
        if (address >= FIXED_CODE_START && address < FIXED_CODE_END) {
-               sprintf(buf, "<0x%p> /* Maybe fixed code section */", (void *)address);
+               /* Problem in fixed code section? */
+               strcat(buf, "/* Maybe fixed code section */");
+               return;
+
+       } else if (address < CONFIG_BOOT_LOAD) {
+               /* Problem somewhere before the kernel start address */
+               strcat(buf, "/* Maybe null pointer? */");
+               return;
+
+       } else if (address >= COREMMR_BASE) {
+               strcat(buf, "/* core mmrs */");
+               return;
+
+       } else if (address >= SYSMMR_BASE) {
+               strcat(buf, "/* system mmrs */");
+               return;
+
+       } else if (address >= L1_ROM_START && address < L1_ROM_START + L1_ROM_LENGTH) {
+               strcat(buf, "/* on-chip L1 ROM */");
                return;
        }
 
-       /* Problem somewhere before the kernel start address */
-       if (address < CONFIG_BOOT_LOAD) {
-               sprintf(buf, "<0x%p> /* Maybe null pointer? */", (void *)address);
+       /*
+        * Don't walk any of the vmas if we are oopsing, it has been known
+        * to cause problems - corrupt vmas (kernel crashes) cause double faults
+        */
+       if (oops_in_progress) {
+               strcat(buf, "/* kernel dynamic memory (maybe user-space) */");
                return;
        }
 
@@ -136,6 +138,12 @@ static void decode_address(char *buf, unsigned long address)
                if (!mm)
                        continue;
 
+               if (!down_read_trylock(&mm->mmap_sem)) {
+                       if (!in_atomic)
+                               mmput(mm);
+                       continue;
+               }
+
                for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
                        struct vm_area_struct *vma;
 
@@ -170,28 +178,32 @@ static void decode_address(char *buf, unsigned long address)
                                                offset = (address - vma->vm_start) +
                                                         (vma->vm_pgoff << PAGE_SHIFT);
 
-                                       sprintf(buf, "<0x%p> [ %s + 0x%lx ]",
-                                               (void *)address, name, offset);
+                                       sprintf(buf, "[ %s + 0x%lx ]", name, offset);
                                } else
-                                       sprintf(buf, "<0x%p> [ %s vma:0x%lx-0x%lx]",
-                                               (void *)address, name,
-                                               vma->vm_start, vma->vm_end);
+                                       sprintf(buf, "[ %s vma:0x%lx-0x%lx]",
+                                               name, vma->vm_start, vma->vm_end);
 
+                               up_read(&mm->mmap_sem);
                                if (!in_atomic)
                                        mmput(mm);
 
-                               if (!strlen(buf))
-                                       sprintf(buf, "<0x%p> [ %s ] dynamic memory", (void *)address, name);
+                               if (buf[0] == '\0')
+                                       sprintf(buf, "[ %s ] dynamic memory", name);
 
                                goto done;
                        }
                }
+
+               up_read(&mm->mmap_sem);
                if (!in_atomic)
                        mmput(mm);
        }
 
-       /* we were unable to find this address anywhere */
-       sprintf(buf, "<0x%p> /* kernel dynamic memory */", (void *)address);
+       /*
+        * we were unable to find this address anywhere,
+        * or some MMs were skipped because they were in use.
+        */
+       sprintf(buf, "/* kernel dynamic memory */");
 
 done:
        write_unlock_irqrestore(&tasklist_lock, flags);
@@ -210,17 +222,17 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
        console_verbose();
        oops_in_progress = 1;
 #ifdef CONFIG_DEBUG_VERBOSE
-       printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
+       printk(KERN_EMERG "Double Fault\n");
 #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
        if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
-               unsigned int cpu = smp_processor_id();
+               unsigned int cpu = raw_smp_processor_id();
                char buf[150];
-               decode_address(buf, cpu_pda[cpu].retx);
+               decode_address(buf, cpu_pda[cpu].retx_doublefault);
                printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
-                       (unsigned int)cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE, buf);
-               decode_address(buf, cpu_pda[cpu].dcplb_fault_addr);
+                       (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf);
+               decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr);
                printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
-               decode_address(buf, cpu_pda[cpu].icplb_fault_addr);
+               decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr);
                printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
 
                decode_address(buf, fp->retx);
@@ -238,14 +250,18 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
 
 }
 
-asmlinkage void trap_c(struct pt_regs *fp)
+static int kernel_mode_regs(struct pt_regs *regs)
+{
+       return regs->ipend & 0xffc0;
+}
+
+asmlinkage notrace 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
+       unsigned int cpu = raw_smp_processor_id();
+       const char *strerror = NULL;
        int sig = 0;
        siginfo_t info;
        unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
@@ -259,28 +275,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * double faults if the stack has become corrupt
         */
 
-       /* If the fault was caused by a kernel thread, or interrupt handler
-        * we will kernel panic, so the system reboots.
-        * If KGDB is enabled, don't set this for kernel breakpoints
-       */
-
-       /* TODO: check to see if we are in some sort of deferred HWERR
-        * that we should be able to recover from, not kernel panic
-        */
-       if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
-#ifdef CONFIG_KGDB
-               && (trapnr != VEC_EXCPT02)
-#endif
-       ){
-               console_verbose();
-               oops_in_progress = 1;
-       } else if (current) {
-               if (current->mm == NULL) {
-                       console_verbose();
-                       oops_in_progress = 1;
-               }
-       }
-
        /* trap_c() will be called for exceptions. During exceptions
         * processing, the pc value should be set with retx value.
         * With this change we can cleanup some code in signal.c- TODO
@@ -307,15 +301,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a breakpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x03 - User Defined, userspace stack overflow */
        case VEC_EXCPT03:
                info.si_code = SEGV_STACKFLOW;
                sig = SIGSEGV;
-               verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x02 - KGDB initial connection and break signal trap */
@@ -324,7 +318,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = TRAP_ILLTRAP;
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP();
-               return;
+               goto traps_done;
 #endif
        /* 0x04 - User Defined */
        /* 0x05 - User Defined */
@@ -344,7 +338,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_EXCPT04 ... VEC_EXCPT15:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x10 HW Single step, handled here */
@@ -353,15 +347,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a single step in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x11 - Trace Buffer Full, handled here */
        case VEC_OVFLOW:
                info.si_code = TRAP_TRACEFLOW;
                sig = SIGTRAP;
-               verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x12 - Reserved, Caught by default */
@@ -381,37 +375,54 @@ asmlinkage void trap_c(struct pt_regs *fp)
        /* 0x20 - Reserved, Caught by default */
        /* 0x21 - Undefined Instruction, handled here */
        case VEC_UNDEF_I:
+#ifdef CONFIG_BUG
+               if (kernel_mode_regs(fp)) {
+                       switch (report_bug(fp->pc, fp)) {
+                       case BUG_TRAP_TYPE_NONE:
+                               break;
+                       case BUG_TRAP_TYPE_WARN:
+                               dump_bfin_trace_buffer();
+                               fp->pc += 2;
+                               goto traps_done;
+                       case BUG_TRAP_TYPE_BUG:
+                               /* call to panic() will dump trace, and it is
+                                * off at this point, so it won't be clobbered
+                                */
+                               panic("BUG()");
+                       }
+               }
+#endif
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x22 - Illegal Instruction Combination, handled here */
        case VEC_ILGAL_I:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x23 - Data CPLB protection violation, handled here */
        case VEC_CPLB_VL:
                info.si_code = ILL_CPLB_VI;
-               sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+               sig = SIGSEGV;
+               strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x24 - Data access misaligned, handled here */
        case VEC_MISALI_D:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x25 - Unrecoverable Event, handled here */
        case VEC_UNCOV:
                info.si_code = ILL_ILLEXCPT;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
@@ -419,7 +430,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_CPLB_M:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE);
                break;
        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
        case VEC_CPLB_MHIT:
@@ -427,10 +438,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "NULL pointer access\n");
+                       strerror = KERN_NOTICE "NULL pointer access\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x28 - Emulation Watchpoint, handled here */
@@ -440,8 +451,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
                pr_debug(EXC_0x28(KERN_DEBUG));
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a watchpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
 #ifdef CONFIG_BF535
@@ -449,7 +460,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
                info.si_code = BUS_OPFETCH;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+               strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n";
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
 #else
@@ -459,21 +470,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_MISALI_I:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2B - Instruction CPLB protection violation, handled here */
        case VEC_CPLB_I_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
        case VEC_CPLB_I_M:
                info.si_code = ILL_CPLB_MISS;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE);
                break;
        /* 0x2D - Instruction CPLB Multiple Hits, handled here */
        case VEC_CPLB_I_MHIT:
@@ -481,17 +492,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "Jump to NULL address\n");
+                       strerror = KERN_NOTICE "Jump to NULL address\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2E - Illegal use of Supervisor Resource, handled here */
        case VEC_ILL_RES:
                info.si_code = ILL_PRVOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2F - Reserved, Caught by default */
@@ -519,17 +530,47 @@ asmlinkage void trap_c(struct pt_regs *fp)
                case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
                        info.si_code = BUS_ADRALN;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x2(KERN_NOTICE);
                        break;
                /* External Memory Addressing Error */
                case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
+                       if (ANOMALY_05000310) {
+                               static unsigned long anomaly_rets;
+
+                               if ((fp->pc >= (L1_CODE_START + L1_CODE_LENGTH - 512)) &&
+                                   (fp->pc < (L1_CODE_START + L1_CODE_LENGTH))) {
+                                       /*
+                                        * A false hardware error will happen while fetching at
+                                        * the L1 instruction SRAM boundary.  Ignore it.
+                                        */
+                                       anomaly_rets = fp->rets;
+                                       goto traps_done;
+                               } else if (fp->rets == anomaly_rets) {
+                                       /*
+                                        * While boundary code returns to a function, at the ret
+                                        * point, a new false hardware error might occur too based
+                                        * on tests.  Ignore it too.
+                                        */
+                                       goto traps_done;
+                               } else if ((fp->rets >= (L1_CODE_START + L1_CODE_LENGTH - 512)) &&
+                                          (fp->rets < (L1_CODE_START + L1_CODE_LENGTH))) {
+                                       /*
+                                        * If boundary code calls a function, at the entry point,
+                                        * a new false hardware error maybe happen based on tests.
+                                        * Ignore it too.
+                                        */
+                                       goto traps_done;
+                               } else
+                                       anomaly_rets = 0;
+                       }
+
                        info.si_code = BUS_ADRERR;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x3(KERN_NOTICE);
                        break;
                /* Performance Monitor Overflow */
                case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-                       verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x12(KERN_NOTICE);
                        break;
                /* RAISE 5 instruction */
                case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -546,7 +587,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * if we get here we hit a reserved one, so panic
         */
        default:
-               oops_in_progress = 1;
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
                verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
@@ -557,7 +597,18 @@ asmlinkage void trap_c(struct pt_regs *fp)
 
        BUG_ON(sig == 0);
 
+       /* If the fault was caused by a kernel thread, or interrupt handler
+        * we will kernel panic, so the system reboots.
+        */
+       if (kernel_mode_regs(fp) || (current && !current->mm)) {
+               console_verbose();
+               oops_in_progress = 1;
+       }
+
        if (sig != SIGTRAP) {
+               if (strerror)
+                       verbose_printk(strerror);
+
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
                show_regs(fp);
@@ -566,15 +617,14 @@ asmlinkage void trap_c(struct pt_regs *fp)
 #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
                if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
                        verbose_printk(KERN_NOTICE "No trace since you do not have "
-                               "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
-                               KERN_NOTICE "\n");
+                              "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n\n");
                else
 #endif
                        dump_bfin_trace_buffer();
 
                if (oops_in_progress) {
                        /* Dump the current kernel stack */
-                       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
+                       verbose_printk(KERN_NOTICE "Kernel Stack\n");
                        show_stack(current, NULL);
                        print_modules();
 #ifndef CONFIG_ACCESS_CHECK
@@ -599,15 +649,27 @@ asmlinkage void trap_c(struct pt_regs *fp)
        {
                info.si_signo = sig;
                info.si_errno = 0;
-               info.si_addr = (void __user *)fp->pc;
+               switch (trapnr) {
+               case VEC_CPLB_VL:
+               case VEC_MISALI_D:
+               case VEC_CPLB_M:
+               case VEC_CPLB_MHIT:
+                       info.si_addr = (void __user *)cpu_pda[cpu].dcplb_fault_addr;
+                       break;
+               default:
+                       info.si_addr = (void __user *)fp->pc;
+                       break;
+               }
                force_sig_info(sig, &info, current);
        }
 
-       if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
+       if ((ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8)) ||
+           (ANOMALY_05000281 && trapnr == VEC_HWERR) ||
+           (ANOMALY_05000189 && (trapnr == VEC_CPLB_I_VL || trapnr == VEC_CPLB_VL)))
                fp->pc = SAFE_USER_INSTRUCTION;
 
+ traps_done:
        trace_buffer_restore(j);
-       return;
 }
 
 /* Typical exception handling routines */
@@ -616,61 +678,34 @@ asmlinkage void trap_c(struct pt_regs *fp)
 
 /*
  * Similar to get_user, do some address checking, then dereference
- * Return true on sucess, false on bad address
+ * Return true on success, false on bad address
  */
 static bool get_instruction(unsigned short *val, unsigned short *address)
 {
-
-       unsigned long addr;
-
-       addr = (unsigned long)address;
+       unsigned long addr = (unsigned long)address;
 
        /* Check for odd addresses */
        if (addr & 0x1)
                return false;
 
-       /* Check that things do not wrap around */
-       if (addr > (addr + 2))
+       /* MMR region will never have instructions */
+       if (addr >= SYSMMR_BASE)
                return false;
 
-       /*
-        * Since we are in exception context, we need to do a little address checking
-        * We need to make sure we are only accessing valid memory, and
-        * we don't read something in the async space that can hang forever
-        */
-       if ((addr >= FIXED_CODE_START && (addr + 2) <= physical_mem_end) ||
-#if L2_LENGTH != 0
-           (addr >= L2_START && (addr + 2) <= (L2_START + L2_LENGTH)) ||
-#endif
-           (addr >= BOOT_ROM_START && (addr + 2) <= (BOOT_ROM_START + BOOT_ROM_LENGTH)) ||
-#if L1_DATA_A_LENGTH != 0
-           (addr >= L1_DATA_A_START && (addr + 2) <= (L1_DATA_A_START + L1_DATA_A_LENGTH)) ||
-#endif
-#if L1_DATA_B_LENGTH != 0
-           (addr >= L1_DATA_B_START && (addr + 2) <= (L1_DATA_B_START + L1_DATA_B_LENGTH)) ||
-#endif
-           (addr >= L1_SCRATCH_START && (addr + 2) <= (L1_SCRATCH_START + L1_SCRATCH_LENGTH)) ||
-           (!(bfin_read_EBIU_AMBCTL0() & B0RDYEN) &&
-              addr >= ASYNC_BANK0_BASE && (addr + 2) <= (ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)) ||
-           (!(bfin_read_EBIU_AMBCTL0() & B1RDYEN) &&
-              addr >= ASYNC_BANK1_BASE && (addr + 2) <= (ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)) ||
-           (!(bfin_read_EBIU_AMBCTL1() & B2RDYEN) &&
-              addr >= ASYNC_BANK2_BASE && (addr + 2) <= (ASYNC_BANK2_BASE + ASYNC_BANK1_SIZE)) ||
-           (!(bfin_read_EBIU_AMBCTL1() & B3RDYEN) &&
-             addr >= ASYNC_BANK3_BASE && (addr + 2) <= (ASYNC_BANK3_BASE + ASYNC_BANK1_SIZE))) {
-               *val = *address;
-               return true;
-       }
-
-#if L1_CODE_LENGTH != 0
-       if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
-               isram_memcpy(val, address, 2);
-               return true;
+       switch (bfin_mem_access_type(addr, 2)) {
+               case BFIN_MEM_ACCESS_CORE:
+               case BFIN_MEM_ACCESS_CORE_ONLY:
+                       *val = *address;
+                       return true;
+               case BFIN_MEM_ACCESS_DMA:
+                       dma_memcpy(val, address, 2);
+                       return true;
+               case BFIN_MEM_ACCESS_ITEST:
+                       isram_memcpy(val, address, 2);
+                       return true;
+               default: /* invalid access */
+                       return false;
        }
-#endif
-
-
-       return false;
 }
 
 /*
@@ -697,7 +732,7 @@ static void decode_instruction(unsigned short *address)
                        verbose_printk("RTE");
                else if (opcode == 0x0025)
                        verbose_printk("EMUEXCPT");
-               else if (opcode == 0x0040 && opcode <= 0x0047)
+               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);
@@ -792,6 +827,18 @@ void dump_bfin_trace_buffer(void)
 }
 EXPORT_SYMBOL(dump_bfin_trace_buffer);
 
+#ifdef CONFIG_BUG
+int is_valid_bugaddr(unsigned long addr)
+{
+       unsigned short opcode;
+
+       if (!get_instruction(&opcode, (unsigned short *)addr))
+               return 0;
+
+       return opcode == BFIN_BUG_OPCODE;
+}
+#endif
+
 /*
  * Checks to see if the address pointed to is either a
  * 16-bit CALL instruction, or a 32-bit CALL instruction
@@ -900,11 +947,11 @@ void show_stack(struct task_struct *task, unsigned long *stack)
                frame_no = 0;
 
                for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
-                    addr <= endstack; addr++, i++) {
+                    addr < endstack; addr++, i++) {
 
                        ret_addr = 0;
                        if (!j && i % 8 == 0)
-                               printk("\n" KERN_NOTICE "%p:",addr);
+                               printk(KERN_NOTICE "%p:",addr);
 
                        /* if it is an odd address, or zero, just skip it */
                        if (*addr & 0x1 || !*addr)
@@ -945,6 +992,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        }
 #endif
 }
+EXPORT_SYMBOL(show_stack);
 
 void dump_stack(void)
 {
@@ -987,16 +1035,16 @@ void dump_bfin_process(struct pt_regs *fp)
            !((unsigned long)current & 0x3) && current->pid) {
                verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
                if (current->comm >= (char *)FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
+                       verbose_printk(KERN_NOTICE "COMM=%s PID=%d",
                                current->comm, current->pid);
                else
-                       verbose_printk(KERN_NOTICE "COMM= invalid\n");
+                       verbose_printk(KERN_NOTICE "COMM= invalid");
 
-               printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu);
+               printk(KERN_CONT " 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"
-                               KERN_NOTICE "\n",
+                       verbose_printk(KERN_NOTICE
+                               "TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
+                               " BSS = 0x%p-0x%p  USER-STACK = 0x%p\n\n",
                                (void *)current->mm->start_code,
                                (void *)current->mm->end_code,
                                (void *)current->mm->start_data,
@@ -1007,8 +1055,8 @@ void dump_bfin_process(struct pt_regs *fp)
                else
                        verbose_printk(KERN_NOTICE "invalid mm\n");
        } else
-               verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
-                    "No Valid process in current context\n");
+               verbose_printk(KERN_NOTICE
+                              "No Valid process in current context\n");
 #endif
 }
 
@@ -1026,7 +1074,7 @@ void dump_bfin_mem(struct pt_regs *fp)
             addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
             addr++) {
                if (!((unsigned long)addr & 0xF))
-                       verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
+                       verbose_printk(KERN_NOTICE "0x%p: ", addr);
 
                if (!get_instruction(&val, addr)) {
                                val = 0;
@@ -1054,9 +1102,9 @@ void dump_bfin_mem(struct pt_regs *fp)
            oops_in_progress)){
                verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
 #ifndef CONFIG_DEBUG_HWERR
-               verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
-                       KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
-                        " better idea where it came from\n");
+               verbose_printk(KERN_NOTICE
+"The remaining message may be meaningless\n"
+"You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n");
 #else
                /* If we are handling only one peripheral interrupt
                 * and current mm and pid are valid, and the last error
@@ -1068,7 +1116,7 @@ void dump_bfin_mem(struct pt_regs *fp)
                        /* And the last RETI points to the current userspace context */
                        if ((fp + 1)->pc >= current->mm->start_code &&
                            (fp + 1)->pc <= current->mm->end_code) {
-                               verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
+                               verbose_printk(KERN_NOTICE "It might be better to look around here :\n");
                                verbose_printk(KERN_NOTICE "-------------------------------------------\n");
                                show_regs(fp + 1);
                                verbose_printk(KERN_NOTICE "-------------------------------------------\n");
@@ -1086,7 +1134,7 @@ void show_regs(struct pt_regs *fp)
        struct irqaction *action;
        unsigned int i;
        unsigned long flags = 0;
-       unsigned int cpu = smp_processor_id();
+       unsigned int cpu = raw_smp_processor_id();
        unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
 
        verbose_printk(KERN_NOTICE "\n");
@@ -1112,9 +1160,16 @@ void show_regs(struct pt_regs *fp)
 
        verbose_printk(KERN_NOTICE "%s", linux_banner);
 
-       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",
-               (long)fp->seqstat, fp->ipend, fp->syscfg);
+       verbose_printk(KERN_NOTICE "\nSEQUENCER STATUS:\t\t%s\n", print_tainted());
+       verbose_printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  IMASK: %04lx  SYSCFG: %04lx\n",
+               (long)fp->seqstat, fp->ipend, cpu_pda[raw_smp_processor_id()].ex_imask, fp->syscfg);
+       if (fp->ipend & EVT_IRPTEN)
+               verbose_printk(KERN_NOTICE "  Global Interrupts Disabled (IPEND[4])\n");
+       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG13 | EVT_IVG12 | EVT_IVG11 |
+                       EVT_IVG10 | EVT_IVG9 | EVT_IVG8 | EVT_IVG7 | EVT_IVTMR)))
+               verbose_printk(KERN_NOTICE "  Peripheral interrupts masked off\n");
+       if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG15 | EVT_IVG14)))
+               verbose_printk(KERN_NOTICE "  Kernel interrupts masked off\n");
        if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
                verbose_printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
                        (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
@@ -1144,7 +1199,7 @@ void show_regs(struct pt_regs *fp)
        if (fp->ipend & ~0x3F) {
                for (i = 0; i < (NR_IRQS - 1); i++) {
                        if (!in_atomic)
-                               spin_lock_irqsave(&irq_desc[i].lock, flags);
+                               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
 
                        action = irq_desc[i].action;
                        if (!action)
@@ -1159,7 +1214,7 @@ void show_regs(struct pt_regs *fp)
                        verbose_printk("\n");
 unlock:
                        if (!in_atomic)
-                               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+                               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
                }
        }
 
@@ -1182,7 +1237,7 @@ unlock:
                verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
        }
 
-       verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
+       verbose_printk(KERN_NOTICE "PROCESSOR STATE:\n");
        verbose_printk(KERN_NOTICE " R0 : %08lx    R1 : %08lx    R2 : %08lx    R3 : %08lx\n",
                fp->r0, fp->r1, fp->r2, fp->r3);
        verbose_printk(KERN_NOTICE " R4 : %08lx    R5 : %08lx    R6 : %08lx    R7 : %08lx\n",