1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __ASM_ALPHA_FPU_H
3 #define __ASM_ALPHA_FPU_H
4 
5 #include <asm/special_insns.h>
6 #include <uapi/asm/fpu.h>
7 
8 /* The following two functions don't need trapb/excb instructions
9    around the mf_fpcr/mt_fpcr instructions because (a) the kernel
10    never generates arithmetic faults and (b) call_pal instructions
11    are implied trap barriers.  */
12 
13 static inline unsigned long
rdfpcr(void)14 rdfpcr(void)
15 {
16 	unsigned long tmp, ret;
17 
18 	preempt_disable();
19 	if (current_thread_info()->status & TS_SAVED_FP) {
20 		ret = current_thread_info()->fp[31];
21 	} else {
22 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
23 		__asm__ __volatile__ (
24 			"ftoit $f0,%0\n\t"
25 			"mf_fpcr $f0\n\t"
26 			"ftoit $f0,%1\n\t"
27 			"itoft %0,$f0"
28 			: "=r"(tmp), "=r"(ret));
29 #else
30 		__asm__ __volatile__ (
31 			"stt $f0,%0\n\t"
32 			"mf_fpcr $f0\n\t"
33 			"stt $f0,%1\n\t"
34 			"ldt $f0,%0"
35 			: "=m"(tmp), "=m"(ret));
36 #endif
37 	}
38 	preempt_enable();
39 
40 	return ret;
41 }
42 
43 static inline void
wrfpcr(unsigned long val)44 wrfpcr(unsigned long val)
45 {
46 	unsigned long tmp;
47 
48 	preempt_disable();
49 	if (current_thread_info()->status & TS_SAVED_FP) {
50 		current_thread_info()->status |= TS_RESTORE_FP;
51 		current_thread_info()->fp[31] = val;
52 	} else {
53 #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
54 		__asm__ __volatile__ (
55 			"ftoit $f0,%0\n\t"
56 			"itoft %1,$f0\n\t"
57 			"mt_fpcr $f0\n\t"
58 			"itoft %0,$f0"
59 			: "=&r"(tmp) : "r"(val));
60 #else
61 		__asm__ __volatile__ (
62 			"stt $f0,%0\n\t"
63 			"ldt $f0,%1\n\t"
64 			"mt_fpcr $f0\n\t"
65 			"ldt $f0,%0"
66 			: "=m"(tmp) : "m"(val));
67 #endif
68 	}
69 	preempt_enable();
70 }
71 
72 static inline unsigned long
swcr_update_status(unsigned long swcr,unsigned long fpcr)73 swcr_update_status(unsigned long swcr, unsigned long fpcr)
74 {
75 	/* EV6 implements most of the bits in hardware.  Collect
76 	   the acrued exception bits from the real fpcr.  */
77 	if (implver() == IMPLVER_EV6) {
78 		swcr &= ~IEEE_STATUS_MASK;
79 		swcr |= (fpcr >> 35) & IEEE_STATUS_MASK;
80 	}
81 	return swcr;
82 }
83 
84 extern unsigned long alpha_read_fp_reg (unsigned long reg);
85 extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
86 extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
87 extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
88 
89 #endif /* __ASM_ALPHA_FPU_H */
90