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
46188860Snwhitehornvoid
47188860Snwhitehornenable_vec(struct thread *td)
48188860Snwhitehorn{
49188860Snwhitehorn	int	msr;
50188860Snwhitehorn	struct	pcb *pcb;
51188860Snwhitehorn	struct	trapframe *tf;
52188860Snwhitehorn
53188860Snwhitehorn	pcb = td->td_pcb;
54188860Snwhitehorn	tf = trapframe(td);
55188860Snwhitehorn
56188860Snwhitehorn	/*
57188860Snwhitehorn	 * Save the thread's Altivec CPU number, and set the CPU's current
58188860Snwhitehorn	 * vector thread
59188860Snwhitehorn	 */
60188860Snwhitehorn	td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
61188860Snwhitehorn	PCPU_SET(vecthread, td);
62188860Snwhitehorn
63188860Snwhitehorn	/*
64188860Snwhitehorn	 * Enable the vector unit for when the thread returns from the
65188860Snwhitehorn	 * exception. If this is the first time the unit has been used by
66188860Snwhitehorn	 * the thread, initialise the vector registers and VSCR to 0, and
67188860Snwhitehorn	 * set the flag to indicate that the vector unit is in use.
68188860Snwhitehorn	 */
69188860Snwhitehorn	tf->srr1 |= PSL_VEC;
70188860Snwhitehorn	if (!(pcb->pcb_flags & PCB_VEC)) {
71188860Snwhitehorn		memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
72188860Snwhitehorn		pcb->pcb_flags |= PCB_VEC;
73188860Snwhitehorn	}
74188860Snwhitehorn
75188860Snwhitehorn	/*
76188860Snwhitehorn	 * Temporarily enable the vector unit so the registers
77188860Snwhitehorn	 * can be restored.
78188860Snwhitehorn	 */
79188860Snwhitehorn	msr = mfmsr();
80188860Snwhitehorn	mtmsr(msr | PSL_VEC);
81188860Snwhitehorn	isync();
82188860Snwhitehorn
83188860Snwhitehorn	/*
84188860Snwhitehorn	 * Restore VSCR by first loading it into a vector and then into VSCR.
85188860Snwhitehorn	 * (this needs to done before loading the user's vector registers
86188860Snwhitehorn	 * since we need to use a scratch vector register)
87188860Snwhitehorn	 */
88188860Snwhitehorn	__asm __volatile("vxor 0,0,0; lvewx 0,0,%0; mtvscr 0" \
89188860Snwhitehorn			  :: "b"(&pcb->pcb_vec.vscr));
90188860Snwhitehorn
91188860Snwhitehorn#define LVX(n)   __asm ("lvx " #n ",0,%0" \
92188860Snwhitehorn		:: "b"(&pcb->pcb_vec.vr[n]));
93188860Snwhitehorn	LVX(0);		LVX(1);		LVX(2);		LVX(3);
94188860Snwhitehorn	LVX(4);		LVX(5);		LVX(6);		LVX(7);
95188860Snwhitehorn	LVX(8);		LVX(9);		LVX(10);	LVX(11);
96188860Snwhitehorn	LVX(12);	LVX(13);	LVX(14);	LVX(15);
97188860Snwhitehorn	LVX(16);	LVX(17);	LVX(18);	LVX(19);
98188860Snwhitehorn	LVX(20);	LVX(21);	LVX(22);	LVX(23);
99188860Snwhitehorn	LVX(24);	LVX(25);	LVX(26);	LVX(27);
100188860Snwhitehorn	LVX(28);	LVX(29);	LVX(30);	LVX(31);
101188860Snwhitehorn#undef LVX
102188860Snwhitehorn
103188860Snwhitehorn	isync();
104188860Snwhitehorn	mtmsr(msr);
105188860Snwhitehorn}
106188860Snwhitehorn
107188860Snwhitehornvoid
108188860Snwhitehornsave_vec(struct thread *td)
109188860Snwhitehorn{
110188860Snwhitehorn	int	msr;
111188860Snwhitehorn	struct	pcb *pcb;
112188860Snwhitehorn
113188860Snwhitehorn	pcb = td->td_pcb;
114188860Snwhitehorn
115188860Snwhitehorn	/*
116188860Snwhitehorn	 * Temporarily re-enable the vector unit during the save
117188860Snwhitehorn	 */
118188860Snwhitehorn	msr = mfmsr();
119188860Snwhitehorn	mtmsr(msr | PSL_VEC);
120188860Snwhitehorn	isync();
121188860Snwhitehorn
122188860Snwhitehorn	/*
123188860Snwhitehorn	 * Save the vector registers and VSCR to the PCB
124188860Snwhitehorn	 */
125188860Snwhitehorn#define STVX(n)   __asm ("stvx %1,0,%0" \
126188860Snwhitehorn		:: "b"(pcb->pcb_vec.vr[n]), "n"(n));
127188860Snwhitehorn	STVX(0);	STVX(1);	STVX(2);	STVX(3);
128188860Snwhitehorn	STVX(4);	STVX(5);	STVX(6);	STVX(7);
129188860Snwhitehorn	STVX(8);	STVX(9);	STVX(10);	STVX(11);
130188860Snwhitehorn	STVX(12);	STVX(13);	STVX(14);	STVX(15);
131188860Snwhitehorn	STVX(16);	STVX(17);	STVX(18);	STVX(19);
132188860Snwhitehorn	STVX(20);	STVX(21);	STVX(22);	STVX(23);
133188860Snwhitehorn	STVX(24);	STVX(25);	STVX(26);	STVX(27);
134188860Snwhitehorn	STVX(28);	STVX(29);	STVX(30);	STVX(31);
135188860Snwhitehorn#undef STVX
136188860Snwhitehorn
137188860Snwhitehorn	__asm __volatile("mfvscr 0; stvewx 0,0,%0" :: "b"(&pcb->pcb_vec.vscr));
138188860Snwhitehorn
139188860Snwhitehorn	/*
140188860Snwhitehorn	 * Disable vector unit again
141188860Snwhitehorn	 */
142188860Snwhitehorn	isync();
143188860Snwhitehorn	mtmsr(msr);
144188860Snwhitehorn
145188860Snwhitehorn	/*
146188860Snwhitehorn	 * Clear the current vec thread and pcb's CPU id
147188860Snwhitehorn	 * XXX should this be left clear to allow lazy save/restore ?
148188860Snwhitehorn	 */
149188860Snwhitehorn	pcb->pcb_veccpu = INT_MAX;
150188860Snwhitehorn	PCPU_SET(vecthread, NULL);
151188860Snwhitehorn}
152188860Snwhitehorn
153