atpic.c revision 133017
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 133017 2004-08-02 15:31:10Z scottl $"); 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> 46129876Sphk#include <sys/module.h> 47121985Sjhb#include <sys/mutex.h> 48121985Sjhb 49121985Sjhb#include <machine/cpufunc.h> 50121985Sjhb#include <machine/frame.h> 51121985Sjhb#include <machine/intr_machdep.h> 52121985Sjhb#include <machine/md_var.h> 53121985Sjhb#include <machine/resource.h> 54121985Sjhb#include <machine/segments.h> 55121985Sjhb 56124188Sjhb#include <dev/ic/i8259.h> 57121985Sjhb#include <i386/isa/icu.h> 58122051Snyan#ifdef PC98 59122051Snyan#include <pc98/pc98/pc98.h> 60122051Snyan#else 61121985Sjhb#include <i386/isa/isa.h> 62122051Snyan#endif 63121985Sjhb#include <isa/isavar.h> 64121985Sjhb 65121985Sjhb#define MASTER 0 66121985Sjhb#define SLAVE 1 67121985Sjhb 68124188Sjhb/* 69129131Sjhb * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and 70129131Sjhb * PC-AT machines wire the slave PIC to pin 2 on the master PIC. 71129131Sjhb */ 72129131Sjhb#ifdef PC98 73129131Sjhb#define ICU_SLAVEID 7 74129131Sjhb#else 75129131Sjhb#define ICU_SLAVEID 2 76129131Sjhb#endif 77129131Sjhb 78129131Sjhb/* 79124188Sjhb * Determine the base master and slave modes not including auto EOI support. 80124188Sjhb * All machines that FreeBSD supports use 8086 mode. 81124188Sjhb */ 82121985Sjhb#ifdef PC98 83124188Sjhb/* 84124188Sjhb * PC-98 machines do not support auto EOI on the second PIC. Also, it 85124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC 86124188Sjhb * uses special fully nested mode. 87124188Sjhb */ 88124188Sjhb#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 89124188Sjhb#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 90121985Sjhb#else 91124188Sjhb#define BASE_MASTER_MODE ICW4_8086 92124188Sjhb#define BASE_SLAVE_MODE ICW4_8086 93121985Sjhb#endif 94124188Sjhb 95124188Sjhb/* Enable automatic EOI if requested. */ 96121985Sjhb#ifdef AUTO_EOI_1 97124188Sjhb#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 98121985Sjhb#else 99124188Sjhb#define MASTER_MODE BASE_MASTER_MODE 100121985Sjhb#endif 101121985Sjhb#ifdef AUTO_EOI_2 102124188Sjhb#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 103121985Sjhb#else 104124188Sjhb#define SLAVE_MODE BASE_SLAVE_MODE 105121985Sjhb#endif 106121985Sjhb 107129131Sjhb#define IRQ_MASK(irq) (1 << (irq)) 108129131Sjhb#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 109128875Sjhb 110128875Sjhb#define NUM_ISA_IRQS 16 111128875Sjhb 112121985Sjhbstatic void atpic_init(void *dummy); 113121985Sjhb 114121985Sjhbunsigned int imen; /* XXX */ 115129009Snyan#ifndef PC98 116128929Sjhbstatic int using_elcr; 117129009Snyan#endif 118121985Sjhb 119121985Sjhbinthand_t 120121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 121121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 122121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 123121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 124121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 125121985Sjhb IDTVEC(atpic_intr15); 126121985Sjhb 127121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 128121985Sjhb 129128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 130121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 131121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 132128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 133128931Sjhb IDT_IO_INTS + (base), (imenptr) } 134121985Sjhb 135121985Sjhb#define INTSRC(irq) \ 136128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 137128929Sjhb (irq) % 8 } 138121985Sjhb 139121985Sjhbstruct atpic { 140121985Sjhb struct pic at_pic; 141121985Sjhb int at_ioaddr; 142121985Sjhb int at_irqbase; 143121985Sjhb uint8_t at_intbase; 144121985Sjhb uint8_t *at_imen; 145121985Sjhb}; 146121985Sjhb 147121985Sjhbstruct atpic_intsrc { 148121985Sjhb struct intsrc at_intsrc; 149121985Sjhb inthand_t *at_intr; 150128929Sjhb int at_irq; /* Relative to PIC base. */ 151128929Sjhb enum intr_trigger at_trigger; 152122897Sjhb u_long at_count; 153122897Sjhb u_long at_straycount; 154121985Sjhb}; 155121985Sjhb 156121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 157133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 158121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 159121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 160121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 161121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 162121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 163121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 164128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 165128931Sjhb enum intr_polarity pol); 166121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 167121985Sjhb 168121985Sjhbstatic struct atpic atpics[] = { 169121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 170121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 171121985Sjhb}; 172121985Sjhb 173121985Sjhbstatic struct atpic_intsrc atintrs[] = { 174121985Sjhb INTSRC(0), 175121985Sjhb INTSRC(1), 176121985Sjhb INTSRC(2), 177121985Sjhb INTSRC(3), 178121985Sjhb INTSRC(4), 179121985Sjhb INTSRC(5), 180121985Sjhb INTSRC(6), 181121985Sjhb INTSRC(7), 182121985Sjhb INTSRC(8), 183121985Sjhb INTSRC(9), 184121985Sjhb INTSRC(10), 185121985Sjhb INTSRC(11), 186121985Sjhb INTSRC(12), 187121985Sjhb INTSRC(13), 188121985Sjhb INTSRC(14), 189121985Sjhb INTSRC(15), 190121985Sjhb}; 191121985Sjhb 192129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 193128875Sjhb 194133017Sscottlstatic __inline void 195133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 196133017Sscottl{ 197133017Sscottl 198133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 199133017Sscottl ("%s: mismatched pic", __func__)); 200133017Sscottl#ifndef AUTO_EOI_1 201133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 202133017Sscottl#endif 203133017Sscottl} 204133017Sscottl 205133017Sscottl/* 206133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 207133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 208133017Sscottl */ 209133017Sscottlstatic __inline void 210133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 211133017Sscottl{ 212133017Sscottl 213133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 214133017Sscottl ("%s: mismatched pic", __func__)); 215133017Sscottl#ifndef AUTO_EOI_2 216133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 217133017Sscottl#ifndef AUTO_EOI_1 218133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 219133017Sscottl#endif 220133017Sscottl#endif 221133017Sscottl} 222133017Sscottl 223121985Sjhbstatic void 224121985Sjhbatpic_enable_source(struct intsrc *isrc) 225121985Sjhb{ 226121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 227121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 228121985Sjhb 229121985Sjhb mtx_lock_spin(&icu_lock); 230128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 231128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 232128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 233128875Sjhb } 234121985Sjhb mtx_unlock_spin(&icu_lock); 235121985Sjhb} 236121985Sjhb 237121985Sjhbstatic void 238133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 239121985Sjhb{ 240121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 241121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 242121985Sjhb 243121985Sjhb mtx_lock_spin(&icu_lock); 244133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 245133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 246133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 247133017Sscottl } 248133017Sscottl 249133017Sscottl /* 250133017Sscottl * Take care to call these functions directly instead of through 251133017Sscottl * a function pointer. All of the referenced variables should 252133017Sscottl * still be hot in the cache. 253133017Sscottl */ 254133017Sscottl if (eoi == PIC_EOI) { 255133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 256133017Sscottl _atpic_eoi_master(isrc); 257133017Sscottl else 258133017Sscottl _atpic_eoi_slave(isrc); 259133017Sscottl } 260133017Sscottl 261121985Sjhb mtx_unlock_spin(&icu_lock); 262121985Sjhb} 263121985Sjhb 264121985Sjhbstatic void 265121985Sjhbatpic_eoi_master(struct intsrc *isrc) 266121985Sjhb{ 267121985Sjhb#ifndef AUTO_EOI_1 268121985Sjhb mtx_lock_spin(&icu_lock); 269133017Sscottl _atpic_eoi_master(isrc); 270121985Sjhb mtx_unlock_spin(&icu_lock); 271121985Sjhb#endif 272121985Sjhb} 273121985Sjhb 274121985Sjhbstatic void 275121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 276121985Sjhb{ 277121985Sjhb#ifndef AUTO_EOI_2 278121985Sjhb mtx_lock_spin(&icu_lock); 279133017Sscottl _atpic_eoi_slave(isrc); 280121985Sjhb mtx_unlock_spin(&icu_lock); 281121985Sjhb#endif 282121985Sjhb} 283121985Sjhb 284121985Sjhbstatic void 285121985Sjhbatpic_enable_intr(struct intsrc *isrc) 286121985Sjhb{ 287121985Sjhb} 288121985Sjhb 289121985Sjhbstatic int 290121985Sjhbatpic_vector(struct intsrc *isrc) 291121985Sjhb{ 292121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 293121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 294121985Sjhb 295121985Sjhb return (IRQ(ap, ai)); 296121985Sjhb} 297121985Sjhb 298121985Sjhbstatic int 299121985Sjhbatpic_source_pending(struct intsrc *isrc) 300121985Sjhb{ 301121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 302121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 303121985Sjhb 304128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 305121985Sjhb} 306121985Sjhb 307121985Sjhbstatic void 308121985Sjhbatpic_resume(struct intsrc *isrc) 309121985Sjhb{ 310121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 311121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 312121985Sjhb 313128929Sjhb if (ai->at_irq == 0) { 314121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 315129009Snyan#ifndef PC98 316128929Sjhb if (ap == &atpics[SLAVE] && using_elcr) 317128929Sjhb elcr_resume(); 318129009Snyan#endif 319128929Sjhb } 320121985Sjhb} 321121985Sjhb 322128931Sjhbstatic int 323128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 324128931Sjhb enum intr_polarity pol) 325128931Sjhb{ 326128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 327128931Sjhb u_int vector; 328128931Sjhb 329128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 330128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 331128931Sjhb trig = INTR_TRIGGER_EDGE; 332128931Sjhb if (pol == INTR_POLARITY_CONFORM) 333128931Sjhb pol = INTR_POLARITY_HIGH; 334128931Sjhb vector = atpic_vector(isrc); 335128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 336128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 337128931Sjhb printf( 338128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 339128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 340128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 341128931Sjhb return (EINVAL); 342128931Sjhb } 343128931Sjhb 344128931Sjhb /* If there is no change, just return. */ 345128931Sjhb if (ai->at_trigger == trig) 346128931Sjhb return (0); 347128931Sjhb 348129009Snyan#ifdef PC98 349129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 350129009Snyan trig == INTR_TRIGGER_LEVEL) { 351129009Snyan if (bootverbose) 352129009Snyan printf( 353129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 354129009Snyan vector); 355129009Snyan return (EINVAL); 356129009Snyan } 357129009Snyan return (ENXIO); 358129009Snyan#else 359128931Sjhb /* 360128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 361128931Sjhb * that way if asked. At least some ELCR registers ignore setting 362128931Sjhb * these bits as well. 363128931Sjhb */ 364128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 365128931Sjhb trig == INTR_TRIGGER_LEVEL) { 366128931Sjhb if (bootverbose) 367128931Sjhb printf( 368128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 369128931Sjhb vector); 370128931Sjhb return (EINVAL); 371128931Sjhb } 372128931Sjhb if (!using_elcr) { 373128931Sjhb if (bootverbose) 374128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 375128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 376128931Sjhb "level/low"); 377128931Sjhb return (ENXIO); 378128931Sjhb } 379128931Sjhb if (bootverbose) 380128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 381128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 382128931Sjhb mtx_lock_spin(&icu_lock); 383128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 384128931Sjhb ai->at_trigger = trig; 385128931Sjhb mtx_unlock_spin(&icu_lock); 386128931Sjhb return (0); 387129009Snyan#endif /* PC98 */ 388128931Sjhb} 389128931Sjhb 390121985Sjhbstatic void 391121985Sjhbi8259_init(struct atpic *pic, int slave) 392121985Sjhb{ 393121985Sjhb int imr_addr; 394121985Sjhb 395121985Sjhb /* Reset the PIC and program with next four bytes. */ 396121985Sjhb mtx_lock_spin(&icu_lock); 397121985Sjhb#ifdef DEV_MCA 398122692Sjhb /* MCA uses level triggered interrupts. */ 399121985Sjhb if (MCA_system) 400122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 401121985Sjhb else 402121985Sjhb#endif 403122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 404121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 405121985Sjhb 406121985Sjhb /* Start vector. */ 407121985Sjhb outb(imr_addr, pic->at_intbase); 408121985Sjhb 409121985Sjhb /* 410121985Sjhb * Setup slave links. For the master pic, indicate what line 411121985Sjhb * the slave is configured on. For the slave indicate 412121985Sjhb * which line on the master we are connected to. 413121985Sjhb */ 414121985Sjhb if (slave) 415129131Sjhb outb(imr_addr, ICU_SLAVEID); 416121985Sjhb else 417129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 418121985Sjhb 419121985Sjhb /* Set mode. */ 420121985Sjhb if (slave) 421121985Sjhb outb(imr_addr, SLAVE_MODE); 422121985Sjhb else 423121985Sjhb outb(imr_addr, MASTER_MODE); 424121985Sjhb 425121985Sjhb /* Set interrupt enable mask. */ 426121985Sjhb outb(imr_addr, *pic->at_imen); 427121985Sjhb 428121985Sjhb /* Reset is finished, default to IRR on read. */ 429122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 430121985Sjhb 431121985Sjhb#ifndef PC98 432122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 433121985Sjhb if (!slave) 434122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 435121985Sjhb#endif 436121985Sjhb mtx_unlock_spin(&icu_lock); 437121985Sjhb} 438121985Sjhb 439121985Sjhbvoid 440121985Sjhbatpic_startup(void) 441121985Sjhb{ 442122897Sjhb struct atpic_intsrc *ai; 443122897Sjhb int i; 444121985Sjhb 445121985Sjhb /* Start off with all interrupts disabled. */ 446121985Sjhb imen = 0xffff; 447121985Sjhb i8259_init(&atpics[MASTER], 0); 448121985Sjhb i8259_init(&atpics[SLAVE], 1); 449121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 450122897Sjhb 451122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 452128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 453122897Sjhb if (i == ICU_SLAVEID) 454122897Sjhb continue; 455122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 456122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 457122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 458122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 459122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 460122897Sjhb } 461128929Sjhb 462128929Sjhb#ifdef DEV_MCA 463128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 464128929Sjhb if (MCA_system) 465128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 466128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 467128929Sjhb else 468128929Sjhb#endif 469128929Sjhb 470129009Snyan#ifdef PC98 471129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 472129009Snyan switch (i) { 473129009Snyan case 0: 474129009Snyan case 1: 475129009Snyan case 7: 476129009Snyan case 8: 477129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 478129009Snyan break; 479129009Snyan default: 480129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 481129009Snyan break; 482129009Snyan } 483129009Snyan#else 484128929Sjhb /* 485128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 486128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 487128929Sjhb * edge triggered and that everything else is level triggered. 488128929Sjhb * We only use the trigger information to reprogram the ELCR if 489128929Sjhb * we have one and as an optimization to avoid masking edge 490128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 491128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 492129095Sjhb * assume level trigger for any interrupt that we aren't sure is 493129095Sjhb * edge triggered. 494128929Sjhb */ 495128929Sjhb if (elcr_probe() == 0) { 496128929Sjhb using_elcr = 1; 497128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 498128929Sjhb ai->at_trigger = elcr_read_trigger(i); 499128929Sjhb } else { 500128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 501128929Sjhb switch (i) { 502128929Sjhb case 0: 503128929Sjhb case 1: 504128929Sjhb case 2: 505128929Sjhb case 8: 506128929Sjhb case 13: 507128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 508128929Sjhb break; 509128929Sjhb default: 510128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 511128929Sjhb break; 512128929Sjhb } 513128929Sjhb } 514129009Snyan#endif /* PC98 */ 515121985Sjhb} 516121985Sjhb 517121985Sjhbstatic void 518121985Sjhbatpic_init(void *dummy __unused) 519121985Sjhb{ 520128875Sjhb struct atpic_intsrc *ai; 521121985Sjhb int i; 522121985Sjhb 523121985Sjhb /* Loop through all interrupt sources and add them. */ 524128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 525121985Sjhb if (i == ICU_SLAVEID) 526121985Sjhb continue; 527128875Sjhb intr_register_source(&ai->at_intsrc); 528121985Sjhb } 529121985Sjhb} 530121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 531121985Sjhb 532121985Sjhbvoid 533122572Sjhbatpic_handle_intr(struct intrframe iframe) 534121985Sjhb{ 535121985Sjhb struct intsrc *isrc; 536121985Sjhb 537129131Sjhb KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS, 538121985Sjhb ("unknown int %d\n", iframe.if_vec)); 539121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 540122898Sjhb 541122898Sjhb /* 542122898Sjhb * If we don't have an ithread, see if this is a spurious 543122898Sjhb * interrupt. 544122898Sjhb */ 545122898Sjhb if (isrc->is_ithread == NULL && 546122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 547122898Sjhb int port, isr; 548122898Sjhb 549122898Sjhb /* 550122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 551122898Sjhb * pending. Reset read register back to IRR when done. 552122898Sjhb */ 553122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 554122898Sjhb mtx_lock_spin(&icu_lock); 555122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 556122898Sjhb isr = inb(port); 557122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 558122898Sjhb mtx_unlock_spin(&icu_lock); 559129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 560122898Sjhb return; 561122898Sjhb } 562121985Sjhb intr_execute_handlers(isrc, &iframe); 563121985Sjhb} 564121985Sjhb 565121985Sjhb#ifdef DEV_ISA 566121985Sjhb/* 567121985Sjhb * Bus attachment for the ISA PIC. 568121985Sjhb */ 569121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 570121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 571121985Sjhb { 0 } 572121985Sjhb}; 573121985Sjhb 574121985Sjhbstatic int 575121985Sjhbatpic_probe(device_t dev) 576121985Sjhb{ 577121985Sjhb int result; 578121985Sjhb 579121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 580121985Sjhb if (result <= 0) 581121985Sjhb device_quiet(dev); 582121985Sjhb return (result); 583121985Sjhb} 584121985Sjhb 585121985Sjhb/* 586121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 587121985Sjhb * between the two PIC components. If we're using the APIC, however, 588121985Sjhb * this may not be the case, and as such we should free the resource. 589121985Sjhb * (XXX untested) 590121985Sjhb * 591121985Sjhb * The generic ISA attachment code will handle allocating any other resources 592121985Sjhb * that we don't explicitly claim here. 593121985Sjhb */ 594121985Sjhbstatic int 595121985Sjhbatpic_attach(device_t dev) 596121985Sjhb{ 597121985Sjhb struct resource *res; 598121985Sjhb int rid; 599121985Sjhb 600121985Sjhb /* Try to allocate our IRQ and then free it. */ 601121985Sjhb rid = 0; 602127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 603121985Sjhb if (res != NULL) 604121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 605121985Sjhb return (0); 606121985Sjhb} 607121985Sjhb 608121985Sjhbstatic device_method_t atpic_methods[] = { 609121985Sjhb /* Device interface */ 610121985Sjhb DEVMETHOD(device_probe, atpic_probe), 611121985Sjhb DEVMETHOD(device_attach, atpic_attach), 612121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 613121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 614121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 615121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 616121985Sjhb { 0, 0 } 617121985Sjhb}; 618121985Sjhb 619121985Sjhbstatic driver_t atpic_driver = { 620121985Sjhb "atpic", 621121985Sjhb atpic_methods, 622121985Sjhb 1, /* no softc */ 623121985Sjhb}; 624121985Sjhb 625121985Sjhbstatic devclass_t atpic_devclass; 626121985Sjhb 627121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 628122051Snyan#ifndef PC98 629121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 630122051Snyan#endif 631121985Sjhb 632121985Sjhb/* 633121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 634121985Sjhb * and is only suitable for use at probe time. 635121985Sjhb */ 636121985Sjhbintrmask_t 637121985Sjhbisa_irq_pending(void) 638121985Sjhb{ 639121985Sjhb u_char irr1; 640121985Sjhb u_char irr2; 641121985Sjhb 642121985Sjhb irr1 = inb(IO_ICU1); 643121985Sjhb irr2 = inb(IO_ICU2); 644121985Sjhb return ((irr2 << 8) | irr1); 645121985Sjhb} 646121985Sjhb#endif /* DEV_ISA */ 647