atpic.c revision 169391
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 169391 2007-05-08 21:29:14Z 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), \ 128169391Sjhb atpic_enable_intr, atpic_disable_intr, atpic_vector, \ 129169391Sjhb atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\ 130169391Sjhb atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \ 131169391Sjhb (imenptr) } 132121985Sjhb 133121985Sjhb#define INTSRC(irq) \ 134128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 135128929Sjhb (irq) % 8 } 136121985Sjhb 137121985Sjhbstruct atpic { 138121985Sjhb struct pic at_pic; 139121985Sjhb int at_ioaddr; 140121985Sjhb int at_irqbase; 141121985Sjhb uint8_t at_intbase; 142121985Sjhb uint8_t *at_imen; 143121985Sjhb}; 144121985Sjhb 145121985Sjhbstruct atpic_intsrc { 146121985Sjhb struct intsrc at_intsrc; 147121985Sjhb inthand_t *at_intr; 148128929Sjhb int at_irq; /* Relative to PIC base. */ 149128929Sjhb enum intr_trigger at_trigger; 150122897Sjhb u_long at_count; 151122897Sjhb u_long at_straycount; 152121985Sjhb}; 153121985Sjhb 154121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 155133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 156121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 157121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 158121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 159169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc); 160121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 161163219Sjhbstatic void atpic_resume(struct pic *pic); 162121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 163128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 164128931Sjhb enum intr_polarity pol); 165156124Sjhbstatic void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 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 289169391Sjhbstatic void 290169391Sjhbatpic_disable_intr(struct intsrc *isrc) 291169391Sjhb{ 292169391Sjhb} 293169391Sjhb 294169391Sjhb 295121985Sjhbstatic int 296121985Sjhbatpic_vector(struct intsrc *isrc) 297121985Sjhb{ 298121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 299121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 300121985Sjhb 301121985Sjhb return (IRQ(ap, ai)); 302121985Sjhb} 303121985Sjhb 304121985Sjhbstatic int 305121985Sjhbatpic_source_pending(struct intsrc *isrc) 306121985Sjhb{ 307121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 308121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 309121985Sjhb 310128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 311121985Sjhb} 312121985Sjhb 313121985Sjhbstatic void 314163219Sjhbatpic_resume(struct pic *pic) 315121985Sjhb{ 316163219Sjhb struct atpic *ap = (struct atpic *)pic; 317121985Sjhb 318163219Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 319129009Snyan#ifndef PC98 320163219Sjhb if (ap == &atpics[SLAVE] && elcr_found) 321163219Sjhb elcr_resume(); 322129009Snyan#endif 323121985Sjhb} 324121985Sjhb 325128931Sjhbstatic int 326128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 327128931Sjhb enum intr_polarity pol) 328128931Sjhb{ 329128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 330128931Sjhb u_int vector; 331128931Sjhb 332128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 333128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 334128931Sjhb trig = INTR_TRIGGER_EDGE; 335128931Sjhb if (pol == INTR_POLARITY_CONFORM) 336128931Sjhb pol = INTR_POLARITY_HIGH; 337128931Sjhb vector = atpic_vector(isrc); 338128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 339128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 340128931Sjhb printf( 341128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 342128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 343128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 344128931Sjhb return (EINVAL); 345128931Sjhb } 346128931Sjhb 347128931Sjhb /* If there is no change, just return. */ 348128931Sjhb if (ai->at_trigger == trig) 349128931Sjhb return (0); 350128931Sjhb 351129009Snyan#ifdef PC98 352129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 353129009Snyan trig == INTR_TRIGGER_LEVEL) { 354129009Snyan if (bootverbose) 355129009Snyan printf( 356129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 357129009Snyan vector); 358129009Snyan return (EINVAL); 359129009Snyan } 360129009Snyan return (ENXIO); 361129009Snyan#else 362128931Sjhb /* 363128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 364128931Sjhb * that way if asked. At least some ELCR registers ignore setting 365128931Sjhb * these bits as well. 366128931Sjhb */ 367128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 368128931Sjhb trig == INTR_TRIGGER_LEVEL) { 369128931Sjhb if (bootverbose) 370128931Sjhb printf( 371128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 372128931Sjhb vector); 373128931Sjhb return (EINVAL); 374128931Sjhb } 375140451Sjhb if (!elcr_found) { 376128931Sjhb if (bootverbose) 377128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 378128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 379128931Sjhb "level/low"); 380128931Sjhb return (ENXIO); 381128931Sjhb } 382128931Sjhb if (bootverbose) 383128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 384128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 385128931Sjhb mtx_lock_spin(&icu_lock); 386128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 387128931Sjhb ai->at_trigger = trig; 388128931Sjhb mtx_unlock_spin(&icu_lock); 389128931Sjhb return (0); 390129009Snyan#endif /* PC98 */ 391128931Sjhb} 392128931Sjhb 393121985Sjhbstatic void 394156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 395156124Sjhb{ 396156124Sjhb 397156124Sjhb /* 398156124Sjhb * 8259A's are only used in UP in which case all interrupts always 399156124Sjhb * go to the sole CPU and this function shouldn't even be called. 400156124Sjhb */ 401156124Sjhb panic("%s: bad cookie", __func__); 402156124Sjhb} 403156124Sjhb 404156124Sjhbstatic void 405121985Sjhbi8259_init(struct atpic *pic, int slave) 406121985Sjhb{ 407121985Sjhb int imr_addr; 408121985Sjhb 409121985Sjhb /* Reset the PIC and program with next four bytes. */ 410121985Sjhb mtx_lock_spin(&icu_lock); 411121985Sjhb#ifdef DEV_MCA 412122692Sjhb /* MCA uses level triggered interrupts. */ 413121985Sjhb if (MCA_system) 414122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 415121985Sjhb else 416121985Sjhb#endif 417122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 418121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 419121985Sjhb 420121985Sjhb /* Start vector. */ 421121985Sjhb outb(imr_addr, pic->at_intbase); 422121985Sjhb 423121985Sjhb /* 424121985Sjhb * Setup slave links. For the master pic, indicate what line 425121985Sjhb * the slave is configured on. For the slave indicate 426121985Sjhb * which line on the master we are connected to. 427121985Sjhb */ 428121985Sjhb if (slave) 429129131Sjhb outb(imr_addr, ICU_SLAVEID); 430121985Sjhb else 431129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 432121985Sjhb 433121985Sjhb /* Set mode. */ 434121985Sjhb if (slave) 435121985Sjhb outb(imr_addr, SLAVE_MODE); 436121985Sjhb else 437121985Sjhb outb(imr_addr, MASTER_MODE); 438121985Sjhb 439121985Sjhb /* Set interrupt enable mask. */ 440121985Sjhb outb(imr_addr, *pic->at_imen); 441121985Sjhb 442121985Sjhb /* Reset is finished, default to IRR on read. */ 443122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 444121985Sjhb 445121985Sjhb#ifndef PC98 446122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 447121985Sjhb if (!slave) 448122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 449121985Sjhb#endif 450121985Sjhb mtx_unlock_spin(&icu_lock); 451121985Sjhb} 452121985Sjhb 453121985Sjhbvoid 454121985Sjhbatpic_startup(void) 455121985Sjhb{ 456122897Sjhb struct atpic_intsrc *ai; 457122897Sjhb int i; 458121985Sjhb 459121985Sjhb /* Start off with all interrupts disabled. */ 460121985Sjhb imen = 0xffff; 461121985Sjhb i8259_init(&atpics[MASTER], 0); 462121985Sjhb i8259_init(&atpics[SLAVE], 1); 463121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 464122897Sjhb 465122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 466128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 467122897Sjhb if (i == ICU_SLAVEID) 468122897Sjhb continue; 469122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 470122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 471122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 472122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 473122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 474122897Sjhb } 475128929Sjhb 476128929Sjhb#ifdef DEV_MCA 477128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 478128929Sjhb if (MCA_system) 479128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 480128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 481128929Sjhb else 482128929Sjhb#endif 483128929Sjhb 484129009Snyan#ifdef PC98 485129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 486129009Snyan switch (i) { 487129009Snyan case 0: 488129009Snyan case 1: 489129009Snyan case 7: 490129009Snyan case 8: 491129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 492129009Snyan break; 493129009Snyan default: 494129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 495129009Snyan break; 496129009Snyan } 497129009Snyan#else 498128929Sjhb /* 499128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 500128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 501128929Sjhb * edge triggered and that everything else is level triggered. 502128929Sjhb * We only use the trigger information to reprogram the ELCR if 503128929Sjhb * we have one and as an optimization to avoid masking edge 504128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 505128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 506129095Sjhb * assume level trigger for any interrupt that we aren't sure is 507129095Sjhb * edge triggered. 508128929Sjhb */ 509140451Sjhb if (elcr_found) { 510128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 511128929Sjhb ai->at_trigger = elcr_read_trigger(i); 512128929Sjhb } else { 513128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 514128929Sjhb switch (i) { 515128929Sjhb case 0: 516128929Sjhb case 1: 517128929Sjhb case 2: 518128929Sjhb case 8: 519128929Sjhb case 13: 520128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 521128929Sjhb break; 522128929Sjhb default: 523128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 524128929Sjhb break; 525128929Sjhb } 526128929Sjhb } 527129009Snyan#endif /* PC98 */ 528121985Sjhb} 529121985Sjhb 530121985Sjhbstatic void 531121985Sjhbatpic_init(void *dummy __unused) 532121985Sjhb{ 533128875Sjhb struct atpic_intsrc *ai; 534121985Sjhb int i; 535121985Sjhb 536153136Sjhb /* 537163219Sjhb * Register our PICs, even if we aren't going to use any of their 538163219Sjhb * pins so that they are suspended and resumed. 539163219Sjhb */ 540163219Sjhb if (intr_register_pic(&atpics[0].at_pic) != 0 || 541163219Sjhb intr_register_pic(&atpics[1].at_pic) != 0) 542163219Sjhb panic("Unable to register ATPICs"); 543163219Sjhb 544163219Sjhb /* 545153136Sjhb * If any of the ISA IRQs have an interrupt source already, then 546153136Sjhb * assume that the APICs are being used and don't register any 547153136Sjhb * of our interrupt sources. This makes sure we don't accidentally 548153136Sjhb * use mixed mode. The "accidental" use could otherwise occur on 549153136Sjhb * machines that route the ACPI SCI interrupt to a different ISA 550153136Sjhb * IRQ (at least one machines routes it to IRQ 13) thus disabling 551153136Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 552153136Sjhb * to leak through. We used to depend on this feature for routing 553153136Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 554153136Sjhb */ 555153136Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 556153136Sjhb if (intr_lookup_source(i) != NULL) 557153136Sjhb return; 558153136Sjhb 559121985Sjhb /* Loop through all interrupt sources and add them. */ 560128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 561121985Sjhb if (i == ICU_SLAVEID) 562121985Sjhb continue; 563128875Sjhb intr_register_source(&ai->at_intsrc); 564121985Sjhb } 565121985Sjhb} 566121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 567121985Sjhb 568121985Sjhbvoid 569165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame) 570121985Sjhb{ 571121985Sjhb struct intsrc *isrc; 572121985Sjhb 573153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 574153146Sjhb isrc = &atintrs[vector].at_intsrc; 575122898Sjhb 576122898Sjhb /* 577151658Sjhb * If we don't have an event, see if this is a spurious 578122898Sjhb * interrupt. 579122898Sjhb */ 580153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 581122898Sjhb int port, isr; 582122898Sjhb 583122898Sjhb /* 584122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 585122898Sjhb * pending. Reset read register back to IRR when done. 586122898Sjhb */ 587122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 588122898Sjhb mtx_lock_spin(&icu_lock); 589122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 590122898Sjhb isr = inb(port); 591122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 592122898Sjhb mtx_unlock_spin(&icu_lock); 593129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 594122898Sjhb return; 595122898Sjhb } 596165302Skmacy intr_execute_handlers(isrc, frame); 597121985Sjhb} 598121985Sjhb 599121985Sjhb#ifdef DEV_ISA 600121985Sjhb/* 601121985Sjhb * Bus attachment for the ISA PIC. 602121985Sjhb */ 603121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 604121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 605121985Sjhb { 0 } 606121985Sjhb}; 607121985Sjhb 608121985Sjhbstatic int 609121985Sjhbatpic_probe(device_t dev) 610121985Sjhb{ 611121985Sjhb int result; 612121985Sjhb 613121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 614121985Sjhb if (result <= 0) 615121985Sjhb device_quiet(dev); 616121985Sjhb return (result); 617121985Sjhb} 618121985Sjhb 619121985Sjhb/* 620121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 621121985Sjhb * between the two PIC components. If we're using the APIC, however, 622121985Sjhb * this may not be the case, and as such we should free the resource. 623121985Sjhb * (XXX untested) 624121985Sjhb * 625121985Sjhb * The generic ISA attachment code will handle allocating any other resources 626121985Sjhb * that we don't explicitly claim here. 627121985Sjhb */ 628121985Sjhbstatic int 629121985Sjhbatpic_attach(device_t dev) 630121985Sjhb{ 631121985Sjhb struct resource *res; 632121985Sjhb int rid; 633121985Sjhb 634121985Sjhb /* Try to allocate our IRQ and then free it. */ 635121985Sjhb rid = 0; 636127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 637121985Sjhb if (res != NULL) 638121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 639121985Sjhb return (0); 640121985Sjhb} 641121985Sjhb 642121985Sjhbstatic device_method_t atpic_methods[] = { 643121985Sjhb /* Device interface */ 644121985Sjhb DEVMETHOD(device_probe, atpic_probe), 645121985Sjhb DEVMETHOD(device_attach, atpic_attach), 646121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 647121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 648121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 649121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 650121985Sjhb { 0, 0 } 651121985Sjhb}; 652121985Sjhb 653121985Sjhbstatic driver_t atpic_driver = { 654121985Sjhb "atpic", 655121985Sjhb atpic_methods, 656121985Sjhb 1, /* no softc */ 657121985Sjhb}; 658121985Sjhb 659121985Sjhbstatic devclass_t atpic_devclass; 660121985Sjhb 661121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 662122051Snyan#ifndef PC98 663121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 664122051Snyan#endif 665121985Sjhb 666121985Sjhb/* 667121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 668121985Sjhb * and is only suitable for use at probe time. 669121985Sjhb */ 670121985Sjhbintrmask_t 671121985Sjhbisa_irq_pending(void) 672121985Sjhb{ 673121985Sjhb u_char irr1; 674121985Sjhb u_char irr2; 675121985Sjhb 676121985Sjhb irr1 = inb(IO_ICU1); 677121985Sjhb irr2 = inb(IO_ICU2); 678121985Sjhb return ((irr2 << 8) | irr1); 679121985Sjhb} 680121985Sjhb#endif /* DEV_ISA */ 681