atpic.c revision 277311
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: head/sys/x86/isa/atpic.c 277311 2015-01-18 03:43:47Z imp $"); 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); 89121985Sjhb 90121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 91121985Sjhb 92128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 93121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 94169391Sjhb atpic_enable_intr, atpic_disable_intr, atpic_vector, \ 95169391Sjhb atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\ 96169391Sjhb atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \ 97169391Sjhb (imenptr) } 98121985Sjhb 99121985Sjhb#define INTSRC(irq) \ 100128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 101128929Sjhb (irq) % 8 } 102121985Sjhb 103121985Sjhbstruct atpic { 104121985Sjhb struct pic at_pic; 105121985Sjhb int at_ioaddr; 106121985Sjhb int at_irqbase; 107121985Sjhb uint8_t at_intbase; 108121985Sjhb uint8_t *at_imen; 109121985Sjhb}; 110121985Sjhb 111121985Sjhbstruct atpic_intsrc { 112121985Sjhb struct intsrc at_intsrc; 113121985Sjhb inthand_t *at_intr; 114128929Sjhb int at_irq; /* Relative to PIC base. */ 115128929Sjhb enum intr_trigger at_trigger; 116122897Sjhb u_long at_count; 117122897Sjhb u_long at_straycount; 118121985Sjhb}; 119121985Sjhb 120121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 121133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 122121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 123121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 124121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 125169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc); 126121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 127255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled); 128121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 129128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 130128931Sjhb enum intr_polarity pol); 131195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 132121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 133121985Sjhb 134121985Sjhbstatic struct atpic atpics[] = { 135121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 136121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 137121985Sjhb}; 138121985Sjhb 139121985Sjhbstatic struct atpic_intsrc atintrs[] = { 140121985Sjhb INTSRC(0), 141121985Sjhb INTSRC(1), 142121985Sjhb INTSRC(2), 143121985Sjhb INTSRC(3), 144121985Sjhb INTSRC(4), 145121985Sjhb INTSRC(5), 146121985Sjhb INTSRC(6), 147121985Sjhb INTSRC(7), 148121985Sjhb INTSRC(8), 149121985Sjhb INTSRC(9), 150121985Sjhb INTSRC(10), 151121985Sjhb INTSRC(11), 152121985Sjhb INTSRC(12), 153121985Sjhb INTSRC(13), 154121985Sjhb INTSRC(14), 155121985Sjhb INTSRC(15), 156121985Sjhb}; 157121985Sjhb 158129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 159128875Sjhb 160133017Sscottlstatic __inline void 161133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 162133017Sscottl{ 163133017Sscottl 164133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 165133017Sscottl ("%s: mismatched pic", __func__)); 166133017Sscottl#ifndef AUTO_EOI_1 167133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 168133017Sscottl#endif 169133017Sscottl} 170133017Sscottl 171133017Sscottl/* 172133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 173133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 174133017Sscottl */ 175133017Sscottlstatic __inline void 176133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 177133017Sscottl{ 178133017Sscottl 179133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 180133017Sscottl ("%s: mismatched pic", __func__)); 181133017Sscottl#ifndef AUTO_EOI_2 182133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 183133017Sscottl#ifndef AUTO_EOI_1 184133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 185133017Sscottl#endif 186133017Sscottl#endif 187133017Sscottl} 188133017Sscottl 189121985Sjhbstatic void 190121985Sjhbatpic_enable_source(struct intsrc *isrc) 191121985Sjhb{ 192121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 193121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 194121985Sjhb 195177468Sjhb spinlock_enter(); 196128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 197128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 198128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 199128875Sjhb } 200177468Sjhb spinlock_exit(); 201121985Sjhb} 202121985Sjhb 203121985Sjhbstatic void 204133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 205121985Sjhb{ 206121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 207121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 208121985Sjhb 209177468Sjhb spinlock_enter(); 210133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 211133017Sscottl *ap->at_imen |= IMEN_MASK(ai); 212133017Sscottl outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 213133017Sscottl } 214133017Sscottl 215133017Sscottl /* 216133017Sscottl * Take care to call these functions directly instead of through 217133017Sscottl * a function pointer. All of the referenced variables should 218133017Sscottl * still be hot in the cache. 219133017Sscottl */ 220133017Sscottl if (eoi == PIC_EOI) { 221133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 222133017Sscottl _atpic_eoi_master(isrc); 223133017Sscottl else 224133017Sscottl _atpic_eoi_slave(isrc); 225133017Sscottl } 226133017Sscottl 227177468Sjhb spinlock_exit(); 228121985Sjhb} 229121985Sjhb 230121985Sjhbstatic void 231121985Sjhbatpic_eoi_master(struct intsrc *isrc) 232121985Sjhb{ 233121985Sjhb#ifndef AUTO_EOI_1 234177468Sjhb spinlock_enter(); 235133017Sscottl _atpic_eoi_master(isrc); 236177468Sjhb spinlock_exit(); 237121985Sjhb#endif 238121985Sjhb} 239121985Sjhb 240121985Sjhbstatic void 241121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 242121985Sjhb{ 243121985Sjhb#ifndef AUTO_EOI_2 244177468Sjhb spinlock_enter(); 245133017Sscottl _atpic_eoi_slave(isrc); 246177468Sjhb spinlock_exit(); 247121985Sjhb#endif 248121985Sjhb} 249121985Sjhb 250121985Sjhbstatic void 251121985Sjhbatpic_enable_intr(struct intsrc *isrc) 252121985Sjhb{ 253121985Sjhb} 254121985Sjhb 255169391Sjhbstatic void 256169391Sjhbatpic_disable_intr(struct intsrc *isrc) 257169391Sjhb{ 258169391Sjhb} 259169391Sjhb 260169391Sjhb 261121985Sjhbstatic int 262121985Sjhbatpic_vector(struct intsrc *isrc) 263121985Sjhb{ 264121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 265121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 266121985Sjhb 267121985Sjhb return (IRQ(ap, ai)); 268121985Sjhb} 269121985Sjhb 270121985Sjhbstatic int 271121985Sjhbatpic_source_pending(struct intsrc *isrc) 272121985Sjhb{ 273121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 274121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 275121985Sjhb 276128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 277121985Sjhb} 278121985Sjhb 279121985Sjhbstatic void 280255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled) 281121985Sjhb{ 282163219Sjhb struct atpic *ap = (struct atpic *)pic; 283121985Sjhb 284163219Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 285129009Snyan#ifndef PC98 286163219Sjhb if (ap == &atpics[SLAVE] && elcr_found) 287163219Sjhb elcr_resume(); 288129009Snyan#endif 289121985Sjhb} 290121985Sjhb 291128931Sjhbstatic int 292128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 293128931Sjhb enum intr_polarity pol) 294128931Sjhb{ 295128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 296128931Sjhb u_int vector; 297128931Sjhb 298128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 299128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 300128931Sjhb trig = INTR_TRIGGER_EDGE; 301128931Sjhb if (pol == INTR_POLARITY_CONFORM) 302128931Sjhb pol = INTR_POLARITY_HIGH; 303128931Sjhb vector = atpic_vector(isrc); 304128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 305128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 306128931Sjhb printf( 307128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 308128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 309128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 310128931Sjhb return (EINVAL); 311128931Sjhb } 312128931Sjhb 313128931Sjhb /* If there is no change, just return. */ 314128931Sjhb if (ai->at_trigger == trig) 315128931Sjhb return (0); 316128931Sjhb 317129009Snyan#ifdef PC98 318129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 319129009Snyan trig == INTR_TRIGGER_LEVEL) { 320129009Snyan if (bootverbose) 321129009Snyan printf( 322129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 323129009Snyan vector); 324129009Snyan return (EINVAL); 325129009Snyan } 326129009Snyan return (ENXIO); 327129009Snyan#else 328128931Sjhb /* 329128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 330128931Sjhb * that way if asked. At least some ELCR registers ignore setting 331128931Sjhb * these bits as well. 332128931Sjhb */ 333128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 334128931Sjhb trig == INTR_TRIGGER_LEVEL) { 335128931Sjhb if (bootverbose) 336128931Sjhb printf( 337128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 338128931Sjhb vector); 339128931Sjhb return (EINVAL); 340128931Sjhb } 341140451Sjhb if (!elcr_found) { 342128931Sjhb if (bootverbose) 343128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 344128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 345128931Sjhb "level/low"); 346128931Sjhb return (ENXIO); 347128931Sjhb } 348128931Sjhb if (bootverbose) 349128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 350128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 351177468Sjhb spinlock_enter(); 352128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 353128931Sjhb ai->at_trigger = trig; 354177468Sjhb spinlock_exit(); 355128931Sjhb return (0); 356129009Snyan#endif /* PC98 */ 357128931Sjhb} 358128931Sjhb 359195249Sjhbstatic int 360156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 361156124Sjhb{ 362156124Sjhb 363156124Sjhb /* 364156124Sjhb * 8259A's are only used in UP in which case all interrupts always 365156124Sjhb * go to the sole CPU and this function shouldn't even be called. 366156124Sjhb */ 367156124Sjhb panic("%s: bad cookie", __func__); 368156124Sjhb} 369156124Sjhb 370156124Sjhbstatic void 371121985Sjhbi8259_init(struct atpic *pic, int slave) 372121985Sjhb{ 373121985Sjhb int imr_addr; 374121985Sjhb 375121985Sjhb /* Reset the PIC and program with next four bytes. */ 376177468Sjhb spinlock_enter(); 377121985Sjhb#ifdef DEV_MCA 378122692Sjhb /* MCA uses level triggered interrupts. */ 379121985Sjhb if (MCA_system) 380122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 381121985Sjhb else 382121985Sjhb#endif 383122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 384121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 385121985Sjhb 386121985Sjhb /* Start vector. */ 387121985Sjhb outb(imr_addr, pic->at_intbase); 388121985Sjhb 389121985Sjhb /* 390121985Sjhb * Setup slave links. For the master pic, indicate what line 391121985Sjhb * the slave is configured on. For the slave indicate 392121985Sjhb * which line on the master we are connected to. 393121985Sjhb */ 394121985Sjhb if (slave) 395129131Sjhb outb(imr_addr, ICU_SLAVEID); 396121985Sjhb else 397129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 398121985Sjhb 399121985Sjhb /* Set mode. */ 400121985Sjhb if (slave) 401121985Sjhb outb(imr_addr, SLAVE_MODE); 402121985Sjhb else 403121985Sjhb outb(imr_addr, MASTER_MODE); 404121985Sjhb 405121985Sjhb /* Set interrupt enable mask. */ 406121985Sjhb outb(imr_addr, *pic->at_imen); 407121985Sjhb 408121985Sjhb /* Reset is finished, default to IRR on read. */ 409122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 410121985Sjhb 411121985Sjhb#ifndef PC98 412122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 413121985Sjhb if (!slave) 414122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 415121985Sjhb#endif 416177468Sjhb spinlock_exit(); 417121985Sjhb} 418121985Sjhb 419121985Sjhbvoid 420121985Sjhbatpic_startup(void) 421121985Sjhb{ 422122897Sjhb struct atpic_intsrc *ai; 423122897Sjhb int i; 424121985Sjhb 425121985Sjhb /* Start off with all interrupts disabled. */ 426121985Sjhb imen = 0xffff; 427121985Sjhb i8259_init(&atpics[MASTER], 0); 428121985Sjhb i8259_init(&atpics[SLAVE], 1); 429121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 430122897Sjhb 431122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 432128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 433122897Sjhb if (i == ICU_SLAVEID) 434122897Sjhb continue; 435122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 436122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 437122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 438204309Sattilio ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC); 439122897Sjhb } 440128929Sjhb 441128929Sjhb#ifdef DEV_MCA 442128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 443128929Sjhb if (MCA_system) 444128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 445128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 446128929Sjhb else 447128929Sjhb#endif 448128929Sjhb 449129009Snyan#ifdef PC98 450129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 451129009Snyan switch (i) { 452129009Snyan case 0: 453129009Snyan case 1: 454129009Snyan case 7: 455129009Snyan case 8: 456129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 457129009Snyan break; 458129009Snyan default: 459129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 460129009Snyan break; 461129009Snyan } 462129009Snyan#else 463128929Sjhb /* 464128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 465128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 466128929Sjhb * edge triggered and that everything else is level triggered. 467128929Sjhb * We only use the trigger information to reprogram the ELCR if 468128929Sjhb * we have one and as an optimization to avoid masking edge 469128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 470128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 471129095Sjhb * assume level trigger for any interrupt that we aren't sure is 472129095Sjhb * edge triggered. 473128929Sjhb */ 474140451Sjhb if (elcr_found) { 475128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 476128929Sjhb ai->at_trigger = elcr_read_trigger(i); 477128929Sjhb } else { 478128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 479128929Sjhb switch (i) { 480128929Sjhb case 0: 481128929Sjhb case 1: 482128929Sjhb case 2: 483128929Sjhb case 8: 484128929Sjhb case 13: 485128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 486128929Sjhb break; 487128929Sjhb default: 488128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 489128929Sjhb break; 490128929Sjhb } 491128929Sjhb } 492129009Snyan#endif /* PC98 */ 493121985Sjhb} 494121985Sjhb 495121985Sjhbstatic void 496121985Sjhbatpic_init(void *dummy __unused) 497121985Sjhb{ 498128875Sjhb struct atpic_intsrc *ai; 499121985Sjhb int i; 500121985Sjhb 501153136Sjhb /* 502163219Sjhb * Register our PICs, even if we aren't going to use any of their 503163219Sjhb * pins so that they are suspended and resumed. 504163219Sjhb */ 505163219Sjhb if (intr_register_pic(&atpics[0].at_pic) != 0 || 506163219Sjhb intr_register_pic(&atpics[1].at_pic) != 0) 507163219Sjhb panic("Unable to register ATPICs"); 508163219Sjhb 509163219Sjhb /* 510153136Sjhb * If any of the ISA IRQs have an interrupt source already, then 511153136Sjhb * assume that the APICs are being used and don't register any 512153136Sjhb * of our interrupt sources. This makes sure we don't accidentally 513153136Sjhb * use mixed mode. The "accidental" use could otherwise occur on 514153136Sjhb * machines that route the ACPI SCI interrupt to a different ISA 515153136Sjhb * IRQ (at least one machines routes it to IRQ 13) thus disabling 516153136Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 517153136Sjhb * to leak through. We used to depend on this feature for routing 518153136Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 519153136Sjhb */ 520153136Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 521153136Sjhb if (intr_lookup_source(i) != NULL) 522153136Sjhb return; 523153136Sjhb 524121985Sjhb /* Loop through all interrupt sources and add them. */ 525128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 526121985Sjhb if (i == ICU_SLAVEID) 527121985Sjhb continue; 528128875Sjhb intr_register_source(&ai->at_intsrc); 529121985Sjhb } 530121985Sjhb} 531269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL); 532121985Sjhb 533121985Sjhbvoid 534165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame) 535121985Sjhb{ 536121985Sjhb struct intsrc *isrc; 537121985Sjhb 538153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 539153146Sjhb isrc = &atintrs[vector].at_intsrc; 540122898Sjhb 541122898Sjhb /* 542151658Sjhb * If we don't have an event, see if this is a spurious 543122898Sjhb * interrupt. 544122898Sjhb */ 545153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 546122898Sjhb int port, isr; 547122898Sjhb 548122898Sjhb /* 549122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 550122898Sjhb * pending. Reset read register back to IRR when done. 551122898Sjhb */ 552122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 553177468Sjhb spinlock_enter(); 554122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 555122898Sjhb isr = inb(port); 556122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 557177468Sjhb spinlock_exit(); 558129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 559122898Sjhb return; 560122898Sjhb } 561165302Skmacy intr_execute_handlers(isrc, frame); 562121985Sjhb} 563121985Sjhb 564121985Sjhb#ifdef DEV_ISA 565121985Sjhb/* 566121985Sjhb * Bus attachment for the ISA PIC. 567121985Sjhb */ 568121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 569121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 570121985Sjhb { 0 } 571121985Sjhb}; 572121985Sjhb 573121985Sjhbstatic int 574121985Sjhbatpic_probe(device_t dev) 575121985Sjhb{ 576121985Sjhb int result; 577121985Sjhb 578121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 579121985Sjhb if (result <= 0) 580121985Sjhb device_quiet(dev); 581121985Sjhb return (result); 582121985Sjhb} 583121985Sjhb 584121985Sjhb/* 585121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 586121985Sjhb * between the two PIC components. If we're using the APIC, however, 587121985Sjhb * this may not be the case, and as such we should free the resource. 588121985Sjhb * (XXX untested) 589121985Sjhb * 590121985Sjhb * The generic ISA attachment code will handle allocating any other resources 591121985Sjhb * that we don't explicitly claim here. 592121985Sjhb */ 593121985Sjhbstatic int 594121985Sjhbatpic_attach(device_t dev) 595121985Sjhb{ 596121985Sjhb struct resource *res; 597121985Sjhb int rid; 598121985Sjhb 599121985Sjhb /* Try to allocate our IRQ and then free it. */ 600121985Sjhb rid = 0; 601127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 602121985Sjhb if (res != NULL) 603121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 604121985Sjhb return (0); 605121985Sjhb} 606121985Sjhb 607121985Sjhbstatic device_method_t atpic_methods[] = { 608121985Sjhb /* Device interface */ 609121985Sjhb DEVMETHOD(device_probe, atpic_probe), 610121985Sjhb DEVMETHOD(device_attach, atpic_attach), 611121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 612121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 613121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 614121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 615121985Sjhb { 0, 0 } 616121985Sjhb}; 617121985Sjhb 618121985Sjhbstatic driver_t atpic_driver = { 619121985Sjhb "atpic", 620121985Sjhb atpic_methods, 621121985Sjhb 1, /* no softc */ 622121985Sjhb}; 623121985Sjhb 624121985Sjhbstatic devclass_t atpic_devclass; 625121985Sjhb 626121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 627122051Snyan#ifndef PC98 628121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 629122051Snyan#endif 630121985Sjhb 631121985Sjhb/* 632121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 633121985Sjhb * and is only suitable for use at probe time. 634121985Sjhb */ 635121985Sjhbintrmask_t 636121985Sjhbisa_irq_pending(void) 637121985Sjhb{ 638121985Sjhb u_char irr1; 639121985Sjhb u_char irr2; 640121985Sjhb 641121985Sjhb irr1 = inb(IO_ICU1); 642121985Sjhb irr2 = inb(IO_ICU2); 643121985Sjhb return ((irr2 << 8) | irr1); 644121985Sjhb} 645121985Sjhb#endif /* DEV_ISA */ 646