xref: /openbsd/sys/arch/alpha/dev/shared_intr.c (revision fdb34300)
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