xref: /openbsd/sys/arch/hppa/hppa/fpu.c (revision 859d5ed4)
1 /*	$OpenBSD: fpu.c,v 1.5 2010/08/07 03:50:01 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Joel Sing <jsing@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/proc.h>
22 #include <sys/user.h>
23 
24 #include <machine/cpu.h>
25 #include <machine/cpufunc.h>
26 #include <machine/fpu.h>
27 #include <machine/intr.h>
28 #include <machine/pcb.h>
29 #include <machine/reg.h>
30 
31 __inline void fpu_proc(struct proc *, int);
32 
33 void
fpu_proc_flush(struct proc * p)34 fpu_proc_flush(struct proc *p)
35 {
36 	fpu_proc(p, 0);
37 }
38 
39 void
fpu_proc_save(struct proc * p)40 fpu_proc_save(struct proc *p)
41 {
42 	fpu_proc(p, 1);
43 }
44 
45 __inline void
fpu_proc(struct proc * p,int save)46 fpu_proc(struct proc *p, int save)
47 {
48 	struct cpu_info *ci = curcpu();
49 	struct hppa_fpstate *hfp;
50 	struct cpu_info *fpuci;
51 #ifdef MULTIPROCESSOR
52 	int s;
53 #endif
54 
55 	hfp = (struct hppa_fpstate *)p->p_md.md_regs->tf_cr30;
56 	fpuci = (struct cpu_info *)hfp->hfp_cpu;
57 
58 	if (fpuci == NULL)
59 		return;
60 
61 #ifdef MULTIPROCESSOR
62 	if (fpuci != ci) {
63 
64 		if (hppa_ipi_send(fpuci, HPPA_IPI_FPU_SAVE))
65 			panic("FPU shootdown failed!");
66 
67 		/*
68 		 * The sync is essential here since the volatile on hfp_cpu
69 		 * is ignored by gcc. Without this we will deadlock since
70 		 * hfp_cpu is never reloaded within the loop.
71 		 */
72 		while (hfp->hfp_cpu != NULL)
73 			asm volatile ("sync" ::: "memory");
74 
75 	} else if (p->p_md.md_regs->tf_cr30 == ci->ci_fpu_state) {
76 
77 		s = splipi();
78 		fpu_cpu_save(save);
79 		splx(s);
80 
81 	}
82 #else
83 	if (p->p_md.md_regs->tf_cr30 == ci->ci_fpu_state)
84 		fpu_cpu_save(save);
85 #endif
86 }
87 
88 /*
89  * Save or flush FPU state - note that this must be called at IPL IPI when
90  * running on a MULTIPROCESSOR kernel.
91  */
92 void
fpu_cpu_save(int save)93 fpu_cpu_save(int save)
94 {
95 	struct cpu_info *ci = curcpu();
96 	struct hppa_fpstate *hfp;
97 	struct cpu_info *fpuci;
98 	extern u_int fpu_enable;
99 
100 #ifdef MULTIPROCESSOR
101 	splassert(IPL_IPI);
102 #endif
103 
104 	if (ci->ci_fpu_state == 0)
105 		return;
106 
107 	hfp = (struct hppa_fpstate *)ci->ci_fpu_state;
108 	fpuci = (struct cpu_info *)hfp->hfp_cpu;
109 
110 #ifdef DIAGNOSTIC
111 	if (fpuci != ci)
112 		panic("FPU context is not on this CPU (%p != %p)",
113 		    ci, hfp->hfp_cpu);
114 #endif
115 
116 	if (save) {
117 		mtctl(fpu_enable, CR_CCR);
118 		fpu_save((paddr_t)&hfp->hfp_regs);
119 		mtctl(0, CR_CCR);
120 	} else
121 		fpu_exit();
122 
123 	hfp->hfp_cpu = NULL;
124 	ci->ci_fpu_state = 0;
125 	asm volatile ("sync" ::: "memory");
126 }
127