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