atpic.c revision 129009
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 129009 2004-05-06 13:48:34Z nyan $"); 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 */ 103129009Snyan#ifndef PC98 104128929Sjhbstatic int using_elcr; 105129009Snyan#endif 106121985Sjhb 107121985Sjhbinthand_t 108121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 109121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 110121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 111121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 112121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 113121985Sjhb IDTVEC(atpic_intr15); 114121985Sjhb 115121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 116121985Sjhb 117128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 118121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 119121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 120128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 121128931Sjhb IDT_IO_INTS + (base), (imenptr) } 122121985Sjhb 123121985Sjhb#define INTSRC(irq) \ 124128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 125128929Sjhb (irq) % 8 } 126121985Sjhb 127121985Sjhbstruct atpic { 128121985Sjhb struct pic at_pic; 129121985Sjhb int at_ioaddr; 130121985Sjhb int at_irqbase; 131121985Sjhb uint8_t at_intbase; 132121985Sjhb uint8_t *at_imen; 133121985Sjhb}; 134121985Sjhb 135121985Sjhbstruct atpic_intsrc { 136121985Sjhb struct intsrc at_intsrc; 137121985Sjhb inthand_t *at_intr; 138128929Sjhb int at_irq; /* Relative to PIC base. */ 139128929Sjhb enum intr_trigger at_trigger; 140122897Sjhb u_long at_count; 141122897Sjhb u_long at_straycount; 142121985Sjhb}; 143121985Sjhb 144121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 145121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 146121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 147121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 148121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 149121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 150121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 151121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 152128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 153128931Sjhb enum intr_polarity pol); 154121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 155121985Sjhb 156121985Sjhbstatic struct atpic atpics[] = { 157121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 158121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 159121985Sjhb}; 160121985Sjhb 161121985Sjhbstatic struct atpic_intsrc atintrs[] = { 162121985Sjhb INTSRC(0), 163121985Sjhb INTSRC(1), 164121985Sjhb INTSRC(2), 165121985Sjhb INTSRC(3), 166121985Sjhb INTSRC(4), 167121985Sjhb INTSRC(5), 168121985Sjhb INTSRC(6), 169121985Sjhb INTSRC(7), 170121985Sjhb INTSRC(8), 171121985Sjhb INTSRC(9), 172121985Sjhb INTSRC(10), 173121985Sjhb INTSRC(11), 174121985Sjhb INTSRC(12), 175121985Sjhb INTSRC(13), 176121985Sjhb INTSRC(14), 177121985Sjhb INTSRC(15), 178121985Sjhb}; 179121985Sjhb 180128875SjhbCTASSERT(sizeof(atintrs) / sizeof(struct atpic_intsrc) == NUM_ISA_IRQS); 181128875Sjhb 182121985Sjhbstatic void 183121985Sjhbatpic_enable_source(struct intsrc *isrc) 184121985Sjhb{ 185121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 186121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 187121985Sjhb 188121985Sjhb mtx_lock_spin(&icu_lock); 189128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 190128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 191128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 192128875Sjhb } 193121985Sjhb mtx_unlock_spin(&icu_lock); 194121985Sjhb} 195121985Sjhb 196121985Sjhbstatic void 197121985Sjhbatpic_disable_source(struct intsrc *isrc) 198121985Sjhb{ 199121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 200121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 201121985Sjhb 202128929Sjhb if (ai->at_trigger == INTR_TRIGGER_EDGE) 203128929Sjhb return; 204121985Sjhb mtx_lock_spin(&icu_lock); 205128875Sjhb *ap->at_imen |= IMEN_MASK(ai); 206121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 207121985Sjhb mtx_unlock_spin(&icu_lock); 208121985Sjhb} 209121985Sjhb 210121985Sjhbstatic void 211121985Sjhbatpic_eoi_master(struct intsrc *isrc) 212121985Sjhb{ 213121985Sjhb 214121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 215121985Sjhb ("%s: mismatched pic", __func__)); 216121985Sjhb#ifndef AUTO_EOI_1 217121985Sjhb mtx_lock_spin(&icu_lock); 218121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 219121985Sjhb mtx_unlock_spin(&icu_lock); 220121985Sjhb#endif 221121985Sjhb} 222121985Sjhb 223122572Sjhb/* 224122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works. 225122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it. 226122572Sjhb */ 227121985Sjhbstatic void 228121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 229121985Sjhb{ 230121985Sjhb 231121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 232121985Sjhb ("%s: mismatched pic", __func__)); 233121985Sjhb#ifndef AUTO_EOI_2 234121985Sjhb mtx_lock_spin(&icu_lock); 235121985Sjhb outb(atpics[SLAVE].at_ioaddr, ICU_EOI); 236121985Sjhb#ifndef AUTO_EOI_1 237121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 238121985Sjhb#endif 239121985Sjhb mtx_unlock_spin(&icu_lock); 240121985Sjhb#endif 241121985Sjhb} 242121985Sjhb 243121985Sjhbstatic void 244121985Sjhbatpic_enable_intr(struct intsrc *isrc) 245121985Sjhb{ 246121985Sjhb} 247121985Sjhb 248121985Sjhbstatic int 249121985Sjhbatpic_vector(struct intsrc *isrc) 250121985Sjhb{ 251121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 252121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 253121985Sjhb 254121985Sjhb return (IRQ(ap, ai)); 255121985Sjhb} 256121985Sjhb 257121985Sjhbstatic int 258121985Sjhbatpic_source_pending(struct intsrc *isrc) 259121985Sjhb{ 260121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 261121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 262121985Sjhb 263128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 264121985Sjhb} 265121985Sjhb 266121985Sjhbstatic void 267121985Sjhbatpic_resume(struct intsrc *isrc) 268121985Sjhb{ 269121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 270121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 271121985Sjhb 272128929Sjhb if (ai->at_irq == 0) { 273121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 274129009Snyan#ifndef PC98 275128929Sjhb if (ap == &atpics[SLAVE] && using_elcr) 276128929Sjhb elcr_resume(); 277129009Snyan#endif 278128929Sjhb } 279121985Sjhb} 280121985Sjhb 281128931Sjhbstatic int 282128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 283128931Sjhb enum intr_polarity pol) 284128931Sjhb{ 285128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 286128931Sjhb u_int vector; 287128931Sjhb 288128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 289128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 290128931Sjhb trig = INTR_TRIGGER_EDGE; 291128931Sjhb if (pol == INTR_POLARITY_CONFORM) 292128931Sjhb pol = INTR_POLARITY_HIGH; 293128931Sjhb vector = atpic_vector(isrc); 294128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 295128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 296128931Sjhb printf( 297128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 298128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 299128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 300128931Sjhb return (EINVAL); 301128931Sjhb } 302128931Sjhb 303128931Sjhb /* If there is no change, just return. */ 304128931Sjhb if (ai->at_trigger == trig) 305128931Sjhb return (0); 306128931Sjhb 307129009Snyan#ifdef PC98 308129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 309129009Snyan trig == INTR_TRIGGER_LEVEL) { 310129009Snyan if (bootverbose) 311129009Snyan printf( 312129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 313129009Snyan vector); 314129009Snyan return (EINVAL); 315129009Snyan } 316129009Snyan return (ENXIO); 317129009Snyan#else 318128931Sjhb /* 319128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 320128931Sjhb * that way if asked. At least some ELCR registers ignore setting 321128931Sjhb * these bits as well. 322128931Sjhb */ 323128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 324128931Sjhb trig == INTR_TRIGGER_LEVEL) { 325128931Sjhb if (bootverbose) 326128931Sjhb printf( 327128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 328128931Sjhb vector); 329128931Sjhb return (EINVAL); 330128931Sjhb } 331128931Sjhb if (!using_elcr) { 332128931Sjhb if (bootverbose) 333128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 334128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 335128931Sjhb "level/low"); 336128931Sjhb return (ENXIO); 337128931Sjhb } 338128931Sjhb if (bootverbose) 339128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 340128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 341128931Sjhb mtx_lock_spin(&icu_lock); 342128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 343128931Sjhb ai->at_trigger = trig; 344128931Sjhb mtx_unlock_spin(&icu_lock); 345128931Sjhb return (0); 346129009Snyan#endif /* PC98 */ 347128931Sjhb} 348128931Sjhb 349121985Sjhbstatic void 350121985Sjhbi8259_init(struct atpic *pic, int slave) 351121985Sjhb{ 352121985Sjhb int imr_addr; 353121985Sjhb 354121985Sjhb /* Reset the PIC and program with next four bytes. */ 355121985Sjhb mtx_lock_spin(&icu_lock); 356121985Sjhb#ifdef DEV_MCA 357122692Sjhb /* MCA uses level triggered interrupts. */ 358121985Sjhb if (MCA_system) 359122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 360121985Sjhb else 361121985Sjhb#endif 362122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 363121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 364121985Sjhb 365121985Sjhb /* Start vector. */ 366121985Sjhb outb(imr_addr, pic->at_intbase); 367121985Sjhb 368121985Sjhb /* 369121985Sjhb * Setup slave links. For the master pic, indicate what line 370121985Sjhb * the slave is configured on. For the slave indicate 371121985Sjhb * which line on the master we are connected to. 372121985Sjhb */ 373121985Sjhb if (slave) 374121985Sjhb outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ 375121985Sjhb else 376121985Sjhb outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ 377121985Sjhb 378121985Sjhb /* Set mode. */ 379121985Sjhb if (slave) 380121985Sjhb outb(imr_addr, SLAVE_MODE); 381121985Sjhb else 382121985Sjhb outb(imr_addr, MASTER_MODE); 383121985Sjhb 384121985Sjhb /* Set interrupt enable mask. */ 385121985Sjhb outb(imr_addr, *pic->at_imen); 386121985Sjhb 387121985Sjhb /* Reset is finished, default to IRR on read. */ 388122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 389121985Sjhb 390121985Sjhb#ifndef PC98 391122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 392121985Sjhb if (!slave) 393122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 394121985Sjhb#endif 395121985Sjhb mtx_unlock_spin(&icu_lock); 396121985Sjhb} 397121985Sjhb 398121985Sjhbvoid 399121985Sjhbatpic_startup(void) 400121985Sjhb{ 401122897Sjhb struct atpic_intsrc *ai; 402122897Sjhb int i; 403121985Sjhb 404121985Sjhb /* Start off with all interrupts disabled. */ 405121985Sjhb imen = 0xffff; 406121985Sjhb i8259_init(&atpics[MASTER], 0); 407121985Sjhb i8259_init(&atpics[SLAVE], 1); 408121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 409122897Sjhb 410122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 411128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 412122897Sjhb if (i == ICU_SLAVEID) 413122897Sjhb continue; 414122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 415122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 416122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 417122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 418122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 419122897Sjhb } 420128929Sjhb 421128929Sjhb#ifdef DEV_MCA 422128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 423128929Sjhb if (MCA_system) 424128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 425128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 426128929Sjhb else 427128929Sjhb#endif 428128929Sjhb 429129009Snyan#ifdef PC98 430129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 431129009Snyan switch (i) { 432129009Snyan case 0: 433129009Snyan case 1: 434129009Snyan case 7: 435129009Snyan case 8: 436129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 437129009Snyan break; 438129009Snyan default: 439129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 440129009Snyan break; 441129009Snyan } 442129009Snyan#else 443128929Sjhb /* 444128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 445128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 446128929Sjhb * edge triggered and that everything else is level triggered. 447128929Sjhb * We only use the trigger information to reprogram the ELCR if 448128929Sjhb * we have one and as an optimization to avoid masking edge 449128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 450128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 451128929Sjhb * that is why we assume level trigger for any interrupt that we 452128929Sjhb * aren't sure is edge triggered. 453128929Sjhb */ 454128929Sjhb if (elcr_probe() == 0) { 455128929Sjhb using_elcr = 1; 456128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 457128929Sjhb ai->at_trigger = elcr_read_trigger(i); 458128929Sjhb } else { 459128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 460128929Sjhb switch (i) { 461128929Sjhb case 0: 462128929Sjhb case 1: 463128929Sjhb case 2: 464128929Sjhb case 8: 465128929Sjhb case 13: 466128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 467128929Sjhb break; 468128929Sjhb default: 469128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 470128929Sjhb break; 471128929Sjhb } 472128929Sjhb } 473129009Snyan#endif /* PC98 */ 474121985Sjhb} 475121985Sjhb 476121985Sjhbstatic void 477121985Sjhbatpic_init(void *dummy __unused) 478121985Sjhb{ 479128875Sjhb struct atpic_intsrc *ai; 480121985Sjhb int i; 481121985Sjhb 482121985Sjhb /* Loop through all interrupt sources and add them. */ 483128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 484121985Sjhb if (i == ICU_SLAVEID) 485121985Sjhb continue; 486128875Sjhb intr_register_source(&ai->at_intsrc); 487121985Sjhb } 488121985Sjhb} 489121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 490121985Sjhb 491121985Sjhbvoid 492122572Sjhbatpic_handle_intr(struct intrframe iframe) 493121985Sjhb{ 494121985Sjhb struct intsrc *isrc; 495121985Sjhb 496128438Sobrien KASSERT((u_int)iframe.if_vec < ICU_LEN, 497121985Sjhb ("unknown int %d\n", iframe.if_vec)); 498121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 499122898Sjhb 500122898Sjhb /* 501122898Sjhb * If we don't have an ithread, see if this is a spurious 502122898Sjhb * interrupt. 503122898Sjhb */ 504122898Sjhb if (isrc->is_ithread == NULL && 505122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 506122898Sjhb int port, isr; 507122898Sjhb 508122898Sjhb /* 509122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 510122898Sjhb * pending. Reset read register back to IRR when done. 511122898Sjhb */ 512122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 513122898Sjhb mtx_lock_spin(&icu_lock); 514122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 515122898Sjhb isr = inb(port); 516122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 517122898Sjhb mtx_unlock_spin(&icu_lock); 518122898Sjhb if ((isr & IRQ7) == 0) 519122898Sjhb return; 520122898Sjhb } 521121985Sjhb intr_execute_handlers(isrc, &iframe); 522121985Sjhb} 523121985Sjhb 524121985Sjhb#ifdef DEV_ISA 525121985Sjhb/* 526121985Sjhb * Bus attachment for the ISA PIC. 527121985Sjhb */ 528121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 529121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 530121985Sjhb { 0 } 531121985Sjhb}; 532121985Sjhb 533121985Sjhbstatic int 534121985Sjhbatpic_probe(device_t dev) 535121985Sjhb{ 536121985Sjhb int result; 537121985Sjhb 538121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 539121985Sjhb if (result <= 0) 540121985Sjhb device_quiet(dev); 541121985Sjhb return (result); 542121985Sjhb} 543121985Sjhb 544121985Sjhb/* 545121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 546121985Sjhb * between the two PIC components. If we're using the APIC, however, 547121985Sjhb * this may not be the case, and as such we should free the resource. 548121985Sjhb * (XXX untested) 549121985Sjhb * 550121985Sjhb * The generic ISA attachment code will handle allocating any other resources 551121985Sjhb * that we don't explicitly claim here. 552121985Sjhb */ 553121985Sjhbstatic int 554121985Sjhbatpic_attach(device_t dev) 555121985Sjhb{ 556121985Sjhb struct resource *res; 557121985Sjhb int rid; 558121985Sjhb 559121985Sjhb /* Try to allocate our IRQ and then free it. */ 560121985Sjhb rid = 0; 561127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 562121985Sjhb if (res != NULL) 563121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 564121985Sjhb return (0); 565121985Sjhb} 566121985Sjhb 567121985Sjhbstatic device_method_t atpic_methods[] = { 568121985Sjhb /* Device interface */ 569121985Sjhb DEVMETHOD(device_probe, atpic_probe), 570121985Sjhb DEVMETHOD(device_attach, atpic_attach), 571121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 572121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 573121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 574121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 575121985Sjhb { 0, 0 } 576121985Sjhb}; 577121985Sjhb 578121985Sjhbstatic driver_t atpic_driver = { 579121985Sjhb "atpic", 580121985Sjhb atpic_methods, 581121985Sjhb 1, /* no softc */ 582121985Sjhb}; 583121985Sjhb 584121985Sjhbstatic devclass_t atpic_devclass; 585121985Sjhb 586121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 587122051Snyan#ifndef PC98 588121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 589122051Snyan#endif 590121985Sjhb 591121985Sjhb/* 592121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 593121985Sjhb * and is only suitable for use at probe time. 594121985Sjhb */ 595121985Sjhbintrmask_t 596121985Sjhbisa_irq_pending(void) 597121985Sjhb{ 598121985Sjhb u_char irr1; 599121985Sjhb u_char irr2; 600121985Sjhb 601121985Sjhb irr1 = inb(IO_ICU1); 602121985Sjhb irr2 = inb(IO_ICU2); 603121985Sjhb return ((irr2 << 8) | irr1); 604121985Sjhb} 605121985Sjhb#endif /* DEV_ISA */ 606