]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/booke/spe.c
MFV r336991, r337001:
[FreeBSD/FreeBSD.git] / sys / powerpc / booke / spe.c
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 }