atpic.c revision 151658
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 151658 2005-10-25 19:48:48Z 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> 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 59146049Snyan#include <pc98/cbus/cbus.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 */ 115121985Sjhb 116121985Sjhbinthand_t 117121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 118121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 119121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 120121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 121121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 122121985Sjhb IDTVEC(atpic_intr15); 123121985Sjhb 124121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 125121985Sjhb 126128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 127121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 128121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 129128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 130128931Sjhb IDT_IO_INTS + (base), (imenptr) } 131121985Sjhb 132121985Sjhb#define INTSRC(irq) \ 133128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 134128929Sjhb (irq) % 8 } 135121985Sjhb 136121985Sjhbstruct atpic { 137121985Sjhb struct pic at_pic; 138121985Sjhb int at_ioaddr; 139121985Sjhb int at_irqbase; 140121985Sjhb uint8_t at_intbase; 141121985Sjhb uint8_t *at_imen; 142121985Sjhb}; 143121985Sjhb 144121985Sjhbstruct atpic_intsrc { 145121985Sjhb struct intsrc at_intsrc; 146121985Sjhb inthand_t *at_intr; 147128929Sjhb int at_irq; /* Relative to PIC base. */ 148128929Sjhb enum intr_trigger at_trigger; 149122897Sjhb u_long at_count; 150122897Sjhb u_long at_straycount; 151121985Sjhb}; 152121985Sjhb 153121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 154133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 155121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 156121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 157121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 158121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 159121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 160121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 161128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 162128931Sjhb enum intr_polarity pol); 163121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 164121985Sjhb 165121985Sjhbstatic struct atpic atpics[] = { 166121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 167121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 168121985Sjhb}; 169121985Sjhb 170121985Sjhbstatic struct atpic_intsrc atintrs[] = { 171121985Sjhb INTSRC(0), 172121985Sjhb INTSRC(1), 173121985Sjhb INTSRC(2), 174121985Sjhb INTSRC(3), 175121985Sjhb INTSRC(4), 176121985Sjhb INTSRC(5), 177121985Sjhb INTSRC(6), 178121985Sjhb INTSRC(7), 179121985Sjhb INTSRC(8), 180121985Sjhb INTSRC(9), 181121985Sjhb INTSRC(10), 182121985Sjhb INTSRC(11), 183121985Sjhb INTSRC(12), 184121985Sjhb INTSRC(13), 185121985Sjhb INTSRC(14), 186121985Sjhb INTSRC(15), 187121985Sjhb}; 188121985Sjhb 189129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 190128875Sjhb 191133017Sscottlstatic __inline void 192133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 193133017Sscottl{ 194133017Sscottl 195133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 196133017Sscottl ("%s: mismatched pic", __func__)); 197133017Sscottl#ifndef AUTO_EOI_1 198133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 199133017Sscottl#endif 200133017Sscottl} 201133017Sscottl 202133017Sscottl/* 203133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 204133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 205133017Sscottl */ 206133017Sscottlstatic __inline void 207133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 208133017Sscottl{ 209133017Sscottl 210133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 211133017Sscottl ("%s: mismatched pic", __func__)); 212133017Sscottl#ifndef AUTO_EOI_2 213133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 214133017Sscottl#ifndef AUTO_EOI_1 215133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 216133017Sscottl#endif 217133017Sscottl#endif 218133017Sscottl} 219133017Sscottl 220121985Sjhbstatic void 221121985Sjhbatpic_enable_source(struct intsrc *isrc) 222121985Sjhb{ 223121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 224121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 225121985Sjhb 226121985Sjhb mtx_lock_spin(&icu_lock); 227128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 228128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 229128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 230128875Sjhb } 231121985Sjhb mtx_unlock_spin(&icu_lock); 232121985Sjhb} 233121985Sjhb 234121985Sjhbstatic void 235133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 236121985Sjhb{ 237121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 238121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 239121985Sjhb 240121985Sjhb mtx_lock_spin(&icu_lock); 241133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 242133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 243133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 244133017Sscottl } 245133017Sscottl 246133017Sscottl /* 247133017Sscottl * Take care to call these functions directly instead of through 248133017Sscottl * a function pointer. All of the referenced variables should 249133017Sscottl * still be hot in the cache. 250133017Sscottl */ 251133017Sscottl if (eoi == PIC_EOI) { 252133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 253133017Sscottl _atpic_eoi_master(isrc); 254133017Sscottl else 255133017Sscottl _atpic_eoi_slave(isrc); 256133017Sscottl } 257133017Sscottl 258121985Sjhb mtx_unlock_spin(&icu_lock); 259121985Sjhb} 260121985Sjhb 261121985Sjhbstatic void 262121985Sjhbatpic_eoi_master(struct intsrc *isrc) 263121985Sjhb{ 264121985Sjhb#ifndef AUTO_EOI_1 265121985Sjhb mtx_lock_spin(&icu_lock); 266133017Sscottl _atpic_eoi_master(isrc); 267121985Sjhb mtx_unlock_spin(&icu_lock); 268121985Sjhb#endif 269121985Sjhb} 270121985Sjhb 271121985Sjhbstatic void 272121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 273121985Sjhb{ 274121985Sjhb#ifndef AUTO_EOI_2 275121985Sjhb mtx_lock_spin(&icu_lock); 276133017Sscottl _atpic_eoi_slave(isrc); 277121985Sjhb mtx_unlock_spin(&icu_lock); 278121985Sjhb#endif 279121985Sjhb} 280121985Sjhb 281121985Sjhbstatic void 282121985Sjhbatpic_enable_intr(struct intsrc *isrc) 283121985Sjhb{ 284121985Sjhb} 285121985Sjhb 286121985Sjhbstatic int 287121985Sjhbatpic_vector(struct intsrc *isrc) 288121985Sjhb{ 289121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 290121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 291121985Sjhb 292121985Sjhb return (IRQ(ap, ai)); 293121985Sjhb} 294121985Sjhb 295121985Sjhbstatic int 296121985Sjhbatpic_source_pending(struct intsrc *isrc) 297121985Sjhb{ 298121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 299121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 300121985Sjhb 301128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 302121985Sjhb} 303121985Sjhb 304121985Sjhbstatic void 305121985Sjhbatpic_resume(struct intsrc *isrc) 306121985Sjhb{ 307121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 308121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 309121985Sjhb 310128929Sjhb if (ai->at_irq == 0) { 311121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 312129009Snyan#ifndef PC98 313140451Sjhb if (ap == &atpics[SLAVE] && elcr_found) 314128929Sjhb elcr_resume(); 315129009Snyan#endif 316128929Sjhb } 317121985Sjhb} 318121985Sjhb 319128931Sjhbstatic int 320128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 321128931Sjhb enum intr_polarity pol) 322128931Sjhb{ 323128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 324128931Sjhb u_int vector; 325128931Sjhb 326128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 327128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 328128931Sjhb trig = INTR_TRIGGER_EDGE; 329128931Sjhb if (pol == INTR_POLARITY_CONFORM) 330128931Sjhb pol = INTR_POLARITY_HIGH; 331128931Sjhb vector = atpic_vector(isrc); 332128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 333128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 334128931Sjhb printf( 335128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 336128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 337128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 338128931Sjhb return (EINVAL); 339128931Sjhb } 340128931Sjhb 341128931Sjhb /* If there is no change, just return. */ 342128931Sjhb if (ai->at_trigger == trig) 343128931Sjhb return (0); 344128931Sjhb 345129009Snyan#ifdef PC98 346129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 347129009Snyan trig == INTR_TRIGGER_LEVEL) { 348129009Snyan if (bootverbose) 349129009Snyan printf( 350129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 351129009Snyan vector); 352129009Snyan return (EINVAL); 353129009Snyan } 354129009Snyan return (ENXIO); 355129009Snyan#else 356128931Sjhb /* 357128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 358128931Sjhb * that way if asked. At least some ELCR registers ignore setting 359128931Sjhb * these bits as well. 360128931Sjhb */ 361128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 362128931Sjhb trig == INTR_TRIGGER_LEVEL) { 363128931Sjhb if (bootverbose) 364128931Sjhb printf( 365128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 366128931Sjhb vector); 367128931Sjhb return (EINVAL); 368128931Sjhb } 369140451Sjhb if (!elcr_found) { 370128931Sjhb if (bootverbose) 371128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 372128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 373128931Sjhb "level/low"); 374128931Sjhb return (ENXIO); 375128931Sjhb } 376128931Sjhb if (bootverbose) 377128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 378128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 379128931Sjhb mtx_lock_spin(&icu_lock); 380128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 381128931Sjhb ai->at_trigger = trig; 382128931Sjhb mtx_unlock_spin(&icu_lock); 383128931Sjhb return (0); 384129009Snyan#endif /* PC98 */ 385128931Sjhb} 386128931Sjhb 387121985Sjhbstatic void 388121985Sjhbi8259_init(struct atpic *pic, int slave) 389121985Sjhb{ 390121985Sjhb int imr_addr; 391121985Sjhb 392121985Sjhb /* Reset the PIC and program with next four bytes. */ 393121985Sjhb mtx_lock_spin(&icu_lock); 394121985Sjhb#ifdef DEV_MCA 395122692Sjhb /* MCA uses level triggered interrupts. */ 396121985Sjhb if (MCA_system) 397122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 398121985Sjhb else 399121985Sjhb#endif 400122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 401121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 402121985Sjhb 403121985Sjhb /* Start vector. */ 404121985Sjhb outb(imr_addr, pic->at_intbase); 405121985Sjhb 406121985Sjhb /* 407121985Sjhb * Setup slave links. For the master pic, indicate what line 408121985Sjhb * the slave is configured on. For the slave indicate 409121985Sjhb * which line on the master we are connected to. 410121985Sjhb */ 411121985Sjhb if (slave) 412129131Sjhb outb(imr_addr, ICU_SLAVEID); 413121985Sjhb else 414129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 415121985Sjhb 416121985Sjhb /* Set mode. */ 417121985Sjhb if (slave) 418121985Sjhb outb(imr_addr, SLAVE_MODE); 419121985Sjhb else 420121985Sjhb outb(imr_addr, MASTER_MODE); 421121985Sjhb 422121985Sjhb /* Set interrupt enable mask. */ 423121985Sjhb outb(imr_addr, *pic->at_imen); 424121985Sjhb 425121985Sjhb /* Reset is finished, default to IRR on read. */ 426122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 427121985Sjhb 428121985Sjhb#ifndef PC98 429122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 430121985Sjhb if (!slave) 431122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 432121985Sjhb#endif 433121985Sjhb mtx_unlock_spin(&icu_lock); 434121985Sjhb} 435121985Sjhb 436121985Sjhbvoid 437121985Sjhbatpic_startup(void) 438121985Sjhb{ 439122897Sjhb struct atpic_intsrc *ai; 440122897Sjhb int i; 441121985Sjhb 442121985Sjhb /* Start off with all interrupts disabled. */ 443121985Sjhb imen = 0xffff; 444121985Sjhb i8259_init(&atpics[MASTER], 0); 445121985Sjhb i8259_init(&atpics[SLAVE], 1); 446121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 447122897Sjhb 448122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 449128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 450122897Sjhb if (i == ICU_SLAVEID) 451122897Sjhb continue; 452122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 453122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 454122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 455122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 456122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 457122897Sjhb } 458128929Sjhb 459128929Sjhb#ifdef DEV_MCA 460128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 461128929Sjhb if (MCA_system) 462128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 463128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 464128929Sjhb else 465128929Sjhb#endif 466128929Sjhb 467129009Snyan#ifdef PC98 468129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 469129009Snyan switch (i) { 470129009Snyan case 0: 471129009Snyan case 1: 472129009Snyan case 7: 473129009Snyan case 8: 474129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 475129009Snyan break; 476129009Snyan default: 477129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 478129009Snyan break; 479129009Snyan } 480129009Snyan#else 481128929Sjhb /* 482128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 483128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 484128929Sjhb * edge triggered and that everything else is level triggered. 485128929Sjhb * We only use the trigger information to reprogram the ELCR if 486128929Sjhb * we have one and as an optimization to avoid masking edge 487128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 488128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 489129095Sjhb * assume level trigger for any interrupt that we aren't sure is 490129095Sjhb * edge triggered. 491128929Sjhb */ 492140451Sjhb if (elcr_found) { 493128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 494128929Sjhb ai->at_trigger = elcr_read_trigger(i); 495128929Sjhb } else { 496128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 497128929Sjhb switch (i) { 498128929Sjhb case 0: 499128929Sjhb case 1: 500128929Sjhb case 2: 501128929Sjhb case 8: 502128929Sjhb case 13: 503128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 504128929Sjhb break; 505128929Sjhb default: 506128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 507128929Sjhb break; 508128929Sjhb } 509128929Sjhb } 510129009Snyan#endif /* PC98 */ 511121985Sjhb} 512121985Sjhb 513121985Sjhbstatic void 514121985Sjhbatpic_init(void *dummy __unused) 515121985Sjhb{ 516128875Sjhb struct atpic_intsrc *ai; 517121985Sjhb int i; 518121985Sjhb 519121985Sjhb /* Loop through all interrupt sources and add them. */ 520128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 521121985Sjhb if (i == ICU_SLAVEID) 522121985Sjhb continue; 523128875Sjhb intr_register_source(&ai->at_intsrc); 524121985Sjhb } 525121985Sjhb} 526121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 527121985Sjhb 528121985Sjhbvoid 529122572Sjhbatpic_handle_intr(struct intrframe iframe) 530121985Sjhb{ 531121985Sjhb struct intsrc *isrc; 532121985Sjhb 533129131Sjhb KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS, 534121985Sjhb ("unknown int %d\n", iframe.if_vec)); 535121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 536122898Sjhb 537122898Sjhb /* 538151658Sjhb * If we don't have an event, see if this is a spurious 539122898Sjhb * interrupt. 540122898Sjhb */ 541151658Sjhb if (isrc->is_event == NULL && 542122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 543122898Sjhb int port, isr; 544122898Sjhb 545122898Sjhb /* 546122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 547122898Sjhb * pending. Reset read register back to IRR when done. 548122898Sjhb */ 549122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 550122898Sjhb mtx_lock_spin(&icu_lock); 551122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 552122898Sjhb isr = inb(port); 553122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 554122898Sjhb mtx_unlock_spin(&icu_lock); 555129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 556122898Sjhb return; 557122898Sjhb } 558121985Sjhb intr_execute_handlers(isrc, &iframe); 559121985Sjhb} 560121985Sjhb 561121985Sjhb#ifdef DEV_ISA 562121985Sjhb/* 563121985Sjhb * Bus attachment for the ISA PIC. 564121985Sjhb */ 565121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 566121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 567121985Sjhb { 0 } 568121985Sjhb}; 569121985Sjhb 570121985Sjhbstatic int 571121985Sjhbatpic_probe(device_t dev) 572121985Sjhb{ 573121985Sjhb int result; 574121985Sjhb 575121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 576121985Sjhb if (result <= 0) 577121985Sjhb device_quiet(dev); 578121985Sjhb return (result); 579121985Sjhb} 580121985Sjhb 581121985Sjhb/* 582121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 583121985Sjhb * between the two PIC components. If we're using the APIC, however, 584121985Sjhb * this may not be the case, and as such we should free the resource. 585121985Sjhb * (XXX untested) 586121985Sjhb * 587121985Sjhb * The generic ISA attachment code will handle allocating any other resources 588121985Sjhb * that we don't explicitly claim here. 589121985Sjhb */ 590121985Sjhbstatic int 591121985Sjhbatpic_attach(device_t dev) 592121985Sjhb{ 593121985Sjhb struct resource *res; 594121985Sjhb int rid; 595121985Sjhb 596121985Sjhb /* Try to allocate our IRQ and then free it. */ 597121985Sjhb rid = 0; 598127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 599121985Sjhb if (res != NULL) 600121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 601121985Sjhb return (0); 602121985Sjhb} 603121985Sjhb 604121985Sjhbstatic device_method_t atpic_methods[] = { 605121985Sjhb /* Device interface */ 606121985Sjhb DEVMETHOD(device_probe, atpic_probe), 607121985Sjhb DEVMETHOD(device_attach, atpic_attach), 608121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 609121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 610121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 611121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 612121985Sjhb { 0, 0 } 613121985Sjhb}; 614121985Sjhb 615121985Sjhbstatic driver_t atpic_driver = { 616121985Sjhb "atpic", 617121985Sjhb atpic_methods, 618121985Sjhb 1, /* no softc */ 619121985Sjhb}; 620121985Sjhb 621121985Sjhbstatic devclass_t atpic_devclass; 622121985Sjhb 623121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 624122051Snyan#ifndef PC98 625121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 626122051Snyan#endif 627121985Sjhb 628121985Sjhb/* 629121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 630121985Sjhb * and is only suitable for use at probe time. 631121985Sjhb */ 632121985Sjhbintrmask_t 633121985Sjhbisa_irq_pending(void) 634121985Sjhb{ 635121985Sjhb u_char irr1; 636121985Sjhb u_char irr2; 637121985Sjhb 638121985Sjhb irr1 = inb(IO_ICU1); 639121985Sjhb irr2 = inb(IO_ICU2); 640121985Sjhb return ((irr2 << 8) | irr1); 641121985Sjhb} 642121985Sjhb#endif /* DEV_ISA */ 643