upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / arch / mips / kernel / traps.c
index af1b42b..b7cfe61 100644 (file)
@@ -390,6 +390,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
                goto sig;
        }
 
+       preempt_disable();
+
        if (ll_task == NULL || ll_task == current) {
                ll_bit = 1;
        } else {
@@ -397,6 +399,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
        }
        ll_task = current;
 
+       preempt_enable();
+
        regs->regs[(opcode & RT) >> 16] = value;
 
        compute_return_epc(regs);
@@ -429,12 +433,18 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode)
                signal = SIGBUS;
                goto sig;
        }
+
+       preempt_disable();
+
        if (ll_bit == 0 || ll_task != current) {
                regs->regs[reg] = 0;
+               preempt_enable();
                compute_return_epc(regs);
                return;
        }
 
+       preempt_enable();
+
        if (put_user(regs->regs[reg], vaddr)) {
                signal = SIGSEGV;
                goto sig;
@@ -494,6 +504,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        if (fcr31 & FPU_CSR_UNI_X) {
                int sig;
 
+               preempt_disable();
+
                /*
                 * Unimplemented operation exception.  If we've got the full
                 * software emulator on-board, let's use it...
@@ -519,6 +531,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* Restore the hardware register state */
                restore_fp(current);
 
+               preempt_enable();
+
                /* If something went wrong, signal */
                if (sig)
                        force_sig(sig, current);
@@ -638,6 +652,8 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                break;
 
        case 1:
+               preempt_disable();
+
                own_fpu();
                if (current->used_math) {       /* Using the FPU again.  */
                        restore_fp(current);
@@ -653,6 +669,8 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                                force_sig(sig, current);
                }
 
+               preempt_enable();
+
                return;
 
        case 2:
@@ -892,15 +910,21 @@ extern void tlb_init(void);
 void __init per_cpu_trap_init(void)
 {
        unsigned int cpu = smp_processor_id();
+       unsigned int status_set = ST0_CU0;
 
-       /* Some firmware leaves the BEV flag set, clear it.  */
-       clear_c0_status(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV);
+       /*
+        * Disable coprocessors and select 32-bit or 64-bit addressing
+        * and the 16/32 or 32/32 FPR register model.  Reset the BEV
+        * flag that some firmware may have left set and the TS bit (for
+        * IP27).  Set XX for ISA IV code to work.
+        */
 #ifdef CONFIG_MIPS64
-       set_c0_status(ST0_CU0|ST0_FR|ST0_KX|ST0_SX|ST0_UX);
+       status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
 #endif
-
        if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
-               set_c0_status(ST0_XX);
+               status_set |= ST0_XX;
+       change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
+                        status_set);
 
        /*
         * Some MIPS CPUs have a dedicated interrupt vector which reduces the
@@ -1008,7 +1032,8 @@ void __init trap_init(void)
                set_except_vector(24, handle_mcheck);
 
        if (cpu_has_vce)
-               memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x80);
+               /* Special exception: R4[04]00 uses also the divec space. */
+               memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
        else if (cpu_has_4kex)
                memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
        else