highfp.c revision 198733
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: head/sys/ia64/ia64/highfp.c 198733 2009-10-31 22:27:31Z marcel $");
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
56198733Smarcel	ipi_send(cpu, IPI_HIGH_FP);
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	KASSERT((tf->tf_special.psr & IA64_PSR_DFH) != 0,
96198733Smarcel	    ("(tf->tf_special.psr & IA64_PSR_DFH) == 0"));
97198733Smarcel	cpu = pcb->pcb_fpcpu;
98198733Smarcel#ifdef SMP
99198733Smarcel	if (cpu != NULL && cpu != pcpup) {
100198733Smarcel		KASSERT(cpu->pc_fpcurthread == td,
101198733Smarcel		    ("cpu->pc_fpcurthread != td"));
102198733Smarcel		ia64_highfp_ipi(cpu);
103198733Smarcel	}
104198733Smarcel#endif
105198733Smarcel	td1 = PCPU_GET(fpcurthread);
106198733Smarcel	if (td1 != NULL && td1 != td) {
107198733Smarcel		KASSERT(td1->td_pcb->pcb_fpcpu == pcpup,
108198733Smarcel		    ("td1->td_pcb->pcb_fpcpu != pcpup"));
109198733Smarcel		save_high_fp(&td1->td_pcb->pcb_high_fp);
110198733Smarcel		td1->td_frame->tf_special.psr |= IA64_PSR_DFH;
111198733Smarcel		td1->td_pcb->pcb_fpcpu = NULL;
112198733Smarcel		PCPU_SET(fpcurthread, NULL);
113198733Smarcel		td1 = NULL;
114198733Smarcel	}
115198733Smarcel	if (td1 == NULL) {
116198733Smarcel		KASSERT(pcb->pcb_fpcpu == NULL, ("pcb->pcb_fpcpu != NULL"));
117198733Smarcel		KASSERT(PCPU_GET(fpcurthread) == NULL,
118198733Smarcel		    ("PCPU_GET(fpcurthread) != NULL"));
119198733Smarcel		restore_high_fp(&pcb->pcb_high_fp);
120198733Smarcel		PCPU_SET(fpcurthread, td);
121198733Smarcel		pcb->pcb_fpcpu = pcpup;
122198733Smarcel		tf->tf_special.psr &= ~IA64_PSR_MFH;
123198733Smarcel	}
124198733Smarcel	tf->tf_special.psr &= ~IA64_PSR_DFH;
125198733Smarcel	mtx_unlock_spin(&ia64_highfp_mtx);
126198733Smarcel
127198733Smarcel	return ((td1 != NULL) ? 1 : 0);
128198733Smarcel}
129198733Smarcel
130198733Smarcelint
131198733Smarcelia64_highfp_save(struct thread *td)
132198733Smarcel{
133198733Smarcel	struct pcb *pcb;
134198733Smarcel	struct pcpu *cpu;
135198733Smarcel
136198733Smarcel	pcb = td->td_pcb;
137198733Smarcel
138198733Smarcel	mtx_lock_spin(&ia64_highfp_mtx);
139198733Smarcel	cpu = pcb->pcb_fpcpu;
140198733Smarcel#ifdef SMP
141198733Smarcel	if (cpu != NULL && cpu != pcpup) {
142198733Smarcel		KASSERT(cpu->pc_fpcurthread == td,
143198733Smarcel		    ("cpu->pc_fpcurthread != td"));
144198733Smarcel		ia64_highfp_ipi(cpu);
145198733Smarcel	} else
146198733Smarcel#endif
147198733Smarcel	if (cpu != NULL) {
148198733Smarcel		KASSERT(cpu->pc_fpcurthread == td,
149198733Smarcel		    ("cpu->pc_fpcurthread != td"));
150198733Smarcel		save_high_fp(&pcb->pcb_high_fp);
151198733Smarcel		td->td_frame->tf_special.psr |= IA64_PSR_DFH;
152198733Smarcel		pcb->pcb_fpcpu = NULL;
153198733Smarcel		cpu->pc_fpcurthread = NULL;
154198733Smarcel	}
155198733Smarcel	mtx_unlock_spin(&ia64_highfp_mtx);
156198733Smarcel
157198733Smarcel	return ((cpu != NULL) ? 1 : 0);
158198733Smarcel}
159198733Smarcel
160198733Smarcel#ifdef SMP
161198733Smarcelint
162198733Smarcelia64_highfp_save_ipi(void)
163198733Smarcel{
164198733Smarcel	struct thread *td;
165198733Smarcel
166198733Smarcel	mtx_lock_spin(&ia64_highfp_mtx);
167198733Smarcel	td = PCPU_GET(fpcurthread);
168198733Smarcel	if (td != NULL) {
169198733Smarcel		KASSERT(td->td_pcb->pcb_fpcpu == pcpup,
170198733Smarcel		    ("td->td_pcb->pcb_fpcpu != pcpup"));
171198733Smarcel		save_high_fp(&td->td_pcb->pcb_high_fp);
172198733Smarcel		td->td_frame->tf_special.psr |= IA64_PSR_DFH;
173198733Smarcel		td->td_pcb->pcb_fpcpu = NULL;
174198733Smarcel		PCPU_SET(fpcurthread, NULL);
175198733Smarcel	}
176198733Smarcel	mtx_unlock_spin(&ia64_highfp_mtx);
177198733Smarcel	wakeup(&PCPU_GET(fpcurthread));
178198733Smarcel
179198733Smarcel	return ((td != NULL) ? 1 : 0);
180198733Smarcel}
181198733Smarcel#endif
182