xref: /freebsd/sys/kern/kern_intr.c (revision 1c5bb3eaa14c4be2cc54700ffe7e9dce193f3219)
1425f9fdaSStefan Eßer /*
2425f9fdaSStefan Eßer  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3425f9fdaSStefan Eßer  * All rights reserved.
4425f9fdaSStefan Eßer  *
5425f9fdaSStefan Eßer  * Redistribution and use in source and binary forms, with or without
6425f9fdaSStefan Eßer  * modification, are permitted provided that the following conditions
7425f9fdaSStefan Eßer  * are met:
8425f9fdaSStefan Eßer  * 1. Redistributions of source code must retain the above copyright
9425f9fdaSStefan Eßer  *    notice unmodified, this list of conditions, and the following
10425f9fdaSStefan Eßer  *    disclaimer.
11425f9fdaSStefan Eßer  * 2. Redistributions in binary form must reproduce the above copyright
12425f9fdaSStefan Eßer  *    notice, this list of conditions and the following disclaimer in the
13425f9fdaSStefan Eßer  *    documentation and/or other materials provided with the distribution.
14425f9fdaSStefan Eßer  *
15425f9fdaSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16425f9fdaSStefan Eßer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17425f9fdaSStefan Eßer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18425f9fdaSStefan Eßer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19425f9fdaSStefan Eßer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20425f9fdaSStefan Eßer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21425f9fdaSStefan Eßer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22425f9fdaSStefan Eßer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23425f9fdaSStefan Eßer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24425f9fdaSStefan Eßer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25425f9fdaSStefan Eßer  *
261c5bb3eaSPeter Wemm  * $Id: kern_intr.c,v 1.20 1998/09/26 14:25:31 dfr Exp $
27425f9fdaSStefan Eßer  *
28425f9fdaSStefan Eßer  */
29425f9fdaSStefan Eßer 
303900ddb2SDoug Rabson 
311c5bb3eaSPeter Wemm #include <sys/param.h>
32425f9fdaSStefan Eßer #include <sys/systm.h>
331c5bb3eaSPeter Wemm #include <sys/malloc.h>
34425f9fdaSStefan Eßer #include <sys/errno.h>
35425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
36425f9fdaSStefan Eßer #include <sys/drvresource.h>
37425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
38425f9fdaSStefan Eßer 
3918c5a6c4SBruce Evans #include <machine/ipl.h>
4018c5a6c4SBruce Evans 
41da653c61SDoug Rabson #ifdef __i386__
42425f9fdaSStefan Eßer #include <i386/isa/icu.h>
4368352337SDoug Rabson #include <i386/isa/intr_machdep.h>
44da653c61SDoug Rabson #endif
4518c5a6c4SBruce Evans 
4668352337SDoug Rabson #include <sys/interrupt.h>
47425f9fdaSStefan Eßer 
48425f9fdaSStefan Eßer #include <stddef.h>
49425f9fdaSStefan Eßer 
50da653c61SDoug Rabson #ifdef __i386__
51da653c61SDoug Rabson 
528c046d14SPeter Wemm typedef struct intrec {
538c046d14SPeter Wemm 	intrmask_t	mask;
548c046d14SPeter Wemm 	inthand2_t	*handler;
558c046d14SPeter Wemm 	void		*argument;
568c046d14SPeter Wemm 	struct intrec	*next;
578c046d14SPeter Wemm 	void		*devdata;
588c046d14SPeter Wemm 	int		intr;
598c046d14SPeter Wemm 	intrmask_t	*maskptr;
608c046d14SPeter Wemm 	int		flags;
618c046d14SPeter Wemm } intrec;
628c046d14SPeter Wemm 
63da653c61SDoug Rabson static intrec *intreclist_head[NHWI];
64da653c61SDoug Rabson 
65da653c61SDoug Rabson #endif
66da653c61SDoug Rabson 
6718c5a6c4SBruce Evans struct swilist {
6818c5a6c4SBruce Evans 	swihand_t	*sl_handler;
6918c5a6c4SBruce Evans 	struct swilist	*sl_next;
7018c5a6c4SBruce Evans };
7118c5a6c4SBruce Evans 
7218c5a6c4SBruce Evans static struct swilist swilists[NSWI];
7318c5a6c4SBruce Evans 
74da653c61SDoug Rabson #ifdef __i386__
75da653c61SDoug Rabson 
76425f9fdaSStefan Eßer /*
77425f9fdaSStefan Eßer  * The interrupt multiplexer calls each of the handlers in turn,
78425f9fdaSStefan Eßer  * and applies the associated interrupt mask to "cpl", which is
7977625cfeSSteve Passe  * defined as a ".long" in /sys/i386/isa/ipl.s
80425f9fdaSStefan Eßer  */
81425f9fdaSStefan Eßer 
8277625cfeSSteve Passe #ifndef SMP
83ab36c3d3SBruce Evans static __inline intrmask_t
844407ec71SPeter Wemm splq(intrmask_t mask)
85425f9fdaSStefan Eßer {
864407ec71SPeter Wemm 	intrmask_t tmp = cpl;
87425f9fdaSStefan Eßer 	cpl |= mask;
88425f9fdaSStefan Eßer 	return (tmp);
89425f9fdaSStefan Eßer }
9077625cfeSSteve Passe #endif /* SMP */
91425f9fdaSStefan Eßer 
92425f9fdaSStefan Eßer static void
93425f9fdaSStefan Eßer intr_mux(void *arg)
94425f9fdaSStefan Eßer {
95425f9fdaSStefan Eßer 	intrec *p = arg;
96425f9fdaSStefan Eßer 
97425f9fdaSStefan Eßer 	while (p != NULL) {
98425f9fdaSStefan Eßer 		int oldspl = splq(p->mask);
999a2daf91SBruce Evans 		p->handler(p->argument);
100425f9fdaSStefan Eßer 		splx(oldspl);
101425f9fdaSStefan Eßer 		p = p->next;
102425f9fdaSStefan Eßer 	}
103425f9fdaSStefan Eßer }
104425f9fdaSStefan Eßer 
105425f9fdaSStefan Eßer static intrec*
106425f9fdaSStefan Eßer find_idesc(unsigned *maskptr, int irq)
107425f9fdaSStefan Eßer {
108425f9fdaSStefan Eßer 	intrec *p = intreclist_head[irq];
109425f9fdaSStefan Eßer 
110425f9fdaSStefan Eßer 	while (p && p->maskptr != maskptr)
111425f9fdaSStefan Eßer 		p = p->next;
112425f9fdaSStefan Eßer 
113425f9fdaSStefan Eßer 	return (p);
114425f9fdaSStefan Eßer }
115425f9fdaSStefan Eßer 
116425f9fdaSStefan Eßer static intrec**
117425f9fdaSStefan Eßer find_pred(intrec *idesc, int irq)
118425f9fdaSStefan Eßer {
119425f9fdaSStefan Eßer 	intrec **pp = &intreclist_head[irq];
120425f9fdaSStefan Eßer 	intrec *p = *pp;
121425f9fdaSStefan Eßer 
122425f9fdaSStefan Eßer 	while (p != idesc) {
123425f9fdaSStefan Eßer 		if (p == NULL)
124425f9fdaSStefan Eßer 			return (NULL);
125425f9fdaSStefan Eßer 		pp = &p->next;
126425f9fdaSStefan Eßer 		p = *pp;
127425f9fdaSStefan Eßer 	}
128425f9fdaSStefan Eßer 	return (pp);
129425f9fdaSStefan Eßer }
130425f9fdaSStefan Eßer 
131425f9fdaSStefan Eßer /*
132425f9fdaSStefan Eßer  * Both the low level handler and the shared interrupt multiplexer
133425f9fdaSStefan Eßer  * block out further interrupts as set in the handlers "mask", while
134425f9fdaSStefan Eßer  * the handler is running. In fact *maskptr should be used for this
135425f9fdaSStefan Eßer  * purpose, but since this requires one more pointer dereference on
136425f9fdaSStefan Eßer  * each interrupt, we rather bother update "mask" whenever *maskptr
137425f9fdaSStefan Eßer  * changes. The function "update_masks" should be called **after**
138425f9fdaSStefan Eßer  * all manipulation of the linked list of interrupt handlers hung
139425f9fdaSStefan Eßer  * off of intrdec_head[irq] is complete, since the chain of handlers
140425f9fdaSStefan Eßer  * will both determine the *maskptr values and the instances of mask
141425f9fdaSStefan Eßer  * that are fixed. This function should be called with the irq for
142425f9fdaSStefan Eßer  * which a new handler has been add blocked, since the masks may not
143425f9fdaSStefan Eßer  * yet know about the use of this irq for a device of a certain class.
144425f9fdaSStefan Eßer  */
145425f9fdaSStefan Eßer 
146425f9fdaSStefan Eßer static void
147425f9fdaSStefan Eßer update_mux_masks(void)
148425f9fdaSStefan Eßer {
149425f9fdaSStefan Eßer 	int irq;
150425f9fdaSStefan Eßer 	for (irq = 0; irq < ICU_LEN; irq++) {
151425f9fdaSStefan Eßer 		intrec *idesc = intreclist_head[irq];
152425f9fdaSStefan Eßer 		while (idesc != NULL) {
153425f9fdaSStefan Eßer 			if (idesc->maskptr != NULL) {
154425f9fdaSStefan Eßer 				/* our copy of *maskptr may be stale, refresh */
155425f9fdaSStefan Eßer 				idesc->mask = *idesc->maskptr;
156425f9fdaSStefan Eßer 			}
157425f9fdaSStefan Eßer 			idesc = idesc->next;
158425f9fdaSStefan Eßer 		}
159425f9fdaSStefan Eßer 	}
160425f9fdaSStefan Eßer }
161425f9fdaSStefan Eßer 
162425f9fdaSStefan Eßer static void
1634407ec71SPeter Wemm update_masks(intrmask_t *maskptr, int irq)
164425f9fdaSStefan Eßer {
1654407ec71SPeter Wemm 	intrmask_t mask = 1 << irq;
166425f9fdaSStefan Eßer 
167425f9fdaSStefan Eßer 	if (maskptr == NULL)
168425f9fdaSStefan Eßer 		return;
169425f9fdaSStefan Eßer 
170425f9fdaSStefan Eßer 	if (find_idesc(maskptr, irq) == NULL) {
171425f9fdaSStefan Eßer 		/* no reference to this maskptr was found in this irq's chain */
172425f9fdaSStefan Eßer 		if ((*maskptr & mask) == 0)
173425f9fdaSStefan Eßer 			return;
174425f9fdaSStefan Eßer 		/* the irq was included in the classes mask, remove it */
175425f9fdaSStefan Eßer 		INTRUNMASK(*maskptr, mask);
176425f9fdaSStefan Eßer 	} else {
177425f9fdaSStefan Eßer 		/* a reference to this maskptr was found in this irq's chain */
178425f9fdaSStefan Eßer 		if ((*maskptr & mask) != 0)
179425f9fdaSStefan Eßer 			return;
180425f9fdaSStefan Eßer 		/* put the irq into the classes mask */
181425f9fdaSStefan Eßer 		INTRMASK(*maskptr, mask);
182425f9fdaSStefan Eßer 	}
183425f9fdaSStefan Eßer 	/* we need to update all values in the intr_mask[irq] array */
184425f9fdaSStefan Eßer 	update_intr_masks();
185425f9fdaSStefan Eßer 	/* update mask in chains of the interrupt multiplex handler as well */
186425f9fdaSStefan Eßer 	update_mux_masks();
187425f9fdaSStefan Eßer }
188425f9fdaSStefan Eßer 
189425f9fdaSStefan Eßer /*
190425f9fdaSStefan Eßer  * Add interrupt handler to linked list hung off of intreclist_head[irq]
191425f9fdaSStefan Eßer  * and install shared interrupt multiplex handler, if necessary
192425f9fdaSStefan Eßer  */
193425f9fdaSStefan Eßer 
194425f9fdaSStefan Eßer static int
195425f9fdaSStefan Eßer add_intrdesc(intrec *idesc)
196425f9fdaSStefan Eßer {
197425f9fdaSStefan Eßer 	int irq = idesc->intr;
198425f9fdaSStefan Eßer 
199425f9fdaSStefan Eßer 	intrec *head = intreclist_head[irq];
200425f9fdaSStefan Eßer 
201425f9fdaSStefan Eßer 	if (head == NULL) {
202425f9fdaSStefan Eßer 		/* first handler for this irq, just install it */
203425f9fdaSStefan Eßer 		if (icu_setup(irq, idesc->handler, idesc->argument,
204425f9fdaSStefan Eßer 			      idesc->maskptr, idesc->flags) != 0)
205425f9fdaSStefan Eßer 			return (-1);
206425f9fdaSStefan Eßer 
207a23d65bfSBruce Evans 		update_intrname(irq, (intptr_t)idesc->devdata);
208425f9fdaSStefan Eßer 		/* keep reference */
209425f9fdaSStefan Eßer 		intreclist_head[irq] = idesc;
210425f9fdaSStefan Eßer 	} else {
211425f9fdaSStefan Eßer 		if ((idesc->flags & INTR_EXCL) != 0
212425f9fdaSStefan Eßer 		    || (head->flags & INTR_EXCL) != 0) {
213425f9fdaSStefan Eßer 			/*
214425f9fdaSStefan Eßer 			 * can't append new handler, if either list head or
215425f9fdaSStefan Eßer 			 * new handler do not allow interrupts to be shared
216425f9fdaSStefan Eßer 			 */
217fd35ecc3SNate Williams 			if (bootverbose)
218fd35ecc3SNate Williams 				printf("\tdevice combination doesn't support "
219fd35ecc3SNate Williams 				       "shared irq%d\n", irq);
220425f9fdaSStefan Eßer 			return (-1);
221425f9fdaSStefan Eßer 		}
222425f9fdaSStefan Eßer 		if (head->next == NULL) {
223425f9fdaSStefan Eßer 			/*
224425f9fdaSStefan Eßer 			 * second handler for this irq, replace device driver's
225425f9fdaSStefan Eßer 			 * handler by shared interrupt multiplexer function
226425f9fdaSStefan Eßer 			 */
227425f9fdaSStefan Eßer 			icu_unset(irq, head->handler);
228fbca51f5SSteve Passe 			if (icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0) != 0)
229425f9fdaSStefan Eßer 				return (-1);
230425f9fdaSStefan Eßer 			if (bootverbose)
231425f9fdaSStefan Eßer 				printf("\tusing shared irq%d.\n", irq);
232425f9fdaSStefan Eßer 			update_intrname(irq, -1);
233425f9fdaSStefan Eßer 		}
234425f9fdaSStefan Eßer 		/* just append to the end of the chain */
235425f9fdaSStefan Eßer 		while (head->next != NULL)
236425f9fdaSStefan Eßer 			head = head->next;
237425f9fdaSStefan Eßer 		head->next = idesc;
238425f9fdaSStefan Eßer 	}
239425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
240425f9fdaSStefan Eßer 	return (0);
241425f9fdaSStefan Eßer }
242425f9fdaSStefan Eßer 
243425f9fdaSStefan Eßer /*
244425f9fdaSStefan Eßer  * Add the interrupt handler descriptor data structure created by an
245425f9fdaSStefan Eßer  * earlier call of create_intr() to the linked list for its irq and
246425f9fdaSStefan Eßer  * adjust the interrupt masks if necessary.
247425f9fdaSStefan Eßer  *
248425f9fdaSStefan Eßer  * This function effectively activates the handler.
249425f9fdaSStefan Eßer  */
250425f9fdaSStefan Eßer 
251425f9fdaSStefan Eßer int
252425f9fdaSStefan Eßer intr_connect(intrec *idesc)
253425f9fdaSStefan Eßer {
254425f9fdaSStefan Eßer 	int errcode = -1;
255425f9fdaSStefan Eßer 	int irq;
256425f9fdaSStefan Eßer 
257425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
258425f9fdaSStefan Eßer 	int resflag;
259425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
260425f9fdaSStefan Eßer 
261425f9fdaSStefan Eßer 	if (idesc == NULL)
262425f9fdaSStefan Eßer 		return (-1);
263425f9fdaSStefan Eßer 
264425f9fdaSStefan Eßer 	irq = idesc->intr;
265425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
266425f9fdaSStefan Eßer 	resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED;
267425f9fdaSStefan Eßer 	if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0)
268425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
269425f9fdaSStefan Eßer 	{
270425f9fdaSStefan Eßer 		/* block this irq */
2714407ec71SPeter Wemm 		intrmask_t oldspl = splq(1 << irq);
272425f9fdaSStefan Eßer 
273425f9fdaSStefan Eßer 		/* add irq to class selected by maskptr */
274425f9fdaSStefan Eßer 		errcode = add_intrdesc(idesc);
275425f9fdaSStefan Eßer 		splx(oldspl);
276425f9fdaSStefan Eßer 	}
277fd35ecc3SNate Williams 	if (errcode != 0 && bootverbose)
278425f9fdaSStefan Eßer 		printf("\tintr_connect(irq%d) failed, result=%d\n",
279425f9fdaSStefan Eßer 		       irq, errcode);
280425f9fdaSStefan Eßer 
281425f9fdaSStefan Eßer 	return (errcode);
282425f9fdaSStefan Eßer }
283425f9fdaSStefan Eßer 
284425f9fdaSStefan Eßer /*
285425f9fdaSStefan Eßer  * Remove the interrupt handler descriptor data connected created by an
286425f9fdaSStefan Eßer  * earlier call of intr_connect() from the linked list and adjust the
287425f9fdaSStefan Eßer  * interrupt masks if necessary.
288425f9fdaSStefan Eßer  *
289425f9fdaSStefan Eßer  * This function deactivates the handler.
290425f9fdaSStefan Eßer  */
291425f9fdaSStefan Eßer 
292425f9fdaSStefan Eßer int
293425f9fdaSStefan Eßer intr_disconnect(intrec *idesc)
294425f9fdaSStefan Eßer {
295425f9fdaSStefan Eßer 	intrec **hook, *head;
296425f9fdaSStefan Eßer 	int irq;
297425f9fdaSStefan Eßer 	int errcode = 0;
298425f9fdaSStefan Eßer 
299425f9fdaSStefan Eßer 	if (idesc == NULL)
300425f9fdaSStefan Eßer 		return (-1);
301425f9fdaSStefan Eßer 
302425f9fdaSStefan Eßer 	irq = idesc->intr;
303425f9fdaSStefan Eßer 
304425f9fdaSStefan Eßer 	/* find pointer that keeps the reference to this interrupt descriptor */
305425f9fdaSStefan Eßer 	hook = find_pred(idesc, irq);
306425f9fdaSStefan Eßer 	if (hook == NULL)
307425f9fdaSStefan Eßer 		return (-1);
308425f9fdaSStefan Eßer 
309425f9fdaSStefan Eßer 	/* make copy of original list head, the line after may overwrite it */
310425f9fdaSStefan Eßer 	head = intreclist_head[irq];
311425f9fdaSStefan Eßer 
312425f9fdaSStefan Eßer 	/* unlink: make predecessor point to idesc->next instead of to idesc */
313425f9fdaSStefan Eßer 	*hook = idesc->next;
314425f9fdaSStefan Eßer 
315425f9fdaSStefan Eßer 	/* now check whether the element we removed was the list head */
316425f9fdaSStefan Eßer 	if (idesc == head) {
3174407ec71SPeter Wemm 		intrmask_t oldspl = splq(1 << irq);
318425f9fdaSStefan Eßer 
319425f9fdaSStefan Eßer 		/* we want to remove the list head, which was known to intr_mux */
320fbca51f5SSteve Passe 		icu_unset(irq, (inthand2_t*)intr_mux);
321425f9fdaSStefan Eßer 
322425f9fdaSStefan Eßer 		/* check whether the new list head is the only element on list */
323425f9fdaSStefan Eßer 		head = intreclist_head[irq];
324f9220cdeSStefan Eßer 		if (head != NULL) {
325425f9fdaSStefan Eßer 			if (head->next != NULL) {
326425f9fdaSStefan Eßer 				/* install the multiplex handler with new list head as argument */
327fbca51f5SSteve Passe 				errcode = icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0);
328425f9fdaSStefan Eßer 				if (errcode == 0)
329425f9fdaSStefan Eßer 					update_intrname(irq, -1);
330f9220cdeSStefan Eßer 			} else {
331425f9fdaSStefan Eßer 				/* install the one remaining handler for this irq */
332f9220cdeSStefan Eßer 				errcode = icu_setup(irq, head->handler,
333f9220cdeSStefan Eßer 						    head->argument,
334425f9fdaSStefan Eßer 						    head->maskptr, head->flags);
335425f9fdaSStefan Eßer 				if (errcode == 0)
336a23d65bfSBruce Evans 					update_intrname(irq, (intptr_t)head->devdata);
337425f9fdaSStefan Eßer 			}
338f9220cdeSStefan Eßer 		}
339425f9fdaSStefan Eßer 		splx(oldspl);
340425f9fdaSStefan Eßer 	}
341425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
342425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
343425f9fdaSStefan Eßer 	resource_free(idesc->devdata);
344425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
345425f9fdaSStefan Eßer 	return (0);
346425f9fdaSStefan Eßer }
347425f9fdaSStefan Eßer 
348425f9fdaSStefan Eßer /*
349425f9fdaSStefan Eßer  * Create an interrupt handler descriptor data structure, which later can
350425f9fdaSStefan Eßer  * be activated or deactivated at will by calls of [dis]connect(intrec*).
351425f9fdaSStefan Eßer  *
352425f9fdaSStefan Eßer  * The dev_instance pointer is required for resource management, and will
353425f9fdaSStefan Eßer  * only be passed through to resource_claim().
354425f9fdaSStefan Eßer  *
355425f9fdaSStefan Eßer  * The interrupt handler takes an argument of type (void*), which is not
356425f9fdaSStefan Eßer  * what is currently used for ISA devices. But since the unit number passed
357425f9fdaSStefan Eßer  * to an ISA interrupt handler can be stored in a (void*) variable, this
358425f9fdaSStefan Eßer  * causes no problems. Eventually all the ISA interrupt handlers should be
359425f9fdaSStefan Eßer  * modified to accept the pointer to their private data, too, instead of
360425f9fdaSStefan Eßer  * an integer index.
361425f9fdaSStefan Eßer  *
362425f9fdaSStefan Eßer  * There will be functions that derive a driver and unit name from a
363425f9fdaSStefan Eßer  * dev_instance variable, and those functions will be used to maintain the
364425f9fdaSStefan Eßer  * interrupt counter label array referenced by systat and vmstat to report
365425f9fdaSStefan Eßer  * device interrupt rates (->update_intrlabels).
366425f9fdaSStefan Eßer  */
367425f9fdaSStefan Eßer 
368425f9fdaSStefan Eßer intrec *
369425f9fdaSStefan Eßer intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg,
3704407ec71SPeter Wemm 	     intrmask_t *maskptr, int flags)
371425f9fdaSStefan Eßer {
372425f9fdaSStefan Eßer 	intrec *idesc;
373425f9fdaSStefan Eßer 
374425f9fdaSStefan Eßer 	if (ICU_LEN > 8 * sizeof *maskptr) {
375425f9fdaSStefan Eßer 		printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
376425f9fdaSStefan Eßer 		       ICU_LEN, 8 * sizeof *maskptr);
377425f9fdaSStefan Eßer 		return (NULL);
378425f9fdaSStefan Eßer 	}
379425f9fdaSStefan Eßer 	if ((unsigned)irq >= ICU_LEN) {
380425f9fdaSStefan Eßer 		printf("create_intr: requested irq%d too high, limit is %d\n",
381425f9fdaSStefan Eßer 		       irq, ICU_LEN -1);
382425f9fdaSStefan Eßer 		return (NULL);
383425f9fdaSStefan Eßer 	}
384425f9fdaSStefan Eßer 
385425f9fdaSStefan Eßer 	idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
386425f9fdaSStefan Eßer 	if (idesc) {
387425f9fdaSStefan Eßer 		idesc->next     = NULL;
388425f9fdaSStefan Eßer 		bzero(idesc, sizeof *idesc);
389425f9fdaSStefan Eßer 
390425f9fdaSStefan Eßer 		idesc->devdata  = dev_instance;
391425f9fdaSStefan Eßer 		idesc->handler  = handler;
392425f9fdaSStefan Eßer 		idesc->argument = arg;
393425f9fdaSStefan Eßer 		idesc->maskptr  = maskptr;
394425f9fdaSStefan Eßer 		idesc->intr     = irq;
395425f9fdaSStefan Eßer 		idesc->flags    = flags;
396425f9fdaSStefan Eßer 	}
397425f9fdaSStefan Eßer 	return (idesc);
398425f9fdaSStefan Eßer }
399425f9fdaSStefan Eßer 
400425f9fdaSStefan Eßer /*
401425f9fdaSStefan Eßer  * Return the memory held by the interrupt handler descriptor data structure
402425f9fdaSStefan Eßer  * to the system. Make sure, the handler is not actively used anymore, before.
403425f9fdaSStefan Eßer  */
404425f9fdaSStefan Eßer 
405425f9fdaSStefan Eßer int
406425f9fdaSStefan Eßer intr_destroy(intrec *rec)
407425f9fdaSStefan Eßer {
408425f9fdaSStefan Eßer 	if (intr_disconnect(rec) != 0)
409425f9fdaSStefan Eßer 		return (-1);
410425f9fdaSStefan Eßer 	free(rec, M_DEVBUF);
411425f9fdaSStefan Eßer 	return (0);
412425f9fdaSStefan Eßer }
413425f9fdaSStefan Eßer 
414425f9fdaSStefan Eßer /*
415425f9fdaSStefan Eßer  * Emulate the register_intr() call previously defined as low level function.
416425f9fdaSStefan Eßer  * That function (now icu_setup()) may no longer be directly called, since
417425f9fdaSStefan Eßer  * a conflict between an ISA and PCI interrupt might go by unnocticed, else.
418425f9fdaSStefan Eßer  */
419425f9fdaSStefan Eßer 
420425f9fdaSStefan Eßer int
421425f9fdaSStefan Eßer register_intr(int intr, int device_id, u_int flags,
422425f9fdaSStefan Eßer 	      inthand2_t handler, u_int *maskptr, int unit)
423425f9fdaSStefan Eßer {
424425f9fdaSStefan Eßer 	/* XXX modify to include isa_device instead of device_id */
425425f9fdaSStefan Eßer 	intrec *idesc;
426425f9fdaSStefan Eßer 
427425f9fdaSStefan Eßer 	flags |= INTR_EXCL;
428a23d65bfSBruce Evans 	idesc = intr_create((void *)(intptr_t)device_id, intr, handler,
429a23d65bfSBruce Evans 			    (void*)(intptr_t)unit, maskptr, flags);
430425f9fdaSStefan Eßer 	return (intr_connect(idesc));
431425f9fdaSStefan Eßer }
432425f9fdaSStefan Eßer 
433425f9fdaSStefan Eßer /*
434425f9fdaSStefan Eßer  * Emulate the old unregister_intr() low level function.
435425f9fdaSStefan Eßer  * Make sure there is just one interrupt, that it was
436425f9fdaSStefan Eßer  * registered as non-shared, and that the handlers match.
437425f9fdaSStefan Eßer  */
438425f9fdaSStefan Eßer 
439425f9fdaSStefan Eßer int
440425f9fdaSStefan Eßer unregister_intr(int intr, inthand2_t handler)
441425f9fdaSStefan Eßer {
442425f9fdaSStefan Eßer 	intrec *p = intreclist_head[intr];
443425f9fdaSStefan Eßer 
444425f9fdaSStefan Eßer 	if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler)
445425f9fdaSStefan Eßer 		return (intr_destroy(p));
446425f9fdaSStefan Eßer 	return (EINVAL);
447425f9fdaSStefan Eßer }
4483900ddb2SDoug Rabson 
449da653c61SDoug Rabson #endif /* __i386__ */
450da653c61SDoug Rabson 
45118c5a6c4SBruce Evans void
45218c5a6c4SBruce Evans register_swi(intr, handler)
45318c5a6c4SBruce Evans 	int intr;
45418c5a6c4SBruce Evans 	swihand_t *handler;
45518c5a6c4SBruce Evans {
45618c5a6c4SBruce Evans 	struct swilist *slp, *slq;
45718c5a6c4SBruce Evans 	int s;
45818c5a6c4SBruce Evans 
45918c5a6c4SBruce Evans 	if (intr < NHWI || intr >= NHWI + NSWI)
46018c5a6c4SBruce Evans 		panic("register_swi: bad intr %d", intr);
46118c5a6c4SBruce Evans 	if (handler == swi_generic || handler == swi_null)
46218c5a6c4SBruce Evans 		panic("register_swi: bad handler %p", (void *)handler);
46318c5a6c4SBruce Evans 	slp = &swilists[intr - NHWI];
46418c5a6c4SBruce Evans 	s = splhigh();
46518c5a6c4SBruce Evans 	if (ihandlers[intr] == swi_null)
46618c5a6c4SBruce Evans 		ihandlers[intr] = handler;
46718c5a6c4SBruce Evans 	else {
46818c5a6c4SBruce Evans 		if (slp->sl_next == NULL) {
46918c5a6c4SBruce Evans 			slp->sl_handler = ihandlers[intr];
47018c5a6c4SBruce Evans 			ihandlers[intr] = swi_generic;
47118c5a6c4SBruce Evans 		}
47218c5a6c4SBruce Evans 		slq = malloc(sizeof(*slq), M_DEVBUF, M_NOWAIT);
47318c5a6c4SBruce Evans 		if (slq == NULL)
47418c5a6c4SBruce Evans 			panic("register_swi: malloc failed");
47518c5a6c4SBruce Evans 		slq->sl_handler = handler;
47618c5a6c4SBruce Evans 		slq->sl_next = NULL;
47718c5a6c4SBruce Evans 		while (slp->sl_next != NULL)
47818c5a6c4SBruce Evans 			slp = slp->sl_next;
47918c5a6c4SBruce Evans 		slp->sl_next = slq;
48018c5a6c4SBruce Evans 	}
48118c5a6c4SBruce Evans 	splx(s);
48218c5a6c4SBruce Evans }
48318c5a6c4SBruce Evans 
48418c5a6c4SBruce Evans void
48518c5a6c4SBruce Evans swi_dispatcher(intr)
48618c5a6c4SBruce Evans 	int intr;
48718c5a6c4SBruce Evans {
48818c5a6c4SBruce Evans 	struct swilist *slp;
48918c5a6c4SBruce Evans 
49018c5a6c4SBruce Evans 	slp = &swilists[intr - NHWI];
49118c5a6c4SBruce Evans 	do {
49218c5a6c4SBruce Evans 		(*slp->sl_handler)();
49318c5a6c4SBruce Evans 		slp = slp->sl_next;
49418c5a6c4SBruce Evans 	} while (slp != NULL);
49518c5a6c4SBruce Evans }
49618c5a6c4SBruce Evans 
49718c5a6c4SBruce Evans void
49818c5a6c4SBruce Evans unregister_swi(intr, handler)
49918c5a6c4SBruce Evans 	int intr;
50018c5a6c4SBruce Evans 	swihand_t *handler;
50118c5a6c4SBruce Evans {
50218c5a6c4SBruce Evans 	struct swilist *slfoundpred, *slp, *slq;
50318c5a6c4SBruce Evans 	int s;
50418c5a6c4SBruce Evans 
50518c5a6c4SBruce Evans 	if (intr < NHWI || intr >= NHWI + NSWI)
50618c5a6c4SBruce Evans 		panic("unregister_swi: bad intr %d", intr);
50718c5a6c4SBruce Evans 	if (handler == swi_generic || handler == swi_null)
50818c5a6c4SBruce Evans 		panic("unregister_swi: bad handler %p", (void *)handler);
50918c5a6c4SBruce Evans 	slp = &swilists[intr - NHWI];
51018c5a6c4SBruce Evans 	s = splhigh();
51118c5a6c4SBruce Evans 	if (ihandlers[intr] == handler)
51218c5a6c4SBruce Evans 		ihandlers[intr] = swi_null;
51318c5a6c4SBruce Evans 	else if (slp->sl_next != NULL) {
51418c5a6c4SBruce Evans 		slfoundpred = NULL;
51518c5a6c4SBruce Evans 		for (slq = slp->sl_next; slq != NULL;
51618c5a6c4SBruce Evans 		    slp = slq, slq = slp->sl_next)
51718c5a6c4SBruce Evans 			if (slq->sl_handler == handler)
51818c5a6c4SBruce Evans 				slfoundpred = slp;
51918c5a6c4SBruce Evans 		slp = &swilists[intr - NHWI];
52018c5a6c4SBruce Evans 		if (slfoundpred != NULL) {
52118c5a6c4SBruce Evans 			slq = slfoundpred->sl_next;
52218c5a6c4SBruce Evans 			slfoundpred->sl_next = slq->sl_next;
52318c5a6c4SBruce Evans 			free(slq, M_DEVBUF);
52418c5a6c4SBruce Evans 		} else if (slp->sl_handler == handler) {
52518c5a6c4SBruce Evans 			slq = slp->sl_next;
52618c5a6c4SBruce Evans 			slp->sl_next = slq->sl_next;
52718c5a6c4SBruce Evans 			slp->sl_handler = slq->sl_handler;
52818c5a6c4SBruce Evans 			free(slq, M_DEVBUF);
52918c5a6c4SBruce Evans 		}
53018c5a6c4SBruce Evans 		if (slp->sl_next == NULL)
53118c5a6c4SBruce Evans 			ihandlers[intr] = slp->sl_handler;
53218c5a6c4SBruce Evans 	}
53318c5a6c4SBruce Evans 	splx(s);
53418c5a6c4SBruce Evans }
53518c5a6c4SBruce Evans 
536