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