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