xref: /freebsd/sys/powerpc/booke/spe.c (revision 63d1fd5970ec814904aa0f4580b10a0d302d08b2)
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  *	$NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/proc.h>
39 #include <sys/systm.h>
40 #include <sys/limits.h>
41 
42 #include <machine/altivec.h>
43 #include <machine/pcb.h>
44 #include <machine/psl.h>
45 
46 static void
47 save_vec_int(struct thread *td)
48 {
49 	int	msr;
50 	struct	pcb *pcb;
51 
52 	pcb = td->td_pcb;
53 
54 	/*
55 	 * Temporarily re-enable the vector unit during the save
56 	 */
57 	msr = mfmsr();
58 	mtmsr(msr | PSL_VEC);
59 	isync();
60 
61 	/*
62 	 * Save the vector registers and SPEFSCR to the PCB
63 	 */
64 #define EVSTDW(n)   __asm ("evstdw %1,0(%0)" \
65 		:: "b"(pcb->pcb_vec.vr[n]), "n"(n));
66 	EVSTDW(0);	EVSTDW(1);	EVSTDW(2);	EVSTDW(3);
67 	EVSTDW(4);	EVSTDW(5);	EVSTDW(6);	EVSTDW(7);
68 	EVSTDW(8);	EVSTDW(9);	EVSTDW(10);	EVSTDW(11);
69 	EVSTDW(12);	EVSTDW(13);	EVSTDW(14);	EVSTDW(15);
70 	EVSTDW(16);	EVSTDW(17);	EVSTDW(18);	EVSTDW(19);
71 	EVSTDW(20);	EVSTDW(21);	EVSTDW(22);	EVSTDW(23);
72 	EVSTDW(24);	EVSTDW(25);	EVSTDW(26);	EVSTDW(27);
73 	EVSTDW(28);	EVSTDW(29);	EVSTDW(30);	EVSTDW(31);
74 #undef EVSTDW
75 
76 	__asm ( "evxor 0,0,0\n"
77 		"evaddumiaaw 0,0\n"
78 		"evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.vr[17][0]));
79 	pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
80 
81 	/*
82 	 * Disable vector unit again
83 	 */
84 	isync();
85 	mtmsr(msr);
86 
87 }
88 
89 void
90 enable_vec(struct thread *td)
91 {
92 	int	msr;
93 	struct	pcb *pcb;
94 	struct	trapframe *tf;
95 
96 	pcb = td->td_pcb;
97 	tf = trapframe(td);
98 
99 	/*
100 	 * Save the thread's SPE CPU number, and set the CPU's current
101 	 * vector thread
102 	 */
103 	td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
104 	PCPU_SET(vecthread, td);
105 
106 	/*
107 	 * Enable the vector unit for when the thread returns from the
108 	 * exception. If this is the first time the unit has been used by
109 	 * the thread, initialise the vector registers and VSCR to 0, and
110 	 * set the flag to indicate that the vector unit is in use.
111 	 */
112 	tf->srr1 |= PSL_VEC;
113 	if (!(pcb->pcb_flags & PCB_VEC)) {
114 		memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
115 		pcb->pcb_flags |= PCB_VEC;
116 	}
117 
118 	/*
119 	 * Temporarily enable the vector unit so the registers
120 	 * can be restored.
121 	 */
122 	msr = mfmsr();
123 	mtmsr(msr | PSL_VEC);
124 	isync();
125 
126 	/* Restore SPEFSCR and ACC.  Use %r0 as the scratch for ACC. */
127 	mtspr(SPR_SPEFSCR, pcb->pcb_vec.vscr);
128 	__asm __volatile("evldd 0, 0(%0); evmra 0,0\n"
129 	    :: "b"(&pcb->pcb_vec.vr[17][0]));
130 
131 	/*
132 	 * The lower half of each register will be restored on trap return.  Use
133 	 * %r0 as a scratch register, and restore it last.
134 	 */
135 #define	EVLDW(n)   __asm __volatile("evldw 0, 0(%0); evmergehilo "#n",0,"#n \
136 	    :: "b"(&pcb->pcb_vec.vr[n]));
137 	EVLDW(1);	EVLDW(2);	EVLDW(3);	EVLDW(4);
138 	EVLDW(5);	EVLDW(6);	EVLDW(7);	EVLDW(8);
139 	EVLDW(9);	EVLDW(10);	EVLDW(11);	EVLDW(12);
140 	EVLDW(13);	EVLDW(14);	EVLDW(15);	EVLDW(16);
141 	EVLDW(17);	EVLDW(18);	EVLDW(19);	EVLDW(20);
142 	EVLDW(21);	EVLDW(22);	EVLDW(23);	EVLDW(24);
143 	EVLDW(25);	EVLDW(26);	EVLDW(27);	EVLDW(28);
144 	EVLDW(29);	EVLDW(30);	EVLDW(31);	EVLDW(0);
145 #undef EVLDW
146 
147 	isync();
148 	mtmsr(msr);
149 }
150 
151 void
152 save_vec(struct thread *td)
153 {
154 	struct pcb *pcb;
155 
156 	pcb = td->td_pcb;
157 
158 	save_vec_int(td);
159 
160 	/*
161 	 * Clear the current vec thread and pcb's CPU id
162 	 * XXX should this be left clear to allow lazy save/restore ?
163 	 */
164 	pcb->pcb_veccpu = INT_MAX;
165 	PCPU_SET(vecthread, NULL);
166 }
167 
168 /*
169  * Save SPE state without dropping ownership.  This will only save state if
170  * the current vector-thread is `td'.
171  */
172 void
173 save_vec_nodrop(struct thread *td)
174 {
175 	struct thread *vtd;
176 
177 	vtd = PCPU_GET(vecthread);
178 	if (td != vtd) {
179 		return;
180 	}
181 
182 	save_vec_int(td);
183 }
184