Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / mips / kernel / branch.c
index 01117e9..b6232d9 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/branch.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm/fpu.h>
 #include <asm/inst.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
@@ -21,7 +22,7 @@
  */
 int __compute_return_epc(struct pt_regs *regs)
 {
-       unsigned int *addr, bit, fcr31;
+       unsigned int *addr, bit, fcr31, dspcontrol;
        long epc;
        union mips_instruction insn;
 
@@ -98,6 +99,18 @@ int __compute_return_epc(struct pt_regs *regs)
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
+               case bposge32_op:
+                       if (!cpu_has_dsp)
+                               goto sigill;
+
+                       dspcontrol = rddsp(0x01);
+
+                       if (dspcontrol >= 32) {
+                               epc = epc + 4 + (insn.i_format.simmediate << 2);
+                       } else
+                               epc += 8;
+                       regs->cp0_epc = epc;
+                       break;
                }
                break;
 
@@ -161,14 +174,17 @@ int __compute_return_epc(struct pt_regs *regs)
         * And now the FPA/cp1 branch instructions.
         */
        case cop1_op:
-               if (!cpu_has_fpu)
-                       fcr31 = current->thread.fpu.soft.fcr31;
-               else
+               preempt_disable();
+               if (is_fpu_owner())
                        asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+               else
+                       fcr31 = current->thread.fpu.hard.fcr31;
+               preempt_enable();
+
                bit = (insn.i_format.rt >> 2);
                bit += (bit != 0);
                bit += 23;
-               switch (insn.i_format.rt) {
+               switch (insn.i_format.rt & 3) {
                case 0: /* bc1f */
                case 2: /* bc1fl */
                        if (~fcr31 & (1 << bit))
@@ -196,4 +212,9 @@ unaligned:
        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
        force_sig(SIGBUS, current);
        return -EFAULT;
+
+sigill:
+       printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
+       force_sig(SIGBUS, current);
+       return -EFAULT;
 }