132580301SAttilio Rao /*- 232580301SAttilio Rao * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 332580301SAttilio Rao * All rights reserved. 432580301SAttilio Rao * 532580301SAttilio Rao * Redistribution and use in source and binary forms, with or without 632580301SAttilio Rao * modification, are permitted provided that the following conditions 732580301SAttilio Rao * are met: 832580301SAttilio Rao * 1. Redistributions of source code must retain the above copyright 932580301SAttilio Rao * notice, this list of conditions and the following disclaimer. 1032580301SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright 1132580301SAttilio Rao * notice, this list of conditions and the following disclaimer in the 1232580301SAttilio Rao * documentation and/or other materials provided with the distribution. 1332580301SAttilio Rao * 1432580301SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1532580301SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1632580301SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1732580301SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1832580301SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1932580301SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2032580301SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2132580301SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2232580301SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2332580301SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2432580301SAttilio Rao * SUCH DAMAGE. 2532580301SAttilio Rao */ 2632580301SAttilio Rao 2732580301SAttilio Rao /* 2832580301SAttilio Rao * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 2932580301SAttilio Rao */ 3032580301SAttilio Rao 3132580301SAttilio Rao #include <sys/cdefs.h> 3232580301SAttilio Rao __FBSDID("$FreeBSD$"); 3332580301SAttilio Rao 3432580301SAttilio Rao #include "opt_auto_eoi.h" 3532580301SAttilio Rao #include "opt_isa.h" 368e9b1703SWarner Losh #include "opt_mca.h" 3732580301SAttilio Rao 3832580301SAttilio Rao #include <sys/param.h> 3932580301SAttilio Rao #include <sys/systm.h> 4032580301SAttilio Rao #include <sys/bus.h> 4132580301SAttilio Rao #include <sys/interrupt.h> 4232580301SAttilio Rao #include <sys/kernel.h> 4332580301SAttilio Rao #include <sys/lock.h> 4432580301SAttilio Rao #include <sys/module.h> 4532580301SAttilio Rao 4632580301SAttilio Rao #include <machine/cpufunc.h> 4732580301SAttilio Rao #include <machine/frame.h> 4832580301SAttilio Rao #include <machine/intr_machdep.h> 4932580301SAttilio Rao #include <machine/md_var.h> 5032580301SAttilio Rao #include <machine/resource.h> 5132580301SAttilio Rao #include <machine/segments.h> 5232580301SAttilio Rao 5332580301SAttilio Rao #include <dev/ic/i8259.h> 5432580301SAttilio Rao #include <x86/isa/icu.h> 5532580301SAttilio Rao #ifdef PC98 5632580301SAttilio Rao #include <pc98/cbus/cbus.h> 5732580301SAttilio Rao #else 58f79309d2SWarner Losh #include <isa/isareg.h> 5932580301SAttilio Rao #endif 6032580301SAttilio Rao #include <isa/isavar.h> 61a66412fcSWarner Losh #ifdef DEV_MCA 62a66412fcSWarner Losh #include <i386/bios/mca_machdep.h> 63a66412fcSWarner Losh #endif 6432580301SAttilio Rao 6532580301SAttilio Rao #ifdef __amd64__ 6632580301SAttilio Rao #define SDT_ATPIC SDT_SYSIGT 6732580301SAttilio Rao #define GSEL_ATPIC 0 6832580301SAttilio Rao #else 6932580301SAttilio Rao #define SDT_ATPIC SDT_SYS386IGT 7032580301SAttilio Rao #define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL) 7132580301SAttilio Rao #endif 7232580301SAttilio Rao 7332580301SAttilio Rao #define MASTER 0 7432580301SAttilio Rao #define SLAVE 1 7532580301SAttilio Rao 7632580301SAttilio Rao #define NUM_ISA_IRQS 16 7732580301SAttilio Rao 7832580301SAttilio Rao static void atpic_init(void *dummy); 7932580301SAttilio Rao 8032580301SAttilio Rao unsigned int imen; /* XXX */ 8132580301SAttilio Rao 8232580301SAttilio Rao inthand_t 8332580301SAttilio Rao IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 8432580301SAttilio Rao IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 8532580301SAttilio Rao IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 8632580301SAttilio Rao IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 8732580301SAttilio Rao IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 8832580301SAttilio Rao IDTVEC(atpic_intr15); 8932580301SAttilio Rao 9032580301SAttilio Rao #define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 9132580301SAttilio Rao 9232580301SAttilio Rao #define ATPIC(io, base, eoi, imenptr) \ 9332580301SAttilio Rao { { atpic_enable_source, atpic_disable_source, (eoi), \ 9432580301SAttilio Rao atpic_enable_intr, atpic_disable_intr, atpic_vector, \ 9532580301SAttilio Rao atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\ 9632580301SAttilio Rao atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \ 9732580301SAttilio Rao (imenptr) } 9832580301SAttilio Rao 9932580301SAttilio Rao #define INTSRC(irq) \ 10032580301SAttilio Rao { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 10132580301SAttilio Rao (irq) % 8 } 10232580301SAttilio Rao 10332580301SAttilio Rao struct atpic { 10432580301SAttilio Rao struct pic at_pic; 10532580301SAttilio Rao int at_ioaddr; 10632580301SAttilio Rao int at_irqbase; 10732580301SAttilio Rao uint8_t at_intbase; 10832580301SAttilio Rao uint8_t *at_imen; 10932580301SAttilio Rao }; 11032580301SAttilio Rao 11132580301SAttilio Rao struct atpic_intsrc { 11232580301SAttilio Rao struct intsrc at_intsrc; 11332580301SAttilio Rao inthand_t *at_intr; 11432580301SAttilio Rao int at_irq; /* Relative to PIC base. */ 11532580301SAttilio Rao enum intr_trigger at_trigger; 11632580301SAttilio Rao u_long at_count; 11732580301SAttilio Rao u_long at_straycount; 11832580301SAttilio Rao }; 11932580301SAttilio Rao 12032580301SAttilio Rao static void atpic_enable_source(struct intsrc *isrc); 12132580301SAttilio Rao static void atpic_disable_source(struct intsrc *isrc, int eoi); 12232580301SAttilio Rao static void atpic_eoi_master(struct intsrc *isrc); 12332580301SAttilio Rao static void atpic_eoi_slave(struct intsrc *isrc); 12432580301SAttilio Rao static void atpic_enable_intr(struct intsrc *isrc); 12532580301SAttilio Rao static void atpic_disable_intr(struct intsrc *isrc); 12632580301SAttilio Rao static int atpic_vector(struct intsrc *isrc); 127428b7ca2SJustin T. Gibbs static void atpic_resume(struct pic *pic, bool suspend_cancelled); 12832580301SAttilio Rao static int atpic_source_pending(struct intsrc *isrc); 12932580301SAttilio Rao static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 13032580301SAttilio Rao enum intr_polarity pol); 13132580301SAttilio Rao static int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 13232580301SAttilio Rao static void i8259_init(struct atpic *pic, int slave); 13332580301SAttilio Rao 13432580301SAttilio Rao static struct atpic atpics[] = { 13532580301SAttilio Rao ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 13632580301SAttilio Rao ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 13732580301SAttilio Rao }; 13832580301SAttilio Rao 13932580301SAttilio Rao static struct atpic_intsrc atintrs[] = { 14032580301SAttilio Rao INTSRC(0), 14132580301SAttilio Rao INTSRC(1), 14232580301SAttilio Rao INTSRC(2), 14332580301SAttilio Rao INTSRC(3), 14432580301SAttilio Rao INTSRC(4), 14532580301SAttilio Rao INTSRC(5), 14632580301SAttilio Rao INTSRC(6), 14732580301SAttilio Rao INTSRC(7), 14832580301SAttilio Rao INTSRC(8), 14932580301SAttilio Rao INTSRC(9), 15032580301SAttilio Rao INTSRC(10), 15132580301SAttilio Rao INTSRC(11), 15232580301SAttilio Rao INTSRC(12), 15332580301SAttilio Rao INTSRC(13), 15432580301SAttilio Rao INTSRC(14), 15532580301SAttilio Rao INTSRC(15), 15632580301SAttilio Rao }; 15732580301SAttilio Rao 158*ea24b056SPedro F. Giffuni CTASSERT(nitems(atintrs) == NUM_ISA_IRQS); 15932580301SAttilio Rao 16032580301SAttilio Rao static __inline void 16132580301SAttilio Rao _atpic_eoi_master(struct intsrc *isrc) 16232580301SAttilio Rao { 16332580301SAttilio Rao 16432580301SAttilio Rao KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 16532580301SAttilio Rao ("%s: mismatched pic", __func__)); 16632580301SAttilio Rao #ifndef AUTO_EOI_1 16732580301SAttilio Rao outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 16832580301SAttilio Rao #endif 16932580301SAttilio Rao } 17032580301SAttilio Rao 17132580301SAttilio Rao /* 17232580301SAttilio Rao * The data sheet says no auto-EOI on slave, but it sometimes works. 17332580301SAttilio Rao * So, if AUTO_EOI_2 is enabled, we use it. 17432580301SAttilio Rao */ 17532580301SAttilio Rao static __inline void 17632580301SAttilio Rao _atpic_eoi_slave(struct intsrc *isrc) 17732580301SAttilio Rao { 17832580301SAttilio Rao 17932580301SAttilio Rao KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 18032580301SAttilio Rao ("%s: mismatched pic", __func__)); 18132580301SAttilio Rao #ifndef AUTO_EOI_2 18232580301SAttilio Rao outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 18332580301SAttilio Rao #ifndef AUTO_EOI_1 18432580301SAttilio Rao outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 18532580301SAttilio Rao #endif 18632580301SAttilio Rao #endif 18732580301SAttilio Rao } 18832580301SAttilio Rao 18932580301SAttilio Rao static void 19032580301SAttilio Rao atpic_enable_source(struct intsrc *isrc) 19132580301SAttilio Rao { 19232580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 19332580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 19432580301SAttilio Rao 19532580301SAttilio Rao spinlock_enter(); 19632580301SAttilio Rao if (*ap->at_imen & IMEN_MASK(ai)) { 19732580301SAttilio Rao *ap->at_imen &= ~IMEN_MASK(ai); 19832580301SAttilio Rao outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 19932580301SAttilio Rao } 20032580301SAttilio Rao spinlock_exit(); 20132580301SAttilio Rao } 20232580301SAttilio Rao 20332580301SAttilio Rao static void 20432580301SAttilio Rao atpic_disable_source(struct intsrc *isrc, int eoi) 20532580301SAttilio Rao { 20632580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 20732580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 20832580301SAttilio Rao 20932580301SAttilio Rao spinlock_enter(); 21032580301SAttilio Rao if (ai->at_trigger != INTR_TRIGGER_EDGE) { 21132580301SAttilio Rao *ap->at_imen |= IMEN_MASK(ai); 21232580301SAttilio Rao outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 21332580301SAttilio Rao } 21432580301SAttilio Rao 21532580301SAttilio Rao /* 21632580301SAttilio Rao * Take care to call these functions directly instead of through 21732580301SAttilio Rao * a function pointer. All of the referenced variables should 21832580301SAttilio Rao * still be hot in the cache. 21932580301SAttilio Rao */ 22032580301SAttilio Rao if (eoi == PIC_EOI) { 22132580301SAttilio Rao if (isrc->is_pic == &atpics[MASTER].at_pic) 22232580301SAttilio Rao _atpic_eoi_master(isrc); 22332580301SAttilio Rao else 22432580301SAttilio Rao _atpic_eoi_slave(isrc); 22532580301SAttilio Rao } 22632580301SAttilio Rao 22732580301SAttilio Rao spinlock_exit(); 22832580301SAttilio Rao } 22932580301SAttilio Rao 23032580301SAttilio Rao static void 23132580301SAttilio Rao atpic_eoi_master(struct intsrc *isrc) 23232580301SAttilio Rao { 23332580301SAttilio Rao #ifndef AUTO_EOI_1 23432580301SAttilio Rao spinlock_enter(); 23532580301SAttilio Rao _atpic_eoi_master(isrc); 23632580301SAttilio Rao spinlock_exit(); 23732580301SAttilio Rao #endif 23832580301SAttilio Rao } 23932580301SAttilio Rao 24032580301SAttilio Rao static void 24132580301SAttilio Rao atpic_eoi_slave(struct intsrc *isrc) 24232580301SAttilio Rao { 24332580301SAttilio Rao #ifndef AUTO_EOI_2 24432580301SAttilio Rao spinlock_enter(); 24532580301SAttilio Rao _atpic_eoi_slave(isrc); 24632580301SAttilio Rao spinlock_exit(); 24732580301SAttilio Rao #endif 24832580301SAttilio Rao } 24932580301SAttilio Rao 25032580301SAttilio Rao static void 25132580301SAttilio Rao atpic_enable_intr(struct intsrc *isrc) 25232580301SAttilio Rao { 25332580301SAttilio Rao } 25432580301SAttilio Rao 25532580301SAttilio Rao static void 25632580301SAttilio Rao atpic_disable_intr(struct intsrc *isrc) 25732580301SAttilio Rao { 25832580301SAttilio Rao } 25932580301SAttilio Rao 26032580301SAttilio Rao 26132580301SAttilio Rao static int 26232580301SAttilio Rao atpic_vector(struct intsrc *isrc) 26332580301SAttilio Rao { 26432580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 26532580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 26632580301SAttilio Rao 26732580301SAttilio Rao return (IRQ(ap, ai)); 26832580301SAttilio Rao } 26932580301SAttilio Rao 27032580301SAttilio Rao static int 27132580301SAttilio Rao atpic_source_pending(struct intsrc *isrc) 27232580301SAttilio Rao { 27332580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 27432580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 27532580301SAttilio Rao 27632580301SAttilio Rao return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 27732580301SAttilio Rao } 27832580301SAttilio Rao 27932580301SAttilio Rao static void 280428b7ca2SJustin T. Gibbs atpic_resume(struct pic *pic, bool suspend_cancelled) 28132580301SAttilio Rao { 28232580301SAttilio Rao struct atpic *ap = (struct atpic *)pic; 28332580301SAttilio Rao 28432580301SAttilio Rao i8259_init(ap, ap == &atpics[SLAVE]); 28532580301SAttilio Rao #ifndef PC98 28632580301SAttilio Rao if (ap == &atpics[SLAVE] && elcr_found) 28732580301SAttilio Rao elcr_resume(); 28832580301SAttilio Rao #endif 28932580301SAttilio Rao } 29032580301SAttilio Rao 29132580301SAttilio Rao static int 29232580301SAttilio Rao atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 29332580301SAttilio Rao enum intr_polarity pol) 29432580301SAttilio Rao { 29532580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 29632580301SAttilio Rao u_int vector; 29732580301SAttilio Rao 29832580301SAttilio Rao /* Map conforming values to edge/hi and sanity check the values. */ 29932580301SAttilio Rao if (trig == INTR_TRIGGER_CONFORM) 30032580301SAttilio Rao trig = INTR_TRIGGER_EDGE; 30132580301SAttilio Rao if (pol == INTR_POLARITY_CONFORM) 30232580301SAttilio Rao pol = INTR_POLARITY_HIGH; 30332580301SAttilio Rao vector = atpic_vector(isrc); 30432580301SAttilio Rao if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 30532580301SAttilio Rao (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 30632580301SAttilio Rao printf( 30732580301SAttilio Rao "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 30832580301SAttilio Rao vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 30932580301SAttilio Rao pol == INTR_POLARITY_HIGH ? "high" : "low"); 31032580301SAttilio Rao return (EINVAL); 31132580301SAttilio Rao } 31232580301SAttilio Rao 31332580301SAttilio Rao /* If there is no change, just return. */ 31432580301SAttilio Rao if (ai->at_trigger == trig) 31532580301SAttilio Rao return (0); 31632580301SAttilio Rao 31732580301SAttilio Rao #ifdef PC98 31832580301SAttilio Rao if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 31932580301SAttilio Rao trig == INTR_TRIGGER_LEVEL) { 32032580301SAttilio Rao if (bootverbose) 32132580301SAttilio Rao printf( 32232580301SAttilio Rao "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 32332580301SAttilio Rao vector); 32432580301SAttilio Rao return (EINVAL); 32532580301SAttilio Rao } 32632580301SAttilio Rao return (ENXIO); 32732580301SAttilio Rao #else 32832580301SAttilio Rao /* 32932580301SAttilio Rao * Certain IRQs can never be level/lo, so don't try to set them 33032580301SAttilio Rao * that way if asked. At least some ELCR registers ignore setting 33132580301SAttilio Rao * these bits as well. 33232580301SAttilio Rao */ 33332580301SAttilio Rao if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 33432580301SAttilio Rao trig == INTR_TRIGGER_LEVEL) { 33532580301SAttilio Rao if (bootverbose) 33632580301SAttilio Rao printf( 33732580301SAttilio Rao "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 33832580301SAttilio Rao vector); 33932580301SAttilio Rao return (EINVAL); 34032580301SAttilio Rao } 34132580301SAttilio Rao if (!elcr_found) { 34232580301SAttilio Rao if (bootverbose) 34332580301SAttilio Rao printf("atpic: No ELCR to configure IRQ%u as %s\n", 34432580301SAttilio Rao vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 34532580301SAttilio Rao "level/low"); 34632580301SAttilio Rao return (ENXIO); 34732580301SAttilio Rao } 34832580301SAttilio Rao if (bootverbose) 34932580301SAttilio Rao printf("atpic: Programming IRQ%u as %s\n", vector, 35032580301SAttilio Rao trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 35132580301SAttilio Rao spinlock_enter(); 35232580301SAttilio Rao elcr_write_trigger(atpic_vector(isrc), trig); 35332580301SAttilio Rao ai->at_trigger = trig; 35432580301SAttilio Rao spinlock_exit(); 35532580301SAttilio Rao return (0); 35632580301SAttilio Rao #endif /* PC98 */ 35732580301SAttilio Rao } 35832580301SAttilio Rao 35932580301SAttilio Rao static int 36032580301SAttilio Rao atpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 36132580301SAttilio Rao { 36232580301SAttilio Rao 36332580301SAttilio Rao /* 36432580301SAttilio Rao * 8259A's are only used in UP in which case all interrupts always 36532580301SAttilio Rao * go to the sole CPU and this function shouldn't even be called. 36632580301SAttilio Rao */ 36732580301SAttilio Rao panic("%s: bad cookie", __func__); 36832580301SAttilio Rao } 36932580301SAttilio Rao 37032580301SAttilio Rao static void 37132580301SAttilio Rao i8259_init(struct atpic *pic, int slave) 37232580301SAttilio Rao { 37332580301SAttilio Rao int imr_addr; 37432580301SAttilio Rao 37532580301SAttilio Rao /* Reset the PIC and program with next four bytes. */ 37632580301SAttilio Rao spinlock_enter(); 37732580301SAttilio Rao #ifdef DEV_MCA 37832580301SAttilio Rao /* MCA uses level triggered interrupts. */ 37932580301SAttilio Rao if (MCA_system) 38032580301SAttilio Rao outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 38132580301SAttilio Rao else 38232580301SAttilio Rao #endif 38332580301SAttilio Rao outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 38432580301SAttilio Rao imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 38532580301SAttilio Rao 38632580301SAttilio Rao /* Start vector. */ 38732580301SAttilio Rao outb(imr_addr, pic->at_intbase); 38832580301SAttilio Rao 38932580301SAttilio Rao /* 39032580301SAttilio Rao * Setup slave links. For the master pic, indicate what line 39132580301SAttilio Rao * the slave is configured on. For the slave indicate 39232580301SAttilio Rao * which line on the master we are connected to. 39332580301SAttilio Rao */ 39432580301SAttilio Rao if (slave) 39532580301SAttilio Rao outb(imr_addr, ICU_SLAVEID); 39632580301SAttilio Rao else 39732580301SAttilio Rao outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 39832580301SAttilio Rao 39932580301SAttilio Rao /* Set mode. */ 40032580301SAttilio Rao if (slave) 40132580301SAttilio Rao outb(imr_addr, SLAVE_MODE); 40232580301SAttilio Rao else 40332580301SAttilio Rao outb(imr_addr, MASTER_MODE); 40432580301SAttilio Rao 40532580301SAttilio Rao /* Set interrupt enable mask. */ 40632580301SAttilio Rao outb(imr_addr, *pic->at_imen); 40732580301SAttilio Rao 40832580301SAttilio Rao /* Reset is finished, default to IRR on read. */ 40932580301SAttilio Rao outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 41032580301SAttilio Rao 41132580301SAttilio Rao #ifndef PC98 41232580301SAttilio Rao /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 41332580301SAttilio Rao if (!slave) 41432580301SAttilio Rao outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 41532580301SAttilio Rao #endif 41632580301SAttilio Rao spinlock_exit(); 41732580301SAttilio Rao } 41832580301SAttilio Rao 41932580301SAttilio Rao void 42032580301SAttilio Rao atpic_startup(void) 42132580301SAttilio Rao { 42232580301SAttilio Rao struct atpic_intsrc *ai; 42332580301SAttilio Rao int i; 42432580301SAttilio Rao 42532580301SAttilio Rao /* Start off with all interrupts disabled. */ 42632580301SAttilio Rao imen = 0xffff; 42732580301SAttilio Rao i8259_init(&atpics[MASTER], 0); 42832580301SAttilio Rao i8259_init(&atpics[SLAVE], 1); 42932580301SAttilio Rao atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 43032580301SAttilio Rao 43132580301SAttilio Rao /* Install low-level interrupt handlers for all of our IRQs. */ 43232580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 43332580301SAttilio Rao if (i == ICU_SLAVEID) 43432580301SAttilio Rao continue; 43532580301SAttilio Rao ai->at_intsrc.is_count = &ai->at_count; 43632580301SAttilio Rao ai->at_intsrc.is_straycount = &ai->at_straycount; 43732580301SAttilio Rao setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 43832580301SAttilio Rao ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC); 43932580301SAttilio Rao } 44032580301SAttilio Rao 44132580301SAttilio Rao #ifdef DEV_MCA 44232580301SAttilio Rao /* For MCA systems, all interrupts are level triggered. */ 44332580301SAttilio Rao if (MCA_system) 44432580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 44532580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_LEVEL; 44632580301SAttilio Rao else 44732580301SAttilio Rao #endif 44832580301SAttilio Rao 44932580301SAttilio Rao #ifdef PC98 45032580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 45132580301SAttilio Rao switch (i) { 45232580301SAttilio Rao case 0: 45332580301SAttilio Rao case 1: 45432580301SAttilio Rao case 7: 45532580301SAttilio Rao case 8: 45632580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_EDGE; 45732580301SAttilio Rao break; 45832580301SAttilio Rao default: 45932580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_LEVEL; 46032580301SAttilio Rao break; 46132580301SAttilio Rao } 46232580301SAttilio Rao #else 46332580301SAttilio Rao /* 46432580301SAttilio Rao * Look for an ELCR. If we find one, update the trigger modes. 46532580301SAttilio Rao * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 46632580301SAttilio Rao * edge triggered and that everything else is level triggered. 46732580301SAttilio Rao * We only use the trigger information to reprogram the ELCR if 46832580301SAttilio Rao * we have one and as an optimization to avoid masking edge 46932580301SAttilio Rao * triggered interrupts. For the case that we don't have an ELCR, 47032580301SAttilio Rao * it doesn't hurt to mask an edge triggered interrupt, so we 47132580301SAttilio Rao * assume level trigger for any interrupt that we aren't sure is 47232580301SAttilio Rao * edge triggered. 47332580301SAttilio Rao */ 47432580301SAttilio Rao if (elcr_found) { 47532580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 47632580301SAttilio Rao ai->at_trigger = elcr_read_trigger(i); 47732580301SAttilio Rao } else { 47832580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 47932580301SAttilio Rao switch (i) { 48032580301SAttilio Rao case 0: 48132580301SAttilio Rao case 1: 48232580301SAttilio Rao case 2: 48332580301SAttilio Rao case 8: 48432580301SAttilio Rao case 13: 48532580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_EDGE; 48632580301SAttilio Rao break; 48732580301SAttilio Rao default: 48832580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_LEVEL; 48932580301SAttilio Rao break; 49032580301SAttilio Rao } 49132580301SAttilio Rao } 49232580301SAttilio Rao #endif /* PC98 */ 49332580301SAttilio Rao } 49432580301SAttilio Rao 49532580301SAttilio Rao static void 49632580301SAttilio Rao atpic_init(void *dummy __unused) 49732580301SAttilio Rao { 49832580301SAttilio Rao struct atpic_intsrc *ai; 49932580301SAttilio Rao int i; 50032580301SAttilio Rao 50132580301SAttilio Rao /* 50232580301SAttilio Rao * Register our PICs, even if we aren't going to use any of their 50332580301SAttilio Rao * pins so that they are suspended and resumed. 50432580301SAttilio Rao */ 50532580301SAttilio Rao if (intr_register_pic(&atpics[0].at_pic) != 0 || 50632580301SAttilio Rao intr_register_pic(&atpics[1].at_pic) != 0) 50732580301SAttilio Rao panic("Unable to register ATPICs"); 50832580301SAttilio Rao 50932580301SAttilio Rao /* 51032580301SAttilio Rao * If any of the ISA IRQs have an interrupt source already, then 51132580301SAttilio Rao * assume that the APICs are being used and don't register any 51232580301SAttilio Rao * of our interrupt sources. This makes sure we don't accidentally 51332580301SAttilio Rao * use mixed mode. The "accidental" use could otherwise occur on 51432580301SAttilio Rao * machines that route the ACPI SCI interrupt to a different ISA 51532580301SAttilio Rao * IRQ (at least one machines routes it to IRQ 13) thus disabling 51632580301SAttilio Rao * that APIC ISA routing and allowing the ATPIC source for that IRQ 51732580301SAttilio Rao * to leak through. We used to depend on this feature for routing 51832580301SAttilio Rao * IRQ0 via mixed mode, but now we don't use mixed mode at all. 51932580301SAttilio Rao */ 52032580301SAttilio Rao for (i = 0; i < NUM_ISA_IRQS; i++) 52132580301SAttilio Rao if (intr_lookup_source(i) != NULL) 52232580301SAttilio Rao return; 52332580301SAttilio Rao 52432580301SAttilio Rao /* Loop through all interrupt sources and add them. */ 52532580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 52632580301SAttilio Rao if (i == ICU_SLAVEID) 52732580301SAttilio Rao continue; 52832580301SAttilio Rao intr_register_source(&ai->at_intsrc); 52932580301SAttilio Rao } 53032580301SAttilio Rao } 531e68c8d7fSRoger Pau Monné SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL); 53232580301SAttilio Rao 53332580301SAttilio Rao void 53432580301SAttilio Rao atpic_handle_intr(u_int vector, struct trapframe *frame) 53532580301SAttilio Rao { 53632580301SAttilio Rao struct intsrc *isrc; 53732580301SAttilio Rao 53832580301SAttilio Rao KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 53932580301SAttilio Rao isrc = &atintrs[vector].at_intsrc; 54032580301SAttilio Rao 54132580301SAttilio Rao /* 54232580301SAttilio Rao * If we don't have an event, see if this is a spurious 54332580301SAttilio Rao * interrupt. 54432580301SAttilio Rao */ 54532580301SAttilio Rao if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 54632580301SAttilio Rao int port, isr; 54732580301SAttilio Rao 54832580301SAttilio Rao /* 54932580301SAttilio Rao * Read the ISR register to see if IRQ 7/15 is really 55032580301SAttilio Rao * pending. Reset read register back to IRR when done. 55132580301SAttilio Rao */ 55232580301SAttilio Rao port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 55332580301SAttilio Rao spinlock_enter(); 55432580301SAttilio Rao outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 55532580301SAttilio Rao isr = inb(port); 55632580301SAttilio Rao outb(port, OCW3_SEL | OCW3_RR); 55732580301SAttilio Rao spinlock_exit(); 55832580301SAttilio Rao if ((isr & IRQ_MASK(7)) == 0) 55932580301SAttilio Rao return; 56032580301SAttilio Rao } 56132580301SAttilio Rao intr_execute_handlers(isrc, frame); 56232580301SAttilio Rao } 56332580301SAttilio Rao 56432580301SAttilio Rao #ifdef DEV_ISA 56532580301SAttilio Rao /* 56632580301SAttilio Rao * Bus attachment for the ISA PIC. 56732580301SAttilio Rao */ 56832580301SAttilio Rao static struct isa_pnp_id atpic_ids[] = { 56932580301SAttilio Rao { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 57032580301SAttilio Rao { 0 } 57132580301SAttilio Rao }; 57232580301SAttilio Rao 57332580301SAttilio Rao static int 57432580301SAttilio Rao atpic_probe(device_t dev) 57532580301SAttilio Rao { 57632580301SAttilio Rao int result; 57732580301SAttilio Rao 57832580301SAttilio Rao result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 57932580301SAttilio Rao if (result <= 0) 58032580301SAttilio Rao device_quiet(dev); 58132580301SAttilio Rao return (result); 58232580301SAttilio Rao } 58332580301SAttilio Rao 58432580301SAttilio Rao /* 58532580301SAttilio Rao * We might be granted IRQ 2, as this is typically consumed by chaining 58632580301SAttilio Rao * between the two PIC components. If we're using the APIC, however, 58732580301SAttilio Rao * this may not be the case, and as such we should free the resource. 58832580301SAttilio Rao * (XXX untested) 58932580301SAttilio Rao * 59032580301SAttilio Rao * The generic ISA attachment code will handle allocating any other resources 59132580301SAttilio Rao * that we don't explicitly claim here. 59232580301SAttilio Rao */ 59332580301SAttilio Rao static int 59432580301SAttilio Rao atpic_attach(device_t dev) 59532580301SAttilio Rao { 59632580301SAttilio Rao struct resource *res; 59732580301SAttilio Rao int rid; 59832580301SAttilio Rao 59932580301SAttilio Rao /* Try to allocate our IRQ and then free it. */ 60032580301SAttilio Rao rid = 0; 60132580301SAttilio Rao res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 60232580301SAttilio Rao if (res != NULL) 60332580301SAttilio Rao bus_release_resource(dev, SYS_RES_IRQ, rid, res); 60432580301SAttilio Rao return (0); 60532580301SAttilio Rao } 60632580301SAttilio Rao 60732580301SAttilio Rao static device_method_t atpic_methods[] = { 60832580301SAttilio Rao /* Device interface */ 60932580301SAttilio Rao DEVMETHOD(device_probe, atpic_probe), 61032580301SAttilio Rao DEVMETHOD(device_attach, atpic_attach), 61132580301SAttilio Rao DEVMETHOD(device_detach, bus_generic_detach), 61232580301SAttilio Rao DEVMETHOD(device_shutdown, bus_generic_shutdown), 61332580301SAttilio Rao DEVMETHOD(device_suspend, bus_generic_suspend), 61432580301SAttilio Rao DEVMETHOD(device_resume, bus_generic_resume), 61532580301SAttilio Rao { 0, 0 } 61632580301SAttilio Rao }; 61732580301SAttilio Rao 61832580301SAttilio Rao static driver_t atpic_driver = { 61932580301SAttilio Rao "atpic", 62032580301SAttilio Rao atpic_methods, 62132580301SAttilio Rao 1, /* no softc */ 62232580301SAttilio Rao }; 62332580301SAttilio Rao 62432580301SAttilio Rao static devclass_t atpic_devclass; 62532580301SAttilio Rao 62632580301SAttilio Rao DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 62732580301SAttilio Rao #ifndef PC98 62832580301SAttilio Rao DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 62932580301SAttilio Rao #endif 63032580301SAttilio Rao 63132580301SAttilio Rao /* 63232580301SAttilio Rao * Return a bitmap of the current interrupt requests. This is 8259-specific 63332580301SAttilio Rao * and is only suitable for use at probe time. 63432580301SAttilio Rao */ 63532580301SAttilio Rao intrmask_t 63632580301SAttilio Rao isa_irq_pending(void) 63732580301SAttilio Rao { 63832580301SAttilio Rao u_char irr1; 63932580301SAttilio Rao u_char irr2; 64032580301SAttilio Rao 64132580301SAttilio Rao irr1 = inb(IO_ICU1); 64232580301SAttilio Rao irr2 = inb(IO_ICU2); 64332580301SAttilio Rao return ((irr2 << 8) | irr1); 64432580301SAttilio Rao } 64532580301SAttilio Rao #endif /* DEV_ISA */ 646