OSDN Git Service

MIPS: OCTEON: Enable use of FPU
authorDavid Daney <david.daney@cavium.com>
Wed, 28 May 2014 21:52:04 +0000 (23:52 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 30 May 2014 19:01:09 +0000 (21:01 +0200)
Some versions of the assembler will not assemble CFC1 for OCTEON, so
override the ISA for these.

Add r4k_fpu.o to handle low level FPU initialization.

Modify octeon_switch.S to save the FPU registers.  And include
r4k_switch.S to pick up more FPU support.

Get rid of "#define cpu_has_fpu 0"

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Andreas Herrmann <andreas.herrmann@caviumnetworks.com>
Cc: linux-mips@linux-mips.org
Cc: James Hogan <james.hogan@imgtec.com>
Cc: kvm@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7006/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
arch/mips/kernel/Makefile
arch/mips/kernel/branch.c
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/math-emu/cp1emu.c

index 94ed063..cf80228 100644 (file)
@@ -22,7 +22,6 @@
 #define cpu_has_3k_cache       0
 #define cpu_has_4k_cache       0
 #define cpu_has_tx39_cache     0
-#define cpu_has_fpu            0
 #define cpu_has_counter                1
 #define cpu_has_watch          1
 #define cpu_has_divec          1
index a61d108..008a2fe 100644 (file)
@@ -41,7 +41,7 @@ obj-$(CONFIG_CPU_R4K_FPU)     += r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_R3000)                += r2300_fpu.o r2300_switch.o
 obj-$(CONFIG_CPU_R6000)                += r6000_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_TX39XX)       += r2300_fpu.o r2300_switch.o
-obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o
+obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += r4k_fpu.o octeon_switch.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SMP_UP)           += smp-up.o
index 84888d9..e198d9b 100644 (file)
@@ -562,7 +562,11 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
        case cop1_op:
                preempt_disable();
                if (is_fpu_owner())
-                       asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+                       asm volatile(
+                               ".set push\n"
+                               "\t.set mips1\n"
+                               "\tcfc1\t%0,$31\n"
+                               "\t.set pop" : "=r" (fcr31));
                else
                        fcr31 = current->thread.fpu.fcr31;
                preempt_enable();
index 029e002..f654768 100644 (file)
  * Copyright (C) 2000 MIPS Technologies, Inc.
  *    written by Carsten Langgaard, carstenl@mips.com
  */
-#include <asm/asm.h>
-#include <asm/cachectl.h>
-#include <asm/fpregdef.h>
-#include <asm/mipsregs.h>
-#include <asm/asm-offsets.h>
-#include <asm/pgtable-bits.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-#include <asm/thread_info.h>
-
-#include <asm/asmmacro.h>
-
-/*
- * Offset to the current process status flags, the first 32 bytes of the
- * stack are not used.
- */
-#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
 
+#define USE_ALTERNATE_RESUME_IMPL 1
+       .set push
+       .set arch=mips64r2
+#include "r4k_switch.S"
+       .set pop
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
  *                    struct thread_info *next_ti, int usedfpu)
        cpu_save_nonscratch a0
        LONG_S  ra, THREAD_REG31(a0)
 
+       /*
+        * check if we need to save FPU registers
+        */
+       PTR_L   t3, TASK_THREAD_INFO(a0)
+       LONG_L  t0, TI_FLAGS(t3)
+       li      t1, _TIF_USEDFPU
+       and     t2, t0, t1
+       beqz    t2, 1f
+       nor     t1, zero, t1
+
+       and     t0, t0, t1
+       LONG_S  t0, TI_FLAGS(t3)
+
+       /*
+        * clear saved user stack CU1 bit
+        */
+       LONG_L  t0, ST_OFF(t3)
+       li      t1, ~ST0_CU1
+       and     t0, t0, t1
+       LONG_S  t0, ST_OFF(t3)
+
+       .set push
+       .set arch=mips64r2
+       fpu_save_double a0 t0 t1                # c0_status passed in t0
+                                               # clobbers t1
+       .set pop
+1:
+
+       /* check if we need to save COP2 registers */
+       PTR_L   t2, TASK_THREAD_INFO(a0)
+       LONG_L  t0, ST_OFF(t2)
+       bbit0   t0, 30, 1f
+
+       /* Disable COP2 in the stored process state */
+       li      t1, ST0_CU2
+       xor     t0, t1
+       LONG_S  t0, ST_OFF(t2)
+
+       /* Enable COP2 so we can save it */
+       mfc0    t0, CP0_STATUS
+       or      t0, t1
+       mtc0    t0, CP0_STATUS
+
+       /* Save COP2 */
+       daddu   a0, THREAD_CP2
+       jal octeon_cop2_save
+       dsubu   a0, THREAD_CP2
+
+       /* Disable COP2 now that we are done */
+       mfc0    t0, CP0_STATUS
+       li      t1, ST0_CU2
+       xor     t0, t1
+       mtc0    t0, CP0_STATUS
+
+1:
 #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
        /* Check if we need to store CVMSEG state */
        mfc0    t0, $11,7       /* CvmMemCtl */
        move    $28, a2
        cpu_restore_nonscratch a1
 
-#if (_THREAD_SIZE - 32) < 0x8000
-       PTR_ADDIU       t0, $28, _THREAD_SIZE - 32
-#else
-       PTR_LI          t0, _THREAD_SIZE - 32
-       PTR_ADDU        t0, $28
-#endif
+       PTR_ADDU        t0, $28, _THREAD_SIZE - 32
        set_saved_sp    t0, t1, t2
 
        mfc0    t1, CP0_STATUS          /* Do we really need this? */
index 547c522..81ca3f7 100644 (file)
@@ -28,6 +28,7 @@
  */
 #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
 
+#ifndef USE_ALTERNATE_RESUME_IMPL
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
  *                    struct thread_info *next_ti, s32 fp_save)
        jr      ra
        END(resume)
 
+#endif /* USE_ALTERNATE_RESUME_IMPL */
+
 /*
  * Save a thread's fp context.
  */
index cdfed28..736c17a 100644 (file)
@@ -584,7 +584,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                if (insn.i_format.rs == bc_op) {
                        preempt_disable();
                        if (is_fpu_owner())
-                               asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
+                               asm volatile(
+                                       ".set push\n"
+                                       "\t.set mips1\n"
+                                       "\tcfc1\t%0,$31\n"
+                                       "\t.set pop" : "=r" (fcr31));
                        else
                                fcr31 = current->thread.fpu.fcr31;
                        preempt_enable();