xref: /netbsd-src/sys/arch/riscv/riscv/fpu.c (revision 75b842b84762e0251223b719bf77fbef2e651bf6)
1*75b842b8Sskrll /*	$NetBSD: fpu.c,v 1.3 2023/05/07 12:41:49 skrll Exp $	*/
29687a165Smatt 
39687a165Smatt /*-
49687a165Smatt  * Copyright (c) 2014 The NetBSD Foundation, Inc.
59687a165Smatt  * All rights reserved.
69687a165Smatt  *
79687a165Smatt  * This code is derived from software contributed to The NetBSD Foundation
89687a165Smatt  * by Matt Thomas of 3am Software Foundry.
99687a165Smatt  *
109687a165Smatt  * Redistribution and use in source and binary forms, with or without
119687a165Smatt  * modification, are permitted provided that the following conditions
129687a165Smatt  * are met:
139687a165Smatt  * 1. Redistributions of source code must retain the above copyright
149687a165Smatt  *    notice, this list of conditions and the following disclaimer.
159687a165Smatt  * 2. Redistributions in binary form must reproduce the above copyright
169687a165Smatt  *    notice, this list of conditions and the following disclaimer in the
179687a165Smatt  *    documentation and/or other materials provided with the distribution.
189687a165Smatt  *
199687a165Smatt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209687a165Smatt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219687a165Smatt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229687a165Smatt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239687a165Smatt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249687a165Smatt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259687a165Smatt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269687a165Smatt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279687a165Smatt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289687a165Smatt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299687a165Smatt  * POSSIBILITY OF SUCH DAMAGE.
309687a165Smatt  */
319687a165Smatt 
329687a165Smatt #include <sys/cdefs.h>
33*75b842b8Sskrll __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.3 2023/05/07 12:41:49 skrll Exp $");
349687a165Smatt 
359687a165Smatt #include "opt_multiprocessor.h"
369687a165Smatt 
379687a165Smatt #include <sys/param.h>
389687a165Smatt #include <sys/mutex.h>
399687a165Smatt #include <sys/condvar.h>
409687a165Smatt #include <sys/cpu.h>
419687a165Smatt #include <sys/proc.h>
429687a165Smatt #include <sys/lwp.h>
439687a165Smatt #include <sys/pcu.h>
449687a165Smatt 
459687a165Smatt #include <riscv/locore.h>
46*75b842b8Sskrll #include <riscv/frame.h>
479687a165Smatt 
489687a165Smatt static void fpu_state_save(lwp_t *);
499687a165Smatt static void fpu_state_load(lwp_t *, u_int);
509687a165Smatt static void fpu_state_release(lwp_t *);
519687a165Smatt 
529687a165Smatt const pcu_ops_t pcu_fpu_ops = {
539687a165Smatt 	.pcu_id = PCU_FPU,
549687a165Smatt 	.pcu_state_save = fpu_state_save,
559687a165Smatt 	.pcu_state_load = fpu_state_load,
569687a165Smatt 	.pcu_state_release = fpu_state_release
579687a165Smatt };
589687a165Smatt 
59*75b842b8Sskrll static void
fpu_disable(void)60*75b842b8Sskrll fpu_disable(void)
61*75b842b8Sskrll {
62*75b842b8Sskrll 	csr_sstatus_clear(SR_FS);
63*75b842b8Sskrll }
64*75b842b8Sskrll 
65*75b842b8Sskrll static void
fpu_enable(void)66*75b842b8Sskrll fpu_enable(void)
67*75b842b8Sskrll {
68*75b842b8Sskrll 	csr_sstatus_clear(SR_FS);
69*75b842b8Sskrll 	csr_sstatus_set(__SHIFTIN(SR_FS_CLEAN, SR_FS));
70*75b842b8Sskrll }
71*75b842b8Sskrll 
729687a165Smatt void
fpu_state_save(lwp_t * l)739687a165Smatt fpu_state_save(lwp_t *l)
749687a165Smatt {
75*75b842b8Sskrll //	struct trapframe * const tf = l->l_md.md_utf;
769687a165Smatt 	struct pcb * const pcb = lwp_getpcb(l);
779687a165Smatt 	struct fpreg * const fp = &pcb->pcb_fpregs;
789687a165Smatt 
799687a165Smatt 	KASSERT(l->l_pcu_cpu[PCU_FPU] == curcpu());
809687a165Smatt 
819687a165Smatt 	curcpu()->ci_ev_fpu_saves.ev_count++;
829687a165Smatt 
839687a165Smatt 	// Enable FPU to save FP state
84*75b842b8Sskrll 	fpu_enable();
859687a165Smatt 
869687a165Smatt 	// Save FCSR
87*75b842b8Sskrll 	fp->r_fcsr = fcsr_read();
889687a165Smatt 
899687a165Smatt 	// Save FP register values.
909687a165Smatt 	__asm(	"fsd	f0, (0*%1)(%0)"
919687a165Smatt 	"\n\t"	"fsd	f1, (1*%1)(%0)"
929687a165Smatt 	"\n\t"	"fsd	f2, (2*%1)(%0)"
939687a165Smatt 	"\n\t"	"fsd	f3, (3*%1)(%0)"
949687a165Smatt 	"\n\t"	"fsd	f4, (4*%1)(%0)"
959687a165Smatt 	"\n\t"	"fsd	f5, (5*%1)(%0)"
969687a165Smatt 	"\n\t"	"fsd	f6, (6*%1)(%0)"
979687a165Smatt 	"\n\t"	"fsd	f7, (7*%1)(%0)"
989687a165Smatt 	"\n\t"	"fsd	f8, (8*%1)(%0)"
999687a165Smatt 	"\n\t"	"fsd	f9, (9*%1)(%0)"
1009687a165Smatt 	"\n\t"	"fsd	f10, (10*%1)(%0)"
1019687a165Smatt 	"\n\t"	"fsd	f11, (11*%1)(%0)"
1029687a165Smatt 	"\n\t"	"fsd	f12, (12*%1)(%0)"
1039687a165Smatt 	"\n\t"	"fsd	f13, (13*%1)(%0)"
1049687a165Smatt 	"\n\t"	"fsd	f14, (14*%1)(%0)"
1059687a165Smatt 	"\n\t"	"fsd	f15, (15*%1)(%0)"
1069687a165Smatt 	"\n\t"	"fsd	f16, (16*%1)(%0)"
1079687a165Smatt 	"\n\t"	"fsd	f17, (17*%1)(%0)"
1089687a165Smatt 	"\n\t"	"fsd	f18, (18*%1)(%0)"
1099687a165Smatt 	"\n\t"	"fsd	f19, (19*%1)(%0)"
1109687a165Smatt 	"\n\t"	"fsd	f20, (20*%1)(%0)"
1119687a165Smatt 	"\n\t"	"fsd	f21, (21*%1)(%0)"
1129687a165Smatt 	"\n\t"	"fsd	f22, (22*%1)(%0)"
1139687a165Smatt 	"\n\t"	"fsd	f23, (23*%1)(%0)"
1149687a165Smatt 	"\n\t"	"fsd	f24, (24*%1)(%0)"
1159687a165Smatt 	"\n\t"	"fsd	f25, (25*%1)(%0)"
1169687a165Smatt 	"\n\t"	"fsd	f26, (26*%1)(%0)"
1179687a165Smatt 	"\n\t"	"fsd	f27, (27*%1)(%0)"
1189687a165Smatt 	"\n\t"	"fsd	f28, (28*%1)(%0)"
1199687a165Smatt 	"\n\t"	"fsd	f29, (29*%1)(%0)"
1209687a165Smatt 	"\n\t"	"fsd	f30, (30*%1)(%0)"
1219687a165Smatt 	"\n\t"	"fsd	f31, (31*%1)(%0)"
1229687a165Smatt 	   ::	"r"(fp->r_fpreg),
123*75b842b8Sskrll 		"i"(sizeof(fp->r_fpreg[0])) : "memory");
1249687a165Smatt 
1259687a165Smatt 	// Disable the FPU
126*75b842b8Sskrll 	fpu_disable();
1279687a165Smatt }
1289687a165Smatt 
1299687a165Smatt void
fpu_state_load(lwp_t * l,u_int flags)1309687a165Smatt fpu_state_load(lwp_t *l, u_int flags)
1319687a165Smatt {
1329687a165Smatt 	struct trapframe * const tf = l->l_md.md_utf;
1339687a165Smatt 	struct pcb * const pcb = lwp_getpcb(l);
1349687a165Smatt 	struct fpreg * const fp = &pcb->pcb_fpregs;
1359687a165Smatt 
136*75b842b8Sskrll 	KASSERT(l == curlwp);
137*75b842b8Sskrll //	KASSERT(l->l_pcu_cpu[PCU_FPU] == curcpu());
1389687a165Smatt 
1399687a165Smatt 	// If this is the first time the state is being loaded, zero it first.
1409687a165Smatt 	if (__predict_false((flags & PCU_VALID) == 0)) {
1419687a165Smatt 		memset(fp, 0, sizeof(*fp));
1429687a165Smatt 	}
1439687a165Smatt 
1449687a165Smatt 	// Enable the FP when this lwp return to userspace.
145*75b842b8Sskrll 	tf->tf_sr &= ~SR_FS;
146*75b842b8Sskrll 	tf->tf_sr |= __SHIFTIN(SR_FS_CLEAN, SR_FS);
1479687a165Smatt 
148d42188d8Sandvar 	// If this is a simple reenable, set the FPU enable flag and return
1499687a165Smatt 	if (flags & PCU_REENABLE) {
1509687a165Smatt 		curcpu()->ci_ev_fpu_reenables.ev_count++;
1519687a165Smatt 		return;
1529687a165Smatt 	}
1539687a165Smatt 
1549687a165Smatt 	curcpu()->ci_ev_fpu_loads.ev_count++;
1559687a165Smatt 
1569687a165Smatt 
1579687a165Smatt 	// Enabling to load FP state.  Interrupts will remain on.
158*75b842b8Sskrll 	fpu_enable();
1599687a165Smatt 
1609687a165Smatt 	// load FP registers and establish processes' FP context.
1619687a165Smatt 	__asm(	"fld	f0, (0*%1)(%0)"
1629687a165Smatt 	"\n\t"	"fld	f1, (1*%1)(%0)"
1639687a165Smatt 	"\n\t"	"fld	f2, (2*%1)(%0)"
1649687a165Smatt 	"\n\t"	"fld	f3, (3*%1)(%0)"
1659687a165Smatt 	"\n\t"	"fld	f4, (4*%1)(%0)"
1669687a165Smatt 	"\n\t"	"fld	f5, (5*%1)(%0)"
1679687a165Smatt 	"\n\t"	"fld	f6, (6*%1)(%0)"
1689687a165Smatt 	"\n\t"	"fld	f7, (7*%1)(%0)"
1699687a165Smatt 	"\n\t"	"fld	f8, (8*%1)(%0)"
1709687a165Smatt 	"\n\t"	"fld	f9, (9*%1)(%0)"
1719687a165Smatt 	"\n\t"	"fld	f10, (10*%1)(%0)"
1729687a165Smatt 	"\n\t"	"fld	f11, (11*%1)(%0)"
1739687a165Smatt 	"\n\t"	"fld	f12, (12*%1)(%0)"
1749687a165Smatt 	"\n\t"	"fld	f13, (13*%1)(%0)"
1759687a165Smatt 	"\n\t"	"fld	f14, (14*%1)(%0)"
1769687a165Smatt 	"\n\t"	"fld	f15, (15*%1)(%0)"
1779687a165Smatt 	"\n\t"	"fld	f16, (16*%1)(%0)"
1789687a165Smatt 	"\n\t"	"fld	f17, (17*%1)(%0)"
1799687a165Smatt 	"\n\t"	"fld	f18, (18*%1)(%0)"
1809687a165Smatt 	"\n\t"	"fld	f19, (19*%1)(%0)"
1819687a165Smatt 	"\n\t"	"fld	f20, (20*%1)(%0)"
1829687a165Smatt 	"\n\t"	"fld	f21, (21*%1)(%0)"
1839687a165Smatt 	"\n\t"	"fld	f22, (22*%1)(%0)"
1849687a165Smatt 	"\n\t"	"fld	f23, (23*%1)(%0)"
1859687a165Smatt 	"\n\t"	"fld	f24, (24*%1)(%0)"
1869687a165Smatt 	"\n\t"	"fld	f25, (25*%1)(%0)"
1879687a165Smatt 	"\n\t"	"fld	f26, (26*%1)(%0)"
1889687a165Smatt 	"\n\t"	"fld	f27, (27*%1)(%0)"
1899687a165Smatt 	"\n\t"	"fld	f28, (28*%1)(%0)"
1909687a165Smatt 	"\n\t"	"fld	f29, (29*%1)(%0)"
1919687a165Smatt 	"\n\t"	"fld	f30, (30*%1)(%0)"
1929687a165Smatt 	"\n\t"	"fld	f31, (31*%1)(%0)"
1939687a165Smatt 	   ::	"r"(fp->r_fpreg),
194*75b842b8Sskrll 		"i"(sizeof(fp->r_fpreg[0])): "memory");
1959687a165Smatt 
1969687a165Smatt 	// load FPCSR and disable FPU again
197*75b842b8Sskrll 	fcsr_write(fp->r_fcsr);
198*75b842b8Sskrll 
199*75b842b8Sskrll 	fpu_disable();
2009687a165Smatt }
2019687a165Smatt 
2029687a165Smatt void
fpu_state_release(lwp_t * l)2039687a165Smatt fpu_state_release(lwp_t *l)
2049687a165Smatt {
205*75b842b8Sskrll 	l->l_md.md_utf->tf_sr &= ~SR_FS;
206*75b842b8Sskrll 	fpu_disable();
2079687a165Smatt }
208