1198733Smarcel/*- 2198733Smarcel * Copyright (c) 2009 Marcel Moolenaar 3198733Smarcel * All rights reserved. 4198733Smarcel * 5198733Smarcel * Redistribution and use in source and binary forms, with or without 6198733Smarcel * modification, are permitted provided that the following conditions 7198733Smarcel * are met: 8198733Smarcel * 1. Redistributions of source code must retain the above copyright 9198733Smarcel * notice, this list of conditions and the following disclaimer. 10198733Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11198733Smarcel * notice, this list of conditions and the following disclaimer in the 12198733Smarcel * documentation and/or other materials provided with the distribution. 13198733Smarcel * 14198733Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15198733Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16198733Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17198733Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18198733Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19198733Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20198733Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21198733Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22198733Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23198733Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24198733Smarcel * SUCH DAMAGE. 25198733Smarcel */ 26198733Smarcel 27198733Smarcel#include <sys/cdefs.h> 28198733Smarcel__FBSDID("$FreeBSD$"); 29198733Smarcel 30198733Smarcel#include <sys/param.h> 31198733Smarcel#include <sys/systm.h> 32198733Smarcel#include <sys/kernel.h> 33198733Smarcel#include <sys/lock.h> 34198733Smarcel#include <sys/mutex.h> 35198733Smarcel#include <sys/proc.h> 36198733Smarcel 37198733Smarcel#include <machine/frame.h> 38198733Smarcel#include <machine/md_var.h> 39198733Smarcel#include <machine/smp.h> 40198733Smarcel 41198733Smarcelstatic struct mtx ia64_highfp_mtx; 42198733Smarcel 43198733Smarcelstatic void 44198733Smarcelia64_highfp_init(void *_) 45198733Smarcel{ 46198733Smarcel mtx_init(&ia64_highfp_mtx, "High FP lock", NULL, MTX_SPIN); 47198733Smarcel} 48198733SmarcelSYSINIT(ia64_highfp_init, SI_SUB_LOCK, SI_ORDER_ANY, ia64_highfp_init, NULL); 49198733Smarcel 50198733Smarcel#ifdef SMP 51198733Smarcelstatic int 52198733Smarcelia64_highfp_ipi(struct pcpu *cpu) 53198733Smarcel{ 54198733Smarcel int error; 55198733Smarcel 56205234Smarcel ipi_send(cpu, ia64_ipi_highfp); 57198733Smarcel error = msleep_spin(&cpu->pc_fpcurthread, &ia64_highfp_mtx, 58198733Smarcel "High FP", 0); 59198733Smarcel return (error); 60198733Smarcel} 61198733Smarcel#endif 62198733Smarcel 63198733Smarcelint 64198733Smarcelia64_highfp_drop(struct thread *td) 65198733Smarcel{ 66198733Smarcel struct pcb *pcb; 67198733Smarcel struct pcpu *cpu; 68198733Smarcel 69198733Smarcel pcb = td->td_pcb; 70198733Smarcel 71198733Smarcel mtx_lock_spin(&ia64_highfp_mtx); 72198733Smarcel cpu = pcb->pcb_fpcpu; 73198733Smarcel if (cpu != NULL) { 74198733Smarcel KASSERT(cpu->pc_fpcurthread == td, 75198733Smarcel ("cpu->pc_fpcurthread != td")); 76198733Smarcel td->td_frame->tf_special.psr |= IA64_PSR_DFH; 77198733Smarcel pcb->pcb_fpcpu = NULL; 78198733Smarcel cpu->pc_fpcurthread = NULL; 79198733Smarcel } 80198733Smarcel mtx_unlock_spin(&ia64_highfp_mtx); 81198733Smarcel 82198733Smarcel return ((cpu != NULL) ? 1 : 0); 83198733Smarcel} 84198733Smarcel 85198733Smarcelint 86198733Smarcelia64_highfp_enable(struct thread *td, struct trapframe *tf) 87198733Smarcel{ 88198733Smarcel struct pcb *pcb; 89198733Smarcel struct pcpu *cpu; 90198733Smarcel struct thread *td1; 91198733Smarcel 92198733Smarcel pcb = td->td_pcb; 93198733Smarcel 94198733Smarcel mtx_lock_spin(&ia64_highfp_mtx); 95198733Smarcel cpu = pcb->pcb_fpcpu; 96198733Smarcel#ifdef SMP 97198733Smarcel if (cpu != NULL && cpu != pcpup) { 98198733Smarcel KASSERT(cpu->pc_fpcurthread == td, 99198733Smarcel ("cpu->pc_fpcurthread != td")); 100198733Smarcel ia64_highfp_ipi(cpu); 101198733Smarcel } 102198733Smarcel#endif 103198733Smarcel td1 = PCPU_GET(fpcurthread); 104198733Smarcel if (td1 != NULL && td1 != td) { 105198733Smarcel KASSERT(td1->td_pcb->pcb_fpcpu == pcpup, 106198733Smarcel ("td1->td_pcb->pcb_fpcpu != pcpup")); 107198733Smarcel save_high_fp(&td1->td_pcb->pcb_high_fp); 108198733Smarcel td1->td_frame->tf_special.psr |= IA64_PSR_DFH; 109198733Smarcel td1->td_pcb->pcb_fpcpu = NULL; 110198733Smarcel PCPU_SET(fpcurthread, NULL); 111198733Smarcel td1 = NULL; 112198733Smarcel } 113198733Smarcel if (td1 == NULL) { 114198733Smarcel KASSERT(pcb->pcb_fpcpu == NULL, ("pcb->pcb_fpcpu != NULL")); 115198733Smarcel KASSERT(PCPU_GET(fpcurthread) == NULL, 116198733Smarcel ("PCPU_GET(fpcurthread) != NULL")); 117198733Smarcel restore_high_fp(&pcb->pcb_high_fp); 118198733Smarcel PCPU_SET(fpcurthread, td); 119198733Smarcel pcb->pcb_fpcpu = pcpup; 120198733Smarcel tf->tf_special.psr &= ~IA64_PSR_MFH; 121198733Smarcel } 122198733Smarcel tf->tf_special.psr &= ~IA64_PSR_DFH; 123198733Smarcel mtx_unlock_spin(&ia64_highfp_mtx); 124198733Smarcel 125198733Smarcel return ((td1 != NULL) ? 1 : 0); 126198733Smarcel} 127198733Smarcel 128198733Smarcelint 129198733Smarcelia64_highfp_save(struct thread *td) 130198733Smarcel{ 131198733Smarcel struct pcb *pcb; 132198733Smarcel struct pcpu *cpu; 133198733Smarcel 134198733Smarcel pcb = td->td_pcb; 135198733Smarcel 136198733Smarcel mtx_lock_spin(&ia64_highfp_mtx); 137198733Smarcel cpu = pcb->pcb_fpcpu; 138198733Smarcel#ifdef SMP 139198733Smarcel if (cpu != NULL && cpu != pcpup) { 140198733Smarcel KASSERT(cpu->pc_fpcurthread == td, 141198733Smarcel ("cpu->pc_fpcurthread != td")); 142198733Smarcel ia64_highfp_ipi(cpu); 143198733Smarcel } else 144198733Smarcel#endif 145198733Smarcel if (cpu != NULL) { 146198733Smarcel KASSERT(cpu->pc_fpcurthread == td, 147198733Smarcel ("cpu->pc_fpcurthread != td")); 148198733Smarcel save_high_fp(&pcb->pcb_high_fp); 149198733Smarcel td->td_frame->tf_special.psr |= IA64_PSR_DFH; 150198733Smarcel pcb->pcb_fpcpu = NULL; 151198733Smarcel cpu->pc_fpcurthread = NULL; 152198733Smarcel } 153198733Smarcel mtx_unlock_spin(&ia64_highfp_mtx); 154198733Smarcel 155198733Smarcel return ((cpu != NULL) ? 1 : 0); 156198733Smarcel} 157198733Smarcel 158198733Smarcel#ifdef SMP 159198733Smarcelint 160198733Smarcelia64_highfp_save_ipi(void) 161198733Smarcel{ 162198733Smarcel struct thread *td; 163198733Smarcel 164198733Smarcel mtx_lock_spin(&ia64_highfp_mtx); 165198733Smarcel td = PCPU_GET(fpcurthread); 166198733Smarcel if (td != NULL) { 167198733Smarcel KASSERT(td->td_pcb->pcb_fpcpu == pcpup, 168198733Smarcel ("td->td_pcb->pcb_fpcpu != pcpup")); 169198733Smarcel save_high_fp(&td->td_pcb->pcb_high_fp); 170198733Smarcel td->td_frame->tf_special.psr |= IA64_PSR_DFH; 171198733Smarcel td->td_pcb->pcb_fpcpu = NULL; 172198733Smarcel PCPU_SET(fpcurthread, NULL); 173198733Smarcel } 174198733Smarcel mtx_unlock_spin(&ia64_highfp_mtx); 175198733Smarcel wakeup(&PCPU_GET(fpcurthread)); 176198733Smarcel 177198733Smarcel return ((td != NULL) ? 1 : 0); 178198733Smarcel} 179198733Smarcel#endif 180