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 * 14121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17121985Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24121985Sjhb * SUCH DAMAGE. 25121985Sjhb */ 26121985Sjhb 27121985Sjhb/* 28121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 29121985Sjhb */ 30121985Sjhb 31121985Sjhb#include <sys/cdefs.h> 32121985Sjhb__FBSDID("$FreeBSD: releng/10.3/sys/x86/isa/atpic.c 262192 2014-02-18 20:27:17Z jhb $"); 33121985Sjhb 34121985Sjhb#include "opt_auto_eoi.h" 35121985Sjhb#include "opt_isa.h" 36121985Sjhb 37121985Sjhb#include <sys/param.h> 38121985Sjhb#include <sys/systm.h> 39121985Sjhb#include <sys/bus.h> 40121985Sjhb#include <sys/interrupt.h> 41121985Sjhb#include <sys/kernel.h> 42121985Sjhb#include <sys/lock.h> 43129876Sphk#include <sys/module.h> 44121985Sjhb 45121985Sjhb#include <machine/cpufunc.h> 46121985Sjhb#include <machine/frame.h> 47121985Sjhb#include <machine/intr_machdep.h> 48121985Sjhb#include <machine/md_var.h> 49121985Sjhb#include <machine/resource.h> 50121985Sjhb#include <machine/segments.h> 51121985Sjhb 52124188Sjhb#include <dev/ic/i8259.h> 53204309Sattilio#include <x86/isa/icu.h> 54122051Snyan#ifdef PC98 55146049Snyan#include <pc98/cbus/cbus.h> 56122051Snyan#else 57204309Sattilio#include <x86/isa/isa.h> 58122051Snyan#endif 59121985Sjhb#include <isa/isavar.h> 60121985Sjhb 61204309Sattilio#ifdef __amd64__ 62204309Sattilio#define SDT_ATPIC SDT_SYSIGT 63204309Sattilio#define GSEL_ATPIC 0 64204309Sattilio#else 65204309Sattilio#define SDT_ATPIC SDT_SYS386IGT 66204309Sattilio#define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL) 67204309Sattilio#endif 68204309Sattilio 69121985Sjhb#define MASTER 0 70121985Sjhb#define SLAVE 1 71121985Sjhb 72128875Sjhb#define NUM_ISA_IRQS 16 73128875Sjhb 74121985Sjhbstatic void atpic_init(void *dummy); 75121985Sjhb 76121985Sjhbunsigned int imen; /* XXX */ 77121985Sjhb 78121985Sjhbinthand_t 79121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 80121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 81121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 82121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 83121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 84121985Sjhb IDTVEC(atpic_intr15); 85121985Sjhb 86121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 87121985Sjhb 88128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 89121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 90169391Sjhb atpic_enable_intr, atpic_disable_intr, atpic_vector, \ 91169391Sjhb atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\ 92169391Sjhb atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \ 93169391Sjhb (imenptr) } 94121985Sjhb 95121985Sjhb#define INTSRC(irq) \ 96128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 97128929Sjhb (irq) % 8 } 98121985Sjhb 99121985Sjhbstruct atpic { 100121985Sjhb struct pic at_pic; 101121985Sjhb int at_ioaddr; 102121985Sjhb int at_irqbase; 103121985Sjhb uint8_t at_intbase; 104121985Sjhb uint8_t *at_imen; 105121985Sjhb}; 106121985Sjhb 107121985Sjhbstruct atpic_intsrc { 108121985Sjhb struct intsrc at_intsrc; 109121985Sjhb inthand_t *at_intr; 110128929Sjhb int at_irq; /* Relative to PIC base. */ 111128929Sjhb enum intr_trigger at_trigger; 112122897Sjhb u_long at_count; 113122897Sjhb u_long at_straycount; 114121985Sjhb}; 115121985Sjhb 116121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 117133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 118121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 119121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 120121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 121169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc); 122121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 123255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled); 124121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 125128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 126128931Sjhb enum intr_polarity pol); 127195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 128121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 129121985Sjhb 130121985Sjhbstatic struct atpic atpics[] = { 131121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 132121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 133121985Sjhb}; 134121985Sjhb 135121985Sjhbstatic struct atpic_intsrc atintrs[] = { 136121985Sjhb INTSRC(0), 137121985Sjhb INTSRC(1), 138121985Sjhb INTSRC(2), 139121985Sjhb INTSRC(3), 140121985Sjhb INTSRC(4), 141121985Sjhb INTSRC(5), 142121985Sjhb INTSRC(6), 143121985Sjhb INTSRC(7), 144121985Sjhb INTSRC(8), 145121985Sjhb INTSRC(9), 146121985Sjhb INTSRC(10), 147121985Sjhb INTSRC(11), 148121985Sjhb INTSRC(12), 149121985Sjhb INTSRC(13), 150121985Sjhb INTSRC(14), 151121985Sjhb INTSRC(15), 152121985Sjhb}; 153121985Sjhb 154129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 155128875Sjhb 156133017Sscottlstatic __inline void 157133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 158133017Sscottl{ 159133017Sscottl 160133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 161133017Sscottl ("%s: mismatched pic", __func__)); 162133017Sscottl#ifndef AUTO_EOI_1 163133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 164133017Sscottl#endif 165133017Sscottl} 166133017Sscottl 167133017Sscottl/* 168133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 169133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 170133017Sscottl */ 171133017Sscottlstatic __inline void 172133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 173133017Sscottl{ 174133017Sscottl 175133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 176133017Sscottl ("%s: mismatched pic", __func__)); 177133017Sscottl#ifndef AUTO_EOI_2 178133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 179133017Sscottl#ifndef AUTO_EOI_1 180133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 181133017Sscottl#endif 182133017Sscottl#endif 183133017Sscottl} 184133017Sscottl 185121985Sjhbstatic void 186121985Sjhbatpic_enable_source(struct intsrc *isrc) 187121985Sjhb{ 188121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 189121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 190121985Sjhb 191177468Sjhb spinlock_enter(); 192128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 193128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 194128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 195128875Sjhb } 196177468Sjhb spinlock_exit(); 197121985Sjhb} 198121985Sjhb 199121985Sjhbstatic void 200133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 201121985Sjhb{ 202121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 203121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 204121985Sjhb 205177468Sjhb spinlock_enter(); 206133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 207133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 208133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 209133017Sscottl } 210133017Sscottl 211133017Sscottl /* 212133017Sscottl * Take care to call these functions directly instead of through 213133017Sscottl * a function pointer. All of the referenced variables should 214133017Sscottl * still be hot in the cache. 215133017Sscottl */ 216133017Sscottl if (eoi == PIC_EOI) { 217133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 218133017Sscottl _atpic_eoi_master(isrc); 219133017Sscottl else 220133017Sscottl _atpic_eoi_slave(isrc); 221133017Sscottl } 222133017Sscottl 223177468Sjhb spinlock_exit(); 224121985Sjhb} 225121985Sjhb 226121985Sjhbstatic void 227121985Sjhbatpic_eoi_master(struct intsrc *isrc) 228121985Sjhb{ 229121985Sjhb#ifndef AUTO_EOI_1 230177468Sjhb spinlock_enter(); 231133017Sscottl _atpic_eoi_master(isrc); 232177468Sjhb spinlock_exit(); 233121985Sjhb#endif 234121985Sjhb} 235121985Sjhb 236121985Sjhbstatic void 237121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 238121985Sjhb{ 239121985Sjhb#ifndef AUTO_EOI_2 240177468Sjhb spinlock_enter(); 241133017Sscottl _atpic_eoi_slave(isrc); 242177468Sjhb spinlock_exit(); 243121985Sjhb#endif 244121985Sjhb} 245121985Sjhb 246121985Sjhbstatic void 247121985Sjhbatpic_enable_intr(struct intsrc *isrc) 248121985Sjhb{ 249121985Sjhb} 250121985Sjhb 251169391Sjhbstatic void 252169391Sjhbatpic_disable_intr(struct intsrc *isrc) 253169391Sjhb{ 254169391Sjhb} 255169391Sjhb 256169391Sjhb 257121985Sjhbstatic int 258121985Sjhbatpic_vector(struct intsrc *isrc) 259121985Sjhb{ 260121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 261121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 262121985Sjhb 263121985Sjhb return (IRQ(ap, ai)); 264121985Sjhb} 265121985Sjhb 266121985Sjhbstatic int 267121985Sjhbatpic_source_pending(struct intsrc *isrc) 268121985Sjhb{ 269121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 270121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 271121985Sjhb 272128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 273121985Sjhb} 274121985Sjhb 275121985Sjhbstatic void 276255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled) 277121985Sjhb{ 278163219Sjhb struct atpic *ap = (struct atpic *)pic; 279121985Sjhb 280163219Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 281129009Snyan#ifndef PC98 282163219Sjhb if (ap == &atpics[SLAVE] && elcr_found) 283163219Sjhb elcr_resume(); 284129009Snyan#endif 285121985Sjhb} 286121985Sjhb 287128931Sjhbstatic int 288128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 289128931Sjhb enum intr_polarity pol) 290128931Sjhb{ 291128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 292128931Sjhb u_int vector; 293128931Sjhb 294128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 295128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 296128931Sjhb trig = INTR_TRIGGER_EDGE; 297128931Sjhb if (pol == INTR_POLARITY_CONFORM) 298128931Sjhb pol = INTR_POLARITY_HIGH; 299128931Sjhb vector = atpic_vector(isrc); 300128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 301128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 302128931Sjhb printf( 303128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 304128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 305128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 306128931Sjhb return (EINVAL); 307128931Sjhb } 308128931Sjhb 309128931Sjhb /* If there is no change, just return. */ 310128931Sjhb if (ai->at_trigger == trig) 311128931Sjhb return (0); 312128931Sjhb 313129009Snyan#ifdef PC98 314129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 315129009Snyan trig == INTR_TRIGGER_LEVEL) { 316129009Snyan if (bootverbose) 317129009Snyan printf( 318129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 319129009Snyan vector); 320129009Snyan return (EINVAL); 321129009Snyan } 322129009Snyan return (ENXIO); 323129009Snyan#else 324128931Sjhb /* 325128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 326128931Sjhb * that way if asked. At least some ELCR registers ignore setting 327128931Sjhb * these bits as well. 328128931Sjhb */ 329128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 330128931Sjhb trig == INTR_TRIGGER_LEVEL) { 331128931Sjhb if (bootverbose) 332128931Sjhb printf( 333128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 334128931Sjhb vector); 335128931Sjhb return (EINVAL); 336128931Sjhb } 337140451Sjhb if (!elcr_found) { 338128931Sjhb if (bootverbose) 339128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 340128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 341128931Sjhb "level/low"); 342128931Sjhb return (ENXIO); 343128931Sjhb } 344128931Sjhb if (bootverbose) 345128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 346128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 347177468Sjhb spinlock_enter(); 348128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 349128931Sjhb ai->at_trigger = trig; 350177468Sjhb spinlock_exit(); 351128931Sjhb return (0); 352129009Snyan#endif /* PC98 */ 353128931Sjhb} 354128931Sjhb 355195249Sjhbstatic int 356156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 357156124Sjhb{ 358156124Sjhb 359156124Sjhb /* 360156124Sjhb * 8259A's are only used in UP in which case all interrupts always 361156124Sjhb * go to the sole CPU and this function shouldn't even be called. 362156124Sjhb */ 363156124Sjhb panic("%s: bad cookie", __func__); 364156124Sjhb} 365156124Sjhb 366156124Sjhbstatic void 367121985Sjhbi8259_init(struct atpic *pic, int slave) 368121985Sjhb{ 369121985Sjhb int imr_addr; 370121985Sjhb 371121985Sjhb /* Reset the PIC and program with next four bytes. */ 372177468Sjhb spinlock_enter(); 373121985Sjhb#ifdef DEV_MCA 374122692Sjhb /* MCA uses level triggered interrupts. */ 375121985Sjhb if (MCA_system) 376122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 377121985Sjhb else 378121985Sjhb#endif 379122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 380121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 381121985Sjhb 382121985Sjhb /* Start vector. */ 383121985Sjhb outb(imr_addr, pic->at_intbase); 384121985Sjhb 385121985Sjhb /* 386121985Sjhb * Setup slave links. For the master pic, indicate what line 387121985Sjhb * the slave is configured on. For the slave indicate 388121985Sjhb * which line on the master we are connected to. 389121985Sjhb */ 390121985Sjhb if (slave) 391129131Sjhb outb(imr_addr, ICU_SLAVEID); 392121985Sjhb else 393129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 394121985Sjhb 395121985Sjhb /* Set mode. */ 396121985Sjhb if (slave) 397121985Sjhb outb(imr_addr, SLAVE_MODE); 398121985Sjhb else 399121985Sjhb outb(imr_addr, MASTER_MODE); 400121985Sjhb 401121985Sjhb /* Set interrupt enable mask. */ 402121985Sjhb outb(imr_addr, *pic->at_imen); 403121985Sjhb 404121985Sjhb /* Reset is finished, default to IRR on read. */ 405122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 406121985Sjhb 407121985Sjhb#ifndef PC98 408122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 409121985Sjhb if (!slave) 410122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 411121985Sjhb#endif 412177468Sjhb spinlock_exit(); 413121985Sjhb} 414121985Sjhb 415121985Sjhbvoid 416121985Sjhbatpic_startup(void) 417121985Sjhb{ 418122897Sjhb struct atpic_intsrc *ai; 419122897Sjhb int i; 420121985Sjhb 421121985Sjhb /* Start off with all interrupts disabled. */ 422121985Sjhb imen = 0xffff; 423121985Sjhb i8259_init(&atpics[MASTER], 0); 424121985Sjhb i8259_init(&atpics[SLAVE], 1); 425121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 426122897Sjhb 427122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 428128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 429122897Sjhb if (i == ICU_SLAVEID) 430122897Sjhb continue; 431122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 432122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 433122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 434204309Sattilio ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC); 435122897Sjhb } 436128929Sjhb 437128929Sjhb#ifdef DEV_MCA 438128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 439128929Sjhb if (MCA_system) 440128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 441128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 442128929Sjhb else 443128929Sjhb#endif 444128929Sjhb 445129009Snyan#ifdef PC98 446129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 447129009Snyan switch (i) { 448129009Snyan case 0: 449129009Snyan case 1: 450129009Snyan case 7: 451129009Snyan case 8: 452129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 453129009Snyan break; 454129009Snyan default: 455129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 456129009Snyan break; 457129009Snyan } 458129009Snyan#else 459128929Sjhb /* 460128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 461128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 462128929Sjhb * edge triggered and that everything else is level triggered. 463128929Sjhb * We only use the trigger information to reprogram the ELCR if 464128929Sjhb * we have one and as an optimization to avoid masking edge 465128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 466128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 467129095Sjhb * assume level trigger for any interrupt that we aren't sure is 468129095Sjhb * edge triggered. 469128929Sjhb */ 470140451Sjhb if (elcr_found) { 471128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 472128929Sjhb ai->at_trigger = elcr_read_trigger(i); 473128929Sjhb } else { 474128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 475128929Sjhb switch (i) { 476128929Sjhb case 0: 477128929Sjhb case 1: 478128929Sjhb case 2: 479128929Sjhb case 8: 480128929Sjhb case 13: 481128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 482128929Sjhb break; 483128929Sjhb default: 484128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 485128929Sjhb break; 486128929Sjhb } 487128929Sjhb } 488129009Snyan#endif /* PC98 */ 489121985Sjhb} 490121985Sjhb 491121985Sjhbstatic void 492121985Sjhbatpic_init(void *dummy __unused) 493121985Sjhb{ 494128875Sjhb struct atpic_intsrc *ai; 495121985Sjhb int i; 496121985Sjhb 497153136Sjhb /* 498163219Sjhb * Register our PICs, even if we aren't going to use any of their 499163219Sjhb * pins so that they are suspended and resumed. 500163219Sjhb */ 501163219Sjhb if (intr_register_pic(&atpics[0].at_pic) != 0 || 502163219Sjhb intr_register_pic(&atpics[1].at_pic) != 0) 503163219Sjhb panic("Unable to register ATPICs"); 504163219Sjhb 505163219Sjhb /* 506153136Sjhb * If any of the ISA IRQs have an interrupt source already, then 507153136Sjhb * assume that the APICs are being used and don't register any 508153136Sjhb * of our interrupt sources. This makes sure we don't accidentally 509153136Sjhb * use mixed mode. The "accidental" use could otherwise occur on 510153136Sjhb * machines that route the ACPI SCI interrupt to a different ISA 511153136Sjhb * IRQ (at least one machines routes it to IRQ 13) thus disabling 512153136Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 513153136Sjhb * to leak through. We used to depend on this feature for routing 514153136Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 515153136Sjhb */ 516153136Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 517153136Sjhb if (intr_lookup_source(i) != NULL) 518153136Sjhb return; 519153136Sjhb 520121985Sjhb /* Loop through all interrupt sources and add them. */ 521128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 522121985Sjhb if (i == ICU_SLAVEID) 523121985Sjhb continue; 524128875Sjhb intr_register_source(&ai->at_intsrc); 525121985Sjhb } 526121985Sjhb} 527177253SrwatsonSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL); 528121985Sjhb 529121985Sjhbvoid 530165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame) 531121985Sjhb{ 532121985Sjhb struct intsrc *isrc; 533121985Sjhb 534153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 535153146Sjhb isrc = &atintrs[vector].at_intsrc; 536122898Sjhb 537122898Sjhb /* 538151658Sjhb * If we don't have an event, see if this is a spurious 539122898Sjhb * interrupt. 540122898Sjhb */ 541153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 542122898Sjhb int port, isr; 543122898Sjhb 544122898Sjhb /* 545122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 546122898Sjhb * pending. Reset read register back to IRR when done. 547122898Sjhb */ 548122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 549177468Sjhb spinlock_enter(); 550122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 551122898Sjhb isr = inb(port); 552122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 553177468Sjhb spinlock_exit(); 554129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 555122898Sjhb return; 556122898Sjhb } 557165302Skmacy intr_execute_handlers(isrc, frame); 558121985Sjhb} 559121985Sjhb 560121985Sjhb#ifdef DEV_ISA 561121985Sjhb/* 562121985Sjhb * Bus attachment for the ISA PIC. 563121985Sjhb */ 564121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 565121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 566121985Sjhb { 0 } 567121985Sjhb}; 568121985Sjhb 569121985Sjhbstatic int 570121985Sjhbatpic_probe(device_t dev) 571121985Sjhb{ 572121985Sjhb int result; 573121985Sjhb 574121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 575121985Sjhb if (result <= 0) 576121985Sjhb device_quiet(dev); 577121985Sjhb return (result); 578121985Sjhb} 579121985Sjhb 580121985Sjhb/* 581121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 582121985Sjhb * between the two PIC components. If we're using the APIC, however, 583121985Sjhb * this may not be the case, and as such we should free the resource. 584121985Sjhb * (XXX untested) 585121985Sjhb * 586121985Sjhb * The generic ISA attachment code will handle allocating any other resources 587121985Sjhb * that we don't explicitly claim here. 588121985Sjhb */ 589121985Sjhbstatic int 590121985Sjhbatpic_attach(device_t dev) 591121985Sjhb{ 592121985Sjhb struct resource *res; 593121985Sjhb int rid; 594121985Sjhb 595121985Sjhb /* Try to allocate our IRQ and then free it. */ 596121985Sjhb rid = 0; 597127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 598121985Sjhb if (res != NULL) 599121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 600121985Sjhb return (0); 601121985Sjhb} 602121985Sjhb 603121985Sjhbstatic device_method_t atpic_methods[] = { 604121985Sjhb /* Device interface */ 605121985Sjhb DEVMETHOD(device_probe, atpic_probe), 606121985Sjhb DEVMETHOD(device_attach, atpic_attach), 607121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 608121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 609121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 610121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 611121985Sjhb { 0, 0 } 612121985Sjhb}; 613121985Sjhb 614121985Sjhbstatic driver_t atpic_driver = { 615121985Sjhb "atpic", 616121985Sjhb atpic_methods, 617121985Sjhb 1, /* no softc */ 618121985Sjhb}; 619121985Sjhb 620121985Sjhbstatic devclass_t atpic_devclass; 621121985Sjhb 622121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 623122051Snyan#ifndef PC98 624121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 625122051Snyan#endif 626121985Sjhb 627121985Sjhb/* 628121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 629121985Sjhb * and is only suitable for use at probe time. 630121985Sjhb */ 631121985Sjhbintrmask_t 632121985Sjhbisa_irq_pending(void) 633121985Sjhb{ 634121985Sjhb u_char irr1; 635121985Sjhb u_char irr2; 636121985Sjhb 637121985Sjhb irr1 = inb(IO_ICU1); 638121985Sjhb irr2 = inb(IO_ICU2); 639121985Sjhb return ((irr2 << 8) | irr1); 640121985Sjhb} 641121985Sjhb#endif /* DEV_ISA */ 642