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