Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

David Daney and committed by
Ralf Baechle
a36d8225 dadaa1c2

+75 -27
-1
arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
··· 22 22 #define cpu_has_3k_cache 0 23 23 #define cpu_has_4k_cache 0 24 24 #define cpu_has_tx39_cache 0 25 - #define cpu_has_fpu 0 26 25 #define cpu_has_counter 1 27 26 #define cpu_has_watch 1 28 27 #define cpu_has_divec 1
+1 -1
arch/mips/kernel/Makefile
··· 41 41 obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o 42 42 obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o 43 43 obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o 44 - obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o 44 + obj-$(CONFIG_CPU_CAVIUM_OCTEON) += r4k_fpu.o octeon_switch.o 45 45 46 46 obj-$(CONFIG_SMP) += smp.o 47 47 obj-$(CONFIG_SMP_UP) += smp-up.o
+5 -1
arch/mips/kernel/branch.c
··· 562 562 case cop1_op: 563 563 preempt_disable(); 564 564 if (is_fpu_owner()) 565 - asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); 565 + asm volatile( 566 + ".set push\n" 567 + "\t.set mips1\n" 568 + "\tcfc1\t%0,$31\n" 569 + "\t.set pop" : "=r" (fcr31)); 566 570 else 567 571 fcr31 = current->thread.fpu.fcr31; 568 572 preempt_enable();
+61 -23
arch/mips/kernel/octeon_switch.S
··· 10 10 * Copyright (C) 2000 MIPS Technologies, Inc. 11 11 * written by Carsten Langgaard, carstenl@mips.com 12 12 */ 13 - #include <asm/asm.h> 14 - #include <asm/cachectl.h> 15 - #include <asm/fpregdef.h> 16 - #include <asm/mipsregs.h> 17 - #include <asm/asm-offsets.h> 18 - #include <asm/pgtable-bits.h> 19 - #include <asm/regdef.h> 20 - #include <asm/stackframe.h> 21 - #include <asm/thread_info.h> 22 13 23 - #include <asm/asmmacro.h> 24 - 25 - /* 26 - * Offset to the current process status flags, the first 32 bytes of the 27 - * stack are not used. 28 - */ 29 - #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) 30 - 14 + #define USE_ALTERNATE_RESUME_IMPL 1 15 + .set push 16 + .set arch=mips64r2 17 + #include "r4k_switch.S" 18 + .set pop 31 19 /* 32 20 * task_struct *resume(task_struct *prev, task_struct *next, 33 21 * struct thread_info *next_ti, int usedfpu) ··· 28 40 cpu_save_nonscratch a0 29 41 LONG_S ra, THREAD_REG31(a0) 30 42 43 + /* 44 + * check if we need to save FPU registers 45 + */ 46 + PTR_L t3, TASK_THREAD_INFO(a0) 47 + LONG_L t0, TI_FLAGS(t3) 48 + li t1, _TIF_USEDFPU 49 + and t2, t0, t1 50 + beqz t2, 1f 51 + nor t1, zero, t1 52 + 53 + and t0, t0, t1 54 + LONG_S t0, TI_FLAGS(t3) 55 + 56 + /* 57 + * clear saved user stack CU1 bit 58 + */ 59 + LONG_L t0, ST_OFF(t3) 60 + li t1, ~ST0_CU1 61 + and t0, t0, t1 62 + LONG_S t0, ST_OFF(t3) 63 + 64 + .set push 65 + .set arch=mips64r2 66 + fpu_save_double a0 t0 t1 # c0_status passed in t0 67 + # clobbers t1 68 + .set pop 69 + 1: 70 + 71 + /* check if we need to save COP2 registers */ 72 + PTR_L t2, TASK_THREAD_INFO(a0) 73 + LONG_L t0, ST_OFF(t2) 74 + bbit0 t0, 30, 1f 75 + 76 + /* Disable COP2 in the stored process state */ 77 + li t1, ST0_CU2 78 + xor t0, t1 79 + LONG_S t0, ST_OFF(t2) 80 + 81 + /* Enable COP2 so we can save it */ 82 + mfc0 t0, CP0_STATUS 83 + or t0, t1 84 + mtc0 t0, CP0_STATUS 85 + 86 + /* Save COP2 */ 87 + daddu a0, THREAD_CP2 88 + jal octeon_cop2_save 89 + dsubu a0, THREAD_CP2 90 + 91 + /* Disable COP2 now that we are done */ 92 + mfc0 t0, CP0_STATUS 93 + li t1, ST0_CU2 94 + xor t0, t1 95 + mtc0 t0, CP0_STATUS 96 + 97 + 1: 31 98 #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 32 99 /* Check if we need to store CVMSEG state */ 33 100 mfc0 t0, $11,7 /* CvmMemCtl */ ··· 128 85 move $28, a2 129 86 cpu_restore_nonscratch a1 130 87 131 - #if (_THREAD_SIZE - 32) < 0x8000 132 - PTR_ADDIU t0, $28, _THREAD_SIZE - 32 133 - #else 134 - PTR_LI t0, _THREAD_SIZE - 32 135 - PTR_ADDU t0, $28 136 - #endif 88 + PTR_ADDU t0, $28, _THREAD_SIZE - 32 137 89 set_saved_sp t0, t1, t2 138 90 139 91 mfc0 t1, CP0_STATUS /* Do we really need this? */
+3
arch/mips/kernel/r4k_switch.S
··· 28 28 */ 29 29 #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS) 30 30 31 + #ifndef USE_ALTERNATE_RESUME_IMPL 31 32 /* 32 33 * task_struct *resume(task_struct *prev, task_struct *next, 33 34 * struct thread_info *next_ti, s32 fp_save) ··· 99 98 move v0, a0 100 99 jr ra 101 100 END(resume) 101 + 102 + #endif /* USE_ALTERNATE_RESUME_IMPL */ 102 103 103 104 /* 104 105 * Save a thread's fp context.
+5 -1
arch/mips/math-emu/cp1emu.c
··· 584 584 if (insn.i_format.rs == bc_op) { 585 585 preempt_disable(); 586 586 if (is_fpu_owner()) 587 - asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); 587 + asm volatile( 588 + ".set push\n" 589 + "\t.set mips1\n" 590 + "\tcfc1\t%0,$31\n" 591 + "\t.set pop" : "=r" (fcr31)); 588 592 else 589 593 fcr31 = current->thread.fpu.fcr31; 590 594 preempt_enable();