xref: /linux/arch/alpha/include/asm/fpu.h (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2024b246eSLinus Torvalds #ifndef __ASM_ALPHA_FPU_H
3024b246eSLinus Torvalds #define __ASM_ALPHA_FPU_H
4024b246eSLinus Torvalds 
5ec221208SDavid Howells #include <asm/special_insns.h>
696433f6eSDavid Howells #include <uapi/asm/fpu.h>
7024b246eSLinus Torvalds 
8024b246eSLinus Torvalds /* The following two functions don't need trapb/excb instructions
9024b246eSLinus Torvalds    around the mf_fpcr/mt_fpcr instructions because (a) the kernel
10024b246eSLinus Torvalds    never generates arithmetic faults and (b) call_pal instructions
11024b246eSLinus Torvalds    are implied trap barriers.  */
12024b246eSLinus Torvalds 
13024b246eSLinus Torvalds static inline unsigned long
rdfpcr(void)14024b246eSLinus Torvalds rdfpcr(void)
15024b246eSLinus Torvalds {
16024b246eSLinus Torvalds 	unsigned long tmp, ret;
17024b246eSLinus Torvalds 
18*05096666SAl Viro 	preempt_disable();
19*05096666SAl Viro 	if (current_thread_info()->status & TS_SAVED_FP) {
20*05096666SAl Viro 		ret = current_thread_info()->fp[31];
21*05096666SAl Viro 	} else {
22024b246eSLinus Torvalds #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
23024b246eSLinus Torvalds 		__asm__ __volatile__ (
24024b246eSLinus Torvalds 			"ftoit $f0,%0\n\t"
25024b246eSLinus Torvalds 			"mf_fpcr $f0\n\t"
26024b246eSLinus Torvalds 			"ftoit $f0,%1\n\t"
27024b246eSLinus Torvalds 			"itoft %0,$f0"
28024b246eSLinus Torvalds 			: "=r"(tmp), "=r"(ret));
29024b246eSLinus Torvalds #else
30024b246eSLinus Torvalds 		__asm__ __volatile__ (
31024b246eSLinus Torvalds 			"stt $f0,%0\n\t"
32024b246eSLinus Torvalds 			"mf_fpcr $f0\n\t"
33024b246eSLinus Torvalds 			"stt $f0,%1\n\t"
34024b246eSLinus Torvalds 			"ldt $f0,%0"
35024b246eSLinus Torvalds 			: "=m"(tmp), "=m"(ret));
36024b246eSLinus Torvalds #endif
37*05096666SAl Viro 	}
38*05096666SAl Viro 	preempt_enable();
39024b246eSLinus Torvalds 
40024b246eSLinus Torvalds 	return ret;
41024b246eSLinus Torvalds }
42024b246eSLinus Torvalds 
43024b246eSLinus Torvalds static inline void
wrfpcr(unsigned long val)44024b246eSLinus Torvalds wrfpcr(unsigned long val)
45024b246eSLinus Torvalds {
46024b246eSLinus Torvalds 	unsigned long tmp;
47024b246eSLinus Torvalds 
48*05096666SAl Viro 	preempt_disable();
49*05096666SAl Viro 	if (current_thread_info()->status & TS_SAVED_FP) {
50*05096666SAl Viro 		current_thread_info()->status |= TS_RESTORE_FP;
51*05096666SAl Viro 		current_thread_info()->fp[31] = val;
52*05096666SAl Viro 	} else {
53024b246eSLinus Torvalds #if defined(CONFIG_ALPHA_EV6) || defined(CONFIG_ALPHA_EV67)
54024b246eSLinus Torvalds 		__asm__ __volatile__ (
55024b246eSLinus Torvalds 			"ftoit $f0,%0\n\t"
56024b246eSLinus Torvalds 			"itoft %1,$f0\n\t"
57024b246eSLinus Torvalds 			"mt_fpcr $f0\n\t"
58024b246eSLinus Torvalds 			"itoft %0,$f0"
59024b246eSLinus Torvalds 			: "=&r"(tmp) : "r"(val));
60024b246eSLinus Torvalds #else
61024b246eSLinus Torvalds 		__asm__ __volatile__ (
62024b246eSLinus Torvalds 			"stt $f0,%0\n\t"
63024b246eSLinus Torvalds 			"ldt $f0,%1\n\t"
64024b246eSLinus Torvalds 			"mt_fpcr $f0\n\t"
65024b246eSLinus Torvalds 			"ldt $f0,%0"
66024b246eSLinus Torvalds 			: "=m"(tmp) : "m"(val));
67024b246eSLinus Torvalds #endif
68024b246eSLinus Torvalds 	}
69*05096666SAl Viro 	preempt_enable();
70*05096666SAl Viro }
71024b246eSLinus Torvalds 
72024b246eSLinus Torvalds static inline unsigned long
swcr_update_status(unsigned long swcr,unsigned long fpcr)73024b246eSLinus Torvalds swcr_update_status(unsigned long swcr, unsigned long fpcr)
74024b246eSLinus Torvalds {
75024b246eSLinus Torvalds 	/* EV6 implements most of the bits in hardware.  Collect
76024b246eSLinus Torvalds 	   the acrued exception bits from the real fpcr.  */
77024b246eSLinus Torvalds 	if (implver() == IMPLVER_EV6) {
78024b246eSLinus Torvalds 		swcr &= ~IEEE_STATUS_MASK;
79024b246eSLinus Torvalds 		swcr |= (fpcr >> 35) & IEEE_STATUS_MASK;
80024b246eSLinus Torvalds 	}
81024b246eSLinus Torvalds 	return swcr;
82024b246eSLinus Torvalds }
83024b246eSLinus Torvalds 
84024b246eSLinus Torvalds extern unsigned long alpha_read_fp_reg (unsigned long reg);
85024b246eSLinus Torvalds extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
86024b246eSLinus Torvalds extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
87024b246eSLinus Torvalds extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
88024b246eSLinus Torvalds 
89024b246eSLinus Torvalds #endif /* __ASM_ALPHA_FPU_H */
90