xref: /netbsd-src/sys/arch/mips/mips/mips_dsp.c (revision 66e429480fdf2331b3ef6ed232ef6f43e4c5d59b)
1 /*	$NetBSD: mips_dsp.c,v 1.6 2017/05/07 05:45:07 skrll Exp $	*/
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matt Thomas of 3am Software Foundry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mips_dsp.c,v 1.6 2017/05/07 05:45:07 skrll Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/mutex.h>
37 #include <sys/condvar.h>
38 #include <sys/cpu.h>
39 #include <sys/proc.h>
40 #include <sys/lwp.h>
41 #include <sys/pcu.h>
42 
43 #include <mips/locore.h>
44 #include <mips/regnum.h>
45 #include <mips/pcb.h>
46 
47 static void mips_dsp_state_save(lwp_t *);
48 static void mips_dsp_state_load(lwp_t *, u_int);
49 static void mips_dsp_state_release(lwp_t *);
50 
51 const pcu_ops_t mips_dsp_ops = {
52 	.pcu_id = PCU_DSP,
53 	.pcu_state_save = mips_dsp_state_save,
54 	.pcu_state_load = mips_dsp_state_load,
55 	.pcu_state_release = mips_dsp_state_release
56 };
57 
58 void
dsp_discard(lwp_t * l)59 dsp_discard(lwp_t *l)
60 {
61 	pcu_discard(&mips_dsp_ops, l, false);
62 }
63 
64 void
dsp_load(void)65 dsp_load(void)
66 {
67 	pcu_load(&mips_dsp_ops);
68 }
69 
70 void
dsp_save(lwp_t * l)71 dsp_save(lwp_t *l)
72 {
73 	pcu_save(&mips_dsp_ops, l);
74 }
75 
76 bool
dsp_used_p(const lwp_t * l)77 dsp_used_p(const lwp_t *l)
78 {
79 	return pcu_valid_p(&mips_dsp_ops, l);
80 }
81 
82 void
mips_dsp_state_save(lwp_t * l)83 mips_dsp_state_save(lwp_t *l)
84 {
85 	struct trapframe * const tf = l->l_md.md_utf;
86 	struct pcb * const pcb = lwp_getpcb(l);
87 	mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs;
88 	uint32_t status;
89 
90 	/*
91 	 * Don't do anything if the DSP is already off.
92 	 */
93 	if ((tf->tf_regs[_R_SR] & MIPS_SR_MX) == 0)
94 		return;
95 
96 	l->l_cpu->ci_ev_dsp_saves.ev_count++;
97 
98 	/*
99 	 * load DSP registers and establish lwp's DSP context.
100 	 */
101 	__asm volatile (
102 		".set push"				"\n\t"
103 		".set mips32r2"				"\n\t"
104 		".set dspr2"				"\n\t"
105 		".set noat"				"\n\t"
106 		".set noreorder"			"\n\t"
107 		"mfc0	%[status], $%[cp0_status]"	"\n\t"
108 		"or	%[status], %[mips_sr_mx]"	"\n\t"
109 		"mtc0	%[status], $%[cp0_status]"	"\n\t"
110 		"ehb"					"\n\t"
111 		"mflo	%[mullo1], $ac1"		"\n\t"
112 		"mfhi	%[mulhi1], $ac1"		"\n\t"
113 		"mflo	%[mullo2], $ac2"		"\n\t"
114 		"mfhi	%[mulhi2], $ac2"		"\n\t"
115 		"mflo	%[mullo3], $ac3"		"\n\t"
116 		"mfhi	%[mulhi3], $ac3"		"\n\t"
117 		"rddsp	%[dspctl]"			"\n\t"
118 		"xor	%[status], %[mips_sr_mx]"	"\n\t"
119 		"mtc0	%[status], $%[cp0_status]"	"\n\t"
120 		"ehb"					"\n\t"
121 		".set pop"
122 	    :	[status] "=&r" (status),
123 		[mullo1] "=r"(dsp[_R_MULLO1 - _R_DSPBASE]),
124 		[mulhi1] "=r"(dsp[_R_MULHI1 - _R_DSPBASE]),
125 		[mullo2] "=r"(dsp[_R_MULLO2 - _R_DSPBASE]),
126 		[mulhi2] "=r"(dsp[_R_MULHI2 - _R_DSPBASE]),
127 		[mullo3] "=r"(dsp[_R_MULLO3 - _R_DSPBASE]),
128 		[mulhi3] "=r"(dsp[_R_MULHI3 - _R_DSPBASE]),
129 		[dspctl] "=r"(dsp[_R_DSPCTL - _R_DSPBASE])
130 	    :	[mips_sr_mx] "r"(MIPS_SR_MX),
131 		[cp0_status] "n"(MIPS_COP_0_STATUS));
132 }
133 
134 void
mips_dsp_state_load(lwp_t * l,u_int flags)135 mips_dsp_state_load(lwp_t *l, u_int flags)
136 {
137 	struct trapframe * const tf = l->l_md.md_utf;
138 	struct pcb * const pcb = lwp_getpcb(l);
139 	mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs;
140 	uint32_t status;
141 
142 	l->l_cpu->ci_ev_dsp_loads.ev_count++;
143 
144 	/*
145 	 * If this is the first time the state is being loaded, zero it first.
146 	 */
147 	if (__predict_false((flags & PCU_VALID) == 0)) {
148 		memset(&pcb->pcb_dspregs, 0, sizeof(pcb->pcb_dspregs));
149 	}
150 
151 	/*
152 	 * Enable the DSP when this lwp return to userspace.
153 	 */
154 	tf->tf_regs[_R_SR] |= MIPS_SR_MX;
155 
156 	/*
157 	 * load DSP registers and establish lwp's DSP context.
158 	 */
159 	__asm volatile (
160 		".set push"				"\n\t"
161 		".set mips32r2"				"\n\t"
162 		".set dspr2"				"\n\t"
163 		".set noat"				"\n\t"
164 		".set noreorder"			"\n\t"
165 		"mfc0	%[status], $%[cp0_status]"	"\n\t"
166 		"or	%[status], %[mips_sr_mx]"	"\n\t"
167 		"mtc0	%[status], $%[cp0_status]"	"\n\t"
168 		"ehb"					"\n\t"
169 		"mtlo	%[mullo1], $ac1"		"\n\t"
170 		"mthi	%[mulhi1], $ac1"		"\n\t"
171 		"mtlo	%[mullo2], $ac2"		"\n\t"
172 		"mthi	%[mulhi2], $ac2"		"\n\t"
173 		"mtlo	%[mullo3], $ac3"		"\n\t"
174 		"mthi	%[mulhi3], $ac3"		"\n\t"
175 		"wrdsp	%[dspctl]"			"\n\t"
176 		"xor	%[status], %[mips_sr_mx]"	"\n\t"
177 		"mtc0	%[status], $%[cp0_status]"	"\n\t"
178 		"ehb"					"\n\t"
179 		".set pop"
180 	    :	[status] "=&r" (status)
181 	    :	[mullo1] "r"(dsp[_R_MULLO1 - _R_DSPBASE]),
182 		[mulhi1] "r"(dsp[_R_MULHI1 - _R_DSPBASE]),
183 		[mullo2] "r"(dsp[_R_MULLO2 - _R_DSPBASE]),
184 		[mulhi2] "r"(dsp[_R_MULHI2 - _R_DSPBASE]),
185 		[mullo3] "r"(dsp[_R_MULLO3 - _R_DSPBASE]),
186 		[mulhi3] "r"(dsp[_R_MULHI3 - _R_DSPBASE]),
187 		[dspctl] "r"(dsp[_R_DSPCTL - _R_DSPBASE]),
188 		[mips_sr_mx] "r"(MIPS_SR_MX),
189 		[cp0_status] "n"(MIPS_COP_0_STATUS));
190 }
191 
192 void
mips_dsp_state_release(lwp_t * l)193 mips_dsp_state_release(lwp_t *l)
194 {
195 	KASSERT(l == curlwp);
196 	l->l_md.md_utf->tf_regs[_R_SR] &= ~MIPS_SR_MX;
197 }
198