]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/mips/kernel/traps.c
[MIPS] Add support for MIPS CMP platform.
[linux-2.6-omap-h63xx.git] / arch / mips / kernel / traps.c
index d51f4e98455ff6bef4e9b6fd47d131b33a204b9b..88185cd40c3b5eb04c1c6f2318df575f4db1400c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/bootmem.h>
 #include <linux/interrupt.h>
+#include <linux/ptrace.h>
 
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset);
 
 static void show_raw_backtrace(unsigned long reg29)
 {
-       unsigned long *sp = (unsigned long *)reg29;
+       unsigned long *sp = (unsigned long *)(reg29 & ~3);
        unsigned long addr;
 
        printk("Call Trace:");
 #ifdef CONFIG_KALLSYMS
        printk("\n");
 #endif
-       while (!kstack_end(sp)) {
-               addr = *sp++;
-               if (__kernel_text_address(addr))
-                       print_ip_sym(addr);
+#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000)
+       if (IS_KVA01(sp)) {
+               while (!kstack_end(sp)) {
+                       addr = *sp++;
+                       if (__kernel_text_address(addr))
+                               print_ip_sym(addr);
+               }
+               printk("\n");
        }
-       printk("\n");
 }
 
 #ifdef CONFIG_KALLSYMS
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack);
 static void show_code(unsigned int __user *pc)
 {
        long i;
+       unsigned short __user *pc16 = NULL;
 
        printk("\nCode:");
 
+       if ((unsigned long)pc & 1)
+               pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
        for(i = -3 ; i < 6 ; i++) {
                unsigned int insn;
-               if (__get_user(insn, pc + i)) {
+               if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
                        printk(" (Bad address in epc)\n");
                        break;
                }
-               printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>'));
+               printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
        }
 }
 
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs)
 
 void show_registers(const struct pt_regs *regs)
 {
+       const int field = 2 * sizeof(unsigned long);
+
        __show_regs(regs);
        print_modules();
-       printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
-               current->comm, task_pid_nr(current), current_thread_info(), current);
+       printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n",
+              current->comm, current->pid, current_thread_info(), current,
+             field, current_thread_info()->tp_value);
+       if (cpu_has_userlocal) {
+               unsigned long tls;
+
+               tls = read_c0_userlocal();
+               if (tls != current_thread_info()->tp_value)
+                       printk("*HwTLS: %0*lx\n", field, tls);
+       }
+
        show_stacktrace(current, regs);
        show_code((unsigned int __user *) regs->cp0_epc);
        printk("\n");
@@ -985,6 +1003,21 @@ asmlinkage void do_reserved(struct pt_regs *regs)
              (regs->cp0_cause & 0x7f) >> 2);
 }
 
+static int __initdata l1parity = 1;
+static int __init nol1parity(char *s)
+{
+       l1parity = 0;
+       return 1;
+}
+__setup("nol1par", nol1parity);
+static int __initdata l2parity = 1;
+static int __init nol2parity(char *s)
+{
+       l2parity = 0;
+       return 1;
+}
+__setup("nol2par", nol2parity);
+
 /*
  * Some MIPS CPUs can enable/disable for cache parity detection, but do
  * it different ways.
@@ -994,6 +1027,62 @@ static inline void parity_protection_init(void)
        switch (current_cpu_type()) {
        case CPU_24K:
        case CPU_34K:
+       case CPU_74K:
+       case CPU_1004K:
+               {
+#define ERRCTL_PE      0x80000000
+#define ERRCTL_L2P     0x00800000
+                       unsigned long errctl;
+                       unsigned int l1parity_present, l2parity_present;
+
+                       errctl = read_c0_ecc();
+                       errctl &= ~(ERRCTL_PE|ERRCTL_L2P);
+
+                       /* probe L1 parity support */
+                       write_c0_ecc(errctl | ERRCTL_PE);
+                       back_to_back_c0_hazard();
+                       l1parity_present = (read_c0_ecc() & ERRCTL_PE);
+
+                       /* probe L2 parity support */
+                       write_c0_ecc(errctl|ERRCTL_L2P);
+                       back_to_back_c0_hazard();
+                       l2parity_present = (read_c0_ecc() & ERRCTL_L2P);
+
+                       if (l1parity_present && l2parity_present) {
+                               if (l1parity)
+                                       errctl |= ERRCTL_PE;
+                               if (l1parity ^ l2parity)
+                                       errctl |= ERRCTL_L2P;
+                       } else if (l1parity_present) {
+                               if (l1parity)
+                                       errctl |= ERRCTL_PE;
+                       } else if (l2parity_present) {
+                               if (l2parity)
+                                       errctl |= ERRCTL_L2P;
+                       } else {
+                               /* No parity available */
+                       }
+
+                       printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl);
+
+                       write_c0_ecc(errctl);
+                       back_to_back_c0_hazard();
+                       errctl = read_c0_ecc();
+                       printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl);
+
+                       if (l1parity_present)
+                               printk(KERN_INFO "Cache parity protection %sabled\n",
+                                      (errctl & ERRCTL_PE) ? "en" : "dis");
+
+                       if (l2parity_present) {
+                               if (l1parity_present && l1parity)
+                                       errctl ^= ERRCTL_L2P;
+                               printk(KERN_INFO "L2 cache parity protection %sabled\n",
+                                      (errctl & ERRCTL_L2P) ? "en" : "dis");
+                       }
+               }
+               break;
+
        case CPU_5KC:
                write_c0_ecc(0x80000000);
                back_to_back_c0_hazard();
@@ -1353,7 +1442,6 @@ void __cpuinit per_cpu_trap_init(void)
        change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
                         status_set);
 
-#ifdef CONFIG_CPU_MIPSR2
        if (cpu_has_mips_r2) {
                unsigned int enable = 0x0000000f;
 
@@ -1362,7 +1450,6 @@ void __cpuinit per_cpu_trap_init(void)
 
                write_c0_hwrena(enable);
        }
-#endif
 
 #ifdef CONFIG_MIPS_MT_SMTC
        if (!secondaryTC) {