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