1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32 /*-
33 * Copyright (c) 2001 Jake Burkholder.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
58 * form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
59 */
60
61 #include <sys/cdefs.h>
62 __FBSDID("$FreeBSD$");
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/queue.h>
67 #include <sys/bus.h>
68 #include <sys/errno.h>
69 #include <sys/interrupt.h>
70 #include <sys/ktr.h>
71 #include <sys/lock.h>
72 #include <sys/mutex.h>
73 #include <sys/pcpu.h>
74 #include <sys/proc.h>
75 #include <sys/vmmeter.h>
76
77 #include <machine/frame.h>
78 #include <machine/intr_machdep.h>
79
80 #define MAX_STRAY_LOG 5
81
82 CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
83
84 ih_func_t *intr_handlers[PIL_MAX];
85 uint16_t pil_countp[PIL_MAX];
86
87 struct intr_vector intr_vectors[IV_MAX];
88 uint16_t intr_countp[IV_MAX];
89 static u_long intr_stray_count[IV_MAX];
90
91 static const char *pil_names[] = {
92 "stray",
93 "low", /* PIL_LOW */
94 "ithrd", /* PIL_ITHREAD */
95 "rndzvs", /* PIL_RENDEZVOUS */
96 "ast", /* PIL_AST */
97 "stop", /* PIL_STOP */
98 "stray", "stray", "stray", "stray", "stray", "stray", "stray",
99 "fast", /* PIL_FAST */
100 "tick", /* PIL_TICK */
101 };
102
103 /* protect the intr_vectors table */
104 static struct mtx intr_table_lock;
105
106 static void intr_enable_eoi(void *);
107 static void intr_execute_handlers(void *);
108 static void intr_stray_level(struct trapframe *);
109 static void intr_stray_vector(void *);
110 static int intrcnt_setname(const char *, int);
111 static void intrcnt_updatename(int, const char *, int);
112
113 /*
114 * not MPSAFE
115 */
116 static void
117 intrcnt_updatename(int vec, const char *name, int ispil)
118 {
119 static int intrcnt_index, stray_pil_index, stray_vec_index;
120 int name_index;
121
122 if (intrnames[0] == '\0') {
123 /* for bitbucket */
124 if (bootverbose)
125 printf("initalizing intr_countp\n");
126 intrcnt_setname("???", intrcnt_index++);
127
128 stray_vec_index = intrcnt_index++;
129 intrcnt_setname("stray", stray_vec_index);
130 for (name_index = 0; name_index < IV_MAX; name_index++)
131 intr_countp[name_index] = stray_vec_index;
132
133 stray_pil_index = intrcnt_index++;
134 intrcnt_setname("pil", stray_pil_index);
135 for (name_index = 0; name_index < PIL_MAX; name_index++)
136 pil_countp[name_index] = stray_pil_index;
137 }
138
139 if (name == NULL)
140 name = "???";
141
142 if (!ispil && intr_countp[vec] != stray_vec_index)
143 name_index = intr_countp[vec];
144 else if (ispil && pil_countp[vec] != stray_pil_index)
145 name_index = pil_countp[vec];
146 else
147 name_index = intrcnt_index++;
148
149 if (intrcnt_setname(name, name_index))
150 name_index = 0;
151
152 if (!ispil)
153 intr_countp[vec] = name_index;
154 else
155 pil_countp[vec] = name_index;
156 }
157
158 static int
159 intrcnt_setname(const char *name, int index)
160 {
161
162 if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
163 return (E2BIG);
164 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
165 MAXCOMLEN, name);
166 return (0);
167 }
168
169 void
170 intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
171 {
172 char pilname[MAXCOMLEN + 1];
173 u_long ps;
174
175 ps = intr_disable();
176 if (vec != -1) {
177 intr_vectors[vec].iv_func = ivf;
178 intr_vectors[vec].iv_arg = iva;
179 intr_vectors[vec].iv_pri = pri;
180 intr_vectors[vec].iv_vec = vec;
181 }
182 snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
183 intrcnt_updatename(pri, pilname, 1);
184 intr_handlers[pri] = ihf;
185 intr_restore(ps);
186 }
187
188 static void
189 intr_stray_level(struct trapframe *tf)
190 {
191
192 printf("stray level interrupt %ld\n", tf->tf_level);
193 }
194
195 static void
196 intr_stray_vector(void *cookie)
197 {
198 struct intr_vector *iv;
199
200 iv = cookie;
201 if (intr_stray_count[iv->iv_vec] < MAX_STRAY_LOG) {
202 printf("stray vector interrupt %d\n", iv->iv_vec);
203 intr_stray_count[iv->iv_vec]++;
204 if (intr_stray_count[iv->iv_vec] >= MAX_STRAY_LOG)
205 printf("got %d stray interrupt %d's: not logging "
206 "anymore\n", MAX_STRAY_LOG, iv->iv_vec);
207 }
208 }
209
210 void
211 intr_init1()
212 {
213 int i;
214
215 /* Mark all interrupts as being stray. */
216 for (i = 0; i < PIL_MAX; i++)
217 intr_handlers[i] = intr_stray_level;
218 for (i = 0; i < IV_MAX; i++) {
219 intr_vectors[i].iv_func = intr_stray_vector;
220 intr_vectors[i].iv_arg = &intr_vectors[i];
221 intr_vectors[i].iv_pri = PIL_LOW;
222 intr_vectors[i].iv_vec = i;
223 intr_vectors[i].iv_refcnt = 0;
224 }
225 intr_handlers[PIL_LOW] = intr_fast;
226 }
227
228 void
229 intr_init2()
230 {
231
232 mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
233 }
234
235 static void
236 intr_enable_eoi(void *arg)
237 {
238 struct intr_vector *iv;
239 const struct intr_controller *ic;
240
241 iv = arg;
242 ic = iv->iv_ic;
243 ic->ic_enable(iv);
244 ic->ic_eoi(iv);
245 }
246
247 static void
248 intr_execute_handlers(void *cookie)
249 {
250 struct intr_vector *iv;
251 #ifndef INTR_FILTER
252 struct intr_event *ie;
253 struct intr_handler *ih;
254 int error, thread, ret;
255 #endif
256
257 iv = cookie;
258 #ifndef INTR_FILTER
259 ie = iv->iv_event;
260 if (iv->iv_ic == NULL || ie == NULL) {
261 intr_stray_vector(iv);
262 return;
263 }
264
265 /* Execute fast interrupt handlers directly. */
266 ret = 0;
267 thread = 0;
268 critical_enter();
269 TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
270 if (ih->ih_filter == NULL) {
271 thread = 1;
272 continue;
273 }
274 MPASS(ih->ih_filter != NULL && ih->ih_argument != NULL);
275 CTR3(KTR_INTR, "%s: executing handler %p(%p)", __func__,
276 ih->ih_filter, ih->ih_argument);
277 ret = ih->ih_filter(ih->ih_argument);
278 /*
279 * Wrapper handler special case: see
280 * i386/intr_machdep.c::intr_execute_handlers()
281 */
282 if (!thread) {
283 if (ret == FILTER_SCHEDULE_THREAD)
284 thread = 1;
285 }
286 }
287 if (!thread)
288 intr_enable_eoi(iv);
289
290 /* Schedule a heavyweight interrupt process. */
291 if (thread)
292 error = intr_event_schedule_thread(ie);
293 else if (TAILQ_EMPTY(&ie->ie_handlers))
294 error = EINVAL;
295 else
296 error = 0;
297 critical_exit();
298 if (error == EINVAL)
299 #else
300 if (intr_event_handle(iv->iv_event, NULL) != 0)
301 #endif
302 intr_stray_vector(iv);
303 }
304
305 int
306 intr_controller_register(int vec, const struct intr_controller *ic,
307 void *icarg)
308 {
309 struct intr_event *ie;
310 struct intr_vector *iv;
311 int error;
312
313 iv = &intr_vectors[vec];
314 mtx_lock_spin(&intr_table_lock);
315 ie = iv->iv_event;
316 mtx_unlock_spin(&intr_table_lock);
317 if (ie != NULL)
318 return (EEXIST);
319 /*
320 * Testing shows that at least with the interrupt controllers of
321 * Psycho and Schizo bridges enabling an interrupt doesn't cause
322 * an outstanding interrupt to be issued to the CPU. Thus we can't
323 * use a function doing disable+EOI for the "disable" pointer as
324 * done on other architectures because this would lead to a lost
325 * interrupt if it triggers while we are still processing the
326 * previous one. Instead we use an enable+EOI approach because as
327 * outlined in the Tomatillo documentation clearing an interrupt
328 * in the interrupt controller causes it to be (re)issued to the
329 * CPU as long as the source of a level sensitive interrupt is
330 * not cleared.
331 */
332 error = intr_event_create(&ie, iv, 0, intr_enable_eoi,
333 #ifdef INTR_FILTER
334 ic->ic_eoi, ic->ic_disable, "vec%d:", vec);
335 #else
336 "vec%d:", vec);
337 #endif
338 if (error != 0)
339 return (error);
340 mtx_lock_spin(&intr_table_lock);
341 if (iv->iv_event != NULL) {
342 mtx_unlock_spin(&intr_table_lock);
343 intr_event_destroy(ie);
344 return (EEXIST);
345 }
346 iv->iv_ic = ic;
347 iv->iv_icarg = icarg;
348 iv->iv_event = ie;
349 iv->iv_mid = PCPU_GET(mid);
350 mtx_unlock_spin(&intr_table_lock);
351 return (0);
352 }
353
354 int
355 inthand_add(const char *name, int vec, driver_filter_t *filt,
356 driver_intr_t *handler, void *arg, int flags, void **cookiep)
357 {
358 const struct intr_controller *ic;
359 struct intr_event *ie;
360 struct intr_handler *ih;
361 struct intr_vector *iv;
362 int error, fast;
363
364 iv = &intr_vectors[vec];
365 mtx_lock_spin(&intr_table_lock);
366 ic = iv->iv_ic;
367 ie = iv->iv_event;
368 mtx_unlock_spin(&intr_table_lock);
369 if (ic == NULL || ie == NULL)
370 return (EINVAL);
371
372 error = intr_event_add_handler(ie, name, filt, handler, arg,
373 intr_priority(flags), flags, cookiep);
374 if (error != 0)
375 return (error);
376
377 mtx_lock_spin(&intr_table_lock);
378 /* Disable the interrupt while we fiddle with it. */
379 ic->ic_disable(iv);
380 iv->iv_refcnt++;
381 if (iv->iv_refcnt == 1)
382 intr_setup(filt != NULL ? PIL_FAST : PIL_ITHREAD, intr_fast,
383 vec, intr_execute_handlers, iv);
384 else if (filt != NULL) {
385 /*
386 * Check if we need to upgrade from PIL_ITHREAD to PIL_FAST.
387 * Given that apart from the on-board SCCs and UARTs shared
388 * interrupts are rather uncommon on sparc64 this sould be
389 * pretty rare in practice.
390 */
391 fast = 0;
392 TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
393 if (ih->ih_filter != NULL && ih->ih_filter != filt) {
394 fast = 1;
395 break;
396 }
397 }
398 if (fast == 0)
399 intr_setup(PIL_FAST, intr_fast, vec,
400 intr_execute_handlers, iv);
401 }
402 intr_stray_count[vec] = 0;
403 intrcnt_updatename(vec, ie->ie_fullname, 0);
404 /* Ensure the interrupt is cleared, it might have triggered before. */
405 intr_enable_eoi(iv);
406 mtx_unlock_spin(&intr_table_lock);
407 return (0);
408 }
409
410 int
411 inthand_remove(int vec, void *cookie)
412 {
413 struct intr_vector *iv;
414 int error;
415
416 error = intr_event_remove_handler(cookie);
417 if (error == 0) {
418 /*
419 * XXX: maybe this should be done regardless of whether
420 * intr_event_remove_handler() succeeded?
421 */
422 iv = &intr_vectors[vec];
423 mtx_lock_spin(&intr_table_lock);
424 iv->iv_refcnt--;
425 if (iv->iv_refcnt == 0) {
426 /*
427 * Don't disable the interrupt for now, so that
428 * stray interrupts get detected...
429 */
430 intr_setup(PIL_LOW, intr_fast, vec,
431 intr_stray_vector, iv);
432 }
433 mtx_unlock_spin(&intr_table_lock);
434 }
435 return (error);
436 }
Cache object: a290c50dcf750fee58ce7736486d61ea
|