Loading...
Note: File does not exist in v3.5.6.
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Author: Huacai Chen <chenhuacai@loongson.cn>
4 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
5 */
6#ifndef _ASM_FPU_H
7#define _ASM_FPU_H
8
9#include <linux/sched.h>
10#include <linux/sched/task_stack.h>
11#include <linux/ptrace.h>
12#include <linux/thread_info.h>
13#include <linux/bitops.h>
14
15#include <asm/cpu.h>
16#include <asm/cpu-features.h>
17#include <asm/current.h>
18#include <asm/loongarch.h>
19#include <asm/processor.h>
20#include <asm/ptrace.h>
21
22struct sigcontext;
23
24extern void _init_fpu(unsigned int);
25extern void _save_fp(struct loongarch_fpu *);
26extern void _restore_fp(struct loongarch_fpu *);
27
28/*
29 * Mask the FCSR Cause bits according to the Enable bits, observing
30 * that Unimplemented is always enabled.
31 */
32static inline unsigned long mask_fcsr_x(unsigned long fcsr)
33{
34 return fcsr & ((fcsr & FPU_CSR_ALL_E) <<
35 (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E)));
36}
37
38static inline int is_fp_enabled(void)
39{
40 return (csr_read32(LOONGARCH_CSR_EUEN) & CSR_EUEN_FPEN) ?
41 1 : 0;
42}
43
44#define enable_fpu() set_csr_euen(CSR_EUEN_FPEN)
45
46#define disable_fpu() clear_csr_euen(CSR_EUEN_FPEN)
47
48#define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU)
49
50static inline int is_fpu_owner(void)
51{
52 return test_thread_flag(TIF_USEDFPU);
53}
54
55static inline void __own_fpu(void)
56{
57 enable_fpu();
58 set_thread_flag(TIF_USEDFPU);
59 KSTK_EUEN(current) |= CSR_EUEN_FPEN;
60}
61
62static inline void own_fpu_inatomic(int restore)
63{
64 if (cpu_has_fpu && !is_fpu_owner()) {
65 __own_fpu();
66 if (restore)
67 _restore_fp(¤t->thread.fpu);
68 }
69}
70
71static inline void own_fpu(int restore)
72{
73 preempt_disable();
74 own_fpu_inatomic(restore);
75 preempt_enable();
76}
77
78static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
79{
80 if (is_fpu_owner()) {
81 if (save)
82 _save_fp(&tsk->thread.fpu);
83 disable_fpu();
84 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
85 }
86 KSTK_EUEN(tsk) &= ~(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
87}
88
89static inline void lose_fpu(int save)
90{
91 preempt_disable();
92 lose_fpu_inatomic(save, current);
93 preempt_enable();
94}
95
96static inline void init_fpu(void)
97{
98 unsigned int fcsr = current->thread.fpu.fcsr;
99
100 __own_fpu();
101 _init_fpu(fcsr);
102 set_used_math();
103}
104
105static inline void save_fp(struct task_struct *tsk)
106{
107 if (cpu_has_fpu)
108 _save_fp(&tsk->thread.fpu);
109}
110
111static inline void restore_fp(struct task_struct *tsk)
112{
113 if (cpu_has_fpu)
114 _restore_fp(&tsk->thread.fpu);
115}
116
117static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
118{
119 if (tsk == current) {
120 preempt_disable();
121 if (is_fpu_owner())
122 _save_fp(¤t->thread.fpu);
123 preempt_enable();
124 }
125
126 return tsk->thread.fpu.fpr;
127}
128
129#endif /* _ASM_FPU_H */