1*fdb34300Sderaadt /* $OpenBSD: shared_intr.c,v 1.22 2015/09/02 14:07:43 deraadt 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 *
intr_typename(type)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 *
alpha_shared_intr_alloc(n)677f36164aSderaadt alpha_shared_intr_alloc(n)
687f36164aSderaadt unsigned int n;
697f36164aSderaadt {
707f36164aSderaadt struct alpha_shared_intr *intr;
717f36164aSderaadt unsigned int i;
727f36164aSderaadt
735714159aSdoug intr = mallocarray(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
alpha_shared_intr_dispatch(intr,num)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) {
100ebfa0537Smiod #if defined(MULTIPROCESSOR)
101ebfa0537Smiod /* XXX Need to support IPL_MPSAFE eventually. */
102ebfa0537Smiod if (ih->ih_level < IPL_CLOCK)
103ebfa0537Smiod __mp_lock(&kernel_lock);
104ebfa0537Smiod #endif
1057f36164aSderaadt /*
1067f36164aSderaadt * The handler returns one of three values:
1077f36164aSderaadt * 0: This interrupt wasn't for me.
1087f36164aSderaadt * 1: This interrupt was for me.
1097f36164aSderaadt * -1: This interrupt might have been for me, but I can't say
1107f36164aSderaadt * for sure.
1117f36164aSderaadt */
112323a282bSderaadt rv = (*ih->ih_fn)(ih->ih_arg);
113323a282bSderaadt if (rv)
11484b67413Saaron ih->ih_count.ec_count++;
115ebfa0537Smiod #if defined(MULTIPROCESSOR)
116ebfa0537Smiod if (ih->ih_level < IPL_CLOCK)
117ebfa0537Smiod __mp_unlock(&kernel_lock);
118ebfa0537Smiod #endif
1197f36164aSderaadt handled = handled || (rv != 0);
120323a282bSderaadt if (intr_shared_edge == 0 && rv == 1)
121323a282bSderaadt break;
1227f36164aSderaadt }
1237f36164aSderaadt
1247f36164aSderaadt return (handled);
1257f36164aSderaadt }
1267f36164aSderaadt
1277f36164aSderaadt void *
alpha_shared_intr_establish(intr,num,type,level,fn,arg,basename)1287f36164aSderaadt alpha_shared_intr_establish(intr, num, type, level, fn, arg, basename)
1297f36164aSderaadt struct alpha_shared_intr *intr;
1307f36164aSderaadt unsigned int num;
1317f36164aSderaadt int type, level;
132c4071fd1Smillert int (*fn)(void *);
1337f36164aSderaadt void *arg;
1347f36164aSderaadt const char *basename;
1357f36164aSderaadt {
1367f36164aSderaadt struct alpha_shared_intrhand *ih;
1377f36164aSderaadt
1387f36164aSderaadt if (intr[num].intr_sharetype == IST_UNUSABLE) {
1397f36164aSderaadt printf("alpha_shared_intr_establish: %s %d: unusable\n",
1407f36164aSderaadt basename, num);
1417f36164aSderaadt return NULL;
1427f36164aSderaadt }
1437f36164aSderaadt
1447f36164aSderaadt /* no point in sleeping unless someone can free memory. */
1457f36164aSderaadt ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
1467f36164aSderaadt if (ih == NULL)
1477f36164aSderaadt panic("alpha_shared_intr_establish: can't malloc intrhand");
1487f36164aSderaadt
1497f36164aSderaadt #ifdef DIAGNOSTIC
1507f36164aSderaadt if (type == IST_NONE)
1517f36164aSderaadt panic("alpha_shared_intr_establish: bogus type");
1527f36164aSderaadt #endif
1537f36164aSderaadt
1547f36164aSderaadt switch (intr[num].intr_sharetype) {
1557f36164aSderaadt case IST_EDGE:
156323a282bSderaadt intr_shared_edge = 1;
157323a282bSderaadt /* FALLTHROUGH */
1587f36164aSderaadt case IST_LEVEL:
1597f36164aSderaadt if (type == intr[num].intr_sharetype)
1607f36164aSderaadt break;
1617f36164aSderaadt case IST_PULSE:
1627f36164aSderaadt if (type != IST_NONE) {
1635cf5f4a3Smiod if (TAILQ_EMPTY(&intr[num].intr_q)) {
1647f36164aSderaadt printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n",
1657f36164aSderaadt basename, num, intr_typename(type),
1667f36164aSderaadt intr_typename(intr[num].intr_sharetype));
1677f36164aSderaadt type = intr[num].intr_sharetype;
1687f36164aSderaadt } else {
1697f36164aSderaadt panic("alpha_shared_intr_establish: %s %d: can't share %s with %s",
1707f36164aSderaadt basename, num, intr_typename(type),
1717f36164aSderaadt intr_typename(intr[num].intr_sharetype));
1727f36164aSderaadt }
1737f36164aSderaadt }
1747f36164aSderaadt break;
1757f36164aSderaadt
1767f36164aSderaadt case IST_NONE:
1777f36164aSderaadt /* not currently used; safe */
1787f36164aSderaadt break;
1797f36164aSderaadt }
1807f36164aSderaadt
181aed035abSart ih->ih_intrhead = intr;
1827f36164aSderaadt ih->ih_fn = fn;
1837f36164aSderaadt ih->ih_arg = arg;
1847f36164aSderaadt ih->ih_level = level;
185aed035abSart ih->ih_num = num;
1864667bebbSmatthew evcount_attach(&ih->ih_count, basename, &ih->ih_num);
1877f36164aSderaadt
1887f36164aSderaadt intr[num].intr_sharetype = type;
1897f36164aSderaadt TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q);
1907f36164aSderaadt
1917f36164aSderaadt return (ih);
1927f36164aSderaadt }
1937f36164aSderaadt
194aed035abSart void
alpha_shared_intr_disestablish(intr,cookie)195962a9e54Smiod alpha_shared_intr_disestablish(intr, cookie)
196aed035abSart struct alpha_shared_intr *intr;
197aed035abSart void *cookie;
198aed035abSart {
199aed035abSart struct alpha_shared_intrhand *ih = cookie;
200aed035abSart unsigned int num = ih->ih_num;
201aed035abSart
202aed035abSart /*
203aed035abSart * Just remove it from the list and free the entry. We let
204aed035abSart * the caller deal with resetting the share type, if appropriate.
205aed035abSart */
20684b67413Saaron evcount_detach(&ih->ih_count);
207aed035abSart TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q);
208*fdb34300Sderaadt free(ih, M_DEVBUF, sizeof *ih);
209aed035abSart }
210aed035abSart
2117f36164aSderaadt int
alpha_shared_intr_get_sharetype(intr,num)2127f36164aSderaadt alpha_shared_intr_get_sharetype(intr, num)
2137f36164aSderaadt struct alpha_shared_intr *intr;
2147f36164aSderaadt unsigned int num;
2157f36164aSderaadt {
2167f36164aSderaadt
2177f36164aSderaadt return (intr[num].intr_sharetype);
2187f36164aSderaadt }
2197f36164aSderaadt
2207f36164aSderaadt int
alpha_shared_intr_isactive(intr,num)2217f36164aSderaadt alpha_shared_intr_isactive(intr, num)
2227f36164aSderaadt struct alpha_shared_intr *intr;
2237f36164aSderaadt unsigned int num;
2247f36164aSderaadt {
2257f36164aSderaadt
2265cf5f4a3Smiod return (!TAILQ_EMPTY(&intr[num].intr_q));
2277f36164aSderaadt }
2287f36164aSderaadt
229c62181b1Sbrad int
alpha_shared_intr_firstactive(struct alpha_shared_intr * intr,unsigned int num)230c62181b1Sbrad alpha_shared_intr_firstactive(struct alpha_shared_intr *intr, unsigned int num)
231c62181b1Sbrad {
232c62181b1Sbrad
233c62181b1Sbrad return (!TAILQ_EMPTY(&intr[num].intr_q) &&
234c62181b1Sbrad TAILQ_NEXT(intr[num].intr_q.tqh_first, ih_q) == NULL);
235c62181b1Sbrad }
236c62181b1Sbrad
2377f36164aSderaadt void
alpha_shared_intr_set_dfltsharetype(intr,num,newdfltsharetype)2387f36164aSderaadt alpha_shared_intr_set_dfltsharetype(intr, num, newdfltsharetype)
2397f36164aSderaadt struct alpha_shared_intr *intr;
2407f36164aSderaadt unsigned int num;
2417f36164aSderaadt int newdfltsharetype;
2427f36164aSderaadt {
2437f36164aSderaadt
2447f36164aSderaadt #ifdef DIAGNOSTIC
2457f36164aSderaadt if (alpha_shared_intr_isactive(intr, num))
2467f36164aSderaadt panic("alpha_shared_intr_set_dfltsharetype on active intr");
2477f36164aSderaadt #endif
2487f36164aSderaadt
2497f36164aSderaadt intr[num].intr_dfltsharetype = newdfltsharetype;
2507f36164aSderaadt intr[num].intr_sharetype = intr[num].intr_dfltsharetype;
2517f36164aSderaadt }
2527f36164aSderaadt
2537f36164aSderaadt void
alpha_shared_intr_set_maxstrays(intr,num,newmaxstrays)2547f36164aSderaadt alpha_shared_intr_set_maxstrays(intr, num, newmaxstrays)
2557f36164aSderaadt struct alpha_shared_intr *intr;
2567f36164aSderaadt unsigned int num;
2577f36164aSderaadt int newmaxstrays;
2587f36164aSderaadt {
259aed035abSart int s = splhigh();
2607f36164aSderaadt intr[num].intr_maxstrays = newmaxstrays;
2617f36164aSderaadt intr[num].intr_nstrays = 0;
262aed035abSart splx(s);
2637f36164aSderaadt }
2647f36164aSderaadt
2657f36164aSderaadt void
alpha_shared_intr_reset_strays(intr,num)26617a294c7Smartin alpha_shared_intr_reset_strays(intr, num)
26717a294c7Smartin struct alpha_shared_intr *intr;
26817a294c7Smartin unsigned int num;
26917a294c7Smartin {
27017a294c7Smartin
27117a294c7Smartin /*
27217a294c7Smartin * Don't bother blocking interrupts; this doesn't have to be
27317a294c7Smartin * precise, but it does need to be fast.
27417a294c7Smartin */
27517a294c7Smartin intr[num].intr_nstrays = 0;
27617a294c7Smartin }
27717a294c7Smartin
27817a294c7Smartin void
alpha_shared_intr_stray(intr,num,basename)2797f36164aSderaadt alpha_shared_intr_stray(intr, num, basename)
2807f36164aSderaadt struct alpha_shared_intr *intr;
2817f36164aSderaadt unsigned int num;
2827f36164aSderaadt const char *basename;
2837f36164aSderaadt {
2847f36164aSderaadt
2857f36164aSderaadt intr[num].intr_nstrays++;
2862564b0f4Smillert
2872564b0f4Smillert if (intr[num].intr_maxstrays == 0)
2882564b0f4Smillert return;
2892564b0f4Smillert
2907f36164aSderaadt if (intr[num].intr_nstrays <= intr[num].intr_maxstrays)
2917f36164aSderaadt log(LOG_ERR, "stray %s %d%s\n", basename, num,
2927f36164aSderaadt intr[num].intr_nstrays >= intr[num].intr_maxstrays ?
2937f36164aSderaadt "; stopped logging" : "");
2947f36164aSderaadt }
295aed035abSart
296aed035abSart void
alpha_shared_intr_set_private(intr,num,v)297aed035abSart alpha_shared_intr_set_private(intr, num, v)
298aed035abSart struct alpha_shared_intr *intr;
299aed035abSart unsigned int num;
300aed035abSart void *v;
301aed035abSart {
302aed035abSart
303aed035abSart intr[num].intr_private = v;
304aed035abSart }
305aed035abSart
306aed035abSart void *
alpha_shared_intr_get_private(intr,num)307aed035abSart alpha_shared_intr_get_private(intr, num)
308aed035abSart struct alpha_shared_intr *intr;
309aed035abSart unsigned int num;
310aed035abSart {
311aed035abSart
312aed035abSart return (intr[num].intr_private);
313aed035abSart }
314