1188860Snwhitehorn/*-
2188860Snwhitehorn * Copyright (C) 1996 Wolfgang Solfrank.
3188860Snwhitehorn * Copyright (C) 1996 TooLs GmbH.
4188860Snwhitehorn * All rights reserved.
5188860Snwhitehorn *
6188860Snwhitehorn * Redistribution and use in source and binary forms, with or without
7188860Snwhitehorn * modification, are permitted provided that the following conditions
8188860Snwhitehorn * are met:
9188860Snwhitehorn * 1. Redistributions of source code must retain the above copyright
10188860Snwhitehorn *    notice, this list of conditions and the following disclaimer.
11188860Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
12188860Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
13188860Snwhitehorn *    documentation and/or other materials provided with the distribution.
14188860Snwhitehorn * 3. All advertising materials mentioning features or use of this software
15188860Snwhitehorn *    must display the following acknowledgement:
16188860Snwhitehorn *	This product includes software developed by TooLs GmbH.
17188860Snwhitehorn * 4. The name of TooLs GmbH may not be used to endorse or promote products
18188860Snwhitehorn *    derived from this software without specific prior written permission.
19188860Snwhitehorn *
20188860Snwhitehorn * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21188860Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22188860Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23188860Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24188860Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25188860Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26188860Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27188860Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28188860Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29188860Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30188860Snwhitehorn *
31188860Snwhitehorn *	$NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $
32188860Snwhitehorn */
33188860Snwhitehorn
34188860Snwhitehorn#include <sys/cdefs.h>
35188860Snwhitehorn__FBSDID("$FreeBSD$");
36188860Snwhitehorn
37188860Snwhitehorn#include <sys/param.h>
38188860Snwhitehorn#include <sys/proc.h>
39188860Snwhitehorn#include <sys/systm.h>
40188860Snwhitehorn#include <sys/limits.h>
41188860Snwhitehorn
42188860Snwhitehorn#include <machine/altivec.h>
43188860Snwhitehorn#include <machine/pcb.h>
44188860Snwhitehorn#include <machine/psl.h>
45188860Snwhitehorn
46276634Sjhibbitsstatic void
47276634Sjhibbitssave_vec_int(struct thread *td)
48276634Sjhibbits{
49276634Sjhibbits	int	msr;
50276634Sjhibbits	struct	pcb *pcb;
51276634Sjhibbits
52276634Sjhibbits	pcb = td->td_pcb;
53276634Sjhibbits
54276634Sjhibbits	/*
55276634Sjhibbits	 * Temporarily re-enable the vector unit during the save
56276634Sjhibbits	 */
57276634Sjhibbits	msr = mfmsr();
58276634Sjhibbits	mtmsr(msr | PSL_VEC);
59276634Sjhibbits	isync();
60276634Sjhibbits
61276634Sjhibbits	/*
62276634Sjhibbits	 * Save the vector registers and VSCR to the PCB
63276634Sjhibbits	 */
64276634Sjhibbits#define STVX(n)   __asm ("stvx %1,0,%0" \
65276634Sjhibbits		:: "b"(pcb->pcb_vec.vr[n]), "n"(n));
66276634Sjhibbits	STVX(0);	STVX(1);	STVX(2);	STVX(3);
67276634Sjhibbits	STVX(4);	STVX(5);	STVX(6);	STVX(7);
68276634Sjhibbits	STVX(8);	STVX(9);	STVX(10);	STVX(11);
69276634Sjhibbits	STVX(12);	STVX(13);	STVX(14);	STVX(15);
70276634Sjhibbits	STVX(16);	STVX(17);	STVX(18);	STVX(19);
71276634Sjhibbits	STVX(20);	STVX(21);	STVX(22);	STVX(23);
72276634Sjhibbits	STVX(24);	STVX(25);	STVX(26);	STVX(27);
73276634Sjhibbits	STVX(28);	STVX(29);	STVX(30);	STVX(31);
74276634Sjhibbits#undef STVX
75276634Sjhibbits
76276634Sjhibbits	__asm __volatile("mfvscr 0; stvewx 0,0,%0" :: "b"(&pcb->pcb_vec.vscr));
77276634Sjhibbits
78276634Sjhibbits	/*
79276634Sjhibbits	 * Disable vector unit again
80276634Sjhibbits	 */
81276634Sjhibbits	isync();
82276634Sjhibbits	mtmsr(msr);
83276634Sjhibbits
84276634Sjhibbits}
85276634Sjhibbits
86188860Snwhitehornvoid
87188860Snwhitehornenable_vec(struct thread *td)
88188860Snwhitehorn{
89188860Snwhitehorn	int	msr;
90188860Snwhitehorn	struct	pcb *pcb;
91188860Snwhitehorn	struct	trapframe *tf;
92188860Snwhitehorn
93188860Snwhitehorn	pcb = td->td_pcb;
94188860Snwhitehorn	tf = trapframe(td);
95188860Snwhitehorn
96188860Snwhitehorn	/*
97188860Snwhitehorn	 * Save the thread's Altivec CPU number, and set the CPU's current
98188860Snwhitehorn	 * vector thread
99188860Snwhitehorn	 */
100188860Snwhitehorn	td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
101188860Snwhitehorn	PCPU_SET(vecthread, td);
102188860Snwhitehorn
103188860Snwhitehorn	/*
104188860Snwhitehorn	 * Enable the vector unit for when the thread returns from the
105188860Snwhitehorn	 * exception. If this is the first time the unit has been used by
106188860Snwhitehorn	 * the thread, initialise the vector registers and VSCR to 0, and
107188860Snwhitehorn	 * set the flag to indicate that the vector unit is in use.
108188860Snwhitehorn	 */
109188860Snwhitehorn	tf->srr1 |= PSL_VEC;
110188860Snwhitehorn	if (!(pcb->pcb_flags & PCB_VEC)) {
111188860Snwhitehorn		memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
112188860Snwhitehorn		pcb->pcb_flags |= PCB_VEC;
113188860Snwhitehorn	}
114188860Snwhitehorn
115188860Snwhitehorn	/*
116188860Snwhitehorn	 * Temporarily enable the vector unit so the registers
117188860Snwhitehorn	 * can be restored.
118188860Snwhitehorn	 */
119188860Snwhitehorn	msr = mfmsr();
120188860Snwhitehorn	mtmsr(msr | PSL_VEC);
121188860Snwhitehorn	isync();
122188860Snwhitehorn
123188860Snwhitehorn	/*
124188860Snwhitehorn	 * Restore VSCR by first loading it into a vector and then into VSCR.
125188860Snwhitehorn	 * (this needs to done before loading the user's vector registers
126188860Snwhitehorn	 * since we need to use a scratch vector register)
127188860Snwhitehorn	 */
128188860Snwhitehorn	__asm __volatile("vxor 0,0,0; lvewx 0,0,%0; mtvscr 0" \
129188860Snwhitehorn			  :: "b"(&pcb->pcb_vec.vscr));
130188860Snwhitehorn
131188860Snwhitehorn#define LVX(n)   __asm ("lvx " #n ",0,%0" \
132188860Snwhitehorn		:: "b"(&pcb->pcb_vec.vr[n]));
133188860Snwhitehorn	LVX(0);		LVX(1);		LVX(2);		LVX(3);
134188860Snwhitehorn	LVX(4);		LVX(5);		LVX(6);		LVX(7);
135188860Snwhitehorn	LVX(8);		LVX(9);		LVX(10);	LVX(11);
136188860Snwhitehorn	LVX(12);	LVX(13);	LVX(14);	LVX(15);
137188860Snwhitehorn	LVX(16);	LVX(17);	LVX(18);	LVX(19);
138188860Snwhitehorn	LVX(20);	LVX(21);	LVX(22);	LVX(23);
139188860Snwhitehorn	LVX(24);	LVX(25);	LVX(26);	LVX(27);
140188860Snwhitehorn	LVX(28);	LVX(29);	LVX(30);	LVX(31);
141188860Snwhitehorn#undef LVX
142188860Snwhitehorn
143188860Snwhitehorn	isync();
144188860Snwhitehorn	mtmsr(msr);
145188860Snwhitehorn}
146188860Snwhitehorn
147188860Snwhitehornvoid
148188860Snwhitehornsave_vec(struct thread *td)
149188860Snwhitehorn{
150276634Sjhibbits	struct pcb *pcb;
151188860Snwhitehorn
152188860Snwhitehorn	pcb = td->td_pcb;
153188860Snwhitehorn
154276634Sjhibbits	save_vec_int(td);
155188860Snwhitehorn
156188860Snwhitehorn	/*
157188860Snwhitehorn	 * Clear the current vec thread and pcb's CPU id
158188860Snwhitehorn	 * XXX should this be left clear to allow lazy save/restore ?
159188860Snwhitehorn	 */
160188860Snwhitehorn	pcb->pcb_veccpu = INT_MAX;
161188860Snwhitehorn	PCPU_SET(vecthread, NULL);
162188860Snwhitehorn}
163188860Snwhitehorn
164276634Sjhibbits/*
165276634Sjhibbits * Save altivec state without dropping ownership.  This will only save state if
166276634Sjhibbits * the current vector-thread is `td'.
167276634Sjhibbits */
168276634Sjhibbitsvoid
169276634Sjhibbitssave_vec_nodrop(struct thread *td)
170276634Sjhibbits{
171276634Sjhibbits	struct thread *vtd;
172276634Sjhibbits
173276634Sjhibbits	vtd = PCPU_GET(vecthread);
174276634Sjhibbits	if (td != vtd) {
175276634Sjhibbits		return;
176276634Sjhibbits	}
177276634Sjhibbits
178276634Sjhibbits	save_vec_int(td);
179276634Sjhibbits}
180