atpic.c revision 156124
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 156124 2006-02-28 22:24:55Z 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, \ 129156124Sjhb atpic_resume, atpic_config_intr, atpic_assign_cpu }, (io), \ 130156124Sjhb (base), 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); 163156124Sjhbstatic void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 164121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 165121985Sjhb 166121985Sjhbstatic struct atpic atpics[] = { 167121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 168121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 169121985Sjhb}; 170121985Sjhb 171121985Sjhbstatic struct atpic_intsrc atintrs[] = { 172121985Sjhb INTSRC(0), 173121985Sjhb INTSRC(1), 174121985Sjhb INTSRC(2), 175121985Sjhb INTSRC(3), 176121985Sjhb INTSRC(4), 177121985Sjhb INTSRC(5), 178121985Sjhb INTSRC(6), 179121985Sjhb INTSRC(7), 180121985Sjhb INTSRC(8), 181121985Sjhb INTSRC(9), 182121985Sjhb INTSRC(10), 183121985Sjhb INTSRC(11), 184121985Sjhb INTSRC(12), 185121985Sjhb INTSRC(13), 186121985Sjhb INTSRC(14), 187121985Sjhb INTSRC(15), 188121985Sjhb}; 189121985Sjhb 190129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 191128875Sjhb 192133017Sscottlstatic __inline void 193133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 194133017Sscottl{ 195133017Sscottl 196133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 197133017Sscottl ("%s: mismatched pic", __func__)); 198133017Sscottl#ifndef AUTO_EOI_1 199133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 200133017Sscottl#endif 201133017Sscottl} 202133017Sscottl 203133017Sscottl/* 204133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 205133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 206133017Sscottl */ 207133017Sscottlstatic __inline void 208133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 209133017Sscottl{ 210133017Sscottl 211133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 212133017Sscottl ("%s: mismatched pic", __func__)); 213133017Sscottl#ifndef AUTO_EOI_2 214133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 215133017Sscottl#ifndef AUTO_EOI_1 216133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 217133017Sscottl#endif 218133017Sscottl#endif 219133017Sscottl} 220133017Sscottl 221121985Sjhbstatic void 222121985Sjhbatpic_enable_source(struct intsrc *isrc) 223121985Sjhb{ 224121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 225121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 226121985Sjhb 227121985Sjhb mtx_lock_spin(&icu_lock); 228128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 229128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 230128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 231128875Sjhb } 232121985Sjhb mtx_unlock_spin(&icu_lock); 233121985Sjhb} 234121985Sjhb 235121985Sjhbstatic void 236133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 237121985Sjhb{ 238121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 239121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 240121985Sjhb 241121985Sjhb mtx_lock_spin(&icu_lock); 242133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 243133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 244133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 245133017Sscottl } 246133017Sscottl 247133017Sscottl /* 248133017Sscottl * Take care to call these functions directly instead of through 249133017Sscottl * a function pointer. All of the referenced variables should 250133017Sscottl * still be hot in the cache. 251133017Sscottl */ 252133017Sscottl if (eoi == PIC_EOI) { 253133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 254133017Sscottl _atpic_eoi_master(isrc); 255133017Sscottl else 256133017Sscottl _atpic_eoi_slave(isrc); 257133017Sscottl } 258133017Sscottl 259121985Sjhb mtx_unlock_spin(&icu_lock); 260121985Sjhb} 261121985Sjhb 262121985Sjhbstatic void 263121985Sjhbatpic_eoi_master(struct intsrc *isrc) 264121985Sjhb{ 265121985Sjhb#ifndef AUTO_EOI_1 266121985Sjhb mtx_lock_spin(&icu_lock); 267133017Sscottl _atpic_eoi_master(isrc); 268121985Sjhb mtx_unlock_spin(&icu_lock); 269121985Sjhb#endif 270121985Sjhb} 271121985Sjhb 272121985Sjhbstatic void 273121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 274121985Sjhb{ 275121985Sjhb#ifndef AUTO_EOI_2 276121985Sjhb mtx_lock_spin(&icu_lock); 277133017Sscottl _atpic_eoi_slave(isrc); 278121985Sjhb mtx_unlock_spin(&icu_lock); 279121985Sjhb#endif 280121985Sjhb} 281121985Sjhb 282121985Sjhbstatic void 283121985Sjhbatpic_enable_intr(struct intsrc *isrc) 284121985Sjhb{ 285121985Sjhb} 286121985Sjhb 287121985Sjhbstatic int 288121985Sjhbatpic_vector(struct intsrc *isrc) 289121985Sjhb{ 290121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 291121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 292121985Sjhb 293121985Sjhb return (IRQ(ap, ai)); 294121985Sjhb} 295121985Sjhb 296121985Sjhbstatic int 297121985Sjhbatpic_source_pending(struct intsrc *isrc) 298121985Sjhb{ 299121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 300121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 301121985Sjhb 302128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 303121985Sjhb} 304121985Sjhb 305121985Sjhbstatic void 306121985Sjhbatpic_resume(struct intsrc *isrc) 307121985Sjhb{ 308121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 309121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 310121985Sjhb 311128929Sjhb if (ai->at_irq == 0) { 312121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 313129009Snyan#ifndef PC98 314140451Sjhb if (ap == &atpics[SLAVE] && elcr_found) 315128929Sjhb elcr_resume(); 316129009Snyan#endif 317128929Sjhb } 318121985Sjhb} 319121985Sjhb 320128931Sjhbstatic int 321128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 322128931Sjhb enum intr_polarity pol) 323128931Sjhb{ 324128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 325128931Sjhb u_int vector; 326128931Sjhb 327128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 328128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 329128931Sjhb trig = INTR_TRIGGER_EDGE; 330128931Sjhb if (pol == INTR_POLARITY_CONFORM) 331128931Sjhb pol = INTR_POLARITY_HIGH; 332128931Sjhb vector = atpic_vector(isrc); 333128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 334128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 335128931Sjhb printf( 336128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 337128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 338128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 339128931Sjhb return (EINVAL); 340128931Sjhb } 341128931Sjhb 342128931Sjhb /* If there is no change, just return. */ 343128931Sjhb if (ai->at_trigger == trig) 344128931Sjhb return (0); 345128931Sjhb 346129009Snyan#ifdef PC98 347129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 348129009Snyan trig == INTR_TRIGGER_LEVEL) { 349129009Snyan if (bootverbose) 350129009Snyan printf( 351129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 352129009Snyan vector); 353129009Snyan return (EINVAL); 354129009Snyan } 355129009Snyan return (ENXIO); 356129009Snyan#else 357128931Sjhb /* 358128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 359128931Sjhb * that way if asked. At least some ELCR registers ignore setting 360128931Sjhb * these bits as well. 361128931Sjhb */ 362128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 363128931Sjhb trig == INTR_TRIGGER_LEVEL) { 364128931Sjhb if (bootverbose) 365128931Sjhb printf( 366128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 367128931Sjhb vector); 368128931Sjhb return (EINVAL); 369128931Sjhb } 370140451Sjhb if (!elcr_found) { 371128931Sjhb if (bootverbose) 372128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 373128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 374128931Sjhb "level/low"); 375128931Sjhb return (ENXIO); 376128931Sjhb } 377128931Sjhb if (bootverbose) 378128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 379128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 380128931Sjhb mtx_lock_spin(&icu_lock); 381128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 382128931Sjhb ai->at_trigger = trig; 383128931Sjhb mtx_unlock_spin(&icu_lock); 384128931Sjhb return (0); 385129009Snyan#endif /* PC98 */ 386128931Sjhb} 387128931Sjhb 388121985Sjhbstatic void 389156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 390156124Sjhb{ 391156124Sjhb 392156124Sjhb /* 393156124Sjhb * 8259A's are only used in UP in which case all interrupts always 394156124Sjhb * go to the sole CPU and this function shouldn't even be called. 395156124Sjhb */ 396156124Sjhb panic("%s: bad cookie", __func__); 397156124Sjhb} 398156124Sjhb 399156124Sjhbstatic void 400121985Sjhbi8259_init(struct atpic *pic, int slave) 401121985Sjhb{ 402121985Sjhb int imr_addr; 403121985Sjhb 404121985Sjhb /* Reset the PIC and program with next four bytes. */ 405121985Sjhb mtx_lock_spin(&icu_lock); 406121985Sjhb#ifdef DEV_MCA 407122692Sjhb /* MCA uses level triggered interrupts. */ 408121985Sjhb if (MCA_system) 409122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 410121985Sjhb else 411121985Sjhb#endif 412122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 413121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 414121985Sjhb 415121985Sjhb /* Start vector. */ 416121985Sjhb outb(imr_addr, pic->at_intbase); 417121985Sjhb 418121985Sjhb /* 419121985Sjhb * Setup slave links. For the master pic, indicate what line 420121985Sjhb * the slave is configured on. For the slave indicate 421121985Sjhb * which line on the master we are connected to. 422121985Sjhb */ 423121985Sjhb if (slave) 424129131Sjhb outb(imr_addr, ICU_SLAVEID); 425121985Sjhb else 426129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 427121985Sjhb 428121985Sjhb /* Set mode. */ 429121985Sjhb if (slave) 430121985Sjhb outb(imr_addr, SLAVE_MODE); 431121985Sjhb else 432121985Sjhb outb(imr_addr, MASTER_MODE); 433121985Sjhb 434121985Sjhb /* Set interrupt enable mask. */ 435121985Sjhb outb(imr_addr, *pic->at_imen); 436121985Sjhb 437121985Sjhb /* Reset is finished, default to IRR on read. */ 438122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 439121985Sjhb 440121985Sjhb#ifndef PC98 441122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 442121985Sjhb if (!slave) 443122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 444121985Sjhb#endif 445121985Sjhb mtx_unlock_spin(&icu_lock); 446121985Sjhb} 447121985Sjhb 448121985Sjhbvoid 449121985Sjhbatpic_startup(void) 450121985Sjhb{ 451122897Sjhb struct atpic_intsrc *ai; 452122897Sjhb int i; 453121985Sjhb 454121985Sjhb /* Start off with all interrupts disabled. */ 455121985Sjhb imen = 0xffff; 456121985Sjhb i8259_init(&atpics[MASTER], 0); 457121985Sjhb i8259_init(&atpics[SLAVE], 1); 458121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 459122897Sjhb 460122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 461128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 462122897Sjhb if (i == ICU_SLAVEID) 463122897Sjhb continue; 464122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 465122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 466122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 467122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 468122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 469122897Sjhb } 470128929Sjhb 471128929Sjhb#ifdef DEV_MCA 472128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 473128929Sjhb if (MCA_system) 474128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 475128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 476128929Sjhb else 477128929Sjhb#endif 478128929Sjhb 479129009Snyan#ifdef PC98 480129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 481129009Snyan switch (i) { 482129009Snyan case 0: 483129009Snyan case 1: 484129009Snyan case 7: 485129009Snyan case 8: 486129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 487129009Snyan break; 488129009Snyan default: 489129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 490129009Snyan break; 491129009Snyan } 492129009Snyan#else 493128929Sjhb /* 494128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 495128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 496128929Sjhb * edge triggered and that everything else is level triggered. 497128929Sjhb * We only use the trigger information to reprogram the ELCR if 498128929Sjhb * we have one and as an optimization to avoid masking edge 499128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 500128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 501129095Sjhb * assume level trigger for any interrupt that we aren't sure is 502129095Sjhb * edge triggered. 503128929Sjhb */ 504140451Sjhb if (elcr_found) { 505128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 506128929Sjhb ai->at_trigger = elcr_read_trigger(i); 507128929Sjhb } else { 508128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 509128929Sjhb switch (i) { 510128929Sjhb case 0: 511128929Sjhb case 1: 512128929Sjhb case 2: 513128929Sjhb case 8: 514128929Sjhb case 13: 515128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 516128929Sjhb break; 517128929Sjhb default: 518128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 519128929Sjhb break; 520128929Sjhb } 521128929Sjhb } 522129009Snyan#endif /* PC98 */ 523121985Sjhb} 524121985Sjhb 525121985Sjhbstatic void 526121985Sjhbatpic_init(void *dummy __unused) 527121985Sjhb{ 528128875Sjhb struct atpic_intsrc *ai; 529121985Sjhb int i; 530121985Sjhb 531153136Sjhb /* 532153136Sjhb * If any of the ISA IRQs have an interrupt source already, then 533153136Sjhb * assume that the APICs are being used and don't register any 534153136Sjhb * of our interrupt sources. This makes sure we don't accidentally 535153136Sjhb * use mixed mode. The "accidental" use could otherwise occur on 536153136Sjhb * machines that route the ACPI SCI interrupt to a different ISA 537153136Sjhb * IRQ (at least one machines routes it to IRQ 13) thus disabling 538153136Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 539153136Sjhb * to leak through. We used to depend on this feature for routing 540153136Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 541153136Sjhb */ 542153136Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 543153136Sjhb if (intr_lookup_source(i) != NULL) 544153136Sjhb return; 545153136Sjhb 546121985Sjhb /* Loop through all interrupt sources and add them. */ 547128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 548121985Sjhb if (i == ICU_SLAVEID) 549121985Sjhb continue; 550128875Sjhb intr_register_source(&ai->at_intsrc); 551121985Sjhb } 552121985Sjhb} 553121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 554121985Sjhb 555121985Sjhbvoid 556153146Sjhbatpic_handle_intr(u_int vector, struct trapframe frame) 557121985Sjhb{ 558121985Sjhb struct intsrc *isrc; 559121985Sjhb 560153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 561153146Sjhb isrc = &atintrs[vector].at_intsrc; 562122898Sjhb 563122898Sjhb /* 564151658Sjhb * If we don't have an event, see if this is a spurious 565122898Sjhb * interrupt. 566122898Sjhb */ 567153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 568122898Sjhb int port, isr; 569122898Sjhb 570122898Sjhb /* 571122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 572122898Sjhb * pending. Reset read register back to IRR when done. 573122898Sjhb */ 574122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 575122898Sjhb mtx_lock_spin(&icu_lock); 576122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 577122898Sjhb isr = inb(port); 578122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 579122898Sjhb mtx_unlock_spin(&icu_lock); 580129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 581122898Sjhb return; 582122898Sjhb } 583153146Sjhb intr_execute_handlers(isrc, &frame); 584121985Sjhb} 585121985Sjhb 586121985Sjhb#ifdef DEV_ISA 587121985Sjhb/* 588121985Sjhb * Bus attachment for the ISA PIC. 589121985Sjhb */ 590121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 591121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 592121985Sjhb { 0 } 593121985Sjhb}; 594121985Sjhb 595121985Sjhbstatic int 596121985Sjhbatpic_probe(device_t dev) 597121985Sjhb{ 598121985Sjhb int result; 599121985Sjhb 600121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 601121985Sjhb if (result <= 0) 602121985Sjhb device_quiet(dev); 603121985Sjhb return (result); 604121985Sjhb} 605121985Sjhb 606121985Sjhb/* 607121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 608121985Sjhb * between the two PIC components. If we're using the APIC, however, 609121985Sjhb * this may not be the case, and as such we should free the resource. 610121985Sjhb * (XXX untested) 611121985Sjhb * 612121985Sjhb * The generic ISA attachment code will handle allocating any other resources 613121985Sjhb * that we don't explicitly claim here. 614121985Sjhb */ 615121985Sjhbstatic int 616121985Sjhbatpic_attach(device_t dev) 617121985Sjhb{ 618121985Sjhb struct resource *res; 619121985Sjhb int rid; 620121985Sjhb 621121985Sjhb /* Try to allocate our IRQ and then free it. */ 622121985Sjhb rid = 0; 623127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 624121985Sjhb if (res != NULL) 625121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 626121985Sjhb return (0); 627121985Sjhb} 628121985Sjhb 629121985Sjhbstatic device_method_t atpic_methods[] = { 630121985Sjhb /* Device interface */ 631121985Sjhb DEVMETHOD(device_probe, atpic_probe), 632121985Sjhb DEVMETHOD(device_attach, atpic_attach), 633121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 634121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 635121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 636121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 637121985Sjhb { 0, 0 } 638121985Sjhb}; 639121985Sjhb 640121985Sjhbstatic driver_t atpic_driver = { 641121985Sjhb "atpic", 642121985Sjhb atpic_methods, 643121985Sjhb 1, /* no softc */ 644121985Sjhb}; 645121985Sjhb 646121985Sjhbstatic devclass_t atpic_devclass; 647121985Sjhb 648121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 649122051Snyan#ifndef PC98 650121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 651122051Snyan#endif 652121985Sjhb 653121985Sjhb/* 654121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 655121985Sjhb * and is only suitable for use at probe time. 656121985Sjhb */ 657121985Sjhbintrmask_t 658121985Sjhbisa_irq_pending(void) 659121985Sjhb{ 660121985Sjhb u_char irr1; 661121985Sjhb u_char irr2; 662121985Sjhb 663121985Sjhb irr1 = inb(IO_ICU1); 664121985Sjhb irr2 = inb(IO_ICU2); 665121985Sjhb return ((irr2 << 8) | irr1); 666121985Sjhb} 667121985Sjhb#endif /* DEV_ISA */ 668