intr_machdep.c revision 173799
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: head/sys/sparc64/sparc64/intr_machdep.c 173799 2007-11-21 04:03:51Z scottl $"); 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 82CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector)); 83 84ih_func_t *intr_handlers[PIL_MAX]; 85uint16_t pil_countp[PIL_MAX]; 86 87struct intr_vector intr_vectors[IV_MAX]; 88uint16_t intr_countp[IV_MAX]; 89static u_long intr_stray_count[IV_MAX]; 90 91static 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 */ 104static struct mtx intr_table_lock; 105 106static void intr_enable_eoi(void *); 107static void intr_execute_handlers(void *); 108static void intr_stray_level(struct trapframe *); 109static void intr_stray_vector(void *); 110static int intrcnt_setname(const char *, int); 111static void intrcnt_updatename(int, const char *, int); 112 113/* 114 * not MPSAFE 115 */ 116static void 117intrcnt_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 158static int 159intrcnt_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 169void 170intr_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 188static void 189intr_stray_level(struct trapframe *tf) 190{ 191 192 printf("stray level interrupt %ld\n", tf->tf_level); 193} 194 195static void 196intr_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 210void 211intr_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 228void 229intr_init2() 230{ 231 232 mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN); 233} 234 235static void 236intr_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 247static void 248intr_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 305int 306intr_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 354int 355inthand_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 410int 411inthand_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} 437