forked from Minki/linux
MIPS: OCTEON: Enable use of FPU
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>
This commit is contained in:
parent
dadaa1c2c0
commit
a36d8225bc
@ -22,7 +22,6 @@
|
|||||||
#define cpu_has_3k_cache 0
|
#define cpu_has_3k_cache 0
|
||||||
#define cpu_has_4k_cache 0
|
#define cpu_has_4k_cache 0
|
||||||
#define cpu_has_tx39_cache 0
|
#define cpu_has_tx39_cache 0
|
||||||
#define cpu_has_fpu 0
|
|
||||||
#define cpu_has_counter 1
|
#define cpu_has_counter 1
|
||||||
#define cpu_has_watch 1
|
#define cpu_has_watch 1
|
||||||
#define cpu_has_divec 1
|
#define cpu_has_divec 1
|
||||||
|
@ -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_R3000) += r2300_fpu.o r2300_switch.o
|
||||||
obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_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_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) += smp.o
|
||||||
obj-$(CONFIG_SMP_UP) += smp-up.o
|
obj-$(CONFIG_SMP_UP) += smp-up.o
|
||||||
|
@ -562,7 +562,11 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
|
|||||||
case cop1_op:
|
case cop1_op:
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
if (is_fpu_owner())
|
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
|
else
|
||||||
fcr31 = current->thread.fpu.fcr31;
|
fcr31 = current->thread.fpu.fcr31;
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
@ -10,24 +10,12 @@
|
|||||||
* Copyright (C) 2000 MIPS Technologies, Inc.
|
* Copyright (C) 2000 MIPS Technologies, Inc.
|
||||||
* written by Carsten Langgaard, carstenl@mips.com
|
* 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,
|
* task_struct *resume(task_struct *prev, task_struct *next,
|
||||||
* struct thread_info *next_ti, int usedfpu)
|
* struct thread_info *next_ti, int usedfpu)
|
||||||
@ -40,6 +28,61 @@
|
|||||||
cpu_save_nonscratch a0
|
cpu_save_nonscratch a0
|
||||||
LONG_S ra, THREAD_REG31(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
|
#if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
|
||||||
/* Check if we need to store CVMSEG state */
|
/* Check if we need to store CVMSEG state */
|
||||||
mfc0 t0, $11,7 /* CvmMemCtl */
|
mfc0 t0, $11,7 /* CvmMemCtl */
|
||||||
@ -85,12 +128,7 @@
|
|||||||
move $28, a2
|
move $28, a2
|
||||||
cpu_restore_nonscratch a1
|
cpu_restore_nonscratch a1
|
||||||
|
|
||||||
#if (_THREAD_SIZE - 32) < 0x8000
|
PTR_ADDU t0, $28, _THREAD_SIZE - 32
|
||||||
PTR_ADDIU t0, $28, _THREAD_SIZE - 32
|
|
||||||
#else
|
|
||||||
PTR_LI t0, _THREAD_SIZE - 32
|
|
||||||
PTR_ADDU t0, $28
|
|
||||||
#endif
|
|
||||||
set_saved_sp t0, t1, t2
|
set_saved_sp t0, t1, t2
|
||||||
|
|
||||||
mfc0 t1, CP0_STATUS /* Do we really need this? */
|
mfc0 t1, CP0_STATUS /* Do we really need this? */
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
|
#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
|
||||||
|
|
||||||
|
#ifndef USE_ALTERNATE_RESUME_IMPL
|
||||||
/*
|
/*
|
||||||
* task_struct *resume(task_struct *prev, task_struct *next,
|
* task_struct *resume(task_struct *prev, task_struct *next,
|
||||||
* struct thread_info *next_ti, s32 fp_save)
|
* struct thread_info *next_ti, s32 fp_save)
|
||||||
@ -99,6 +100,8 @@
|
|||||||
jr ra
|
jr ra
|
||||||
END(resume)
|
END(resume)
|
||||||
|
|
||||||
|
#endif /* USE_ALTERNATE_RESUME_IMPL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save a thread's fp context.
|
* Save a thread's fp context.
|
||||||
*/
|
*/
|
||||||
|
@ -584,7 +584,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
|
|||||||
if (insn.i_format.rs == bc_op) {
|
if (insn.i_format.rs == bc_op) {
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
if (is_fpu_owner())
|
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
|
else
|
||||||
fcr31 = current->thread.fpu.fcr31;
|
fcr31 = current->thread.fpu.fcr31;
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
Loading…
Reference in New Issue
Block a user