1243791Sdim/*- 2243791Sdim * Copyright (C) 1996 Wolfgang Solfrank. 3243791Sdim * Copyright (C) 1996 TooLs GmbH. 4243791Sdim * All rights reserved. 5243791Sdim * 6243791Sdim * Redistribution and use in source and binary forms, with or without 7243791Sdim * modification, are permitted provided that the following conditions 8243791Sdim * are met: 9243791Sdim * 1. Redistributions of source code must retain the above copyright 10243791Sdim * notice, this list of conditions and the following disclaimer. 11243791Sdim * 2. Redistributions in binary form must reproduce the above copyright 12243791Sdim * notice, this list of conditions and the following disclaimer in the 13243791Sdim * documentation and/or other materials provided with the distribution. 14243791Sdim * 3. All advertising materials mentioning features or use of this software 15243791Sdim * must display the following acknowledgement: 16243791Sdim * This product includes software developed by TooLs GmbH. 17243791Sdim * 4. The name of TooLs GmbH may not be used to endorse or promote products 18243791Sdim * derived from this software without specific prior written permission. 19243791Sdim * 20243791Sdim * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21243791Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22243791Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23243791Sdim * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24243791Sdim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25243791Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26243791Sdim * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27243791Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28243791Sdim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29243791Sdim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30243791Sdim * 31243791Sdim * $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $ 32243791Sdim */ 33243791Sdim 34243791Sdim#include <sys/cdefs.h> 35243791Sdim__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/powerpc/altivec.c 188860 2009-02-20 17:48:40Z nwhitehorn $"); 36243791Sdim 37243791Sdim#include <sys/param.h> 38243791Sdim#include <sys/proc.h> 39243791Sdim#include <sys/systm.h> 40243791Sdim#include <sys/limits.h> 41243791Sdim 42243791Sdim#include <machine/altivec.h> 43243791Sdim#include <machine/pcb.h> 44243791Sdim#include <machine/psl.h> 45243791Sdim 46243791Sdimvoid 47243791Sdimenable_vec(struct thread *td) 48243791Sdim{ 49243791Sdim int msr; 50243791Sdim struct pcb *pcb; 51243791Sdim struct trapframe *tf; 52243791Sdim 53243791Sdim pcb = td->td_pcb; 54243791Sdim tf = trapframe(td); 55243791Sdim 56243791Sdim /* 57243791Sdim * Save the thread's Altivec CPU number, and set the CPU's current 58243791Sdim * vector thread 59243791Sdim */ 60243791Sdim td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); 61243791Sdim PCPU_SET(vecthread, td); 62243791Sdim 63243791Sdim /* 64243791Sdim * Enable the vector unit for when the thread returns from the 65243791Sdim * exception. If this is the first time the unit has been used by 66243791Sdim * the thread, initialise the vector registers and VSCR to 0, and 67243791Sdim * set the flag to indicate that the vector unit is in use. 68243791Sdim */ 69243791Sdim tf->srr1 |= PSL_VEC; 70243791Sdim if (!(pcb->pcb_flags & PCB_VEC)) { 71243791Sdim memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec); 72243791Sdim pcb->pcb_flags |= PCB_VEC; 73243791Sdim } 74243791Sdim 75243791Sdim /* 76243791Sdim * Temporarily enable the vector unit so the registers 77243791Sdim * can be restored. 78243791Sdim */ 79243791Sdim msr = mfmsr(); 80243791Sdim mtmsr(msr | PSL_VEC); 81243791Sdim isync(); 82243791Sdim 83243791Sdim /* 84243791Sdim * Restore VSCR by first loading it into a vector and then into VSCR. 85243791Sdim * (this needs to done before loading the user's vector registers 86243791Sdim * since we need to use a scratch vector register) 87243791Sdim */ 88243791Sdim __asm __volatile("vxor 0,0,0; lvewx 0,0,%0; mtvscr 0" \ 89243791Sdim :: "b"(&pcb->pcb_vec.vscr)); 90243791Sdim 91243791Sdim#define LVX(n) __asm ("lvx " #n ",0,%0" \ 92243791Sdim :: "b"(&pcb->pcb_vec.vr[n])); 93243791Sdim LVX(0); LVX(1); LVX(2); LVX(3); 94243791Sdim LVX(4); LVX(5); LVX(6); LVX(7); 95243791Sdim LVX(8); LVX(9); LVX(10); LVX(11); 96243791Sdim LVX(12); LVX(13); LVX(14); LVX(15); 97243791Sdim LVX(16); LVX(17); LVX(18); LVX(19); 98243791Sdim LVX(20); LVX(21); LVX(22); LVX(23); 99243791Sdim LVX(24); LVX(25); LVX(26); LVX(27); 100243791Sdim LVX(28); LVX(29); LVX(30); LVX(31); 101243791Sdim#undef LVX 102243791Sdim 103243791Sdim isync(); 104243791Sdim mtmsr(msr); 105243791Sdim} 106243791Sdim 107243791Sdimvoid 108243791Sdimsave_vec(struct thread *td) 109243791Sdim{ 110243791Sdim int msr; 111243791Sdim struct pcb *pcb; 112243791Sdim 113243791Sdim pcb = td->td_pcb; 114243791Sdim 115243791Sdim /* 116243791Sdim * Temporarily re-enable the vector unit during the save 117243791Sdim */ 118243791Sdim msr = mfmsr(); 119243791Sdim mtmsr(msr | PSL_VEC); 120243791Sdim isync(); 121243791Sdim 122243791Sdim /* 123243791Sdim * Save the vector registers and VSCR to the PCB 124243791Sdim */ 125243791Sdim#define STVX(n) __asm ("stvx %1,0,%0" \ 126243791Sdim :: "b"(pcb->pcb_vec.vr[n]), "n"(n)); 127243791Sdim STVX(0); STVX(1); STVX(2); STVX(3); 128243791Sdim STVX(4); STVX(5); STVX(6); STVX(7); 129243791Sdim STVX(8); STVX(9); STVX(10); STVX(11); 130243791Sdim STVX(12); STVX(13); STVX(14); STVX(15); 131243791Sdim STVX(16); STVX(17); STVX(18); STVX(19); 132243791Sdim STVX(20); STVX(21); STVX(22); STVX(23); 133243791Sdim STVX(24); STVX(25); STVX(26); STVX(27); 134243791Sdim STVX(28); STVX(29); STVX(30); STVX(31); 135243791Sdim#undef STVX 136243791Sdim 137243791Sdim __asm __volatile("mfvscr 0; stvewx 0,0,%0" :: "b"(&pcb->pcb_vec.vscr)); 138243791Sdim 139243791Sdim /* 140243791Sdim * Disable vector unit again 141243791Sdim */ 142243791Sdim isync(); 143243791Sdim mtmsr(msr); 144243791Sdim 145243791Sdim /* 146243791Sdim * Clear the current vec thread and pcb's CPU id 147243791Sdim * XXX should this be left clear to allow lazy save/restore ? 148243791Sdim */ 149243791Sdim pcb->pcb_veccpu = INT_MAX; 150243791Sdim PCPU_SET(vecthread, NULL); 151243791Sdim} 152243791Sdim 153243791Sdim