blob: 8294ed4aaa2cc950aec294aa69d50c16ee7f443d [file] [log] [blame]
David Brazdil0f672f62019-12-10 10:32:29 +00001/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (C) 2005-2018 Andes Technology Corporation */
3
4#ifndef __ASM_NDS32_FPU_H
5#define __ASM_NDS32_FPU_H
6
7#if IS_ENABLED(CONFIG_FPU)
8#ifndef __ASSEMBLY__
9#include <linux/sched/task_stack.h>
10#include <linux/preempt.h>
11#include <asm/ptrace.h>
12
13extern bool has_fpu;
14
15extern void save_fpu(struct task_struct *__tsk);
16extern void load_fpu(const struct fpu_struct *fpregs);
17extern bool do_fpu_exception(unsigned int subtype, struct pt_regs *regs);
18extern int do_fpuemu(struct pt_regs *regs, struct fpu_struct *fpu);
19
20#define test_tsk_fpu(regs) (regs->fucop_ctl & FUCOP_CTL_mskCP0EN)
21
22/*
23 * Initially load the FPU with signalling NANS. This bit pattern
24 * has the property that no matter whether considered as single or as
25 * double precision, it still represents a signalling NAN.
26 */
27
28#define sNAN64 0xFFFFFFFFFFFFFFFFULL
29#define sNAN32 0xFFFFFFFFUL
30
31#if IS_ENABLED(CONFIG_SUPPORT_DENORMAL_ARITHMETIC)
32/*
33 * Denormalized number is unsupported by nds32 FPU. Hence the operation
34 * is treated as underflow cases when the final result is a denormalized
35 * number. To enhance precision, underflow exception trap should be
36 * enabled by default and kerenl will re-execute it by fpu emulator
37 * when getting underflow exception.
38 */
39#define FPCSR_INIT (FPCSR_mskUDFE | FPCSR_mskIEXE)
40#else
41#define FPCSR_INIT 0x0UL
42#endif
43
44extern const struct fpu_struct init_fpuregs;
45
46static inline void disable_ptreg_fpu(struct pt_regs *regs)
47{
48 regs->fucop_ctl &= ~FUCOP_CTL_mskCP0EN;
49}
50
51static inline void enable_ptreg_fpu(struct pt_regs *regs)
52{
53 regs->fucop_ctl |= FUCOP_CTL_mskCP0EN;
54}
55
56static inline void enable_fpu(void)
57{
58 unsigned long fucop_ctl;
59
60 fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) | FUCOP_CTL_mskCP0EN;
61 __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
62 __nds32__isb();
63}
64
65static inline void disable_fpu(void)
66{
67 unsigned long fucop_ctl;
68
69 fucop_ctl = __nds32__mfsr(NDS32_SR_FUCOP_CTL) & ~FUCOP_CTL_mskCP0EN;
70 __nds32__mtsr(fucop_ctl, NDS32_SR_FUCOP_CTL);
71 __nds32__isb();
72}
73
74static inline void lose_fpu(void)
75{
76 preempt_disable();
77#if IS_ENABLED(CONFIG_LAZY_FPU)
78 if (last_task_used_math == current) {
79 last_task_used_math = NULL;
80#else
81 if (test_tsk_fpu(task_pt_regs(current))) {
82#endif
83 save_fpu(current);
84 }
85 disable_ptreg_fpu(task_pt_regs(current));
86 preempt_enable();
87}
88
89static inline void own_fpu(void)
90{
91 preempt_disable();
92#if IS_ENABLED(CONFIG_LAZY_FPU)
93 if (last_task_used_math != current) {
94 if (last_task_used_math != NULL)
95 save_fpu(last_task_used_math);
96 load_fpu(&current->thread.fpu);
97 last_task_used_math = current;
98 }
99#else
100 if (!test_tsk_fpu(task_pt_regs(current))) {
101 load_fpu(&current->thread.fpu);
102 }
103#endif
104 enable_ptreg_fpu(task_pt_regs(current));
105 preempt_enable();
106}
107
108#if !IS_ENABLED(CONFIG_LAZY_FPU)
109static inline void unlazy_fpu(struct task_struct *tsk)
110{
111 preempt_disable();
112 if (test_tsk_fpu(task_pt_regs(tsk)))
113 save_fpu(tsk);
114 preempt_enable();
115}
116#endif /* !CONFIG_LAZY_FPU */
117static inline void clear_fpu(struct pt_regs *regs)
118{
119 preempt_disable();
120 if (test_tsk_fpu(regs))
121 disable_ptreg_fpu(regs);
122 preempt_enable();
123}
124#endif /* CONFIG_FPU */
125#endif /* __ASSEMBLY__ */
126#endif /* __ASM_NDS32_FPU_H */