summaryrefslogtreecommitdiff
path: root/arch/nds32/include
diff options
context:
space:
mode:
Diffstat (limited to 'arch/nds32/include')
-rw-r--r--arch/nds32/include/asm/bitfield.h15
-rw-r--r--arch/nds32/include/asm/fpu.h114
-rw-r--r--arch/nds32/include/asm/processor.h7
-rw-r--r--arch/nds32/include/uapi/asm/sigcontext.h5
4 files changed, 141 insertions, 0 deletions
diff --git a/arch/nds32/include/asm/bitfield.h b/arch/nds32/include/asm/bitfield.h
index 19b2841219ad..c1619730192a 100644
--- a/arch/nds32/include/asm/bitfield.h
+++ b/arch/nds32/include/asm/bitfield.h
@@ -251,6 +251,11 @@
#define ITYPE_mskSTYPE ( 0xF << ITYPE_offSTYPE )
#define ITYPE_mskCPID ( 0x3 << ITYPE_offCPID )
+/* Additional definitions of ITYPE register for FPU */
+#define FPU_DISABLE_EXCEPTION (0x1 << ITYPE_offSTYPE)
+#define FPU_EXCEPTION (0x2 << ITYPE_offSTYPE)
+#define FPU_CPID 0 /* FPU Co-Processor ID is 0 */
+
#define NDS32_VECTOR_mskNONEXCEPTION 0x78
#define NDS32_VECTOR_offEXCEPTION 8
#define NDS32_VECTOR_offINTERRUPT 9
@@ -926,6 +931,7 @@
#define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT )
#define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT )
#define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX)
+#define FPCSR_mskALLE_NO_UDFE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskIEXE)
#define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE)
#define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT)
@@ -946,6 +952,15 @@
#define FPCFG_mskIMVER ( 0x1F << FPCFG_offIMVER )
#define FPCFG_mskAVER ( 0x1F << FPCFG_offAVER )
+/* 8 Single precision or 4 double precision registers are available */
+#define SP8_DP4_reg 0
+/* 16 Single precision or 8 double precision registers are available */
+#define SP16_DP8_reg 1
+/* 32 Single precision or 16 double precision registers are available */
+#define SP32_DP16_reg 2
+/* 32 Single precision or 32 double precision registers are available */
+#define SP32_DP32_reg 3
+
/******************************************************************************
* fucpr: FUCOP_CTL (FPU and Coprocessor Enable Control Register)
*****************************************************************************/
diff --git a/arch/nds32/include/asm/fpu.h b/arch/nds32/include/asm/fpu.h
new file mode 100644
index 000000000000..f7a7f6b2ea8f
--- /dev/null
+++ b/arch/nds32/include/asm/fpu.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2005-2018 Andes Technology Corporation */
+
+#ifndef __ASM_NDS32_FPU_H
+#define __ASM_NDS32_FPU_H
+
+#if IS_ENABLED(CONFIG_FPU)
+#ifndef __ASSEMBLY__
+#include <linux/sched/task_stack.h>
+#include <linux/preempt.h>
+#include <asm/ptrace.h>
+
+extern bool has_fpu;
+
+extern void save_fpu(struct task_struct *__tsk);
+extern void load_fpu(const struct fpu_struct *fpregs);
+extern bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs);
+
+#define test_tsk_fpu(regs) (regs->fucop_ctl & FUCOP_CTL_mskCP0EN)
+
+/*
+ * Initially load the FPU with signalling NANS. This bit pattern
+ * has the property that no matter whether considered as single or as
+ * double precision, it still represents a signalling NAN.
+ */
+
+#define sNAN64 0xFFFFFFFFFFFFFFFFULL
+#define sNAN32 0xFFFFFFFFUL
+
+#define FPCSR_INIT 0x0UL
+
+extern const struct fpu_struct init_fpuregs;
+
+static inline void disable_ptreg_fpu(struct pt_regs *regs)
+{
+ regs->fucop_ctl &= ~FUCOP_CTL_mskCP0EN;
+}
+
+static inline void enable_ptreg_fpu(struct pt_regs *regs)
+{
+ regs->fucop_ctl |= FUCOP_CTL_mskCP0EN;
+}
+
+static inline void enable_fpu(void)
+{
+ unsigned long fucop_ctl;
+
+ fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) | FUCOP_CTL_mskCP0EN;
+ __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
+ __nds32__isb();
+}
+
+static inline void disable_fpu(void)
+{
+ unsigned long fucop_ctl;
+
+ fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) & ~FUCOP_CTL_mskCP0EN;
+ __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
+ __nds32__isb();
+}
+
+static inline void lose_fpu(void)
+{
+ preempt_disable();
+#if IS_ENABLED(CONFIG_LAZY_FPU)
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+#else
+ if (test_tsk_fpu(task_pt_regs(current))) {
+#endif
+ save_fpu(current);
+ }
+ disable_ptreg_fpu(task_pt_regs(current));
+ preempt_enable();
+}
+
+static inline void own_fpu(void)
+{
+ preempt_disable();
+#if IS_ENABLED(CONFIG_LAZY_FPU)
+ if (last_task_used_math != current) {
+ if (last_task_used_math != NULL)
+ save_fpu(last_task_used_math);
+ load_fpu(&current->thread.fpu);
+ last_task_used_math = current;
+ }
+#else
+ if (!test_tsk_fpu(task_pt_regs(current))) {
+ load_fpu(&current->thread.fpu);
+ }
+#endif
+ enable_ptreg_fpu(task_pt_regs(current));
+ preempt_enable();
+}
+
+#if !IS_ENABLED(CONFIG_LAZY_FPU)
+static inline void unlazy_fpu(struct task_struct *tsk)
+{
+ preempt_disable();
+ if (test_tsk_fpu(task_pt_regs(tsk)))
+ save_fpu(tsk);
+ preempt_enable();
+}
+#endif /* !CONFIG_LAZY_FPU */
+static inline void clear_fpu(struct pt_regs *regs)
+{
+ preempt_disable();
+ if (test_tsk_fpu(regs))
+ disable_ptreg_fpu(regs);
+ preempt_enable();
+}
+#endif /* CONFIG_FPU */
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_NDS32_FPU_H */
diff --git a/arch/nds32/include/asm/processor.h b/arch/nds32/include/asm/processor.h
index c2660f566bac..72024f8bc129 100644
--- a/arch/nds32/include/asm/processor.h
+++ b/arch/nds32/include/asm/processor.h
@@ -35,6 +35,8 @@ struct thread_struct {
unsigned long address;
unsigned long trap_no;
unsigned long error_code;
+
+ struct fpu_struct fpu;
};
#define INIT_THREAD { }
@@ -72,6 +74,11 @@ struct task_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
+#if IS_ENABLED(CONFIG_FPU)
+#if !IS_ENABLED(CONFIG_UNLAZU_FPU)
+extern struct task_struct *last_task_used_math;
+#endif
+#endif
/* Prepare to copy thread state - unlazy all lazy status */
#define prepare_to_copy(tsk) do { } while (0)
diff --git a/arch/nds32/include/uapi/asm/sigcontext.h b/arch/nds32/include/uapi/asm/sigcontext.h
index 00567b237b0c..1257a78e3ae1 100644
--- a/arch/nds32/include/uapi/asm/sigcontext.h
+++ b/arch/nds32/include/uapi/asm/sigcontext.h
@@ -9,6 +9,10 @@
* before the signal handler was invoked. Note: only add new entries
* to the end of the structure.
*/
+struct fpu_struct {
+ unsigned long long fd_regs[32];
+ unsigned long fpcsr;
+};
struct zol_struct {
unsigned long nds32_lc; /* $LC */
@@ -54,6 +58,7 @@ struct sigcontext {
unsigned long fault_address;
unsigned long used_math_flag;
/* FPU Registers */
+ struct fpu_struct fpu;
struct zol_struct zol;
};