atpic.c revision 329462
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: stable/11/sys/x86/isa/atpic.c 329462 2018-02-17 18:00:01Z kib $"); 33121985Sjhb 34121985Sjhb#include "opt_auto_eoi.h" 35121985Sjhb#include "opt_isa.h" 36277285Simp#include "opt_mca.h" 37121985Sjhb 38121985Sjhb#include <sys/param.h> 39121985Sjhb#include <sys/systm.h> 40121985Sjhb#include <sys/bus.h> 41121985Sjhb#include <sys/interrupt.h> 42121985Sjhb#include <sys/kernel.h> 43121985Sjhb#include <sys/lock.h> 44129876Sphk#include <sys/module.h> 45121985Sjhb 46121985Sjhb#include <machine/cpufunc.h> 47121985Sjhb#include <machine/frame.h> 48121985Sjhb#include <machine/intr_machdep.h> 49121985Sjhb#include <machine/md_var.h> 50121985Sjhb#include <machine/resource.h> 51121985Sjhb#include <machine/segments.h> 52121985Sjhb 53124188Sjhb#include <dev/ic/i8259.h> 54204309Sattilio#include <x86/isa/icu.h> 55122051Snyan#ifdef PC98 56146049Snyan#include <pc98/cbus/cbus.h> 57122051Snyan#else 58263379Simp#include <isa/isareg.h> 59122051Snyan#endif 60121985Sjhb#include <isa/isavar.h> 61277311Simp#ifdef DEV_MCA 62277311Simp#include <i386/bios/mca_machdep.h> 63277311Simp#endif 64121985Sjhb 65204309Sattilio#ifdef __amd64__ 66204309Sattilio#define SDT_ATPIC SDT_SYSIGT 67204309Sattilio#define GSEL_ATPIC 0 68204309Sattilio#else 69204309Sattilio#define SDT_ATPIC SDT_SYS386IGT 70204309Sattilio#define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL) 71204309Sattilio#endif 72204309Sattilio 73121985Sjhb#define MASTER 0 74121985Sjhb#define SLAVE 1 75121985Sjhb 76128875Sjhb#define NUM_ISA_IRQS 16 77128875Sjhb 78121985Sjhbstatic void atpic_init(void *dummy); 79121985Sjhb 80121985Sjhbunsigned int imen; /* XXX */ 81121985Sjhb 82121985Sjhbinthand_t 83121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 84121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 85121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 86121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 87121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 88121985Sjhb IDTVEC(atpic_intr15); 89329462Skib/* XXXKIB i386 uses stubs until pti comes */ 90329462Skibinthand_t 91329462Skib IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti), 92329462Skib IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti), 93329462Skib IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti), 94329462Skib IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti), 95329462Skib IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti), 96329462Skib IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti), 97329462Skib IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti), 98329462Skib IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti); 99121985Sjhb 100121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 101121985Sjhb 102128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 103121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 104169391Sjhb atpic_enable_intr, atpic_disable_intr, atpic_vector, \ 105169391Sjhb atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\ 106169391Sjhb atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \ 107169391Sjhb (imenptr) } 108121985Sjhb 109121985Sjhb#define INTSRC(irq) \ 110128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 111329462Skib IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 } 112121985Sjhb 113121985Sjhbstruct atpic { 114121985Sjhb struct pic at_pic; 115121985Sjhb int at_ioaddr; 116121985Sjhb int at_irqbase; 117121985Sjhb uint8_t at_intbase; 118121985Sjhb uint8_t *at_imen; 119121985Sjhb}; 120121985Sjhb 121121985Sjhbstruct atpic_intsrc { 122121985Sjhb struct intsrc at_intsrc; 123329462Skib inthand_t *at_intr, *at_intr_pti; 124128929Sjhb int at_irq; /* Relative to PIC base. */ 125128929Sjhb enum intr_trigger at_trigger; 126122897Sjhb u_long at_count; 127122897Sjhb u_long at_straycount; 128121985Sjhb}; 129121985Sjhb 130121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 131133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 132121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 133121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 134121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 135169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc); 136121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 137255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled); 138121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 139128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 140128931Sjhb enum intr_polarity pol); 141195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 142121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 143121985Sjhb 144121985Sjhbstatic struct atpic atpics[] = { 145121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 146121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 147121985Sjhb}; 148121985Sjhb 149121985Sjhbstatic struct atpic_intsrc atintrs[] = { 150121985Sjhb INTSRC(0), 151121985Sjhb INTSRC(1), 152121985Sjhb INTSRC(2), 153121985Sjhb INTSRC(3), 154121985Sjhb INTSRC(4), 155121985Sjhb INTSRC(5), 156121985Sjhb INTSRC(6), 157121985Sjhb INTSRC(7), 158121985Sjhb INTSRC(8), 159121985Sjhb INTSRC(9), 160121985Sjhb INTSRC(10), 161121985Sjhb INTSRC(11), 162121985Sjhb INTSRC(12), 163121985Sjhb INTSRC(13), 164121985Sjhb INTSRC(14), 165121985Sjhb INTSRC(15), 166121985Sjhb}; 167121985Sjhb 168298308SpfgCTASSERT(nitems(atintrs) == NUM_ISA_IRQS); 169128875Sjhb 170133017Sscottlstatic __inline void 171133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 172133017Sscottl{ 173133017Sscottl 174133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 175133017Sscottl ("%s: mismatched pic", __func__)); 176133017Sscottl#ifndef AUTO_EOI_1 177133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 178133017Sscottl#endif 179133017Sscottl} 180133017Sscottl 181133017Sscottl/* 182133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 183133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 184133017Sscottl */ 185133017Sscottlstatic __inline void 186133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 187133017Sscottl{ 188133017Sscottl 189133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 190133017Sscottl ("%s: mismatched pic", __func__)); 191133017Sscottl#ifndef AUTO_EOI_2 192133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 193133017Sscottl#ifndef AUTO_EOI_1 194133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 195133017Sscottl#endif 196133017Sscottl#endif 197133017Sscottl} 198133017Sscottl 199121985Sjhbstatic void 200121985Sjhbatpic_enable_source(struct intsrc *isrc) 201121985Sjhb{ 202121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 203121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 204121985Sjhb 205177468Sjhb spinlock_enter(); 206128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 207128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 208128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 209128875Sjhb } 210177468Sjhb spinlock_exit(); 211121985Sjhb} 212121985Sjhb 213121985Sjhbstatic void 214133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 215121985Sjhb{ 216121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 217121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 218121985Sjhb 219177468Sjhb spinlock_enter(); 220133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 221133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 222133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 223133017Sscottl } 224133017Sscottl 225133017Sscottl /* 226133017Sscottl * Take care to call these functions directly instead of through 227133017Sscottl * a function pointer. All of the referenced variables should 228133017Sscottl * still be hot in the cache. 229133017Sscottl */ 230133017Sscottl if (eoi == PIC_EOI) { 231133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 232133017Sscottl _atpic_eoi_master(isrc); 233133017Sscottl else 234133017Sscottl _atpic_eoi_slave(isrc); 235133017Sscottl } 236133017Sscottl 237177468Sjhb spinlock_exit(); 238121985Sjhb} 239121985Sjhb 240121985Sjhbstatic void 241121985Sjhbatpic_eoi_master(struct intsrc *isrc) 242121985Sjhb{ 243121985Sjhb#ifndef AUTO_EOI_1 244177468Sjhb spinlock_enter(); 245133017Sscottl _atpic_eoi_master(isrc); 246177468Sjhb spinlock_exit(); 247121985Sjhb#endif 248121985Sjhb} 249121985Sjhb 250121985Sjhbstatic void 251121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 252121985Sjhb{ 253121985Sjhb#ifndef AUTO_EOI_2 254177468Sjhb spinlock_enter(); 255133017Sscottl _atpic_eoi_slave(isrc); 256177468Sjhb spinlock_exit(); 257121985Sjhb#endif 258121985Sjhb} 259121985Sjhb 260121985Sjhbstatic void 261121985Sjhbatpic_enable_intr(struct intsrc *isrc) 262121985Sjhb{ 263121985Sjhb} 264121985Sjhb 265169391Sjhbstatic void 266169391Sjhbatpic_disable_intr(struct intsrc *isrc) 267169391Sjhb{ 268169391Sjhb} 269169391Sjhb 270169391Sjhb 271121985Sjhbstatic int 272121985Sjhbatpic_vector(struct intsrc *isrc) 273121985Sjhb{ 274121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 275121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 276121985Sjhb 277121985Sjhb return (IRQ(ap, ai)); 278121985Sjhb} 279121985Sjhb 280121985Sjhbstatic int 281121985Sjhbatpic_source_pending(struct intsrc *isrc) 282121985Sjhb{ 283121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 284121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 285121985Sjhb 286128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 287121985Sjhb} 288121985Sjhb 289121985Sjhbstatic void 290255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled) 291121985Sjhb{ 292163219Sjhb struct atpic *ap = (struct atpic *)pic; 293121985Sjhb 294163219Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 295129009Snyan#ifndef PC98 296163219Sjhb if (ap == &atpics[SLAVE] && elcr_found) 297163219Sjhb elcr_resume(); 298129009Snyan#endif 299121985Sjhb} 300121985Sjhb 301128931Sjhbstatic int 302128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 303128931Sjhb enum intr_polarity pol) 304128931Sjhb{ 305128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 306128931Sjhb u_int vector; 307128931Sjhb 308128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 309128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 310128931Sjhb trig = INTR_TRIGGER_EDGE; 311128931Sjhb if (pol == INTR_POLARITY_CONFORM) 312128931Sjhb pol = INTR_POLARITY_HIGH; 313128931Sjhb vector = atpic_vector(isrc); 314128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 315128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 316128931Sjhb printf( 317128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 318128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 319128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 320128931Sjhb return (EINVAL); 321128931Sjhb } 322128931Sjhb 323128931Sjhb /* If there is no change, just return. */ 324128931Sjhb if (ai->at_trigger == trig) 325128931Sjhb return (0); 326128931Sjhb 327129009Snyan#ifdef PC98 328129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 329129009Snyan trig == INTR_TRIGGER_LEVEL) { 330129009Snyan if (bootverbose) 331129009Snyan printf( 332129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 333129009Snyan vector); 334129009Snyan return (EINVAL); 335129009Snyan } 336129009Snyan return (ENXIO); 337129009Snyan#else 338128931Sjhb /* 339128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 340128931Sjhb * that way if asked. At least some ELCR registers ignore setting 341128931Sjhb * these bits as well. 342128931Sjhb */ 343128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 344128931Sjhb trig == INTR_TRIGGER_LEVEL) { 345128931Sjhb if (bootverbose) 346128931Sjhb printf( 347128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 348128931Sjhb vector); 349128931Sjhb return (EINVAL); 350128931Sjhb } 351140451Sjhb if (!elcr_found) { 352128931Sjhb if (bootverbose) 353128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 354128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 355128931Sjhb "level/low"); 356128931Sjhb return (ENXIO); 357128931Sjhb } 358128931Sjhb if (bootverbose) 359128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 360128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 361177468Sjhb spinlock_enter(); 362128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 363128931Sjhb ai->at_trigger = trig; 364177468Sjhb spinlock_exit(); 365128931Sjhb return (0); 366129009Snyan#endif /* PC98 */ 367128931Sjhb} 368128931Sjhb 369195249Sjhbstatic int 370156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 371156124Sjhb{ 372156124Sjhb 373156124Sjhb /* 374156124Sjhb * 8259A's are only used in UP in which case all interrupts always 375156124Sjhb * go to the sole CPU and this function shouldn't even be called. 376156124Sjhb */ 377156124Sjhb panic("%s: bad cookie", __func__); 378156124Sjhb} 379156124Sjhb 380156124Sjhbstatic void 381121985Sjhbi8259_init(struct atpic *pic, int slave) 382121985Sjhb{ 383121985Sjhb int imr_addr; 384121985Sjhb 385121985Sjhb /* Reset the PIC and program with next four bytes. */ 386177468Sjhb spinlock_enter(); 387121985Sjhb#ifdef DEV_MCA 388122692Sjhb /* MCA uses level triggered interrupts. */ 389121985Sjhb if (MCA_system) 390122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 391121985Sjhb else 392121985Sjhb#endif 393122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 394121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 395121985Sjhb 396121985Sjhb /* Start vector. */ 397121985Sjhb outb(imr_addr, pic->at_intbase); 398121985Sjhb 399121985Sjhb /* 400121985Sjhb * Setup slave links. For the master pic, indicate what line 401121985Sjhb * the slave is configured on. For the slave indicate 402121985Sjhb * which line on the master we are connected to. 403121985Sjhb */ 404121985Sjhb if (slave) 405129131Sjhb outb(imr_addr, ICU_SLAVEID); 406121985Sjhb else 407129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 408121985Sjhb 409121985Sjhb /* Set mode. */ 410121985Sjhb if (slave) 411121985Sjhb outb(imr_addr, SLAVE_MODE); 412121985Sjhb else 413121985Sjhb outb(imr_addr, MASTER_MODE); 414121985Sjhb 415121985Sjhb /* Set interrupt enable mask. */ 416121985Sjhb outb(imr_addr, *pic->at_imen); 417121985Sjhb 418121985Sjhb /* Reset is finished, default to IRR on read. */ 419122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 420121985Sjhb 421121985Sjhb#ifndef PC98 422122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 423121985Sjhb if (!slave) 424122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 425121985Sjhb#endif 426177468Sjhb spinlock_exit(); 427121985Sjhb} 428121985Sjhb 429121985Sjhbvoid 430121985Sjhbatpic_startup(void) 431121985Sjhb{ 432122897Sjhb struct atpic_intsrc *ai; 433122897Sjhb int i; 434121985Sjhb 435121985Sjhb /* Start off with all interrupts disabled. */ 436121985Sjhb imen = 0xffff; 437121985Sjhb i8259_init(&atpics[MASTER], 0); 438121985Sjhb i8259_init(&atpics[SLAVE], 1); 439121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 440122897Sjhb 441122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 442128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 443122897Sjhb if (i == ICU_SLAVEID) 444122897Sjhb continue; 445122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 446122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 447122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 448329462Skib ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC, 449329462Skib SEL_KPL, GSEL_ATPIC); 450122897Sjhb } 451128929Sjhb 452128929Sjhb#ifdef DEV_MCA 453128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 454128929Sjhb if (MCA_system) 455128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 456128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 457128929Sjhb else 458128929Sjhb#endif 459128929Sjhb 460129009Snyan#ifdef PC98 461129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 462129009Snyan switch (i) { 463129009Snyan case 0: 464129009Snyan case 1: 465129009Snyan case 7: 466129009Snyan case 8: 467129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 468129009Snyan break; 469129009Snyan default: 470129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 471129009Snyan break; 472129009Snyan } 473129009Snyan#else 474128929Sjhb /* 475128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 476128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 477128929Sjhb * edge triggered and that everything else is level triggered. 478128929Sjhb * We only use the trigger information to reprogram the ELCR if 479128929Sjhb * we have one and as an optimization to avoid masking edge 480128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 481128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 482129095Sjhb * assume level trigger for any interrupt that we aren't sure is 483129095Sjhb * edge triggered. 484128929Sjhb */ 485140451Sjhb if (elcr_found) { 486128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 487128929Sjhb ai->at_trigger = elcr_read_trigger(i); 488128929Sjhb } else { 489128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 490128929Sjhb switch (i) { 491128929Sjhb case 0: 492128929Sjhb case 1: 493128929Sjhb case 2: 494128929Sjhb case 8: 495128929Sjhb case 13: 496128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 497128929Sjhb break; 498128929Sjhb default: 499128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 500128929Sjhb break; 501128929Sjhb } 502128929Sjhb } 503129009Snyan#endif /* PC98 */ 504121985Sjhb} 505121985Sjhb 506121985Sjhbstatic void 507121985Sjhbatpic_init(void *dummy __unused) 508121985Sjhb{ 509128875Sjhb struct atpic_intsrc *ai; 510121985Sjhb int i; 511121985Sjhb 512153136Sjhb /* 513163219Sjhb * Register our PICs, even if we aren't going to use any of their 514163219Sjhb * pins so that they are suspended and resumed. 515163219Sjhb */ 516163219Sjhb if (intr_register_pic(&atpics[0].at_pic) != 0 || 517163219Sjhb intr_register_pic(&atpics[1].at_pic) != 0) 518163219Sjhb panic("Unable to register ATPICs"); 519163219Sjhb 520163219Sjhb /* 521153136Sjhb * If any of the ISA IRQs have an interrupt source already, then 522153136Sjhb * assume that the APICs are being used and don't register any 523153136Sjhb * of our interrupt sources. This makes sure we don't accidentally 524153136Sjhb * use mixed mode. The "accidental" use could otherwise occur on 525153136Sjhb * machines that route the ACPI SCI interrupt to a different ISA 526153136Sjhb * IRQ (at least one machines routes it to IRQ 13) thus disabling 527153136Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 528153136Sjhb * to leak through. We used to depend on this feature for routing 529153136Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 530153136Sjhb */ 531153136Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 532153136Sjhb if (intr_lookup_source(i) != NULL) 533153136Sjhb return; 534153136Sjhb 535121985Sjhb /* Loop through all interrupt sources and add them. */ 536128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 537121985Sjhb if (i == ICU_SLAVEID) 538121985Sjhb continue; 539128875Sjhb intr_register_source(&ai->at_intsrc); 540121985Sjhb } 541121985Sjhb} 542269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL); 543121985Sjhb 544121985Sjhbvoid 545165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame) 546121985Sjhb{ 547121985Sjhb struct intsrc *isrc; 548121985Sjhb 549153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 550153146Sjhb isrc = &atintrs[vector].at_intsrc; 551122898Sjhb 552122898Sjhb /* 553151658Sjhb * If we don't have an event, see if this is a spurious 554122898Sjhb * interrupt. 555122898Sjhb */ 556153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 557122898Sjhb int port, isr; 558122898Sjhb 559122898Sjhb /* 560122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 561122898Sjhb * pending. Reset read register back to IRR when done. 562122898Sjhb */ 563122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 564177468Sjhb spinlock_enter(); 565122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 566122898Sjhb isr = inb(port); 567122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 568177468Sjhb spinlock_exit(); 569129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 570122898Sjhb return; 571122898Sjhb } 572165302Skmacy intr_execute_handlers(isrc, frame); 573121985Sjhb} 574121985Sjhb 575121985Sjhb#ifdef DEV_ISA 576121985Sjhb/* 577121985Sjhb * Bus attachment for the ISA PIC. 578121985Sjhb */ 579121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 580121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 581121985Sjhb { 0 } 582121985Sjhb}; 583121985Sjhb 584121985Sjhbstatic int 585121985Sjhbatpic_probe(device_t dev) 586121985Sjhb{ 587121985Sjhb int result; 588121985Sjhb 589121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 590121985Sjhb if (result <= 0) 591121985Sjhb device_quiet(dev); 592121985Sjhb return (result); 593121985Sjhb} 594121985Sjhb 595121985Sjhb/* 596121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 597121985Sjhb * between the two PIC components. If we're using the APIC, however, 598121985Sjhb * this may not be the case, and as such we should free the resource. 599121985Sjhb * (XXX untested) 600121985Sjhb * 601121985Sjhb * The generic ISA attachment code will handle allocating any other resources 602121985Sjhb * that we don't explicitly claim here. 603121985Sjhb */ 604121985Sjhbstatic int 605121985Sjhbatpic_attach(device_t dev) 606121985Sjhb{ 607121985Sjhb struct resource *res; 608121985Sjhb int rid; 609121985Sjhb 610121985Sjhb /* Try to allocate our IRQ and then free it. */ 611121985Sjhb rid = 0; 612127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 613121985Sjhb if (res != NULL) 614121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 615121985Sjhb return (0); 616121985Sjhb} 617121985Sjhb 618121985Sjhbstatic device_method_t atpic_methods[] = { 619121985Sjhb /* Device interface */ 620121985Sjhb DEVMETHOD(device_probe, atpic_probe), 621121985Sjhb DEVMETHOD(device_attach, atpic_attach), 622121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 623121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 624121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 625121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 626121985Sjhb { 0, 0 } 627121985Sjhb}; 628121985Sjhb 629121985Sjhbstatic driver_t atpic_driver = { 630121985Sjhb "atpic", 631121985Sjhb atpic_methods, 632121985Sjhb 1, /* no softc */ 633121985Sjhb}; 634121985Sjhb 635121985Sjhbstatic devclass_t atpic_devclass; 636121985Sjhb 637121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 638122051Snyan#ifndef PC98 639121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 640122051Snyan#endif 641121985Sjhb 642121985Sjhb/* 643121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 644121985Sjhb * and is only suitable for use at probe time. 645121985Sjhb */ 646121985Sjhbintrmask_t 647121985Sjhbisa_irq_pending(void) 648121985Sjhb{ 649121985Sjhb u_char irr1; 650121985Sjhb u_char irr2; 651121985Sjhb 652121985Sjhb irr1 = inb(IO_ICU1); 653121985Sjhb irr2 = inb(IO_ICU2); 654121985Sjhb return ((irr2 << 8) | irr1); 655121985Sjhb} 656121985Sjhb#endif /* DEV_ISA */ 657