atpic.c revision 129876
1/*- 2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30/* 31 * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 129876 2004-05-30 17:57:46Z phk $"); 36 37#include "opt_auto_eoi.h" 38#include "opt_isa.h" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/bus.h> 43#include <sys/interrupt.h> 44#include <sys/kernel.h> 45#include <sys/lock.h> 46#include <sys/module.h> 47#include <sys/mutex.h> 48 49#include <machine/cpufunc.h> 50#include <machine/frame.h> 51#include <machine/intr_machdep.h> 52#include <machine/md_var.h> 53#include <machine/resource.h> 54#include <machine/segments.h> 55 56#include <dev/ic/i8259.h> 57#include <i386/isa/icu.h> 58#ifdef PC98 59#include <pc98/pc98/pc98.h> 60#else 61#include <i386/isa/isa.h> 62#endif 63#include <isa/isavar.h> 64 65#define MASTER 0 66#define SLAVE 1 67 68/* 69 * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and 70 * PC-AT machines wire the slave PIC to pin 2 on the master PIC. 71 */ 72#ifdef PC98 73#define ICU_SLAVEID 7 74#else 75#define ICU_SLAVEID 2 76#endif 77 78/* 79 * Determine the base master and slave modes not including auto EOI support. 80 * All machines that FreeBSD supports use 8086 mode. 81 */ 82#ifdef PC98 83/* 84 * PC-98 machines do not support auto EOI on the second PIC. Also, it 85 * seems that PC-98 machine PICs use buffered mode, and the master PIC 86 * uses special fully nested mode. 87 */ 88#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 89#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 90#else 91#define BASE_MASTER_MODE ICW4_8086 92#define BASE_SLAVE_MODE ICW4_8086 93#endif 94 95/* Enable automatic EOI if requested. */ 96#ifdef AUTO_EOI_1 97#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 98#else 99#define MASTER_MODE BASE_MASTER_MODE 100#endif 101#ifdef AUTO_EOI_2 102#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 103#else 104#define SLAVE_MODE BASE_SLAVE_MODE 105#endif 106 107#define IRQ_MASK(irq) (1 << (irq)) 108#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 109 110#define NUM_ISA_IRQS 16 111 112static void atpic_init(void *dummy); 113 114unsigned int imen; /* XXX */ 115#ifndef PC98 116static int using_elcr; 117#endif 118 119inthand_t 120 IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 121 IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 122 IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 123 IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 124 IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 125 IDTVEC(atpic_intr15); 126 127#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 128 129#define ATPIC(io, base, eoi, imenptr) \ 130 { { atpic_enable_source, atpic_disable_source, (eoi), \ 131 atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 132 atpic_resume, atpic_config_intr }, (io), (base), \ 133 IDT_IO_INTS + (base), (imenptr) } 134 135#define INTSRC(irq) \ 136 { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 137 (irq) % 8 } 138 139struct atpic { 140 struct pic at_pic; 141 int at_ioaddr; 142 int at_irqbase; 143 uint8_t at_intbase; 144 uint8_t *at_imen; 145}; 146 147struct atpic_intsrc { 148 struct intsrc at_intsrc; 149 inthand_t *at_intr; 150 int at_irq; /* Relative to PIC base. */ 151 enum intr_trigger at_trigger; 152 u_long at_count; 153 u_long at_straycount; 154}; 155 156static void atpic_enable_source(struct intsrc *isrc); 157static void atpic_disable_source(struct intsrc *isrc); 158static void atpic_eoi_master(struct intsrc *isrc); 159static void atpic_eoi_slave(struct intsrc *isrc); 160static void atpic_enable_intr(struct intsrc *isrc); 161static int atpic_vector(struct intsrc *isrc); 162static void atpic_resume(struct intsrc *isrc); 163static int atpic_source_pending(struct intsrc *isrc); 164static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 165 enum intr_polarity pol); 166static void i8259_init(struct atpic *pic, int slave); 167 168static struct atpic atpics[] = { 169 ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 170 ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 171}; 172 173static struct atpic_intsrc atintrs[] = { 174 INTSRC(0), 175 INTSRC(1), 176 INTSRC(2), 177 INTSRC(3), 178 INTSRC(4), 179 INTSRC(5), 180 INTSRC(6), 181 INTSRC(7), 182 INTSRC(8), 183 INTSRC(9), 184 INTSRC(10), 185 INTSRC(11), 186 INTSRC(12), 187 INTSRC(13), 188 INTSRC(14), 189 INTSRC(15), 190}; 191 192CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 193 194static void 195atpic_enable_source(struct intsrc *isrc) 196{ 197 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 198 struct atpic *ap = (struct atpic *)isrc->is_pic; 199 200 mtx_lock_spin(&icu_lock); 201 if (*ap->at_imen & IMEN_MASK(ai)) { 202 *ap->at_imen &= ~IMEN_MASK(ai); 203 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 204 } 205 mtx_unlock_spin(&icu_lock); 206} 207 208static void 209atpic_disable_source(struct intsrc *isrc) 210{ 211 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 212 struct atpic *ap = (struct atpic *)isrc->is_pic; 213 214 if (ai->at_trigger == INTR_TRIGGER_EDGE) 215 return; 216 mtx_lock_spin(&icu_lock); 217 *ap->at_imen |= IMEN_MASK(ai); 218 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 219 mtx_unlock_spin(&icu_lock); 220} 221 222static void 223atpic_eoi_master(struct intsrc *isrc) 224{ 225 226 KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 227 ("%s: mismatched pic", __func__)); 228#ifndef AUTO_EOI_1 229 mtx_lock_spin(&icu_lock); 230 outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 231 mtx_unlock_spin(&icu_lock); 232#endif 233} 234 235/* 236 * The data sheet says no auto-EOI on slave, but it sometimes works. 237 * So, if AUTO_EOI_2 is enabled, we use it. 238 */ 239static void 240atpic_eoi_slave(struct intsrc *isrc) 241{ 242 243 KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 244 ("%s: mismatched pic", __func__)); 245#ifndef AUTO_EOI_2 246 mtx_lock_spin(&icu_lock); 247 outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 248#ifndef AUTO_EOI_1 249 outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 250#endif 251 mtx_unlock_spin(&icu_lock); 252#endif 253} 254 255static void 256atpic_enable_intr(struct intsrc *isrc) 257{ 258} 259 260static int 261atpic_vector(struct intsrc *isrc) 262{ 263 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 264 struct atpic *ap = (struct atpic *)isrc->is_pic; 265 266 return (IRQ(ap, ai)); 267} 268 269static int 270atpic_source_pending(struct intsrc *isrc) 271{ 272 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 273 struct atpic *ap = (struct atpic *)isrc->is_pic; 274 275 return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 276} 277 278static void 279atpic_resume(struct intsrc *isrc) 280{ 281 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 282 struct atpic *ap = (struct atpic *)isrc->is_pic; 283 284 if (ai->at_irq == 0) { 285 i8259_init(ap, ap == &atpics[SLAVE]); 286#ifndef PC98 287 if (ap == &atpics[SLAVE] && using_elcr) 288 elcr_resume(); 289#endif 290 } 291} 292 293static int 294atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 295 enum intr_polarity pol) 296{ 297 struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 298 u_int vector; 299 300 /* Map conforming values to edge/hi and sanity check the values. */ 301 if (trig == INTR_TRIGGER_CONFORM) 302 trig = INTR_TRIGGER_EDGE; 303 if (pol == INTR_POLARITY_CONFORM) 304 pol = INTR_POLARITY_HIGH; 305 vector = atpic_vector(isrc); 306 if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 307 (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 308 printf( 309 "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 310 vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 311 pol == INTR_POLARITY_HIGH ? "high" : "low"); 312 return (EINVAL); 313 } 314 315 /* If there is no change, just return. */ 316 if (ai->at_trigger == trig) 317 return (0); 318 319#ifdef PC98 320 if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 321 trig == INTR_TRIGGER_LEVEL) { 322 if (bootverbose) 323 printf( 324 "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 325 vector); 326 return (EINVAL); 327 } 328 return (ENXIO); 329#else 330 /* 331 * Certain IRQs can never be level/lo, so don't try to set them 332 * that way if asked. At least some ELCR registers ignore setting 333 * these bits as well. 334 */ 335 if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 336 trig == INTR_TRIGGER_LEVEL) { 337 if (bootverbose) 338 printf( 339 "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 340 vector); 341 return (EINVAL); 342 } 343 if (!using_elcr) { 344 if (bootverbose) 345 printf("atpic: No ELCR to configure IRQ%u as %s\n", 346 vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 347 "level/low"); 348 return (ENXIO); 349 } 350 if (bootverbose) 351 printf("atpic: Programming IRQ%u as %s\n", vector, 352 trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 353 mtx_lock_spin(&icu_lock); 354 elcr_write_trigger(atpic_vector(isrc), trig); 355 ai->at_trigger = trig; 356 mtx_unlock_spin(&icu_lock); 357 return (0); 358#endif /* PC98 */ 359} 360 361static void 362i8259_init(struct atpic *pic, int slave) 363{ 364 int imr_addr; 365 366 /* Reset the PIC and program with next four bytes. */ 367 mtx_lock_spin(&icu_lock); 368#ifdef DEV_MCA 369 /* MCA uses level triggered interrupts. */ 370 if (MCA_system) 371 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 372 else 373#endif 374 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 375 imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 376 377 /* Start vector. */ 378 outb(imr_addr, pic->at_intbase); 379 380 /* 381 * Setup slave links. For the master pic, indicate what line 382 * the slave is configured on. For the slave indicate 383 * which line on the master we are connected to. 384 */ 385 if (slave) 386 outb(imr_addr, ICU_SLAVEID); 387 else 388 outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 389 390 /* Set mode. */ 391 if (slave) 392 outb(imr_addr, SLAVE_MODE); 393 else 394 outb(imr_addr, MASTER_MODE); 395 396 /* Set interrupt enable mask. */ 397 outb(imr_addr, *pic->at_imen); 398 399 /* Reset is finished, default to IRR on read. */ 400 outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 401 402#ifndef PC98 403 /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 404 if (!slave) 405 outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 406#endif 407 mtx_unlock_spin(&icu_lock); 408} 409 410void 411atpic_startup(void) 412{ 413 struct atpic_intsrc *ai; 414 int i; 415 416 /* Start off with all interrupts disabled. */ 417 imen = 0xffff; 418 i8259_init(&atpics[MASTER], 0); 419 i8259_init(&atpics[SLAVE], 1); 420 atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 421 422 /* Install low-level interrupt handlers for all of our IRQs. */ 423 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 424 if (i == ICU_SLAVEID) 425 continue; 426 ai->at_intsrc.is_count = &ai->at_count; 427 ai->at_intsrc.is_straycount = &ai->at_straycount; 428 setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 429 ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 430 GSEL(GCODE_SEL, SEL_KPL)); 431 } 432 433#ifdef DEV_MCA 434 /* For MCA systems, all interrupts are level triggered. */ 435 if (MCA_system) 436 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 437 ai->at_trigger = INTR_TRIGGER_LEVEL; 438 else 439#endif 440 441#ifdef PC98 442 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 443 switch (i) { 444 case 0: 445 case 1: 446 case 7: 447 case 8: 448 ai->at_trigger = INTR_TRIGGER_EDGE; 449 break; 450 default: 451 ai->at_trigger = INTR_TRIGGER_LEVEL; 452 break; 453 } 454#else 455 /* 456 * Look for an ELCR. If we find one, update the trigger modes. 457 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 458 * edge triggered and that everything else is level triggered. 459 * We only use the trigger information to reprogram the ELCR if 460 * we have one and as an optimization to avoid masking edge 461 * triggered interrupts. For the case that we don't have an ELCR, 462 * it doesn't hurt to mask an edge triggered interrupt, so we 463 * assume level trigger for any interrupt that we aren't sure is 464 * edge triggered. 465 */ 466 if (elcr_probe() == 0) { 467 using_elcr = 1; 468 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 469 ai->at_trigger = elcr_read_trigger(i); 470 } else { 471 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 472 switch (i) { 473 case 0: 474 case 1: 475 case 2: 476 case 8: 477 case 13: 478 ai->at_trigger = INTR_TRIGGER_EDGE; 479 break; 480 default: 481 ai->at_trigger = INTR_TRIGGER_LEVEL; 482 break; 483 } 484 } 485#endif /* PC98 */ 486} 487 488static void 489atpic_init(void *dummy __unused) 490{ 491 struct atpic_intsrc *ai; 492 int i; 493 494 /* Loop through all interrupt sources and add them. */ 495 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 496 if (i == ICU_SLAVEID) 497 continue; 498 intr_register_source(&ai->at_intsrc); 499 } 500} 501SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 502 503void 504atpic_handle_intr(struct intrframe iframe) 505{ 506 struct intsrc *isrc; 507 508 KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS, 509 ("unknown int %d\n", iframe.if_vec)); 510 isrc = &atintrs[iframe.if_vec].at_intsrc; 511 512 /* 513 * If we don't have an ithread, see if this is a spurious 514 * interrupt. 515 */ 516 if (isrc->is_ithread == NULL && 517 (iframe.if_vec == 7 || iframe.if_vec == 15)) { 518 int port, isr; 519 520 /* 521 * Read the ISR register to see if IRQ 7/15 is really 522 * pending. Reset read register back to IRR when done. 523 */ 524 port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 525 mtx_lock_spin(&icu_lock); 526 outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 527 isr = inb(port); 528 outb(port, OCW3_SEL | OCW3_RR); 529 mtx_unlock_spin(&icu_lock); 530 if ((isr & IRQ_MASK(7)) == 0) 531 return; 532 } 533 intr_execute_handlers(isrc, &iframe); 534} 535 536#ifdef DEV_ISA 537/* 538 * Bus attachment for the ISA PIC. 539 */ 540static struct isa_pnp_id atpic_ids[] = { 541 { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 542 { 0 } 543}; 544 545static int 546atpic_probe(device_t dev) 547{ 548 int result; 549 550 result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 551 if (result <= 0) 552 device_quiet(dev); 553 return (result); 554} 555 556/* 557 * We might be granted IRQ 2, as this is typically consumed by chaining 558 * between the two PIC components. If we're using the APIC, however, 559 * this may not be the case, and as such we should free the resource. 560 * (XXX untested) 561 * 562 * The generic ISA attachment code will handle allocating any other resources 563 * that we don't explicitly claim here. 564 */ 565static int 566atpic_attach(device_t dev) 567{ 568 struct resource *res; 569 int rid; 570 571 /* Try to allocate our IRQ and then free it. */ 572 rid = 0; 573 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 574 if (res != NULL) 575 bus_release_resource(dev, SYS_RES_IRQ, rid, res); 576 return (0); 577} 578 579static device_method_t atpic_methods[] = { 580 /* Device interface */ 581 DEVMETHOD(device_probe, atpic_probe), 582 DEVMETHOD(device_attach, atpic_attach), 583 DEVMETHOD(device_detach, bus_generic_detach), 584 DEVMETHOD(device_shutdown, bus_generic_shutdown), 585 DEVMETHOD(device_suspend, bus_generic_suspend), 586 DEVMETHOD(device_resume, bus_generic_resume), 587 { 0, 0 } 588}; 589 590static driver_t atpic_driver = { 591 "atpic", 592 atpic_methods, 593 1, /* no softc */ 594}; 595 596static devclass_t atpic_devclass; 597 598DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 599#ifndef PC98 600DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 601#endif 602 603/* 604 * Return a bitmap of the current interrupt requests. This is 8259-specific 605 * and is only suitable for use at probe time. 606 */ 607intrmask_t 608isa_irq_pending(void) 609{ 610 u_char irr1; 611 u_char irr2; 612 613 irr1 = inb(IO_ICU1); 614 irr2 = inb(IO_ICU2); 615 return ((irr2 << 8) | irr1); 616} 617#endif /* DEV_ISA */ 618