xref: /netbsd/sys/arch/hpcmips/hpcmips/interrupt.c (revision bf9ec67e)
1 /*	$NetBSD: interrupt.c,v 1.7 2002/01/29 18:38:32 uch Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include "opt_vr41xx.h"
40 #include "opt_tx39xx.h"
41 
42 #include <sys/param.h>
43 #include <sys/malloc.h>
44 
45 #include <uvm/uvm_extern.h>
46 
47 #include <machine/sysconf.h>
48 
49 extern const u_int32_t __ipl_sr_bits_vr[];
50 extern const u_int32_t __ipl_sr_bits_tx[];
51 
52 const u_int32_t ipl_si_to_sr[_IPL_NSOFT] = {
53 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
54 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
55 	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTNET */
56 	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTSERIAL */
57 };
58 
59 const u_int32_t *ipl_sr_bits;
60 struct hpcmips_soft_intrhand *softnet_intrhand;
61 struct hpcmips_soft_intr hpcmips_soft_intrs[_IPL_NSOFT];
62 
63 void
64 intr_init()
65 {
66 
67 	ipl_sr_bits = CPUISMIPS3 ? __ipl_sr_bits_vr : __ipl_sr_bits_tx;
68 }
69 
70 #if defined(VR41XX) && defined(TX39XX)
71 /*
72  * cpu_intr:
73  *
74  *	handle MIPS CPU interrupt.
75  *	if VR41XX only or TX39XX only kernel, directly jump to each handler
76  *	(tx/tx39icu.c, vr/vr.c), don't use this dispather.
77  *
78  */
79 void
80 cpu_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending)
81 {
82 
83 	(*platform.cpu_intr)(status, cause, pc, ipending);
84 }
85 #endif /* VR41XX && TX39XX */
86 
87 /*
88  * softintr:
89  *
90  *	dispatch pending software interrupt handler.
91  */
92 void
93 softintr(u_int32_t ipending)
94 {
95 	struct hpcmips_soft_intr *asi;
96 	struct hpcmips_soft_intrhand *sih;
97 	int i, s;
98 
99 	ipending &= (MIPS_SOFT_INT_MASK_1 | MIPS_SOFT_INT_MASK_0);
100 	if (ipending == 0)
101 		return;
102 
103 	_clrsoftintr(ipending);
104 
105 	for (i = _IPL_NSOFT - 1; i >= 0; i--) {
106 		if ((ipending & ipl_si_to_sr[i]) == 0)
107 			continue;
108 
109 		asi = &hpcmips_soft_intrs[i];
110 
111 		if (TAILQ_FIRST(&asi->softintr_q) != NULL)
112 			asi->softintr_evcnt.ev_count++;
113 
114 		for (;;) {
115 			s = splhigh();
116 
117 			sih = TAILQ_FIRST(&asi->softintr_q);
118 			if (sih != NULL) {
119 				TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
120 				sih->sih_pending = 0;
121 			}
122 
123 			splx(s);
124 
125 			if (sih == NULL)
126 				break;
127 
128 			uvmexp.softs++;
129 			(*sih->sih_fn)(sih->sih_arg);
130 		}
131 	}
132 }
133 
134 /*
135  * softintr_init:
136  *
137  *	Initialize the software interrupt system.
138  */
139 void
140 softintr_init(void)
141 {
142 	static const char *softintr_names[] = IPL_SOFTNAMES;
143 	struct hpcmips_soft_intr *asi;
144 	int i;
145 
146 	for (i = 0; i < _IPL_NSOFT; i++) {
147 		asi = &hpcmips_soft_intrs[i];
148 		TAILQ_INIT(&asi->softintr_q);
149 		asi->softintr_ipl = IPL_SOFT + i;
150 		simple_lock_init(&asi->softintr_slock);
151 		evcnt_attach_dynamic(&asi->softintr_evcnt, EVCNT_TYPE_INTR,
152 		    NULL, "soft", softintr_names[i]);
153 	}
154 
155 	/* XXX Establish legacy soft interrupt handlers. */
156 	softnet_intrhand = softintr_establish(IPL_SOFTNET,
157 	    (void (*)(void *))netintr, NULL);
158 
159 	assert(softnet_intrhand != NULL);
160 }
161 
162 /*
163  * softintr_establish:		[interface]
164  *
165  *	Register a software interrupt handler.
166  */
167 void *
168 softintr_establish(int ipl, void (*func)(void *), void *arg)
169 {
170 	struct hpcmips_soft_intr *asi;
171 	struct hpcmips_soft_intrhand *sih;
172 
173 	if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) ||
174 			    ipl < IPL_SOFT))
175 		panic("softintr_establish");
176 
177 	asi = &hpcmips_soft_intrs[ipl - IPL_SOFT];
178 
179 	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
180 	if (__predict_true(sih != NULL)) {
181 		sih->sih_intrhead = asi;
182 		sih->sih_fn = func;
183 		sih->sih_arg = arg;
184 		sih->sih_pending = 0;
185 	}
186 	return (sih);
187 }
188 
189 /*
190  * softintr_disestablish:	[interface]
191  *
192  *	Unregister a software interrupt handler.
193  */
194 void
195 softintr_disestablish(void *arg)
196 {
197 	struct hpcmips_soft_intrhand *sih = arg;
198 	struct hpcmips_soft_intr *asi = sih->sih_intrhead;
199 	int s;
200 
201 	s = splhigh();
202 	if (sih->sih_pending) {
203 		TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
204 		sih->sih_pending = 0;
205 	}
206 	splx(s);
207 
208 	free(sih, M_DEVBUF);
209 }
210