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