linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / mips / kernel / traps.c
index 954a198..005debb 100644 (file)
@@ -11,6 +11,7 @@
  * Copyright (C) 2000, 01 MIPS Technologies, Inc.
  * Copyright (C) 2002, 2003, 2004, 2005  Maciej W. Rozycki
  */
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/module.h>
@@ -41,7 +42,6 @@
 #include <asm/watch.h>
 #include <asm/types.h>
 
-extern asmlinkage void handle_int(void);
 extern asmlinkage void handle_tlbm(void);
 extern asmlinkage void handle_tlbl(void);
 extern asmlinkage void handle_tlbs(void);
@@ -64,7 +64,7 @@ extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
-       struct mips_fpu_struct *ctx);
+       struct mips_fpu_soft_struct *ctx);
 
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
@@ -279,16 +279,9 @@ static DEFINE_SPINLOCK(die_lock);
 NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
 {
        static int die_counter;
-#ifdef CONFIG_MIPS_MT_SMTC
-       unsigned long dvpret = dvpe();
-#endif /* CONFIG_MIPS_MT_SMTC */
 
        console_verbose();
        spin_lock_irq(&die_lock);
-       bust_spinlocks(1);
-#ifdef CONFIG_MIPS_MT_SMTC
-       mips_mt_regdump(dvpret);
-#endif /* CONFIG_MIPS_MT_SMTC */
        printk("%s[#%d]:\n", str, ++die_counter);
        show_registers(regs);
        spin_unlock_irq(&die_lock);
@@ -569,8 +562,6 @@ asmlinkage void do_ov(struct pt_regs *regs)
  */
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
-       die_if_kernel("FP exception in kernel code", regs);
-
        if (fcr31 & FPU_CSR_UNI_X) {
                int sig;
 
@@ -585,7 +576,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                }
 #endif
                /*
-                * Unimplemented operation exception.  If we've got the full
+                * Unimplemented operation exception.  If we've got the full
                 * software emulator on-board, let's use it...
                 *
                 * Force FPU to dump state into task/thread context.  We're
@@ -601,7 +592,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                preempt_enable();
 
                /* Run the emulator */
-               sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu);
+               sig = fpu_emulator_cop1Handler (regs,
+                       &current->thread.fpu.soft);
 
                preempt_disable();
 
@@ -610,7 +602,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                 * We can't allow the emulated instruction to leave any of
                 * the cause bit set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               current->thread.fpu.soft.fcr31 &= ~FPU_CSR_ALL_X;
 
                /* Restore the hardware register state */
                restore_fp(current);
@@ -755,46 +747,15 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
                if (!cpu_has_fpu) {
                        int sig = fpu_emulator_cop1Handler(regs,
-                                               &current->thread.fpu);
+                                               &current->thread.fpu.soft);
                        if (sig)
                                force_sig(sig, current);
-#ifdef CONFIG_MIPS_MT_FPAFF
-                       else {
-                       /*
-                        * MIPS MT processors may have fewer FPU contexts
-                        * than CPU threads. If we've emulated more than
-                        * some threshold number of instructions, force
-                        * migration to a "CPU" that has FP support.
-                        */
-                        if(mt_fpemul_threshold > 0
-                        && ((current->thread.emulated_fp++
-                           > mt_fpemul_threshold))) {
-                         /*
-                          * If there's no FPU present, or if the
-                          * application has already restricted
-                          * the allowed set to exclude any CPUs
-                          * with FPUs, we'll skip the procedure.
-                          */
-                         if (cpus_intersects(current->cpus_allowed,
-                                               mt_fpu_cpumask)) {
-                           cpumask_t tmask;
-
-                           cpus_and(tmask,
-                                       current->thread.user_cpus_allowed,
-                                       mt_fpu_cpumask);
-                           set_cpus_allowed(current, tmask);
-                           current->thread.mflags |= MF_FPUBOUND;
-                         }
-                        }
-                       }
-#endif /* CONFIG_MIPS_MT_FPAFF */
                }
 
                return;
 
        case 2:
        case 3:
-               die_if_kernel("do_cpu invoked from kernel context!", regs);
                break;
        }
 
@@ -819,62 +780,19 @@ asmlinkage void do_watch(struct pt_regs *regs)
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
-       const int field = 2 * sizeof(unsigned long);
-       int multi_match = regs->cp0_status & ST0_TS;
-
        show_regs(regs);
-
-       if (multi_match) {
-               printk("Index   : %0x\n", read_c0_index());
-               printk("Pagemask: %0x\n", read_c0_pagemask());
-               printk("EntryHi : %0*lx\n", field, read_c0_entryhi());
-               printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0());
-               printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1());
-               printk("\n");
-               dump_tlb_all();
-       }
-
-       show_code((unsigned int *) regs->cp0_epc);
-
+       dump_tlb_all();
        /*
         * Some chips may have other causes of machine check (e.g. SB1
         * graduation timer)
         */
        panic("Caught Machine Check exception - %scaused by multiple "
              "matching entries in the TLB.",
-             (multi_match) ? "" : "not ");
+             (regs->cp0_status & ST0_TS) ? "" : "not ");
 }
 
 asmlinkage void do_mt(struct pt_regs *regs)
 {
-       int subcode;
-
-       subcode = (read_vpe_c0_vpecontrol() & VPECONTROL_EXCPT)
-                       >> VPECONTROL_EXCPT_SHIFT;
-       switch (subcode) {
-       case 0:
-               printk(KERN_DEBUG "Thread Underflow\n");
-               break;
-       case 1:
-               printk(KERN_DEBUG "Thread Overflow\n");
-               break;
-       case 2:
-               printk(KERN_DEBUG "Invalid YIELD Qualifier\n");
-               break;
-       case 3:
-               printk(KERN_DEBUG "Gating Storage Exception\n");
-               break;
-       case 4:
-               printk(KERN_DEBUG "YIELD Scheduler Exception\n");
-               break;
-       case 5:
-               printk(KERN_DEBUG "Gating Storage Schedulier Exception\n");
-               break;
-       default:
-               printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n",
-                       subcode);
-               break;
-       }
        die_if_kernel("MIPS MT Thread exception in kernel", regs);
 
        force_sig(SIGILL, current);
@@ -915,7 +833,6 @@ static inline void parity_protection_init(void)
 {
        switch (current_cpu_data.cputype) {
        case CPU_24K:
-       case CPU_34K:
        case CPU_5KC:
                write_c0_ecc(0x80000000);
                back_to_back_c0_hazard();
@@ -980,10 +897,10 @@ void ejtag_exception_handler(struct pt_regs *regs)
        unsigned long depc, old_epc;
        unsigned int debug;
 
-       printk(KERN_DEBUG "SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
+       printk("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
        depc = read_c0_depc();
        debug = read_c0_debug();
-       printk(KERN_DEBUG "c0_depc = %0*lx, DEBUG = %08x\n", field, depc, debug);
+       printk("c0_depc = %0*lx, DEBUG = %08x\n", field, depc, debug);
        if (debug & 0x80000000) {
                /*
                 * In branch delay slot.
@@ -1001,7 +918,7 @@ void ejtag_exception_handler(struct pt_regs *regs)
        write_c0_depc(depc);
 
 #if 0
-       printk(KERN_DEBUG "\n\n----- Enable EJTAG single stepping ----\n\n");
+       printk("\n\n----- Enable EJTAG single stepping ----\n\n");
        write_c0_debug(debug | 0x100);
 #endif
 }
@@ -1011,15 +928,7 @@ void ejtag_exception_handler(struct pt_regs *regs)
  */
 void nmi_exception_handler(struct pt_regs *regs)
 {
-#ifdef CONFIG_MIPS_MT_SMTC
-       unsigned long dvpret = dvpe();
-       bust_spinlocks(1);
-       printk("NMI taken!!!!\n");
-       mips_mt_regdump(dvpret);
-#else
-       bust_spinlocks(1);
        printk("NMI taken!!!!\n");
-#endif /* CONFIG_MIPS_MT_SMTC */
        die("NMI", regs);
        while(1) ;
 }
@@ -1049,29 +958,29 @@ void *set_except_vector(int n, void *addr)
        return (void *)old_handler;
 }
 
-#ifdef CONFIG_CPU_MIPSR2_SRS
+#ifdef CONFIG_CPU_MIPSR2
 /*
- * MIPSR2 shadow register set allocation
+ * Shadow register allocation
  * FIXME: SMP...
  */
 
-static struct shadow_registers {
-       /*
-        * Number of shadow register sets supported
-        */
-       unsigned long sr_supported;
-       /*
-        * Bitmap of allocated shadow registers
-        */
-       unsigned long sr_allocated;
+/* MIPSR2 shadow register sets */
+struct shadow_registers {
+       spinlock_t sr_lock;     /*  */
+       int sr_supported;       /* Number of shadow register sets supported */
+       int sr_allocated;       /* Bitmap of allocated shadow registers */
 } shadow_registers;
 
-static void mips_srs_init(void)
+void mips_srs_init(void)
 {
+#ifdef CONFIG_CPU_MIPSR2_SRS
        shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
-       printk(KERN_INFO "%d MIPSR2 register sets available\n",
-              shadow_registers.sr_supported);
+       printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported);
+#else
+       shadow_registers.sr_supported = 1;
+#endif
        shadow_registers.sr_allocated = 1;      /* Set 0 used by kernel */
+       spin_lock_init(&shadow_registers.sr_lock);
 }
 
 int mips_srs_max(void)
@@ -1079,30 +988,38 @@ int mips_srs_max(void)
        return shadow_registers.sr_supported;
 }
 
-int mips_srs_alloc(void)
+int mips_srs_alloc (void)
 {
        struct shadow_registers *sr = &shadow_registers;
+       unsigned long flags;
        int set;
 
-again:
-       set = find_first_zero_bit(&sr->sr_allocated, sr->sr_supported);
-       if (set >= sr->sr_supported)
-               return -1;
+       spin_lock_irqsave(&sr->sr_lock, flags);
 
-       if (test_and_set_bit(set, &sr->sr_allocated))
-               goto again;
+       for (set = 0; set < sr->sr_supported; set++) {
+               if ((sr->sr_allocated & (1 << set)) == 0) {
+                       sr->sr_allocated |= 1 << set;
+                       spin_unlock_irqrestore(&sr->sr_lock, flags);
+                       return set;
+               }
+       }
 
-       return set;
+       /* None available */
+       spin_unlock_irqrestore(&sr->sr_lock, flags);
+       return -1;
 }
 
-void mips_srs_free(int set)
+void mips_srs_free (int set)
 {
        struct shadow_registers *sr = &shadow_registers;
+       unsigned long flags;
 
-       clear_bit(set, &sr->sr_allocated);
+       spin_lock_irqsave(&sr->sr_lock, flags);
+       sr->sr_allocated &= ~(1 << set);
+       spin_unlock_irqrestore(&sr->sr_lock, flags);
 }
 
-static void *set_vi_srs_handler(int n, void *addr, int srs)
+void *set_vi_srs_handler (int n, void *addr, int srs)
 {
        unsigned long handler;
        unsigned long old_handler = vi_handlers[n];
@@ -1115,7 +1032,8 @@ static void *set_vi_srs_handler(int n, void *addr, int srs)
        if (addr == NULL) {
                handler = (unsigned long) do_default_vi;
                srs = 0;
-       } else
+       }
+       else
                handler = (unsigned long) addr;
        vi_handlers[n] = (unsigned long) addr;
 
@@ -1127,7 +1045,8 @@ static void *set_vi_srs_handler(int n, void *addr, int srs)
        if (cpu_has_veic) {
                if (board_bind_eic_interrupt)
                        board_bind_eic_interrupt (n, srs);
-       } else if (cpu_has_vint) {
+       }
+       else if (cpu_has_vint) {
                /* SRSMap is only defined if shadow sets are implemented */
                if (mips_srs_max() > 1)
                        change_c0_srsmap (0xf << n*4, srs << n*4);
@@ -1141,15 +1060,6 @@ static void *set_vi_srs_handler(int n, void *addr, int srs)
 
                extern char except_vec_vi, except_vec_vi_lui;
                extern char except_vec_vi_ori, except_vec_vi_end;
-#ifdef CONFIG_MIPS_MT_SMTC
-               /*
-                * We need to provide the SMTC vectored interrupt handler
-                * not only with the address of the handler, but with the
-                * Status.IM bit to be masked before going there.
-                */
-               extern char except_vec_vi_mori;
-               const int mori_offset = &except_vec_vi_mori - &except_vec_vi;
-#endif /* CONFIG_MIPS_MT_SMTC */
                const int handler_len = &except_vec_vi_end - &except_vec_vi;
                const int lui_offset = &except_vec_vi_lui - &except_vec_vi;
                const int ori_offset = &except_vec_vi_ori - &except_vec_vi;
@@ -1163,12 +1073,6 @@ static void *set_vi_srs_handler(int n, void *addr, int srs)
                }
 
                memcpy (b, &except_vec_vi, handler_len);
-#ifdef CONFIG_MIPS_MT_SMTC
-               if (n > 7)
-                       printk("Vector index %d exceeds SMTC maximum\n", n);
-               w = (u32 *)(b + mori_offset);
-               *w = (*w & 0xffff0000) | (0x100 << n);
-#endif /* CONFIG_MIPS_MT_SMTC */
                w = (u32 *)(b + lui_offset);
                *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
                w = (u32 *)(b + ori_offset);
@@ -1191,18 +1095,11 @@ static void *set_vi_srs_handler(int n, void *addr, int srs)
        return (void *)old_handler;
 }
 
-void *set_vi_handler(int n, void *addr)
+void *set_vi_handler (int n, void *addr)
 {
-       return set_vi_srs_handler(n, addr, 0);
+       return set_vi_srs_handler (n, addr, 0);
 }
-
-#else
-
-static inline void mips_srs_init(void)
-{
-}
-
-#endif /* CONFIG_CPU_MIPSR2_SRS */
+#endif
 
 /*
  * This is used by native signal handling
@@ -1216,29 +1113,8 @@ extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
 extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
 extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
 
-#ifdef CONFIG_SMP
-static int smp_save_fp_context(struct sigcontext *sc)
-{
-       return cpu_has_fpu
-              ? _save_fp_context(sc)
-              : fpu_emulator_save_context(sc);
-}
-
-static int smp_restore_fp_context(struct sigcontext *sc)
-{
-       return cpu_has_fpu
-              ? _restore_fp_context(sc)
-              : fpu_emulator_restore_context(sc);
-}
-#endif
-
 static inline void signal_init(void)
 {
-#ifdef CONFIG_SMP
-       /* For now just do the cpu_has_fpu check when the functions are invoked */
-       save_fp_context = smp_save_fp_context;
-       restore_fp_context = smp_restore_fp_context;
-#else
        if (cpu_has_fpu) {
                save_fp_context = _save_fp_context;
                restore_fp_context = _restore_fp_context;
@@ -1246,7 +1122,6 @@ static inline void signal_init(void)
                save_fp_context = fpu_emulator_save_context;
                restore_fp_context = fpu_emulator_restore_context;
        }
-#endif
 }
 
 #ifdef CONFIG_MIPS32_COMPAT
@@ -1283,20 +1158,6 @@ void __init per_cpu_trap_init(void)
 {
        unsigned int cpu = smp_processor_id();
        unsigned int status_set = ST0_CU0;
-#ifdef CONFIG_MIPS_MT_SMTC
-       int secondaryTC = 0;
-       int bootTC = (cpu == 0);
-
-       /*
-        * Only do per_cpu_trap_init() for first TC of Each VPE.
-        * Note that this hack assumes that the SMTC init code
-        * assigns TCs consecutively and in ascending order.
-        */
-
-       if (((read_c0_tcbind() & TCBIND_CURTC) != 0) &&
-           ((read_c0_tcbind() & TCBIND_CURVPE) == cpu_data[cpu - 1].vpe_id))
-               secondaryTC = 1;
-#endif /* CONFIG_MIPS_MT_SMTC */
 
        /*
         * Disable coprocessors and select 32-bit or 64-bit addressing
@@ -1319,10 +1180,6 @@ void __init per_cpu_trap_init(void)
        write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */
 #endif
 
-#ifdef CONFIG_MIPS_MT_SMTC
-       if (!secondaryTC) {
-#endif /* CONFIG_MIPS_MT_SMTC */
-
        /*
         * Interrupt handling.
         */
@@ -1339,9 +1196,6 @@ void __init per_cpu_trap_init(void)
                } else
                        set_c0_cause(CAUSEF_IV);
        }
-#ifdef CONFIG_MIPS_MT_SMTC
-       }
-#endif /* CONFIG_MIPS_MT_SMTC */
 
        cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
        TLBMISS_HANDLER_SETUP();
@@ -1351,14 +1205,8 @@ void __init per_cpu_trap_init(void)
        BUG_ON(current->mm);
        enter_lazy_tlb(&init_mm, current);
 
-#ifdef CONFIG_MIPS_MT_SMTC
-       if (bootTC) {
-#endif /* CONFIG_MIPS_MT_SMTC */
-               cpu_cache_init();
-               tlb_init();
-#ifdef CONFIG_MIPS_MT_SMTC
-       }
-#endif /* CONFIG_MIPS_MT_SMTC */
+       cpu_cache_init();
+       tlb_init();
 }
 
 /* Install CPU exception handler */
@@ -1392,7 +1240,9 @@ void __init trap_init(void)
        else
                ebase = CAC_BASE;
 
+#ifdef CONFIG_CPU_MIPSR2
        mips_srs_init();
+#endif
 
        per_cpu_trap_init();
 
@@ -1428,7 +1278,7 @@ void __init trap_init(void)
        if (cpu_has_veic || cpu_has_vint) {
                int nvec = cpu_has_veic ? 64 : 8;
                for (i = 0; i < nvec; i++)
-                       set_vi_handler(i, NULL);
+                       set_vi_handler (i, NULL);
        }
        else if (cpu_has_divec)
                set_handler(0x200, &except_vec4, 0x8);
@@ -1447,7 +1297,6 @@ void __init trap_init(void)
        if (board_be_init)
                board_be_init();
 
-       set_except_vector(0, handle_int);
        set_except_vector(1, handle_tlbm);
        set_except_vector(2, handle_tlbl);
        set_except_vector(3, handle_tlbs);