atpic.c revision 122051
1121985Sjhb/*- 2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121985Sjhb * All rights reserved. 4121985Sjhb * 5121985Sjhb * Redistribution and use in source and binary forms, with or without 6121985Sjhb * modification, are permitted provided that the following conditions 7121985Sjhb * are met: 8121985Sjhb * 1. Redistributions of source code must retain the above copyright 9121985Sjhb * notice, this list of conditions and the following disclaimer. 10121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121985Sjhb * notice, this list of conditions and the following disclaimer in the 12121985Sjhb * documentation and/or other materials provided with the distribution. 13121985Sjhb * 3. Neither the name of the author nor the names of any co-contributors 14121985Sjhb * may be used to endorse or promote products derived from this software 15121985Sjhb * without specific prior written permission. 16121985Sjhb * 17121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121985Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121985Sjhb * SUCH DAMAGE. 28121985Sjhb */ 29121985Sjhb 30121985Sjhb/* 31121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 32121985Sjhb */ 33121985Sjhb 34121985Sjhb#include <sys/cdefs.h> 35121985Sjhb__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 122051 2003-11-04 13:13:04Z nyan $"); 36121985Sjhb 37121985Sjhb#include "opt_auto_eoi.h" 38121985Sjhb#include "opt_isa.h" 39121985Sjhb 40121985Sjhb#include <sys/param.h> 41121985Sjhb#include <sys/systm.h> 42121985Sjhb#include <sys/bus.h> 43121985Sjhb#include <sys/interrupt.h> 44121985Sjhb#include <sys/kernel.h> 45121985Sjhb#include <sys/lock.h> 46121985Sjhb#include <sys/mutex.h> 47121985Sjhb 48121985Sjhb#include <machine/cpufunc.h> 49121985Sjhb#include <machine/frame.h> 50121985Sjhb#include <machine/intr_machdep.h> 51121985Sjhb#include <machine/md_var.h> 52121985Sjhb#include <machine/resource.h> 53121985Sjhb#include <machine/segments.h> 54121985Sjhb 55121985Sjhb#include <i386/isa/icu.h> 56122051Snyan#ifdef PC98 57122051Snyan#include <pc98/pc98/pc98.h> 58122051Snyan#else 59121985Sjhb#include <i386/isa/isa.h> 60122051Snyan#endif 61121985Sjhb#include <isa/isavar.h> 62121985Sjhb 63121985Sjhb#define MASTER 0 64121985Sjhb#define SLAVE 1 65121985Sjhb 66121985Sjhb/* XXX: Magic numbers */ 67121985Sjhb#ifdef PC98 68121985Sjhb#ifdef AUTO_EOI_1 69121985Sjhb#define MASTER_MODE 0x1f /* Master auto EOI, 8086 mode */ 70121985Sjhb#else 71121985Sjhb#define MASTER_MODE 0x1d /* Master 8086 mode */ 72121985Sjhb#endif 73121985Sjhb#define SLAVE_MODE 9 /* 8086 mode */ 74121985Sjhb#else /* IBM-PC */ 75121985Sjhb#ifdef AUTO_EOI_1 76121985Sjhb#define MASTER_MODE (2 | 1) /* Auto EOI, 8086 mode */ 77121985Sjhb#else 78121985Sjhb#define MASTER_MODE 1 /* 8086 mode */ 79121985Sjhb#endif 80121985Sjhb#ifdef AUTO_EOI_2 81121985Sjhb#define SLAVE_MODE (2 | 1) /* Auto EOI, 8086 mode */ 82121985Sjhb#else 83121985Sjhb#define SLAVE_MODE 1 /* 8086 mode */ 84121985Sjhb#endif 85121985Sjhb#endif /* PC98 */ 86121985Sjhb 87121985Sjhbstatic void atpic_init(void *dummy); 88121985Sjhb 89121985Sjhbunsigned int imen; /* XXX */ 90121985Sjhb 91121985Sjhbinthand_t 92121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 93121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 94121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 95121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 96121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 97121985Sjhb IDTVEC(atpic_intr15); 98121985Sjhb 99121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 100121985Sjhb 101121985Sjhb#define ATPIC(io, base, eoi, imenptr) \ 102121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 103121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 104121985Sjhb atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) } 105121985Sjhb 106121985Sjhb#define INTSRC(irq) \ 107121985Sjhb { { &atpics[(irq) / 8].at_pic }, (irq) % 8, \ 108121985Sjhb IDTVEC(atpic_intr ## irq ) } 109121985Sjhb 110121985Sjhbstruct atpic { 111121985Sjhb struct pic at_pic; 112121985Sjhb int at_ioaddr; 113121985Sjhb int at_irqbase; 114121985Sjhb uint8_t at_intbase; 115121985Sjhb uint8_t *at_imen; 116121985Sjhb}; 117121985Sjhb 118121985Sjhbstruct atpic_intsrc { 119121985Sjhb struct intsrc at_intsrc; 120121985Sjhb int at_irq; /* Relative to PIC base. */ 121121985Sjhb inthand_t *at_intr; 122121985Sjhb}; 123121985Sjhb 124121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 125121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 126121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 127121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 128121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 129121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 130121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 131121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 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 158121985Sjhbstatic void 159121985Sjhbatpic_enable_source(struct intsrc *isrc) 160121985Sjhb{ 161121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 162121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 163121985Sjhb 164121985Sjhb mtx_lock_spin(&icu_lock); 165121985Sjhb *ap->at_imen &= ~(1 << ai->at_irq); 166121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 167121985Sjhb mtx_unlock_spin(&icu_lock); 168121985Sjhb} 169121985Sjhb 170121985Sjhbstatic void 171121985Sjhbatpic_disable_source(struct intsrc *isrc) 172121985Sjhb{ 173121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 174121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 175121985Sjhb 176121985Sjhb mtx_lock_spin(&icu_lock); 177121985Sjhb *ap->at_imen |= (1 << ai->at_irq); 178121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 179121985Sjhb mtx_unlock_spin(&icu_lock); 180121985Sjhb} 181121985Sjhb 182121985Sjhbstatic void 183121985Sjhbatpic_eoi_master(struct intsrc *isrc) 184121985Sjhb{ 185121985Sjhb 186121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 187121985Sjhb ("%s: mismatched pic", __func__)); 188121985Sjhb#ifndef AUTO_EOI_1 189121985Sjhb mtx_lock_spin(&icu_lock); 190121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 191121985Sjhb mtx_unlock_spin(&icu_lock); 192121985Sjhb#endif 193121985Sjhb} 194121985Sjhb 195121985Sjhbstatic void 196121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 197121985Sjhb{ 198121985Sjhb 199121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 200121985Sjhb ("%s: mismatched pic", __func__)); 201121985Sjhb#ifndef AUTO_EOI_2 202121985Sjhb mtx_lock_spin(&icu_lock); 203121985Sjhb outb(atpics[SLAVE].at_ioaddr, ICU_EOI); 204121985Sjhb#ifndef AUTO_EOI_1 205121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 206121985Sjhb#endif 207121985Sjhb mtx_unlock_spin(&icu_lock); 208121985Sjhb#endif 209121985Sjhb} 210121985Sjhb 211121985Sjhbstatic void 212121985Sjhbatpic_enable_intr(struct intsrc *isrc) 213121985Sjhb{ 214121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 215121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 216121985Sjhb register_t eflags; 217121985Sjhb 218121985Sjhb mtx_lock_spin(&icu_lock); 219121985Sjhb eflags = intr_disable(); 220121985Sjhb setidt(ap->at_intbase + ai->at_irq, ai->at_intr, SDT_SYS386IGT, 221121985Sjhb SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 222121985Sjhb intr_restore(eflags); 223121985Sjhb mtx_unlock_spin(&icu_lock); 224121985Sjhb} 225121985Sjhb 226121985Sjhbstatic int 227121985Sjhbatpic_vector(struct intsrc *isrc) 228121985Sjhb{ 229121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 230121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 231121985Sjhb 232121985Sjhb return (IRQ(ap, ai)); 233121985Sjhb} 234121985Sjhb 235121985Sjhbstatic int 236121985Sjhbatpic_source_pending(struct intsrc *isrc) 237121985Sjhb{ 238121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 239121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 240121985Sjhb 241121985Sjhb return (inb(ap->at_ioaddr) & (1 << ai->at_irq)); 242121985Sjhb} 243121985Sjhb 244121985Sjhbstatic void 245121985Sjhbatpic_resume(struct intsrc *isrc) 246121985Sjhb{ 247121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 248121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 249121985Sjhb 250121985Sjhb if (ai->at_irq == 0) 251121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 252121985Sjhb} 253121985Sjhb 254121985Sjhbstatic void 255121985Sjhbi8259_init(struct atpic *pic, int slave) 256121985Sjhb{ 257121985Sjhb int imr_addr; 258121985Sjhb 259121985Sjhb /* Reset the PIC and program with next four bytes. */ 260121985Sjhb mtx_lock_spin(&icu_lock); 261121985Sjhb#ifdef DEV_MCA 262121985Sjhb if (MCA_system) 263121985Sjhb outb(pic->at_ioaddr, 0x19); 264121985Sjhb else 265121985Sjhb#endif 266121985Sjhb outb(pic->at_ioaddr, 0x11); 267121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 268121985Sjhb 269121985Sjhb /* Start vector. */ 270121985Sjhb outb(imr_addr, pic->at_intbase); 271121985Sjhb 272121985Sjhb /* 273121985Sjhb * Setup slave links. For the master pic, indicate what line 274121985Sjhb * the slave is configured on. For the slave indicate 275121985Sjhb * which line on the master we are connected to. 276121985Sjhb */ 277121985Sjhb if (slave) 278121985Sjhb outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ 279121985Sjhb else 280121985Sjhb outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ 281121985Sjhb 282121985Sjhb /* Set mode. */ 283121985Sjhb if (slave) 284121985Sjhb outb(imr_addr, SLAVE_MODE); 285121985Sjhb else 286121985Sjhb outb(imr_addr, MASTER_MODE); 287121985Sjhb 288121985Sjhb /* Set interrupt enable mask. */ 289121985Sjhb outb(imr_addr, *pic->at_imen); 290121985Sjhb 291121985Sjhb /* Reset is finished, default to IRR on read. */ 292121985Sjhb outb(pic->at_ioaddr, 0x0a); 293121985Sjhb 294121985Sjhb#ifndef PC98 295121985Sjhb /* Set priority order to 3-7, 0-2 (com2 first). */ 296121985Sjhb if (!slave) 297121985Sjhb outb(pic->at_ioaddr, 0xc0 | (3 - 1)); 298121985Sjhb#endif 299121985Sjhb mtx_unlock_spin(&icu_lock); 300121985Sjhb} 301121985Sjhb 302121985Sjhbvoid 303121985Sjhbatpic_startup(void) 304121985Sjhb{ 305121985Sjhb 306121985Sjhb /* Start off with all interrupts disabled. */ 307121985Sjhb imen = 0xffff; 308121985Sjhb i8259_init(&atpics[MASTER], 0); 309121985Sjhb i8259_init(&atpics[SLAVE], 1); 310121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 311121985Sjhb} 312121985Sjhb 313121985Sjhbstatic void 314121985Sjhbatpic_init(void *dummy __unused) 315121985Sjhb{ 316121985Sjhb struct atpic_intsrc *ai; 317121985Sjhb int i; 318121985Sjhb 319121985Sjhb /* Loop through all interrupt sources and add them. */ 320121985Sjhb for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { 321121985Sjhb if (i == ICU_SLAVEID) 322121985Sjhb continue; 323121985Sjhb ai = &atintrs[i]; 324121985Sjhb intr_register_source(&ai->at_intsrc); 325121985Sjhb } 326121985Sjhb} 327121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 328121985Sjhb 329121985Sjhbvoid 330121985Sjhbatpic_sched_ithd(struct intrframe iframe) 331121985Sjhb{ 332121985Sjhb struct intsrc *isrc; 333121985Sjhb 334121985Sjhb KASSERT((uint)iframe.if_vec < ICU_LEN, 335121985Sjhb ("unknown int %d\n", iframe.if_vec)); 336121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 337121985Sjhb intr_execute_handlers(isrc, &iframe); 338121985Sjhb} 339121985Sjhb 340121985Sjhb#ifdef DEV_ISA 341121985Sjhb/* 342121985Sjhb * Bus attachment for the ISA PIC. 343121985Sjhb */ 344121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 345121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 346121985Sjhb { 0 } 347121985Sjhb}; 348121985Sjhb 349121985Sjhbstatic int 350121985Sjhbatpic_probe(device_t dev) 351121985Sjhb{ 352121985Sjhb int result; 353121985Sjhb 354121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 355121985Sjhb if (result <= 0) 356121985Sjhb device_quiet(dev); 357121985Sjhb return (result); 358121985Sjhb} 359121985Sjhb 360121985Sjhb/* 361121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 362121985Sjhb * between the two PIC components. If we're using the APIC, however, 363121985Sjhb * this may not be the case, and as such we should free the resource. 364121985Sjhb * (XXX untested) 365121985Sjhb * 366121985Sjhb * The generic ISA attachment code will handle allocating any other resources 367121985Sjhb * that we don't explicitly claim here. 368121985Sjhb */ 369121985Sjhbstatic int 370121985Sjhbatpic_attach(device_t dev) 371121985Sjhb{ 372121985Sjhb struct resource *res; 373121985Sjhb int rid; 374121985Sjhb 375121985Sjhb /* Try to allocate our IRQ and then free it. */ 376121985Sjhb rid = 0; 377121985Sjhb res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 0); 378121985Sjhb if (res != NULL) 379121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 380121985Sjhb return (0); 381121985Sjhb} 382121985Sjhb 383121985Sjhbstatic device_method_t atpic_methods[] = { 384121985Sjhb /* Device interface */ 385121985Sjhb DEVMETHOD(device_probe, atpic_probe), 386121985Sjhb DEVMETHOD(device_attach, atpic_attach), 387121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 388121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 389121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 390121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 391121985Sjhb { 0, 0 } 392121985Sjhb}; 393121985Sjhb 394121985Sjhbstatic driver_t atpic_driver = { 395121985Sjhb "atpic", 396121985Sjhb atpic_methods, 397121985Sjhb 1, /* no softc */ 398121985Sjhb}; 399121985Sjhb 400121985Sjhbstatic devclass_t atpic_devclass; 401121985Sjhb 402121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 403122051Snyan#ifndef PC98 404121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 405122051Snyan#endif 406121985Sjhb 407121985Sjhb/* 408121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 409121985Sjhb * and is only suitable for use at probe time. 410121985Sjhb */ 411121985Sjhbintrmask_t 412121985Sjhbisa_irq_pending(void) 413121985Sjhb{ 414121985Sjhb u_char irr1; 415121985Sjhb u_char irr2; 416121985Sjhb 417121985Sjhb irr1 = inb(IO_ICU1); 418121985Sjhb irr2 = inb(IO_ICU2); 419121985Sjhb return ((irr2 << 8) | irr1); 420121985Sjhb} 421121985Sjhb#endif /* DEV_ISA */ 422