xref: /netbsd-src/sys/arch/mips/mips/spl.S (revision 5b6b6999b32dbb8651ed1a39bf4f1f3f25495ca2)
1/*	$NetBSD: spl.S,v 1.20 2023/05/22 06:50:52 skrll Exp $	*/
2
3/*-
4 * Copyright (c) 2009, 2010 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 <matt@3am-software.com>.
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 "opt_multiprocessor.h"	/* MP kernel? */
33#include "opt_cputype.h"	/* which mips CPU levels do we support? */
34#include "opt_ddb.h"
35
36#include <sys/cdefs.h>
37
38#include <mips/asm.h>
39#include <mips/cpuregs.h>
40
41RCSID("$NetBSD: spl.S,v 1.20 2023/05/22 06:50:52 skrll Exp $")
42
43#include "assym.h"
44
45	.data
46	.globl	_C_LABEL(ipl_sr_map)
47	.type	_C_LABEL(ipl_sr_map),@object
48	.p2align INT_SCALESHIFT
49_C_LABEL(ipl_sr_map):
50	.word	0			/* IPL_NONE */
51	.word	MIPS_SOFT_INT_MASK_0	/* IPL_SOFT{CLOCK,BIO} */
52	.word	MIPS_SOFT_INT_MASK	/* IPL_SOFT{NET,SERIAL} */
53	.word	MIPS_INT_MASK		/* IPL_VM */
54	.word	MIPS_INT_MASK		/* IPL_SCHED */
55	.word	MIPS_INT_MASK		/* IPL_DDB */
56	.word	MIPS_INT_MASK		/* IPL_HIGH */
57
58	.text
59	.set	noreorder
60/*
61 * MIPS processor interrupt control
62 *
63 * Used as building blocks for spl(9) kernel interface.
64 */
65_splraise:
66	/*
67	 * a0 = SR bits to be cleared for this IPL
68	 * a1 = this IPL (IPL_*)
69	 * Can only use a0-a3 and v0-v1
70	 */
71	PTR_L	a3, L_CPU(MIPS_CURLWP)
72	NOP_L					# load delay
73	INT_L	v0, CPU_INFO_CPL(a3)		# get current IPL from cpu_info
74	NOP_L					# load delay
75	sltu	v1, a1, v0			# newipl < curipl
76	bnez	v1, 1f				# yes, don't change.
77	 nop					#  branch delay
78	mfc0	v1, MIPS_COP_0_STATUS		# fetch status register
79	MFC0_HAZARD				# load delay
80	or	v1, MIPS_INT_MASK		# enable all interrupts
81	xor	a0, v1				# disable ipl's masked bits
82	DYNAMIC_STATUS_MASK(a0,v0)		# machine dependent masking
83#if !defined(__mips_o32)
84	or	v1, MIPS_SR_INT_IE		#
85	xor	v1, MIPS_SR_INT_IE		# clear interrupt enable bit
86	mtc0	v1, MIPS_COP_0_STATUS		# disable interrupts
87#else
88	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
89#endif
90	COP0_SYNC
91#ifdef MULTIPROCESSOR
92	PTR_L	a3, L_CPU(MIPS_CURLWP)		# make sure curcpu is correct
93	NOP_L					# load delay
94#endif
95	INT_S	a1, CPU_INFO_CPL(a3)		# save IPL in cpu_info
96	mtc0	a0, MIPS_COP_0_STATUS		# store back
97	COP0_SYNC
98#ifdef PARANOIA
99	jr	ra
100	 nop					#  branch delay
101#endif /* PARANOIA */
1021:
103#ifdef PARANOIA
104	mfc0	v1, MIPS_COP_0_STATUS
105	MFC0_HAZARD				# load delay
106	and	a0, v1				# a1 contains bit that MBZ
1073:	bnez	a0, 3b				# loop forever
108	 nop					#  branch delay
109#endif /* PARANOIA */
110	jr	ra
111	 nop					#  branch delay
112
113STATIC_LEAF(_splsw_splx)
114STATIC_XLEAF(_splsw_splx_noprof)		# does not get mcount hooks
115#ifdef PARANOIA
116	sltiu	v0, a0, IPL_HIGH+1		# v0 = a0 <= IPL_HIGH
11798:	beqz	v0, 98b
118	 nop
119#endif
120	PTR_L	a3, L_CPU(MIPS_CURLWP)		# get cpu_info
121	NOP_L					# load delay
122	INT_L	a2, CPU_INFO_CPL(a3)		# get IPL from cpu_info
123	NOP_L					# load delay
124	beq	a0, a2, 2f			# if same, nothing to do
125	 nop					#  branch delay
126#ifdef PARANOIA
127	sltu	v0, a0, a2			# v0 = a0 < a2
12899:	beqz	v0, 99b				# loop forever if false
129	 nop					#  branch delay
130#endif /* PARANOIA */
131	PTR_LA	v1, _C_LABEL(ipl_sr_map)	# get address of table
132	sll	a2, a0, INT_SCALESHIFT		# convert IPL to array offset
133	PTR_ADDU v1, a2				# add to table addr
134	INT_L	a1, (v1)			# load SR bits for this IPL
1351:
136	mfc0	v1, MIPS_COP_0_STATUS		# fetch status register
137	xor	a1, MIPS_INT_MASK		# invert SR bits
138	or	v1, a1				# set any bits for this IPL
139	DYNAMIC_STATUS_MASK(v1,t0)		# machine dependent masking
140#if !defined(__mips_o32)
141	or	v0, v1, MIPS_SR_INT_IE		#
142	xor	v0, MIPS_SR_INT_IE		# clear interrupt enable bit
143	mtc0	v0, MIPS_COP_0_STATUS		# disable interrupts
144#else
145	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
146#endif
147	COP0_SYNC
148	INT_S	a0, CPU_INFO_CPL(a3)		# save IPL in cpu_info (KSEG0)
149	mtc0	v1, MIPS_COP_0_STATUS		# store back
150	COP0_SYNC
151#ifdef PARANOIA
152	jr	ra
153	 nop					#  branch delay
154#endif /* PARANOIA */
1552:
156#ifdef PARANOIA
157	PTR_LA	v1, _C_LABEL(ipl_sr_map)	# get address of table
158	sll	a2, a0, INT_SCALESHIFT		# convert IPL to array offset
159	PTR_ADDU v1, a2				# add to table addr
160	INT_L	a1, (v1)			# load SR bits for this IPL
161	mfc0	v1, MIPS_COP_0_STATUS
162	MFC0_HAZARD				# load delay
163	and	v1, MIPS_INT_MASK
164	xor	a1, MIPS_INT_MASK
1653:	bne	a1, v1, 3b
166	 nop					#  branch delay
167#endif /* PARANOIA */
168	jr	ra
169	 nop					#  branch delay
170END(_splsw_splx)
171
172STATIC_LEAF(_splsw_spl0)
173	INT_L	v1, _C_LABEL(ipl_sr_map) + 4*IPL_NONE
174	PTR_L	a3, L_CPU(MIPS_CURLWP)
175	or	v1, MIPS_SR_INT_IE		# make sure interrupts are on
176	xor	v1, MIPS_INT_MASK		# invert
177	mfc0	a0, MIPS_COP_0_STATUS
178	MFC0_HAZARD				# load delay
179	or	v0, a0, v1
180	DYNAMIC_STATUS_MASK(v0,t0)		# machine dependent masking
181#if !defined(__mips_o32)
182	or	v1, v0, MIPS_SR_INT_IE		#
183	xor	v1, MIPS_SR_INT_IE		# clear interrupt enable bit
184	mtc0	v1, MIPS_COP_0_STATUS		# disable interrupts
185#else
186	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
187#endif
188	COP0_SYNC
189#if IPL_NONE == 0
190	INT_S	zero, CPU_INFO_CPL(a3)		# set ipl to 0
191#else
192#error IPL_NONE != 0
193#endif
194	mtc0	v0, MIPS_COP_0_STATUS		# enable all sources
195	JR_HB_RA				# return (clear hazards)
196END(_splsw_spl0)
197
198STATIC_LEAF(_splsw_setsoftintr)
199	mfc0	v1, MIPS_COP_0_STATUS		# save status register
200#if !defined(__mips_o32)
201	MFC0_HAZARD				# load delay
202	or	v0, v1, MIPS_SR_INT_IE		#
203	xor	v0, MIPS_SR_INT_IE		# clear interrupt enable bit
204	mtc0	v0, MIPS_COP_0_STATUS		# disable interrupts
205#else
206	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
207#endif
208	COP0_SYNC
209	mfc0	v0, MIPS_COP_0_CAUSE		# fetch cause register
210	MFC0_HAZARD				# load delay
211	or	v0, v0, a0			# set soft intr. bits
212	mtc0	v0, MIPS_COP_0_CAUSE		# store back
213	COP0_SYNC
214	mtc0	v1, MIPS_COP_0_STATUS		# enable interrupts
215	JR_HB_RA				# return (clear hazards)
216END(_splsw_setsoftintr)
217
218STATIC_LEAF(_splsw_clrsoftintr)
219	mfc0	v1, MIPS_COP_0_STATUS		# save status register
220#if !defined(__mips_o32)
221	MFC0_HAZARD				# load delay
222	or	v0, v1, MIPS_SR_INT_IE		#
223	xor	v0, MIPS_SR_INT_IE		# clear interrupt enable bit
224	mtc0	v0, MIPS_COP_0_STATUS		# disable interrupts
225#else
226	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
227#endif
228	COP0_SYNC
229	mfc0	v0, MIPS_COP_0_CAUSE		# fetch cause register
230	nor	a0, zero, a0			# bitwise inverse of A0
231	and	v0, v0, a0			# clear soft intr. bits
232	mtc0	v0, MIPS_COP_0_CAUSE		# store back
233	COP0_SYNC
234	mtc0	v1, MIPS_COP_0_STATUS		# enable interrupts
235	JR_HB_RA				# return (clear hazards)
236END(_splsw_clrsoftintr)
237
238STATIC_LEAF(_splsw_splraise)
239#if defined(DDB) && __mips >= 32
240	tgeiu	a0, IPL_HIGH+1
241#endif
242	move	a1, a0
243	PTR_LA	v1, _C_LABEL(ipl_sr_map)
244	sll	a2, a0, INT_SCALESHIFT
245	PTR_ADDU v1, a2
246	b	_splraise
247	 INT_L	a0, (v1)
248END(_splsw_splraise)
249
250STATIC_LEAF(_splsw_splhigh)
251STATIC_XLEAF(_splsw_splhigh_noprof)
252	PTR_L	a3, L_CPU(MIPS_CURLWP)
253	NOP_L					# load delay
254	INT_L	v0, CPU_INFO_CPL(a3)		# get current IPL from cpu_info
255	li	a1, IPL_HIGH			#
256	beq	v0, a1, 1f			# don't do anything if IPL_HIGH
257	 nop					# branch delay
258	mfc0	v1, MIPS_COP_0_STATUS		# fetch status register
259	MFC0_HAZARD				# load delay
260	and	a0, v1, MIPS_INT_MASK		# select all interrupts
261	xor	a0, v1				# clear all interrupts
262	DYNAMIC_STATUS_MASK(a0,a2)		# machine dependent masking
263	mtc0	a0, MIPS_COP_0_STATUS		# store back
264	COP0_SYNC
265#ifdef MULTIPROCESSOR
266	PTR_L	a3, L_CPU(MIPS_CURLWP)		# make sure curcpu is correct
267	NOP_L					# load delay
268#endif
269	INT_S	a1, CPU_INFO_CPL(a3)		# save IPL in cpu_info
270#ifdef PARANOIA
271	jr	ra				# return
272	 nop					#  branch delay
273#endif /* PARANOIA */
2741:
275#ifdef PARANOIA
276	mfc0	v1, MIPS_COP_0_STATUS		# fetch status register
277	MFC0_HAZARD				# load delay
278	and	v1, MIPS_INT_MASK		# any int bits set?
2792:	bnez	v1, 2b				# loop forever.
280	 nop					# branch delay
281#endif /* PARANOIA */
282	jr	ra				# return
283	 nop					# branch delay
284END(_splsw_splhigh)
285
286	.p2align 4
287STATIC_LEAF(_splsw_splddb)
288	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_DDB
289	b	_splraise
290	 li	a1, IPL_DDB
291	nop
292END(_splsw_splddb)
293
294STATIC_LEAF(_splsw_splsched)
295	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_SCHED
296	b	_splraise
297	 li	a1, IPL_SCHED
298	nop
299END(_splsw_splsched)
300
301STATIC_LEAF(_splsw_splvm)
302	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_VM
303	b	_splraise
304	 li	a1, IPL_VM
305	nop
306END(_splsw_splvm)
307
308STATIC_LEAF(_splsw_splsoftserial)
309	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTSERIAL
310	b	_splraise
311	 li	a1, IPL_SOFTSERIAL
312	nop
313END(_splsw_splsoftserial)
314
315STATIC_LEAF(_splsw_splsoftnet)
316	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTNET
317	b	_splraise
318	 li	a1, IPL_SOFTNET
319	nop
320END(_splsw_splsoftnet)
321
322STATIC_LEAF(_splsw_splsoftbio)
323	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTBIO
324	b	_splraise
325	 li	a1, IPL_SOFTBIO
326	nop
327END(_splsw_splsoftbio)
328
329STATIC_LEAF(_splsw_splsoftclock)
330	INT_L	a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTCLOCK
331	b	_splraise
332	 li	a1, IPL_SOFTCLOCK
333	nop
334END(_splsw_splsoftclock)
335
336STATIC_LEAF(_splsw_splintr)
337	mfc0	ta1, MIPS_COP_0_CAUSE		# get active interrupts
338	MFC0_HAZARD				# load delay
339						# restrict to hard int bits
340	and	v1, ta1, MIPS_HARD_INT_MASK	# now have pending interrupts
341	li	v0, IPL_NONE			#  return IPL_NONE
342	beq	v1, zero, 2f			# quick exit if nothing pending
343	 nop					#  branch delay
344
345	li	v0, IPL_VM			# start at IPL_VM
346	PTR_LA	ta3, _C_LABEL(ipl_sr_map) + 4*IPL_VM
347	INT_L	ta2, -4(ta3)			# load mask for IPL_SOFTSERIAL
348	NOP_L					# load delay
349	xor	ta2, MIPS_INT_MASK		# invert
350	and	v1, ta2				# apply to pending bits
351
3521:
353	INT_L	ta2, (ta3)			# get SR bits for ipl in ta2
354	NOP_L					# load delay
355	xor	ta2, MIPS_INT_MASK		# invert
356	and	ta2, v1				# any match to pending intrs?
357	beq	ta2, zero, 2f			#  no, return ipl
358	 nop					#  branch delay
359
360	PTR_ADDU ta3, 1 << INT_SCALESHIFT	# point to next entry
361	addiu	v0, 1				#  increase ipl by 1
362	b	1b				# and check it
363	 move	v1, ta2				# whittle down pending intrs
364
3652:
366	jr	ra
367	 INT_S	v1, (a0)			# return a new pending mask
368END(_splsw_splintr)
369
370STATIC_LEAF(_splsw_splcheck)
371#ifdef PARANOIA
372	PTR_L	t0, L_CPU(MIPS_CURLWP)
373	NOP_L					# load delay
374	INT_L	t1, CPU_INFO_CPL(t0)		# get current priority level
375
376	mfc0	t0, MIPS_COP_0_STATUS		# get current status
377	MFC0_HAZARD				# load delay
378	and	t0, MIPS_INT_MASK		# just want INT bits
379
380	PTR_LA	t2, _C_LABEL(ipl_sr_map)
381	sll	t1, INT_SCALESHIFT		# shift cpl to array index
382	PTR_ADDU t2, t1
383	INT_L	t3, (t2)			# load value
384	NOP_L					# load delay
385	xor	t3, MIPS_INT_MASK		# invert
3861:	bne	t0, t3, 1b			# loop forever if not equal
387	 nop					#  branch delay
388#endif /* PARANOIA */
389	jr	ra
390	 nop					#  branch delay
391END(_splsw_splcheck)
392
393	.rdata
394	.globl _C_LABEL(std_splsw)
395_C_LABEL(std_splsw):
396        PTR_WORD _C_LABEL(_splsw_splhigh)
397        PTR_WORD _C_LABEL(_splsw_splsched)
398        PTR_WORD _C_LABEL(_splsw_splvm)
399        PTR_WORD _C_LABEL(_splsw_splsoftserial)
400        PTR_WORD _C_LABEL(_splsw_splsoftnet)
401        PTR_WORD _C_LABEL(_splsw_splsoftbio)
402        PTR_WORD _C_LABEL(_splsw_splsoftclock)
403        PTR_WORD _C_LABEL(_splsw_splraise)
404        PTR_WORD _C_LABEL(_splsw_spl0)
405        PTR_WORD _C_LABEL(_splsw_splx)
406        PTR_WORD _C_LABEL(_splsw_splhigh_noprof)
407        PTR_WORD _C_LABEL(_splsw_splx_noprof)
408	PTR_WORD _C_LABEL(_splsw_setsoftintr)
409	PTR_WORD _C_LABEL(_splsw_clrsoftintr)
410	PTR_WORD _C_LABEL(_splsw_splintr)
411	PTR_WORD _C_LABEL(_splsw_splcheck)
412