atpic.c revision 128931
1121985Sjhb/*- 2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121985Sjhb * All rights reserved. 4121985Sjhb * 5121985Sjhb * Redistribution and use in source and binary forms, with or without 6121985Sjhb * modification, are permitted provided that the following conditions 7121985Sjhb * are met: 8121985Sjhb * 1. Redistributions of source code must retain the above copyright 9121985Sjhb * notice, this list of conditions and the following disclaimer. 10121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121985Sjhb * notice, this list of conditions and the following disclaimer in the 12121985Sjhb * documentation and/or other materials provided with the distribution. 13121985Sjhb * 3. Neither the name of the author nor the names of any co-contributors 14121985Sjhb * may be used to endorse or promote products derived from this software 15121985Sjhb * without specific prior written permission. 16121985Sjhb * 17121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121985Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121985Sjhb * SUCH DAMAGE. 28121985Sjhb */ 29121985Sjhb 30121985Sjhb/* 31121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 32121985Sjhb */ 33121985Sjhb 34121985Sjhb#include <sys/cdefs.h> 35121985Sjhb__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 128931 2004-05-04 21:02:56Z jhb $"); 36121985Sjhb 37121985Sjhb#include "opt_auto_eoi.h" 38121985Sjhb#include "opt_isa.h" 39121985Sjhb 40121985Sjhb#include <sys/param.h> 41121985Sjhb#include <sys/systm.h> 42121985Sjhb#include <sys/bus.h> 43121985Sjhb#include <sys/interrupt.h> 44121985Sjhb#include <sys/kernel.h> 45121985Sjhb#include <sys/lock.h> 46121985Sjhb#include <sys/mutex.h> 47121985Sjhb 48121985Sjhb#include <machine/cpufunc.h> 49121985Sjhb#include <machine/frame.h> 50121985Sjhb#include <machine/intr_machdep.h> 51121985Sjhb#include <machine/md_var.h> 52121985Sjhb#include <machine/resource.h> 53121985Sjhb#include <machine/segments.h> 54121985Sjhb 55124188Sjhb#include <dev/ic/i8259.h> 56121985Sjhb#include <i386/isa/icu.h> 57122051Snyan#ifdef PC98 58122051Snyan#include <pc98/pc98/pc98.h> 59122051Snyan#else 60121985Sjhb#include <i386/isa/isa.h> 61122051Snyan#endif 62121985Sjhb#include <isa/isavar.h> 63121985Sjhb 64121985Sjhb#define MASTER 0 65121985Sjhb#define SLAVE 1 66121985Sjhb 67124188Sjhb/* 68124188Sjhb * Determine the base master and slave modes not including auto EOI support. 69124188Sjhb * All machines that FreeBSD supports use 8086 mode. 70124188Sjhb */ 71121985Sjhb#ifdef PC98 72124188Sjhb/* 73124188Sjhb * PC-98 machines do not support auto EOI on the second PIC. Also, it 74124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC 75124188Sjhb * uses special fully nested mode. 76124188Sjhb */ 77124188Sjhb#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 78124188Sjhb#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 79121985Sjhb#else 80124188Sjhb#define BASE_MASTER_MODE ICW4_8086 81124188Sjhb#define BASE_SLAVE_MODE ICW4_8086 82121985Sjhb#endif 83124188Sjhb 84124188Sjhb/* Enable automatic EOI if requested. */ 85121985Sjhb#ifdef AUTO_EOI_1 86124188Sjhb#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 87121985Sjhb#else 88124188Sjhb#define MASTER_MODE BASE_MASTER_MODE 89121985Sjhb#endif 90121985Sjhb#ifdef AUTO_EOI_2 91124188Sjhb#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 92121985Sjhb#else 93124188Sjhb#define SLAVE_MODE BASE_SLAVE_MODE 94121985Sjhb#endif 95121985Sjhb 96128875Sjhb#define IMEN_MASK(ai) (1 << (ai)->at_irq) 97128875Sjhb 98128875Sjhb#define NUM_ISA_IRQS 16 99128875Sjhb 100121985Sjhbstatic void atpic_init(void *dummy); 101121985Sjhb 102121985Sjhbunsigned int imen; /* XXX */ 103128929Sjhbstatic int using_elcr; 104121985Sjhb 105121985Sjhbinthand_t 106121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 107121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 108121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 109121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 110121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 111121985Sjhb IDTVEC(atpic_intr15); 112121985Sjhb 113121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 114121985Sjhb 115128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 116121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 117121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 118128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 119128931Sjhb IDT_IO_INTS + (base), (imenptr) } 120121985Sjhb 121121985Sjhb#define INTSRC(irq) \ 122128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 123128929Sjhb (irq) % 8 } 124121985Sjhb 125121985Sjhbstruct atpic { 126121985Sjhb struct pic at_pic; 127121985Sjhb int at_ioaddr; 128121985Sjhb int at_irqbase; 129121985Sjhb uint8_t at_intbase; 130121985Sjhb uint8_t *at_imen; 131121985Sjhb}; 132121985Sjhb 133121985Sjhbstruct atpic_intsrc { 134121985Sjhb struct intsrc at_intsrc; 135121985Sjhb inthand_t *at_intr; 136128929Sjhb int at_irq; /* Relative to PIC base. */ 137128929Sjhb enum intr_trigger at_trigger; 138122897Sjhb u_long at_count; 139122897Sjhb u_long at_straycount; 140121985Sjhb}; 141121985Sjhb 142121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 143121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 144121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 145121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 146121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 147121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 148121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 149121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 150128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 151128931Sjhb enum intr_polarity pol); 152121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 153121985Sjhb 154121985Sjhbstatic struct atpic atpics[] = { 155121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 156121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 157121985Sjhb}; 158121985Sjhb 159121985Sjhbstatic struct atpic_intsrc atintrs[] = { 160121985Sjhb INTSRC(0), 161121985Sjhb INTSRC(1), 162121985Sjhb INTSRC(2), 163121985Sjhb INTSRC(3), 164121985Sjhb INTSRC(4), 165121985Sjhb INTSRC(5), 166121985Sjhb INTSRC(6), 167121985Sjhb INTSRC(7), 168121985Sjhb INTSRC(8), 169121985Sjhb INTSRC(9), 170121985Sjhb INTSRC(10), 171121985Sjhb INTSRC(11), 172121985Sjhb INTSRC(12), 173121985Sjhb INTSRC(13), 174121985Sjhb INTSRC(14), 175121985Sjhb INTSRC(15), 176121985Sjhb}; 177121985Sjhb 178128875SjhbCTASSERT(sizeof(atintrs) / sizeof(struct atpic_intsrc) == NUM_ISA_IRQS); 179128875Sjhb 180121985Sjhbstatic void 181121985Sjhbatpic_enable_source(struct intsrc *isrc) 182121985Sjhb{ 183121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 184121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 185121985Sjhb 186121985Sjhb mtx_lock_spin(&icu_lock); 187128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 188128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 189128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 190128875Sjhb } 191121985Sjhb mtx_unlock_spin(&icu_lock); 192121985Sjhb} 193121985Sjhb 194121985Sjhbstatic void 195121985Sjhbatpic_disable_source(struct intsrc *isrc) 196121985Sjhb{ 197121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 198121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 199121985Sjhb 200128929Sjhb if (ai->at_trigger == INTR_TRIGGER_EDGE) 201128929Sjhb return; 202121985Sjhb mtx_lock_spin(&icu_lock); 203128875Sjhb *ap->at_imen |= IMEN_MASK(ai); 204121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 205121985Sjhb mtx_unlock_spin(&icu_lock); 206121985Sjhb} 207121985Sjhb 208121985Sjhbstatic void 209121985Sjhbatpic_eoi_master(struct intsrc *isrc) 210121985Sjhb{ 211121985Sjhb 212121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 213121985Sjhb ("%s: mismatched pic", __func__)); 214121985Sjhb#ifndef AUTO_EOI_1 215121985Sjhb mtx_lock_spin(&icu_lock); 216121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 217121985Sjhb mtx_unlock_spin(&icu_lock); 218121985Sjhb#endif 219121985Sjhb} 220121985Sjhb 221122572Sjhb/* 222122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works. 223122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it. 224122572Sjhb */ 225121985Sjhbstatic void 226121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 227121985Sjhb{ 228121985Sjhb 229121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 230121985Sjhb ("%s: mismatched pic", __func__)); 231121985Sjhb#ifndef AUTO_EOI_2 232121985Sjhb mtx_lock_spin(&icu_lock); 233121985Sjhb outb(atpics[SLAVE].at_ioaddr, ICU_EOI); 234121985Sjhb#ifndef AUTO_EOI_1 235121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 236121985Sjhb#endif 237121985Sjhb mtx_unlock_spin(&icu_lock); 238121985Sjhb#endif 239121985Sjhb} 240121985Sjhb 241121985Sjhbstatic void 242121985Sjhbatpic_enable_intr(struct intsrc *isrc) 243121985Sjhb{ 244121985Sjhb} 245121985Sjhb 246121985Sjhbstatic int 247121985Sjhbatpic_vector(struct intsrc *isrc) 248121985Sjhb{ 249121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 250121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 251121985Sjhb 252121985Sjhb return (IRQ(ap, ai)); 253121985Sjhb} 254121985Sjhb 255121985Sjhbstatic int 256121985Sjhbatpic_source_pending(struct intsrc *isrc) 257121985Sjhb{ 258121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 259121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 260121985Sjhb 261128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 262121985Sjhb} 263121985Sjhb 264121985Sjhbstatic void 265121985Sjhbatpic_resume(struct intsrc *isrc) 266121985Sjhb{ 267121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 268121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 269121985Sjhb 270128929Sjhb if (ai->at_irq == 0) { 271121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 272128929Sjhb if (ap == &atpics[SLAVE] && using_elcr) 273128929Sjhb elcr_resume(); 274128929Sjhb } 275121985Sjhb} 276121985Sjhb 277128931Sjhbstatic int 278128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 279128931Sjhb enum intr_polarity pol) 280128931Sjhb{ 281128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 282128931Sjhb u_int vector; 283128931Sjhb 284128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 285128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 286128931Sjhb trig = INTR_TRIGGER_EDGE; 287128931Sjhb if (pol == INTR_POLARITY_CONFORM) 288128931Sjhb pol = INTR_POLARITY_HIGH; 289128931Sjhb vector = atpic_vector(isrc); 290128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 291128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 292128931Sjhb printf( 293128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 294128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 295128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 296128931Sjhb return (EINVAL); 297128931Sjhb } 298128931Sjhb 299128931Sjhb /* If there is no change, just return. */ 300128931Sjhb if (ai->at_trigger == trig) 301128931Sjhb return (0); 302128931Sjhb 303128931Sjhb /* 304128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 305128931Sjhb * that way if asked. At least some ELCR registers ignore setting 306128931Sjhb * these bits as well. 307128931Sjhb */ 308128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 309128931Sjhb trig == INTR_TRIGGER_LEVEL) { 310128931Sjhb if (bootverbose) 311128931Sjhb printf( 312128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 313128931Sjhb vector); 314128931Sjhb return (EINVAL); 315128931Sjhb } 316128931Sjhb if (!using_elcr) { 317128931Sjhb if (bootverbose) 318128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 319128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 320128931Sjhb "level/low"); 321128931Sjhb return (ENXIO); 322128931Sjhb } 323128931Sjhb if (bootverbose) 324128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 325128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 326128931Sjhb mtx_lock_spin(&icu_lock); 327128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 328128931Sjhb ai->at_trigger = trig; 329128931Sjhb mtx_unlock_spin(&icu_lock); 330128931Sjhb return (0); 331128931Sjhb} 332128931Sjhb 333121985Sjhbstatic void 334121985Sjhbi8259_init(struct atpic *pic, int slave) 335121985Sjhb{ 336121985Sjhb int imr_addr; 337121985Sjhb 338121985Sjhb /* Reset the PIC and program with next four bytes. */ 339121985Sjhb mtx_lock_spin(&icu_lock); 340121985Sjhb#ifdef DEV_MCA 341122692Sjhb /* MCA uses level triggered interrupts. */ 342121985Sjhb if (MCA_system) 343122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 344121985Sjhb else 345121985Sjhb#endif 346122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 347121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 348121985Sjhb 349121985Sjhb /* Start vector. */ 350121985Sjhb outb(imr_addr, pic->at_intbase); 351121985Sjhb 352121985Sjhb /* 353121985Sjhb * Setup slave links. For the master pic, indicate what line 354121985Sjhb * the slave is configured on. For the slave indicate 355121985Sjhb * which line on the master we are connected to. 356121985Sjhb */ 357121985Sjhb if (slave) 358121985Sjhb outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ 359121985Sjhb else 360121985Sjhb outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ 361121985Sjhb 362121985Sjhb /* Set mode. */ 363121985Sjhb if (slave) 364121985Sjhb outb(imr_addr, SLAVE_MODE); 365121985Sjhb else 366121985Sjhb outb(imr_addr, MASTER_MODE); 367121985Sjhb 368121985Sjhb /* Set interrupt enable mask. */ 369121985Sjhb outb(imr_addr, *pic->at_imen); 370121985Sjhb 371121985Sjhb /* Reset is finished, default to IRR on read. */ 372122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 373121985Sjhb 374121985Sjhb#ifndef PC98 375122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 376121985Sjhb if (!slave) 377122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 378121985Sjhb#endif 379121985Sjhb mtx_unlock_spin(&icu_lock); 380121985Sjhb} 381121985Sjhb 382121985Sjhbvoid 383121985Sjhbatpic_startup(void) 384121985Sjhb{ 385122897Sjhb struct atpic_intsrc *ai; 386122897Sjhb int i; 387121985Sjhb 388121985Sjhb /* Start off with all interrupts disabled. */ 389121985Sjhb imen = 0xffff; 390121985Sjhb i8259_init(&atpics[MASTER], 0); 391121985Sjhb i8259_init(&atpics[SLAVE], 1); 392121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 393122897Sjhb 394122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 395128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 396122897Sjhb if (i == ICU_SLAVEID) 397122897Sjhb continue; 398122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 399122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 400122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 401122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 402122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 403122897Sjhb } 404128929Sjhb 405128929Sjhb#ifdef DEV_MCA 406128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 407128929Sjhb if (MCA_system) 408128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 409128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 410128929Sjhb else 411128929Sjhb#endif 412128929Sjhb 413128929Sjhb /* 414128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 415128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 416128929Sjhb * edge triggered and that everything else is level triggered. 417128929Sjhb * We only use the trigger information to reprogram the ELCR if 418128929Sjhb * we have one and as an optimization to avoid masking edge 419128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 420128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 421128929Sjhb * that is why we assume level trigger for any interrupt that we 422128929Sjhb * aren't sure is edge triggered. 423128929Sjhb */ 424128929Sjhb if (elcr_probe() == 0) { 425128929Sjhb using_elcr = 1; 426128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 427128929Sjhb ai->at_trigger = elcr_read_trigger(i); 428128929Sjhb } else { 429128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 430128929Sjhb switch (i) { 431128929Sjhb case 0: 432128929Sjhb case 1: 433128929Sjhb case 2: 434128929Sjhb case 8: 435128929Sjhb case 13: 436128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 437128929Sjhb break; 438128929Sjhb default: 439128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 440128929Sjhb break; 441128929Sjhb } 442128929Sjhb } 443121985Sjhb} 444121985Sjhb 445121985Sjhbstatic void 446121985Sjhbatpic_init(void *dummy __unused) 447121985Sjhb{ 448128875Sjhb struct atpic_intsrc *ai; 449121985Sjhb int i; 450121985Sjhb 451121985Sjhb /* Loop through all interrupt sources and add them. */ 452128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 453121985Sjhb if (i == ICU_SLAVEID) 454121985Sjhb continue; 455128875Sjhb intr_register_source(&ai->at_intsrc); 456121985Sjhb } 457121985Sjhb} 458121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 459121985Sjhb 460121985Sjhbvoid 461122572Sjhbatpic_handle_intr(struct intrframe iframe) 462121985Sjhb{ 463121985Sjhb struct intsrc *isrc; 464121985Sjhb 465128438Sobrien KASSERT((u_int)iframe.if_vec < ICU_LEN, 466121985Sjhb ("unknown int %d\n", iframe.if_vec)); 467121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 468122898Sjhb 469122898Sjhb /* 470122898Sjhb * If we don't have an ithread, see if this is a spurious 471122898Sjhb * interrupt. 472122898Sjhb */ 473122898Sjhb if (isrc->is_ithread == NULL && 474122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 475122898Sjhb int port, isr; 476122898Sjhb 477122898Sjhb /* 478122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 479122898Sjhb * pending. Reset read register back to IRR when done. 480122898Sjhb */ 481122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 482122898Sjhb mtx_lock_spin(&icu_lock); 483122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 484122898Sjhb isr = inb(port); 485122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 486122898Sjhb mtx_unlock_spin(&icu_lock); 487122898Sjhb if ((isr & IRQ7) == 0) 488122898Sjhb return; 489122898Sjhb } 490121985Sjhb intr_execute_handlers(isrc, &iframe); 491121985Sjhb} 492121985Sjhb 493121985Sjhb#ifdef DEV_ISA 494121985Sjhb/* 495121985Sjhb * Bus attachment for the ISA PIC. 496121985Sjhb */ 497121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 498121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 499121985Sjhb { 0 } 500121985Sjhb}; 501121985Sjhb 502121985Sjhbstatic int 503121985Sjhbatpic_probe(device_t dev) 504121985Sjhb{ 505121985Sjhb int result; 506121985Sjhb 507121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 508121985Sjhb if (result <= 0) 509121985Sjhb device_quiet(dev); 510121985Sjhb return (result); 511121985Sjhb} 512121985Sjhb 513121985Sjhb/* 514121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 515121985Sjhb * between the two PIC components. If we're using the APIC, however, 516121985Sjhb * this may not be the case, and as such we should free the resource. 517121985Sjhb * (XXX untested) 518121985Sjhb * 519121985Sjhb * The generic ISA attachment code will handle allocating any other resources 520121985Sjhb * that we don't explicitly claim here. 521121985Sjhb */ 522121985Sjhbstatic int 523121985Sjhbatpic_attach(device_t dev) 524121985Sjhb{ 525121985Sjhb struct resource *res; 526121985Sjhb int rid; 527121985Sjhb 528121985Sjhb /* Try to allocate our IRQ and then free it. */ 529121985Sjhb rid = 0; 530127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 531121985Sjhb if (res != NULL) 532121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 533121985Sjhb return (0); 534121985Sjhb} 535121985Sjhb 536121985Sjhbstatic device_method_t atpic_methods[] = { 537121985Sjhb /* Device interface */ 538121985Sjhb DEVMETHOD(device_probe, atpic_probe), 539121985Sjhb DEVMETHOD(device_attach, atpic_attach), 540121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 541121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 542121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 543121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 544121985Sjhb { 0, 0 } 545121985Sjhb}; 546121985Sjhb 547121985Sjhbstatic driver_t atpic_driver = { 548121985Sjhb "atpic", 549121985Sjhb atpic_methods, 550121985Sjhb 1, /* no softc */ 551121985Sjhb}; 552121985Sjhb 553121985Sjhbstatic devclass_t atpic_devclass; 554121985Sjhb 555121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 556122051Snyan#ifndef PC98 557121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 558122051Snyan#endif 559121985Sjhb 560121985Sjhb/* 561121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 562121985Sjhb * and is only suitable for use at probe time. 563121985Sjhb */ 564121985Sjhbintrmask_t 565121985Sjhbisa_irq_pending(void) 566121985Sjhb{ 567121985Sjhb u_char irr1; 568121985Sjhb u_char irr2; 569121985Sjhb 570121985Sjhb irr1 = inb(IO_ICU1); 571121985Sjhb irr2 = inb(IO_ICU2); 572121985Sjhb return ((irr2 << 8) | irr1); 573121985Sjhb} 574121985Sjhb#endif /* DEV_ISA */ 575