1*4667bebbSmatthew /* $OpenBSD: shared_intr.c,v 1.17 2010/09/20 06:33:46 matthew Exp $ */ 2aed035abSart /* $NetBSD: shared_intr.c,v 1.13 2000/03/19 01:46:18 thorpej Exp $ */ 37f36164aSderaadt 47f36164aSderaadt /* 57f36164aSderaadt * Copyright (c) 1996 Carnegie-Mellon University. 67f36164aSderaadt * All rights reserved. 77f36164aSderaadt * 87f36164aSderaadt * Authors: Chris G. Demetriou 97f36164aSderaadt * 107f36164aSderaadt * Permission to use, copy, modify and distribute this software and 117f36164aSderaadt * its documentation is hereby granted, provided that both the copyright 127f36164aSderaadt * notice and this permission notice appear in all copies of the 137f36164aSderaadt * software, derivative works or modified versions, and any portions 147f36164aSderaadt * thereof, and that both notices appear in supporting documentation. 157f36164aSderaadt * 167f36164aSderaadt * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 177f36164aSderaadt * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 187f36164aSderaadt * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 197f36164aSderaadt * 207f36164aSderaadt * Carnegie Mellon requests users of this software to return to 217f36164aSderaadt * 227f36164aSderaadt * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 237f36164aSderaadt * School of Computer Science 247f36164aSderaadt * Carnegie Mellon University 257f36164aSderaadt * Pittsburgh PA 15213-3890 267f36164aSderaadt * 277f36164aSderaadt * any improvements or extensions that they make and grant Carnegie the 287f36164aSderaadt * rights to redistribute these changes. 297f36164aSderaadt */ 307f36164aSderaadt 317f36164aSderaadt /* 327f36164aSderaadt * Common shared-interrupt-line functionality. 337f36164aSderaadt */ 347f36164aSderaadt 357f36164aSderaadt #include <sys/param.h> 36aed035abSart #include <sys/kernel.h> 377f36164aSderaadt #include <sys/systm.h> 387f36164aSderaadt #include <sys/malloc.h> 397f36164aSderaadt #include <sys/syslog.h> 407f36164aSderaadt #include <sys/queue.h> 417f36164aSderaadt 427f36164aSderaadt #include <machine/intr.h> 437f36164aSderaadt 44c4071fd1Smillert static const char *intr_typename(int); 457f36164aSderaadt 467f36164aSderaadt static const char * 477f36164aSderaadt intr_typename(type) 487f36164aSderaadt int type; 497f36164aSderaadt { 507f36164aSderaadt 517f36164aSderaadt switch (type) { 527f36164aSderaadt case IST_UNUSABLE: 537f36164aSderaadt return ("disabled"); 547f36164aSderaadt case IST_NONE: 557f36164aSderaadt return ("none"); 567f36164aSderaadt case IST_PULSE: 577f36164aSderaadt return ("pulsed"); 587f36164aSderaadt case IST_EDGE: 597f36164aSderaadt return ("edge-triggered"); 607f36164aSderaadt case IST_LEVEL: 617f36164aSderaadt return ("level-triggered"); 627f36164aSderaadt } 637f36164aSderaadt panic("intr_typename: unknown type %d", type); 647f36164aSderaadt } 657f36164aSderaadt 667f36164aSderaadt struct alpha_shared_intr * 677f36164aSderaadt alpha_shared_intr_alloc(n) 687f36164aSderaadt unsigned int n; 697f36164aSderaadt { 707f36164aSderaadt struct alpha_shared_intr *intr; 717f36164aSderaadt unsigned int i; 727f36164aSderaadt 737f36164aSderaadt intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF, 747f36164aSderaadt cold ? M_NOWAIT : M_WAITOK); 757f36164aSderaadt if (intr == NULL) 767f36164aSderaadt panic("alpha_shared_intr_alloc: couldn't malloc intr"); 777f36164aSderaadt 787f36164aSderaadt for (i = 0; i < n; i++) { 797f36164aSderaadt TAILQ_INIT(&intr[i].intr_q); 807f36164aSderaadt intr[i].intr_sharetype = IST_NONE; 817f36164aSderaadt intr[i].intr_dfltsharetype = IST_NONE; 827f36164aSderaadt intr[i].intr_nstrays = 0; 837f36164aSderaadt intr[i].intr_maxstrays = 5; 84aed035abSart intr[i].intr_private = NULL; 857f36164aSderaadt } 867f36164aSderaadt 877f36164aSderaadt return (intr); 887f36164aSderaadt } 897f36164aSderaadt 907f36164aSderaadt int 917f36164aSderaadt alpha_shared_intr_dispatch(intr, num) 927f36164aSderaadt struct alpha_shared_intr *intr; 937f36164aSderaadt unsigned int num; 947f36164aSderaadt { 957f36164aSderaadt struct alpha_shared_intrhand *ih; 967f36164aSderaadt int rv, handled; 977f36164aSderaadt 987f36164aSderaadt handled = 0; 995cf5f4a3Smiod TAILQ_FOREACH(ih, &intr[num].intr_q, ih_q) { 1007f36164aSderaadt /* 1017f36164aSderaadt * The handler returns one of three values: 1027f36164aSderaadt * 0: This interrupt wasn't for me. 1037f36164aSderaadt * 1: This interrupt was for me. 1047f36164aSderaadt * -1: This interrupt might have been for me, but I can't say 1057f36164aSderaadt * for sure. 1067f36164aSderaadt */ 10784b67413Saaron if ((rv = (*ih->ih_fn)(ih->ih_arg))) 10884b67413Saaron ih->ih_count.ec_count++; 1097f36164aSderaadt 1107f36164aSderaadt handled = handled || (rv != 0); 1117f36164aSderaadt } 1127f36164aSderaadt 1137f36164aSderaadt return (handled); 1147f36164aSderaadt } 1157f36164aSderaadt 1167f36164aSderaadt void * 1177f36164aSderaadt alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename) 1187f36164aSderaadt struct alpha_shared_intr *intr; 1197f36164aSderaadt unsigned int num; 1207f36164aSderaadt int type, level; 121c4071fd1Smillert int (*fn)(void *); 1227f36164aSderaadt void *arg; 1237f36164aSderaadt const char *basename; 1247f36164aSderaadt { 1257f36164aSderaadt struct alpha_shared_intrhand *ih; 1267f36164aSderaadt 1277f36164aSderaadt if (intr[num].intr_sharetype == IST_UNUSABLE) { 1287f36164aSderaadt printf("alpha_shared_intr_establish: %s %d: unusable\n", 1297f36164aSderaadt basename, num); 1307f36164aSderaadt return NULL; 1317f36164aSderaadt } 1327f36164aSderaadt 1337f36164aSderaadt /* no point in sleeping unless someone can free memory. */ 1347f36164aSderaadt ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 1357f36164aSderaadt if (ih == NULL) 1367f36164aSderaadt panic("alpha_shared_intr_establish: can't malloc intrhand"); 1377f36164aSderaadt 1387f36164aSderaadt #ifdef DIAGNOSTIC 1397f36164aSderaadt if (type == IST_NONE) 1407f36164aSderaadt panic("alpha_shared_intr_establish: bogus type"); 1417f36164aSderaadt #endif 1427f36164aSderaadt 1437f36164aSderaadt switch (intr[num].intr_sharetype) { 1447f36164aSderaadt case IST_EDGE: 1457f36164aSderaadt case IST_LEVEL: 1467f36164aSderaadt if (type == intr[num].intr_sharetype) 1477f36164aSderaadt break; 1487f36164aSderaadt case IST_PULSE: 1497f36164aSderaadt if (type != IST_NONE) { 1505cf5f4a3Smiod if (TAILQ_EMPTY(&intr[num].intr_q)) { 1517f36164aSderaadt printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n", 1527f36164aSderaadt basename, num, intr_typename(type), 1537f36164aSderaadt intr_typename(intr[num].intr_sharetype)); 1547f36164aSderaadt type = intr[num].intr_sharetype; 1557f36164aSderaadt } else { 1567f36164aSderaadt panic("alpha_shared_intr_establish: %s %d: can't share %s with %s", 1577f36164aSderaadt basename, num, intr_typename(type), 1587f36164aSderaadt intr_typename(intr[num].intr_sharetype)); 1597f36164aSderaadt } 1607f36164aSderaadt } 1617f36164aSderaadt break; 1627f36164aSderaadt 1637f36164aSderaadt case IST_NONE: 1647f36164aSderaadt /* not currently used; safe */ 1657f36164aSderaadt break; 1667f36164aSderaadt } 1677f36164aSderaadt 168aed035abSart ih->ih_intrhead = intr; 1697f36164aSderaadt ih->ih_fn = fn; 1707f36164aSderaadt ih->ih_arg = arg; 1717f36164aSderaadt ih->ih_level = level; 172aed035abSart ih->ih_num = num; 173*4667bebbSmatthew evcount_attach(&ih->ih_count, basename, &ih->ih_num); 1747f36164aSderaadt 1757f36164aSderaadt intr[num].intr_sharetype = type; 1767f36164aSderaadt TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q); 1777f36164aSderaadt 1787f36164aSderaadt return (ih); 1797f36164aSderaadt } 1807f36164aSderaadt 181aed035abSart void 182962a9e54Smiod alpha_shared_intr_disestablish(intr, cookie) 183aed035abSart struct alpha_shared_intr *intr; 184aed035abSart void *cookie; 185aed035abSart { 186aed035abSart struct alpha_shared_intrhand *ih = cookie; 187aed035abSart unsigned int num = ih->ih_num; 188aed035abSart 189aed035abSart /* 190aed035abSart * Just remove it from the list and free the entry. We let 191aed035abSart * the caller deal with resetting the share type, if appropriate. 192aed035abSart */ 19384b67413Saaron evcount_detach(&ih->ih_count); 194aed035abSart TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q); 19584b67413Saaron free(ih, M_DEVBUF); 196aed035abSart } 197aed035abSart 1987f36164aSderaadt int 1997f36164aSderaadt alpha_shared_intr_get_sharetype(intr, num) 2007f36164aSderaadt struct alpha_shared_intr *intr; 2017f36164aSderaadt unsigned int num; 2027f36164aSderaadt { 2037f36164aSderaadt 2047f36164aSderaadt return (intr[num].intr_sharetype); 2057f36164aSderaadt } 2067f36164aSderaadt 2077f36164aSderaadt int 2087f36164aSderaadt alpha_shared_intr_isactive(intr, num) 2097f36164aSderaadt struct alpha_shared_intr *intr; 2107f36164aSderaadt unsigned int num; 2117f36164aSderaadt { 2127f36164aSderaadt 2135cf5f4a3Smiod return (!TAILQ_EMPTY(&intr[num].intr_q)); 2147f36164aSderaadt } 2157f36164aSderaadt 216c62181b1Sbrad int 217c62181b1Sbrad alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num) 218c62181b1Sbrad { 219c62181b1Sbrad 220c62181b1Sbrad return (!TAILQ_EMPTY(&intr[num].intr_q) && 221c62181b1Sbrad TAILQ_NEXT(intr[num].intr_q.tqh_first, ih_q) == NULL); 222c62181b1Sbrad } 223c62181b1Sbrad 2247f36164aSderaadt void 2257f36164aSderaadt alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype) 2267f36164aSderaadt struct alpha_shared_intr *intr; 2277f36164aSderaadt unsigned int num; 2287f36164aSderaadt int newdfltsharetype; 2297f36164aSderaadt { 2307f36164aSderaadt 2317f36164aSderaadt #ifdef DIAGNOSTIC 2327f36164aSderaadt if (alpha_shared_intr_isactive(intr, num)) 2337f36164aSderaadt panic("alpha_shared_intr_set_dfltsharetype on active intr"); 2347f36164aSderaadt #endif 2357f36164aSderaadt 2367f36164aSderaadt intr[num].intr_dfltsharetype = newdfltsharetype; 2377f36164aSderaadt intr[num].intr_sharetype = intr[num].intr_dfltsharetype; 2387f36164aSderaadt } 2397f36164aSderaadt 2407f36164aSderaadt void 2417f36164aSderaadt alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays) 2427f36164aSderaadt struct alpha_shared_intr *intr; 2437f36164aSderaadt unsigned int num; 2447f36164aSderaadt int newmaxstrays; 2457f36164aSderaadt { 246aed035abSart int s = splhigh(); 2477f36164aSderaadt intr[num].intr_maxstrays = newmaxstrays; 2487f36164aSderaadt intr[num].intr_nstrays = 0; 249aed035abSart splx(s); 2507f36164aSderaadt } 2517f36164aSderaadt 2527f36164aSderaadt void 25317a294c7Smartin alpha_shared_intr_reset_strays(intr, num) 25417a294c7Smartin struct alpha_shared_intr *intr; 25517a294c7Smartin unsigned int num; 25617a294c7Smartin { 25717a294c7Smartin 25817a294c7Smartin /* 25917a294c7Smartin * Don't bother blocking interrupts; this doesn't have to be 26017a294c7Smartin * precise, but it does need to be fast. 26117a294c7Smartin */ 26217a294c7Smartin intr[num].intr_nstrays = 0; 26317a294c7Smartin } 26417a294c7Smartin 26517a294c7Smartin void 2667f36164aSderaadt alpha_shared_intr_stray(intr, num, basename) 2677f36164aSderaadt struct alpha_shared_intr *intr; 2687f36164aSderaadt unsigned int num; 2697f36164aSderaadt const char *basename; 2707f36164aSderaadt { 2717f36164aSderaadt 2727f36164aSderaadt intr[num].intr_nstrays++; 2732564b0f4Smillert 2742564b0f4Smillert if (intr[num].intr_maxstrays == 0) 2752564b0f4Smillert return; 2762564b0f4Smillert 2777f36164aSderaadt if (intr[num].intr_nstrays <= intr[num].intr_maxstrays) 2787f36164aSderaadt log(LOG_ERR, "stray %s %d%s\n", basename, num, 2797f36164aSderaadt intr[num].intr_nstrays >= intr[num].intr_maxstrays ? 2807f36164aSderaadt "; stopped logging" : ""); 2817f36164aSderaadt } 282aed035abSart 283aed035abSart void 284aed035abSart alpha_shared_intr_set_private(intr, num, v) 285aed035abSart struct alpha_shared_intr *intr; 286aed035abSart unsigned int num; 287aed035abSart void *v; 288aed035abSart { 289aed035abSart 290aed035abSart intr[num].intr_private = v; 291aed035abSart } 292aed035abSart 293aed035abSart void * 294aed035abSart alpha_shared_intr_get_private(intr, num) 295aed035abSart struct alpha_shared_intr *intr; 296aed035abSart unsigned int num; 297aed035abSart { 298aed035abSart 299aed035abSart return (intr[num].intr_private); 300aed035abSart } 301