intr.c revision 1.15 1 /* $NetBSD: intr.c,v 1.15 2007/02/18 07:13:18 matt Exp $ */
2
3 /*
4 * Copyright (c) 1994-1998 Mark Brinicombe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mark Brinicombe
18 * for the NetBSD Project.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * Soft interrupt and other generic interrupt functions.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.15 2007/02/18 07:13:18 matt Exp $");
40
41 #include "opt_irqstats.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/syslog.h>
46 #include <sys/malloc.h>
47 #include <sys/conf.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <machine/atomic.h>
52 #include <machine/intr.h>
53 #include <machine/cpu.h>
54
55 #include <net/netisr.h>
56
57 #include <arm/arm32/machdep.h>
58
59 extern int current_spl_level;
60
61 extern unsigned spl_mask;
62
63 /* Generate soft interrupt counts if IRQSTATS is defined */
64 /* Prototypes */
65 static void clearsoftintr(u_int);
66
67 u_int soft_interrupts = 0;
68
69 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
70 #ifdef IRQSTATS
71 extern u_int sintrcnt[];
72 #define INC_SINTRCNT(x) ++sintrcnt[x]
73 #else
74 #define INC_SINTRCNT(x)
75 #endif /* IRQSTATS */
76 #else
77 #define INC_SINTRCNT(x)
78 #endif /* !__HAVE_GENERIC_SOFT_INTERRUPTS */
79
80 #define COUNT uvmexp.softs;
81
82 /* Prototypes */
83
84 #include "com.h"
85 #if NCOM > 0
86 extern void comsoft(void);
87 #endif /* NCOM > 0 */
88
89 #if NPLCOM > 0
90 extern void plcomsoft(void);
91 #endif /* NPLCOM > 0 */
92
93 /* Eventually these will become macros */
94
95 #define SI_SOFTMASK(si) (1U << (si))
96
97 static inline void
98 clearsoftintr(u_int intrmask)
99 {
100 atomic_clear_bit(&soft_interrupts, intrmask);
101 }
102
103 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
104 void
105 _setsoftintr(int si)
106 {
107 atomic_set_bit(&soft_interrupts, SI_SOFTMASK(si));
108 }
109 #else /* __HAVE_GENERIC_SOFT_INTERRUPTS */
110 #define SI_SOFTNET SOFTIRQ_NET
111 #define SI_SOFTCLOCK SOFTIRQ_CLOCK
112 #define SI_SOFTSERIAL SOFTIRQ_SERIAL
113 void
114 setsoftintr(u_int intrmask)
115 {
116 atomic_set_bit(&soft_interrupts, intrmask);
117 }
118
119 void
120 setsoftclock(void)
121 {
122 atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTCLOCK));
123 }
124
125 void
126 setsoftnet(void)
127 {
128 atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTNET));
129 }
130
131 void
132 setsoftserial(void)
133 {
134 atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTSERIAL));
135 }
136
137 static void
138 softnet(void)
139 {
140 #define DONETISR(bit, fn) do { \
141 if (netisr & (1 << bit)) { \
142 atomic_clear_bit(&netisr, (1 << bit)); \
143 fn(); \
144 } \
145 } while (0)
146
147 #include <net/netisr_dispatch.h>
148
149 #undef DONETISR
150 }
151 #endif /* !__HAVE_GENERIC_SOFT_INTERRUPTS */
152
153 /* Handle software interrupts */
154
155 void
156 dosoftints(void)
157 {
158 u_int softints;
159 int s;
160
161 softints = soft_interrupts & spl_smasks[current_spl_level];
162 if (softints == 0) return;
163
164 /*
165 * Serial software interrupts
166 */
167 if (softints & SI_SOFTMASK(SI_SOFTSERIAL)) {
168 s = splsoftserial();
169 ++COUNT;
170 INC_SINTRCNT(SI_SOFTSERIAL);
171 clearsoftintr(SI_SOFTMASK(SI_SOFTSERIAL));
172 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
173 #if NCOM > 0
174 comsoft();
175 #endif /* NCOM > 0 */
176 #if NPLCOM > 0
177 plcomsoft();
178 #endif /* NPLCOM > 0 */
179 #else
180 softintr_dispatch(SI_SOFTSERIAL);
181 #endif
182 (void)splx(s);
183 }
184
185 /*
186 * Network software interrupts
187 */
188 if (softints & SI_SOFTMASK(SI_SOFTNET)) {
189 s = splsoftnet();
190 ++COUNT;
191 INC_SINTRCNT(SI_SOFTNET);
192 clearsoftintr(SI_SOFTMASK(SI_SOFTNET));
193 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
194 softnet();
195 #else
196 softintr_dispatch(SI_SOFTNET);
197 #endif
198 (void)splx(s);
199 }
200
201 /*
202 * Software clock interrupts
203 */
204 if (softints & SI_SOFTMASK(SI_SOFTCLOCK)) {
205 s = splsoftclock();
206 ++COUNT;
207 INC_SINTRCNT(SI_SOFTCLOCK);
208 clearsoftintr(SI_SOFTMASK(SI_SOFTCLOCK));
209 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
210 softclock(NULL);
211 #else
212 softintr_dispatch(SI_SOFTCLOCK);
213 #endif
214 (void)splx(s);
215 }
216
217 /*
218 * Misc software interrupts
219 */
220 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
221 if (softints & SI_SOFTMASK(SI_SOFT)) {
222 s = splsoft();
223 ++COUNT;
224 clearsoftintr(SI_SOFTMASK(SI_SOFT));
225 softintr_dispatch(SI_SOFT);
226 (void)splx(s);
227 }
228 #endif
229 }
230
231 int current_spl_level = _SPL_SERIAL;
232 u_int spl_masks[_SPL_LEVELS + 1];
233 u_int spl_smasks[_SPL_LEVELS];
234 int safepri = _SPL_0;
235
236 extern u_int irqmasks[];
237
238 void
239 set_spl_masks(void)
240 {
241 int loop;
242
243 for (loop = 0; loop < _SPL_LEVELS; ++loop) {
244 spl_masks[loop] = 0xffffffff;
245 spl_smasks[loop] = 0;
246 }
247
248 spl_masks[_SPL_BIO] = irqmasks[IPL_BIO];
249 spl_masks[_SPL_NET] = irqmasks[IPL_NET];
250 spl_masks[_SPL_SOFTSERIAL] = irqmasks[IPL_TTY];
251 spl_masks[_SPL_TTY] = irqmasks[IPL_TTY];
252 spl_masks[_SPL_VM] = irqmasks[IPL_VM];
253 spl_masks[_SPL_AUDIO] = irqmasks[IPL_AUDIO];
254 spl_masks[_SPL_CLOCK] = irqmasks[IPL_CLOCK];
255 #ifdef IPL_STATCLOCK
256 spl_masks[_SPL_STATCLOCK] = irqmasks[IPL_STATCLOCK];
257 #else
258 spl_masks[_SPL_STATCLOCK] = irqmasks[IPL_CLOCK];
259 #endif
260 spl_masks[_SPL_HIGH] = irqmasks[IPL_HIGH];
261 spl_masks[_SPL_SERIAL] = irqmasks[IPL_SERIAL];
262 spl_masks[_SPL_LEVELS] = 0;
263
264 spl_smasks[_SPL_0] = 0xffffffff;
265 for (loop = 0; loop < _SPL_SOFTSERIAL; ++loop)
266 spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTSERIAL);
267 for (loop = 0; loop < _SPL_SOFTNET; ++loop)
268 spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTNET);
269 for (loop = 0; loop < _SPL_SOFTCLOCK; ++loop)
270 spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTCLOCK);
271 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
272 for (loop = 0; loop < _SPL_SOFT; ++loop)
273 spl_smasks[loop] |= SI_SOFTMASK(SI_SOFT);
274 #endif
275 }
276
277 static const int ipl_to_spl_map[] = {
278 [IPL_NONE] = 1 + _SPL_0,
279 #ifdef IPL_SOFT
280 [IPL_SOFT] = 1 + _SPL_SOFT,
281 #endif /* IPL_SOFTCLOCK */
282 #if defined(IPL_SOFTCLOCK)
283 [IPL_SOFTCLOCK] = 1 + _SPL_SOFTCLOCK,
284 #endif /* defined(IPL_SOFTCLOCK) */
285 #if defined(IPL_SOFTNET)
286 [IPL_SOFTNET] = 1 + _SPL_SOFTNET,
287 #endif /* defined(IPL_SOFTNET) */
288 [IPL_BIO] = 1 + _SPL_BIO,
289 [IPL_NET] = 1 + _SPL_NET,
290 #if defined(IPL_SOFTSERIAL)
291 [IPL_SOFTSERIAL] = 1 + _SPL_SOFTSERIAL,
292 #endif /* defined(IPL_SOFTSERIAL) */
293 [IPL_TTY] = 1 + _SPL_TTY,
294 [IPL_VM] = 1 + _SPL_VM,
295 [IPL_AUDIO] = 1 + _SPL_AUDIO,
296 [IPL_CLOCK] = 1 + _SPL_CLOCK,
297 [IPL_STATCLOCK] = 1 + _SPL_STATCLOCK,
298 [IPL_HIGH] = 1 + _SPL_HIGH,
299 [IPL_SERIAL] = 1 + _SPL_SERIAL,
300 };
301
302 int
303 ipl_to_spl(int ipl)
304 {
305 KASSERT(ipl < __arraycount(ipl_to_spl_map));
306 KASSERT(ipl_to_spl_map[ipl]);
307
308 return ipl_to_spl_map[ipl] - 1;
309 }
310
311 #ifdef DIAGNOSTIC
312 void
313 dump_spl_masks(void)
314 {
315 int loop;
316
317 for (loop = 0; loop < _SPL_LEVELS; ++loop) {
318 printf("spl_mask[%d]=%08x splsmask[%d]=%08x\n", loop,
319 spl_masks[loop], loop, spl_smasks[loop]);
320 }
321 }
322 #endif
323
324 /* End of intr.c */
325