1121985Sjhb/*- 2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121985Sjhb * 4121985Sjhb * Redistribution and use in source and binary forms, with or without 5121985Sjhb * modification, are permitted provided that the following conditions 6121985Sjhb * are met: 7121985Sjhb * 1. Redistributions of source code must retain the above copyright 8121985Sjhb * notice, this list of conditions and the following disclaimer. 9121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright 10121985Sjhb * notice, this list of conditions and the following disclaimer in the 11121985Sjhb * documentation and/or other materials provided with the distribution. 12121985Sjhb * 13121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16121985Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23121985Sjhb * SUCH DAMAGE. 24121985Sjhb */ 25121985Sjhb 26121985Sjhb/* 27121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 28121985Sjhb */ 29121985Sjhb 30121985Sjhb#include <sys/cdefs.h> 31121985Sjhb__FBSDID("$FreeBSD: stable/11/sys/x86/isa/atpic.c 367457 2020-11-07 18:10:59Z dim $"); 32121985Sjhb 33121985Sjhb#include "opt_auto_eoi.h" 34121985Sjhb#include "opt_isa.h" 35277285Simp#include "opt_mca.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 57263379Simp#include <isa/isareg.h> 58122051Snyan#endif 59121985Sjhb#include <isa/isavar.h> 60277311Simp#ifdef DEV_MCA 61277311Simp#include <i386/bios/mca_machdep.h> 62277311Simp#endif 63121985Sjhb 64204309Sattilio#ifdef __amd64__ 65204309Sattilio#define SDT_ATPIC SDT_SYSIGT 66204309Sattilio#define GSEL_ATPIC 0 67204309Sattilio#else 68204309Sattilio#define SDT_ATPIC SDT_SYS386IGT 69204309Sattilio#define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL) 70204309Sattilio#endif 71204309Sattilio 72121985Sjhb#define MASTER 0 73121985Sjhb#define SLAVE 1 74121985Sjhb 75339928Sjhb#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 76339928Sjhb 77128875Sjhb#define NUM_ISA_IRQS 16 78128875Sjhb 79121985Sjhbstatic void atpic_init(void *dummy); 80121985Sjhb 81121985Sjhbinthand_t 82121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 83121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 84121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 85121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 86121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 87121985Sjhb IDTVEC(atpic_intr15); 88329462Skib/* XXXKIB i386 uses stubs until pti comes */ 89329462Skibinthand_t 90329462Skib IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti), 91329462Skib IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti), 92329462Skib IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti), 93329462Skib IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti), 94329462Skib IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti), 95329462Skib IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti), 96329462Skib IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti), 97329462Skib IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti); 98121985Sjhb 99121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 100121985Sjhb 101339928Sjhb#define ATPIC(io, base, eoi) { \ 102339928Sjhb .at_pic = { \ 103340016Sjhb .pic_register_sources = atpic_register_sources, \ 104339928Sjhb .pic_enable_source = atpic_enable_source, \ 105339928Sjhb .pic_disable_source = atpic_disable_source, \ 106339928Sjhb .pic_eoi_source = (eoi), \ 107339928Sjhb .pic_enable_intr = atpic_enable_intr, \ 108339928Sjhb .pic_disable_intr = atpic_disable_intr, \ 109339928Sjhb .pic_vector = atpic_vector, \ 110339928Sjhb .pic_source_pending = atpic_source_pending, \ 111339928Sjhb .pic_resume = atpic_resume, \ 112339928Sjhb .pic_config_intr = atpic_config_intr, \ 113339928Sjhb .pic_assign_cpu = atpic_assign_cpu \ 114339928Sjhb }, \ 115339928Sjhb .at_ioaddr = (io), \ 116339928Sjhb .at_irqbase = (base), \ 117339928Sjhb .at_intbase = IDT_IO_INTS + (base), \ 118339928Sjhb .at_imen = 0xff, \ 119339928Sjhb } 120121985Sjhb 121121985Sjhb#define INTSRC(irq) \ 122128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 123329462Skib IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 } 124121985Sjhb 125121985Sjhbstruct atpic { 126121985Sjhb struct pic at_pic; 127121985Sjhb int at_ioaddr; 128121985Sjhb int at_irqbase; 129121985Sjhb uint8_t at_intbase; 130339928Sjhb uint8_t at_imen; 131121985Sjhb}; 132121985Sjhb 133121985Sjhbstruct atpic_intsrc { 134121985Sjhb struct intsrc at_intsrc; 135329462Skib inthand_t *at_intr, *at_intr_pti; 136128929Sjhb int at_irq; /* Relative to PIC base. */ 137128929Sjhb enum intr_trigger at_trigger; 138122897Sjhb u_long at_count; 139122897Sjhb u_long at_straycount; 140121985Sjhb}; 141121985Sjhb 142340016Sjhbstatic void atpic_register_sources(struct pic *pic); 143121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 144133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi); 145121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 146121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 147121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 148169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc); 149121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 150255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled); 151121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 152128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 153128931Sjhb enum intr_polarity pol); 154195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 155121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 156121985Sjhb 157121985Sjhbstatic struct atpic atpics[] = { 158339928Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master), 159339928Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave) 160121985Sjhb}; 161121985Sjhb 162121985Sjhbstatic struct atpic_intsrc atintrs[] = { 163121985Sjhb INTSRC(0), 164121985Sjhb INTSRC(1), 165121985Sjhb INTSRC(2), 166121985Sjhb INTSRC(3), 167121985Sjhb INTSRC(4), 168121985Sjhb INTSRC(5), 169121985Sjhb INTSRC(6), 170121985Sjhb INTSRC(7), 171121985Sjhb INTSRC(8), 172121985Sjhb INTSRC(9), 173121985Sjhb INTSRC(10), 174121985Sjhb INTSRC(11), 175121985Sjhb INTSRC(12), 176121985Sjhb INTSRC(13), 177121985Sjhb INTSRC(14), 178121985Sjhb INTSRC(15), 179121985Sjhb}; 180121985Sjhb 181298308SpfgCTASSERT(nitems(atintrs) == NUM_ISA_IRQS); 182128875Sjhb 183133017Sscottlstatic __inline void 184133017Sscottl_atpic_eoi_master(struct intsrc *isrc) 185133017Sscottl{ 186133017Sscottl 187133017Sscottl KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 188133017Sscottl ("%s: mismatched pic", __func__)); 189133017Sscottl#ifndef AUTO_EOI_1 190133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 191133017Sscottl#endif 192133017Sscottl} 193133017Sscottl 194133017Sscottl/* 195133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works. 196133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it. 197133017Sscottl */ 198133017Sscottlstatic __inline void 199133017Sscottl_atpic_eoi_slave(struct intsrc *isrc) 200133017Sscottl{ 201133017Sscottl 202133017Sscottl KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 203133017Sscottl ("%s: mismatched pic", __func__)); 204133017Sscottl#ifndef AUTO_EOI_2 205133017Sscottl outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 206133017Sscottl#ifndef AUTO_EOI_1 207133017Sscottl outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 208133017Sscottl#endif 209133017Sscottl#endif 210133017Sscottl} 211133017Sscottl 212121985Sjhbstatic void 213340016Sjhbatpic_register_sources(struct pic *pic) 214340016Sjhb{ 215340016Sjhb struct atpic *ap = (struct atpic *)pic; 216340016Sjhb struct atpic_intsrc *ai; 217340016Sjhb int i; 218340016Sjhb 219340016Sjhb /* 220340016Sjhb * If any of the ISA IRQs have an interrupt source already, then 221340016Sjhb * assume that the I/O APICs are being used and don't register any 222340016Sjhb * of our interrupt sources. This makes sure we don't accidentally 223340016Sjhb * use mixed mode. The "accidental" use could otherwise occur on 224340016Sjhb * machines that route the ACPI SCI interrupt to a different ISA 225340016Sjhb * IRQ (at least one machine routes it to IRQ 13) thus disabling 226340016Sjhb * that APIC ISA routing and allowing the ATPIC source for that IRQ 227340016Sjhb * to leak through. We used to depend on this feature for routing 228340016Sjhb * IRQ0 via mixed mode, but now we don't use mixed mode at all. 229340016Sjhb * 230340016Sjhb * To avoid the slave not register sources after the master 231340016Sjhb * registers its sources, register all IRQs when this function is 232340016Sjhb * called on the master. 233340016Sjhb */ 234340016Sjhb if (ap != &atpics[MASTER]) 235340016Sjhb return; 236340016Sjhb for (i = 0; i < NUM_ISA_IRQS; i++) 237340016Sjhb if (intr_lookup_source(i) != NULL) 238340016Sjhb return; 239340016Sjhb 240340016Sjhb /* Loop through all interrupt sources and add them. */ 241340016Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 242340016Sjhb if (i == ICU_SLAVEID) 243340016Sjhb continue; 244340016Sjhb intr_register_source(&ai->at_intsrc); 245340016Sjhb } 246340016Sjhb} 247340016Sjhb 248340016Sjhbstatic void 249121985Sjhbatpic_enable_source(struct intsrc *isrc) 250121985Sjhb{ 251121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 252121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 253121985Sjhb 254177468Sjhb spinlock_enter(); 255339928Sjhb if (ap->at_imen & IMEN_MASK(ai)) { 256339928Sjhb ap->at_imen &= ~IMEN_MASK(ai); 257339928Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen); 258128875Sjhb } 259177468Sjhb spinlock_exit(); 260121985Sjhb} 261121985Sjhb 262121985Sjhbstatic void 263133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi) 264121985Sjhb{ 265121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 266121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 267121985Sjhb 268177468Sjhb spinlock_enter(); 269133017Sscottl if (ai->at_trigger != INTR_TRIGGER_EDGE) { 270339928Sjhb ap->at_imen |= IMEN_MASK(ai); 271339928Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen); 272133017Sscottl } 273133017Sscottl 274133017Sscottl /* 275133017Sscottl * Take care to call these functions directly instead of through 276133017Sscottl * a function pointer. All of the referenced variables should 277133017Sscottl * still be hot in the cache. 278133017Sscottl */ 279133017Sscottl if (eoi == PIC_EOI) { 280133017Sscottl if (isrc->is_pic == &atpics[MASTER].at_pic) 281133017Sscottl _atpic_eoi_master(isrc); 282133017Sscottl else 283133017Sscottl _atpic_eoi_slave(isrc); 284133017Sscottl } 285133017Sscottl 286177468Sjhb spinlock_exit(); 287121985Sjhb} 288121985Sjhb 289121985Sjhbstatic void 290121985Sjhbatpic_eoi_master(struct intsrc *isrc) 291121985Sjhb{ 292121985Sjhb#ifndef AUTO_EOI_1 293177468Sjhb spinlock_enter(); 294133017Sscottl _atpic_eoi_master(isrc); 295177468Sjhb spinlock_exit(); 296121985Sjhb#endif 297121985Sjhb} 298121985Sjhb 299121985Sjhbstatic void 300121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 301121985Sjhb{ 302121985Sjhb#ifndef AUTO_EOI_2 303177468Sjhb spinlock_enter(); 304133017Sscottl _atpic_eoi_slave(isrc); 305177468Sjhb spinlock_exit(); 306121985Sjhb#endif 307121985Sjhb} 308121985Sjhb 309121985Sjhbstatic void 310121985Sjhbatpic_enable_intr(struct intsrc *isrc) 311121985Sjhb{ 312121985Sjhb} 313121985Sjhb 314169391Sjhbstatic void 315169391Sjhbatpic_disable_intr(struct intsrc *isrc) 316169391Sjhb{ 317169391Sjhb} 318169391Sjhb 319169391Sjhb 320121985Sjhbstatic int 321121985Sjhbatpic_vector(struct intsrc *isrc) 322121985Sjhb{ 323121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 324121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 325121985Sjhb 326121985Sjhb return (IRQ(ap, ai)); 327121985Sjhb} 328121985Sjhb 329121985Sjhbstatic int 330121985Sjhbatpic_source_pending(struct intsrc *isrc) 331121985Sjhb{ 332121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 333121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 334121985Sjhb 335128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 336121985Sjhb} 337121985Sjhb 338121985Sjhbstatic void 339255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled) 340121985Sjhb{ 341163219Sjhb struct atpic *ap = (struct atpic *)pic; 342121985Sjhb 343163219Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 344129009Snyan#ifndef PC98 345163219Sjhb if (ap == &atpics[SLAVE] && elcr_found) 346163219Sjhb elcr_resume(); 347129009Snyan#endif 348121985Sjhb} 349121985Sjhb 350128931Sjhbstatic int 351128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 352128931Sjhb enum intr_polarity pol) 353128931Sjhb{ 354128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 355128931Sjhb u_int vector; 356128931Sjhb 357128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 358128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 359128931Sjhb trig = INTR_TRIGGER_EDGE; 360128931Sjhb if (pol == INTR_POLARITY_CONFORM) 361128931Sjhb pol = INTR_POLARITY_HIGH; 362128931Sjhb vector = atpic_vector(isrc); 363128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 364128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 365128931Sjhb printf( 366128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 367128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 368128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 369128931Sjhb return (EINVAL); 370128931Sjhb } 371128931Sjhb 372128931Sjhb /* If there is no change, just return. */ 373128931Sjhb if (ai->at_trigger == trig) 374128931Sjhb return (0); 375128931Sjhb 376129009Snyan#ifdef PC98 377129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 378129009Snyan trig == INTR_TRIGGER_LEVEL) { 379129009Snyan if (bootverbose) 380129009Snyan printf( 381129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 382129009Snyan vector); 383129009Snyan return (EINVAL); 384129009Snyan } 385129009Snyan return (ENXIO); 386129009Snyan#else 387128931Sjhb /* 388128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 389128931Sjhb * that way if asked. At least some ELCR registers ignore setting 390128931Sjhb * these bits as well. 391128931Sjhb */ 392128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 393128931Sjhb trig == INTR_TRIGGER_LEVEL) { 394128931Sjhb if (bootverbose) 395128931Sjhb printf( 396128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 397128931Sjhb vector); 398128931Sjhb return (EINVAL); 399128931Sjhb } 400140451Sjhb if (!elcr_found) { 401128931Sjhb if (bootverbose) 402128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 403128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 404128931Sjhb "level/low"); 405128931Sjhb return (ENXIO); 406128931Sjhb } 407128931Sjhb if (bootverbose) 408128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 409128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 410177468Sjhb spinlock_enter(); 411128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 412128931Sjhb ai->at_trigger = trig; 413177468Sjhb spinlock_exit(); 414128931Sjhb return (0); 415129009Snyan#endif /* PC98 */ 416128931Sjhb} 417128931Sjhb 418195249Sjhbstatic int 419156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 420156124Sjhb{ 421156124Sjhb 422156124Sjhb /* 423156124Sjhb * 8259A's are only used in UP in which case all interrupts always 424156124Sjhb * go to the sole CPU and this function shouldn't even be called. 425156124Sjhb */ 426156124Sjhb panic("%s: bad cookie", __func__); 427156124Sjhb} 428156124Sjhb 429156124Sjhbstatic void 430121985Sjhbi8259_init(struct atpic *pic, int slave) 431121985Sjhb{ 432121985Sjhb int imr_addr; 433121985Sjhb 434121985Sjhb /* Reset the PIC and program with next four bytes. */ 435177468Sjhb spinlock_enter(); 436121985Sjhb#ifdef DEV_MCA 437122692Sjhb /* MCA uses level triggered interrupts. */ 438121985Sjhb if (MCA_system) 439122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 440121985Sjhb else 441121985Sjhb#endif 442122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 443121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 444121985Sjhb 445121985Sjhb /* Start vector. */ 446121985Sjhb outb(imr_addr, pic->at_intbase); 447121985Sjhb 448121985Sjhb /* 449121985Sjhb * Setup slave links. For the master pic, indicate what line 450121985Sjhb * the slave is configured on. For the slave indicate 451121985Sjhb * which line on the master we are connected to. 452121985Sjhb */ 453121985Sjhb if (slave) 454129131Sjhb outb(imr_addr, ICU_SLAVEID); 455121985Sjhb else 456129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 457121985Sjhb 458121985Sjhb /* Set mode. */ 459121985Sjhb if (slave) 460121985Sjhb outb(imr_addr, SLAVE_MODE); 461121985Sjhb else 462121985Sjhb outb(imr_addr, MASTER_MODE); 463121985Sjhb 464121985Sjhb /* Set interrupt enable mask. */ 465339928Sjhb outb(imr_addr, pic->at_imen); 466121985Sjhb 467121985Sjhb /* Reset is finished, default to IRR on read. */ 468122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 469121985Sjhb 470121985Sjhb#ifndef PC98 471122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 472121985Sjhb if (!slave) 473122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 474121985Sjhb#endif 475177468Sjhb spinlock_exit(); 476121985Sjhb} 477121985Sjhb 478121985Sjhbvoid 479121985Sjhbatpic_startup(void) 480121985Sjhb{ 481122897Sjhb struct atpic_intsrc *ai; 482122897Sjhb int i; 483121985Sjhb 484121985Sjhb /* Start off with all interrupts disabled. */ 485121985Sjhb i8259_init(&atpics[MASTER], 0); 486121985Sjhb i8259_init(&atpics[SLAVE], 1); 487121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 488122897Sjhb 489122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 490128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 491122897Sjhb if (i == ICU_SLAVEID) 492122897Sjhb continue; 493122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 494122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 495122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 496329462Skib ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC, 497329462Skib SEL_KPL, GSEL_ATPIC); 498122897Sjhb } 499128929Sjhb 500128929Sjhb#ifdef DEV_MCA 501128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 502128929Sjhb if (MCA_system) 503128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 504128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 505128929Sjhb else 506128929Sjhb#endif 507128929Sjhb 508129009Snyan#ifdef PC98 509129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 510129009Snyan switch (i) { 511129009Snyan case 0: 512129009Snyan case 1: 513129009Snyan case 7: 514129009Snyan case 8: 515129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 516129009Snyan break; 517129009Snyan default: 518129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 519129009Snyan break; 520129009Snyan } 521129009Snyan#else 522128929Sjhb /* 523128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 524128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 525128929Sjhb * edge triggered and that everything else is level triggered. 526128929Sjhb * We only use the trigger information to reprogram the ELCR if 527128929Sjhb * we have one and as an optimization to avoid masking edge 528128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 529128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 530129095Sjhb * assume level trigger for any interrupt that we aren't sure is 531129095Sjhb * edge triggered. 532128929Sjhb */ 533140451Sjhb if (elcr_found) { 534128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 535128929Sjhb ai->at_trigger = elcr_read_trigger(i); 536128929Sjhb } else { 537128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 538128929Sjhb switch (i) { 539128929Sjhb case 0: 540128929Sjhb case 1: 541128929Sjhb case 2: 542128929Sjhb case 8: 543128929Sjhb case 13: 544128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 545128929Sjhb break; 546128929Sjhb default: 547128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 548128929Sjhb break; 549128929Sjhb } 550128929Sjhb } 551129009Snyan#endif /* PC98 */ 552121985Sjhb} 553121985Sjhb 554121985Sjhbstatic void 555121985Sjhbatpic_init(void *dummy __unused) 556121985Sjhb{ 557121985Sjhb 558153136Sjhb /* 559163219Sjhb * Register our PICs, even if we aren't going to use any of their 560163219Sjhb * pins so that they are suspended and resumed. 561163219Sjhb */ 562163219Sjhb if (intr_register_pic(&atpics[0].at_pic) != 0 || 563163219Sjhb intr_register_pic(&atpics[1].at_pic) != 0) 564163219Sjhb panic("Unable to register ATPICs"); 565163219Sjhb 566340016Sjhb if (num_io_irqs == 0) 567340016Sjhb num_io_irqs = NUM_ISA_IRQS; 568121985Sjhb} 569269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL); 570121985Sjhb 571121985Sjhbvoid 572165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame) 573121985Sjhb{ 574121985Sjhb struct intsrc *isrc; 575121985Sjhb 576153242Sjhb KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 577153146Sjhb isrc = &atintrs[vector].at_intsrc; 578122898Sjhb 579122898Sjhb /* 580151658Sjhb * If we don't have an event, see if this is a spurious 581122898Sjhb * interrupt. 582122898Sjhb */ 583153146Sjhb if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 584122898Sjhb int port, isr; 585122898Sjhb 586122898Sjhb /* 587122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 588122898Sjhb * pending. Reset read register back to IRR when done. 589122898Sjhb */ 590122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 591177468Sjhb spinlock_enter(); 592122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 593122898Sjhb isr = inb(port); 594122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 595177468Sjhb spinlock_exit(); 596129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 597122898Sjhb return; 598122898Sjhb } 599165302Skmacy intr_execute_handlers(isrc, frame); 600121985Sjhb} 601121985Sjhb 602121985Sjhb#ifdef DEV_ISA 603121985Sjhb/* 604121985Sjhb * Bus attachment for the ISA PIC. 605121985Sjhb */ 606121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 607121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 608121985Sjhb { 0 } 609121985Sjhb}; 610121985Sjhb 611121985Sjhbstatic int 612121985Sjhbatpic_probe(device_t dev) 613121985Sjhb{ 614121985Sjhb int result; 615121985Sjhb 616121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 617121985Sjhb if (result <= 0) 618121985Sjhb device_quiet(dev); 619121985Sjhb return (result); 620121985Sjhb} 621121985Sjhb 622121985Sjhb/* 623121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 624121985Sjhb * between the two PIC components. If we're using the APIC, however, 625121985Sjhb * this may not be the case, and as such we should free the resource. 626121985Sjhb * (XXX untested) 627121985Sjhb * 628121985Sjhb * The generic ISA attachment code will handle allocating any other resources 629121985Sjhb * that we don't explicitly claim here. 630121985Sjhb */ 631121985Sjhbstatic int 632121985Sjhbatpic_attach(device_t dev) 633121985Sjhb{ 634121985Sjhb struct resource *res; 635121985Sjhb int rid; 636121985Sjhb 637121985Sjhb /* Try to allocate our IRQ and then free it. */ 638121985Sjhb rid = 0; 639127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 640121985Sjhb if (res != NULL) 641121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 642121985Sjhb return (0); 643121985Sjhb} 644121985Sjhb 645121985Sjhbstatic device_method_t atpic_methods[] = { 646121985Sjhb /* Device interface */ 647121985Sjhb DEVMETHOD(device_probe, atpic_probe), 648121985Sjhb DEVMETHOD(device_attach, atpic_attach), 649121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 650121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 651121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 652121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 653121985Sjhb { 0, 0 } 654121985Sjhb}; 655121985Sjhb 656121985Sjhbstatic driver_t atpic_driver = { 657121985Sjhb "atpic", 658121985Sjhb atpic_methods, 659121985Sjhb 1, /* no softc */ 660121985Sjhb}; 661121985Sjhb 662121985Sjhbstatic devclass_t atpic_devclass; 663121985Sjhb 664121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 665122051Snyan#ifndef PC98 666121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 667122051Snyan#endif 668121985Sjhb 669121985Sjhb/* 670121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 671121985Sjhb * and is only suitable for use at probe time. 672121985Sjhb */ 673121985Sjhbintrmask_t 674121985Sjhbisa_irq_pending(void) 675121985Sjhb{ 676121985Sjhb u_char irr1; 677121985Sjhb u_char irr2; 678121985Sjhb 679121985Sjhb irr1 = inb(IO_ICU1); 680121985Sjhb irr2 = inb(IO_ICU2); 681121985Sjhb return ((irr2 << 8) | irr1); 682121985Sjhb} 683121985Sjhb#endif /* DEV_ISA */ 684