nmi.c revision 89980
155714Skris/*- 255714Skris * Copyright (c) 1991 The Regents of the University of California. 355714Skris * All rights reserved. 455714Skris * 555714Skris * This code is derived from software contributed to Berkeley by 655714Skris * William Jolitz. 755714Skris * 855714Skris * Redistribution and use in source and binary forms, with or without 955714Skris * modification, are permitted provided that the following conditions 1055714Skris * are met: 1155714Skris * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 37 * $FreeBSD: head/sys/i386/isa/nmi.c 89980 2002-01-30 12:41:12Z bde $ 38 */ 39 40#include "opt_auto_eoi.h" 41#include "opt_isa.h" 42#include "opt_mca.h" 43 44#include <sys/param.h> 45#include <sys/bus.h> 46#include <sys/errno.h> 47#include <sys/interrupt.h> 48#include <sys/kernel.h> 49#include <sys/kthread.h> 50#include <sys/lock.h> 51#include <sys/malloc.h> 52#include <sys/module.h> 53#include <sys/mutex.h> 54#include <sys/proc.h> 55#include <sys/syslog.h> 56#include <sys/systm.h> 57#include <sys/unistd.h> 58 59#include <machine/md_var.h> 60#include <machine/segments.h> 61 62#if defined(APIC_IO) 63#include <machine/smptests.h> /** FAST_HI */ 64#include <machine/smp.h> 65#include <machine/resource.h> 66#endif /* APIC_IO */ 67#ifdef PC98 68#include <pc98/pc98/pc98.h> 69#include <pc98/pc98/pc98_machdep.h> 70#include <pc98/pc98/epsonio.h> 71#else 72#include <i386/isa/isa.h> 73#endif 74#include <i386/isa/icu.h> 75 76#ifdef DEV_ISA 77#include <isa/isavar.h> 78#endif 79#include <i386/isa/intr_machdep.h> 80#include <sys/interrupt.h> 81#ifdef APIC_IO 82#include <machine/clock.h> 83#endif 84 85#ifdef DEV_MCA 86#include <i386/isa/mca_machdep.h> 87#endif 88 89/* 90 * Per-interrupt data. 91 */ 92u_long *intr_countp[ICU_LEN]; /* pointers to interrupt counters */ 93driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */ 94struct ithd *ithds[ICU_LEN]; /* real interrupt handler */ 95void *intr_unit[ICU_LEN]; 96 97static struct mtx ithds_table_lock; /* protect the ithds table */ 98 99static inthand_t *fastintr[ICU_LEN] = { 100 &IDTVEC(fastintr0), &IDTVEC(fastintr1), 101 &IDTVEC(fastintr2), &IDTVEC(fastintr3), 102 &IDTVEC(fastintr4), &IDTVEC(fastintr5), 103 &IDTVEC(fastintr6), &IDTVEC(fastintr7), 104 &IDTVEC(fastintr8), &IDTVEC(fastintr9), 105 &IDTVEC(fastintr10), &IDTVEC(fastintr11), 106 &IDTVEC(fastintr12), &IDTVEC(fastintr13), 107 &IDTVEC(fastintr14), &IDTVEC(fastintr15), 108#if defined(APIC_IO) 109 &IDTVEC(fastintr16), &IDTVEC(fastintr17), 110 &IDTVEC(fastintr18), &IDTVEC(fastintr19), 111 &IDTVEC(fastintr20), &IDTVEC(fastintr21), 112 &IDTVEC(fastintr22), &IDTVEC(fastintr23), 113 &IDTVEC(fastintr24), &IDTVEC(fastintr25), 114 &IDTVEC(fastintr26), &IDTVEC(fastintr27), 115 &IDTVEC(fastintr28), &IDTVEC(fastintr29), 116 &IDTVEC(fastintr30), &IDTVEC(fastintr31), 117#endif /* APIC_IO */ 118}; 119 120static inthand_t *slowintr[ICU_LEN] = { 121 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), 122 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), 123 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), 124 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15), 125#if defined(APIC_IO) 126 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19), 127 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23), 128 &IDTVEC(intr24), &IDTVEC(intr25), &IDTVEC(intr26), &IDTVEC(intr27), 129 &IDTVEC(intr28), &IDTVEC(intr29), &IDTVEC(intr30), &IDTVEC(intr31), 130#endif /* APIC_IO */ 131}; 132 133static driver_intr_t isa_strayintr; 134 135static void ithds_init(void *dummy); 136static void ithread_enable(int vector); 137static void ithread_disable(int vector); 138static void init_i8259(void); 139 140#ifdef PC98 141#define NMI_PARITY 0x04 142#define NMI_EPARITY 0x02 143#else 144#define NMI_PARITY (1 << 7) 145#define NMI_IOCHAN (1 << 6) 146#define ENMI_WATCHDOG (1 << 7) 147#define ENMI_BUSTIMER (1 << 6) 148#define ENMI_IOSTATUS (1 << 5) 149#endif 150 151#ifdef DEV_ISA 152/* 153 * Bus attachment for the ISA PIC. 154 */ 155static struct isa_pnp_id atpic_ids[] = { 156 { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 157 { 0 } 158}; 159 160static int 161atpic_probe(device_t dev) 162{ 163 int result; 164 165 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids)) <= 0) 166 device_quiet(dev); 167 return(result); 168} 169 170/* 171 * In the APIC_IO case we might be granted IRQ 2, as this is typically 172 * consumed by chaining between the two PIC components. If we're using 173 * the APIC, however, this may not be the case, and as such we should 174 * free the resource. (XXX untested) 175 * 176 * The generic ISA attachment code will handle allocating any other resources 177 * that we don't explicitly claim here. 178 */ 179static int 180atpic_attach(device_t dev) 181{ 182#ifdef APIC_IO 183 int rid; 184 struct resource *res; 185 186 /* try to allocate our IRQ and then free it */ 187 rid = 0; 188 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 0); 189 if (res != NULL) 190 bus_release_resource(dev, SYS_RES_IRQ, rid, res); 191#endif 192 return(0); 193} 194 195static device_method_t atpic_methods[] = { 196 /* Device interface */ 197 DEVMETHOD(device_probe, atpic_probe), 198 DEVMETHOD(device_attach, atpic_attach), 199 DEVMETHOD(device_detach, bus_generic_detach), 200 DEVMETHOD(device_shutdown, bus_generic_shutdown), 201 DEVMETHOD(device_suspend, bus_generic_suspend), 202 DEVMETHOD(device_resume, bus_generic_resume), 203 { 0, 0 } 204}; 205 206static driver_t atpic_driver = { 207 "atpic", 208 atpic_methods, 209 1, /* no softc */ 210}; 211 212static devclass_t atpic_devclass; 213 214DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 215DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 216#endif /* DEV_ISA */ 217 218/* 219 * Handle a NMI, possibly a machine check. 220 * return true to panic system, false to ignore. 221 */ 222int 223isa_nmi(cd) 224 int cd; 225{ 226 int retval = 0; 227#ifdef PC98 228 int port = inb(0x33); 229 230 log(LOG_CRIT, "NMI PC98 port = %x\n", port); 231 if (epson_machine_id == 0x20) 232 epson_outb(0xc16, epson_inb(0xc16) | 0x1); 233 if (port & NMI_PARITY) { 234 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure."); 235 retval = 1; 236 } else if (port & NMI_EPARITY) { 237 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure."); 238 retval = 1; 239 } else { 240 log(LOG_CRIT, "\nNMI Resume ??\n"); 241 } 242#else /* IBM-PC */ 243 int isa_port = inb(0x61); 244 int eisa_port = inb(0x461); 245 246 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port); 247#ifdef DEV_MCA 248 if (MCA_system && mca_bus_nmi()) 249 return(0); 250#endif 251 252 if (isa_port & NMI_PARITY) { 253 log(LOG_CRIT, "RAM parity error, likely hardware failure."); 254 retval = 1; 255 } 256 257 if (isa_port & NMI_IOCHAN) { 258 log(LOG_CRIT, "I/O channel check, likely hardware failure."); 259 retval = 1; 260 } 261 262 /* 263 * On a real EISA machine, this will never happen. However it can 264 * happen on ISA machines which implement XT style floating point 265 * error handling (very rare). Save them from a meaningless panic. 266 */ 267 if (eisa_port == 0xff) 268 return(retval); 269 270 if (eisa_port & ENMI_WATCHDOG) { 271 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure."); 272 retval = 1; 273 } 274 275 if (eisa_port & ENMI_BUSTIMER) { 276 log(LOG_CRIT, "EISA bus timeout, likely hardware failure."); 277 retval = 1; 278 } 279 280 if (eisa_port & ENMI_IOSTATUS) { 281 log(LOG_CRIT, "EISA I/O port status error."); 282 retval = 1; 283 } 284#endif 285 return(retval); 286} 287 288/* 289 * ICU reinitialize when ICU configuration has lost. 290 */ 291void icu_reinit() 292{ 293 int i; 294 295 mtx_lock_spin(&icu_lock); 296 init_i8259(); 297 for(i=0;i<ICU_LEN;i++) 298 if(intr_handler[i] != isa_strayintr) 299 INTREN(1<<i); 300 mtx_unlock_spin(&icu_lock); 301} 302 303/* 304 * Create a default interrupt table to avoid problems caused by 305 * spurious interrupts during configuration of kernel, then setup 306 * interrupt control unit. 307 */ 308void 309isa_defaultirq() 310{ 311 int i; 312 313 /* icu vectors */ 314 for (i = 0; i < ICU_LEN; i++) 315 icu_unset(i, (driver_intr_t *)NULL); 316 mtx_lock_spin(&icu_lock); 317 init_i8259(); 318 mtx_unlock_spin(&icu_lock); 319} 320 321 322/* 323 *initialize 8259's 324 */ 325static void init_i8259() 326{ 327 328#ifdef DEV_MCA 329 if (MCA_system) 330 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */ 331 else 332#endif 333 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 334 335 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */ 336 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */ 337#ifdef PC98 338#ifdef AUTO_EOI_1 339 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */ 340#else 341 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */ 342#endif 343#else /* IBM-PC */ 344#ifdef AUTO_EOI_1 345 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */ 346#else 347 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */ 348#endif 349#endif /* PC98 */ 350 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */ 351 outb(IO_ICU1, 0x0a); /* default to IRR on read */ 352#ifndef PC98 353 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 354#endif /* !PC98 */ 355 356#ifdef DEV_MCA 357 if (MCA_system) 358 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */ 359 else 360#endif 361 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 362 363 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */ 364 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */ 365#ifdef PC98 366 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */ 367#else /* IBM-PC */ 368#ifdef AUTO_EOI_2 369 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */ 370#else 371 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */ 372#endif 373#endif /* PC98 */ 374 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */ 375 outb(IO_ICU2, 0x0a); /* default to IRR on read */ 376} 377 378/* 379 * Caught a stray interrupt, notify 380 */ 381static void 382isa_strayintr(vcookiep) 383 void *vcookiep; 384{ 385 int intr = (void **)vcookiep - &intr_unit[0]; 386 387 /* 388 * XXX TODO print a different message for #7 if it is for a 389 * glitch. Glitches can be distinguished from real #7's by 390 * testing that the in-service bit is _not_ set. The test 391 * must be done before sending an EOI so it can't be done if 392 * we are using AUTO_EOI_1. 393 */ 394 if (intrcnt[1 + intr] <= 5) 395 log(LOG_ERR, "stray irq %d\n", intr); 396 if (intrcnt[1 + intr] == 5) 397 log(LOG_CRIT, 398 "too many stray irq %d's; not logging any more\n", intr); 399} 400 401#ifdef DEV_ISA 402/* 403 * Return a bitmap of the current interrupt requests. This is 8259-specific 404 * and is only suitable for use at probe time. 405 */ 406intrmask_t 407isa_irq_pending() 408{ 409 u_char irr1; 410 u_char irr2; 411 412 mtx_lock_spin(&icu_lock); 413 irr1 = inb(IO_ICU1); 414 irr2 = inb(IO_ICU2); 415 mtx_unlock_spin(&icu_lock); 416 return ((irr2 << 8) | irr1); 417} 418#endif 419 420/* 421 * Update intrnames array with the specified name. This is used by 422 * vmstat(8) and the like. 423 */ 424static void 425update_intrname(int intr, const char *name) 426{ 427 char buf[32]; 428 char *cp; 429 int name_index, off, strayintr; 430 431 /* 432 * Initialise strings for bitbucket and stray interrupt counters. 433 * These have statically allocated indices 0 and 1 through ICU_LEN. 434 */ 435 if (intrnames[0] == '\0') { 436 off = sprintf(intrnames, "???") + 1; 437 for (strayintr = 0; strayintr < ICU_LEN; strayintr++) 438 off += sprintf(intrnames + off, "stray irq%d", 439 strayintr) + 1; 440 } 441 442 if (name == NULL) 443 name = "???"; 444 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf)) 445 goto use_bitbucket; 446 447 /* 448 * Search for `buf' in `intrnames'. In the usual case when it is 449 * not found, append it to the end if there is enough space (the \0 450 * terminator for the previous string, if any, becomes a separator). 451 */ 452 for (cp = intrnames, name_index = 0; 453 cp != eintrnames && name_index < NR_INTRNAMES; 454 cp += strlen(cp) + 1, name_index++) { 455 if (*cp == '\0') { 456 if (strlen(buf) >= eintrnames - cp) 457 break; 458 strcpy(cp, buf); 459 goto found; 460 } 461 if (strcmp(cp, buf) == 0) 462 goto found; 463 } 464 465use_bitbucket: 466 printf("update_intrname: counting %s irq%d as %s\n", name, intr, 467 intrnames); 468 name_index = 0; 469found: 470 intr_countp[intr] = &intrcnt[name_index]; 471} 472 473int 474icu_setup(int intr, driver_intr_t *handler, void *arg, int flags) 475{ 476#ifdef FAST_HI 477 int select; /* the select register is 8 bits */ 478 int vector; 479 u_int32_t value; /* the window register is 32 bits */ 480#endif /* FAST_HI */ 481 482#if defined(APIC_IO) 483 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */ 484#else 485 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID) 486#endif /* APIC_IO */ 487 return (EINVAL); 488#if 0 489 if (intr_handler[intr] != isa_strayintr) 490 return (EBUSY); 491#endif 492 493 mtx_lock_spin(&icu_lock); 494 intr_handler[intr] = handler; 495 intr_unit[intr] = arg; 496#ifdef FAST_HI 497 if (flags & INTR_FAST) { 498 vector = TPR_FAST_INTS + intr; 499 setidt(vector, fastintr[intr], 500 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 501 } 502 else { 503 vector = TPR_SLOW_INTS + intr; 504#ifdef APIC_INTR_REORDER 505#ifdef APIC_INTR_HIGHPRI_CLOCK 506 /* XXX: Hack (kludge?) for more accurate clock. */ 507 if (intr == apic_8254_intr || intr == 8) { 508 vector = TPR_FAST_INTS + intr; 509 } 510#endif 511#endif 512 setidt(vector, slowintr[intr], 513 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 514 } 515#ifdef APIC_INTR_REORDER 516 set_lapic_isrloc(intr, vector); 517#endif 518 /* 519 * Reprogram the vector in the IO APIC. 520 */ 521 if (int_to_apicintpin[intr].ioapic >= 0) { 522 select = int_to_apicintpin[intr].redirindex; 523 value = io_apic_read(int_to_apicintpin[intr].ioapic, 524 select) & ~IOART_INTVEC; 525 io_apic_write(int_to_apicintpin[intr].ioapic, 526 select, value | vector); 527 } 528#else 529 setidt(ICU_OFFSET + intr, 530 flags & INTR_FAST ? fastintr[intr] : slowintr[intr], 531 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 532#endif /* FAST_HI */ 533 INTREN(1 << intr); 534 mtx_unlock_spin(&icu_lock); 535 return (0); 536} 537 538/* 539 * Dissociate an interrupt handler from an IRQ and set the handler to 540 * the stray interrupt handler. The 'handler' parameter is used only 541 * for consistency checking. 542 */ 543int 544icu_unset(intr, handler) 545 int intr; 546 driver_intr_t *handler; 547{ 548 549 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) 550 return (EINVAL); 551 552 mtx_lock_spin(&icu_lock); 553 INTRDIS(1 << intr); 554 intr_countp[intr] = &intrcnt[1 + intr]; 555 intr_handler[intr] = isa_strayintr; 556 intr_unit[intr] = &intr_unit[intr]; 557#ifdef FAST_HI_XXX 558 /* XXX how do I re-create dvp here? */ 559 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr, 560 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 561#else /* FAST_HI */ 562#ifdef APIC_INTR_REORDER 563 set_lapic_isrloc(intr, ICU_OFFSET + intr); 564#endif 565 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, 566 GSEL(GCODE_SEL, SEL_KPL)); 567#endif /* FAST_HI */ 568 mtx_unlock_spin(&icu_lock); 569 return (0); 570} 571 572static void 573ithds_init(void *dummy) 574{ 575 576 mtx_init(&ithds_table_lock, "ithread table lock", MTX_SPIN); 577} 578SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL); 579 580static void 581ithread_enable(int vector) 582{ 583 584 mtx_lock_spin(&icu_lock); 585 INTREN(1 << vector); 586 mtx_unlock_spin(&icu_lock); 587} 588 589static void 590ithread_disable(int vector) 591{ 592 593 mtx_lock_spin(&icu_lock); 594 INTRDIS(1 << vector); 595 mtx_unlock_spin(&icu_lock); 596} 597 598int 599inthand_add(const char *name, int irq, driver_intr_t handler, void *arg, 600 enum intr_type flags, void **cookiep) 601{ 602 struct ithd *ithd; /* descriptor for the IRQ */ 603 int errcode = 0; 604 int created_ithd = 0; 605 606 /* 607 * Work around a race where more than one CPU may be registering 608 * handlers on the same IRQ at the same time. 609 */ 610 mtx_lock_spin(&ithds_table_lock); 611 ithd = ithds[irq]; 612 mtx_unlock_spin(&ithds_table_lock); 613 if (ithd == NULL) { 614 errcode = ithread_create(&ithd, irq, 0, ithread_disable, 615 ithread_enable, "irq%d:", irq); 616 if (errcode) 617 return (errcode); 618 mtx_lock_spin(&ithds_table_lock); 619 if (ithds[irq] == NULL) { 620 ithds[irq] = ithd; 621 created_ithd++; 622 mtx_unlock_spin(&ithds_table_lock); 623 } else { 624 struct ithd *orphan; 625 626 orphan = ithd; 627 ithd = ithds[irq]; 628 mtx_unlock_spin(&ithds_table_lock); 629 ithread_destroy(orphan); 630 } 631 } 632 633 errcode = ithread_add_handler(ithd, name, handler, arg, 634 ithread_priority(flags), flags, cookiep); 635 636 if ((flags & INTR_FAST) == 0 || errcode) 637 /* 638 * The interrupt process must be in place, but 639 * not necessarily schedulable, before we 640 * initialize the ICU, since it may cause an 641 * immediate interrupt. 642 */ 643 if (icu_setup(irq, &sched_ithd, arg, flags) != 0) 644 panic("inthand_add: Can't initialize ICU"); 645 646 if (errcode) 647 return (errcode); 648 649 if (flags & INTR_FAST) { 650 errcode = icu_setup(irq, handler, arg, flags); 651 if (errcode && bootverbose) 652 printf("\tinthand_add(irq%d) failed, result=%d\n", 653 irq, errcode); 654 if (errcode) 655 return (errcode); 656 } 657 658 update_intrname(irq, name); 659 return (0); 660} 661 662/* 663 * Deactivate and remove linked list the interrupt handler descriptor 664 * data connected created by an earlier call of inthand_add(), then 665 * adjust the interrupt masks if necessary. 666 * 667 * Return the memory held by the interrupt handler descriptor data 668 * structure to the system. First ensure the handler is not actively 669 * in use. 670 */ 671int 672inthand_remove(void *cookie) 673{ 674 675 return (ithread_remove_handler(cookie)); 676} 677