132580301SAttilio Rao /*- 2ebf5747bSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3ebf5747bSPedro F. Giffuni * 432580301SAttilio Rao * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 532580301SAttilio Rao * 632580301SAttilio Rao * Redistribution and use in source and binary forms, with or without 732580301SAttilio Rao * modification, are permitted provided that the following conditions 832580301SAttilio Rao * are met: 932580301SAttilio Rao * 1. Redistributions of source code must retain the above copyright 1032580301SAttilio Rao * notice, this list of conditions and the following disclaimer. 1132580301SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright 1232580301SAttilio Rao * notice, this list of conditions and the following disclaimer in the 1332580301SAttilio Rao * documentation and/or other materials provided with the distribution. 1432580301SAttilio Rao * 1532580301SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1632580301SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1732580301SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1832580301SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1932580301SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2032580301SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2132580301SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2232580301SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2332580301SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2432580301SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2532580301SAttilio Rao * SUCH DAMAGE. 2632580301SAttilio Rao */ 2732580301SAttilio Rao 2832580301SAttilio Rao /* 2932580301SAttilio Rao * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 3032580301SAttilio Rao */ 3132580301SAttilio Rao 3232580301SAttilio Rao #include <sys/cdefs.h> 3332580301SAttilio Rao __FBSDID("$FreeBSD$"); 3432580301SAttilio Rao 3532580301SAttilio Rao #include "opt_auto_eoi.h" 3632580301SAttilio Rao #include "opt_isa.h" 3732580301SAttilio Rao 3832580301SAttilio Rao #include <sys/param.h> 3932580301SAttilio Rao #include <sys/systm.h> 40f115c061SMark Johnston #include <sys/asan.h> 4132580301SAttilio Rao #include <sys/bus.h> 4232580301SAttilio Rao #include <sys/interrupt.h> 4332580301SAttilio Rao #include <sys/kernel.h> 4432580301SAttilio Rao #include <sys/lock.h> 4532580301SAttilio Rao #include <sys/module.h> 46b0f71f1bSMark Johnston #include <sys/msan.h> 4732580301SAttilio Rao 4832580301SAttilio Rao #include <machine/cpufunc.h> 4932580301SAttilio Rao #include <machine/frame.h> 5032580301SAttilio Rao #include <machine/intr_machdep.h> 5132580301SAttilio Rao #include <machine/md_var.h> 5232580301SAttilio Rao #include <machine/resource.h> 5332580301SAttilio Rao #include <machine/segments.h> 5432580301SAttilio Rao 5532580301SAttilio Rao #include <dev/ic/i8259.h> 5632580301SAttilio Rao #include <x86/isa/icu.h> 57f79309d2SWarner Losh #include <isa/isareg.h> 5832580301SAttilio Rao #include <isa/isavar.h> 5932580301SAttilio Rao 6032580301SAttilio Rao #ifdef __amd64__ 6132580301SAttilio Rao #define SDT_ATPIC SDT_SYSIGT 6232580301SAttilio Rao #define GSEL_ATPIC 0 6332580301SAttilio Rao #else 6432580301SAttilio Rao #define SDT_ATPIC SDT_SYS386IGT 6532580301SAttilio Rao #define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL) 6632580301SAttilio Rao #endif 6732580301SAttilio Rao 6832580301SAttilio Rao #define MASTER 0 6932580301SAttilio Rao #define SLAVE 1 7032580301SAttilio Rao 7162a08214SJohn Baldwin #define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 7262a08214SJohn Baldwin 7332580301SAttilio Rao #define NUM_ISA_IRQS 16 7432580301SAttilio Rao 7532580301SAttilio Rao static void atpic_init(void *dummy); 7632580301SAttilio Rao 7732580301SAttilio Rao inthand_t 7832580301SAttilio Rao IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 7932580301SAttilio Rao IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 8032580301SAttilio Rao IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 8132580301SAttilio Rao IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 8232580301SAttilio Rao IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 8332580301SAttilio Rao IDTVEC(atpic_intr15); 84bd50262fSKonstantin Belousov /* XXXKIB i386 uses stubs until pti comes */ 85bd50262fSKonstantin Belousov inthand_t 86bd50262fSKonstantin Belousov IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti), 87bd50262fSKonstantin Belousov IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti), 88bd50262fSKonstantin Belousov IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti), 89bd50262fSKonstantin Belousov IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti), 90bd50262fSKonstantin Belousov IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti), 91bd50262fSKonstantin Belousov IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti), 92bd50262fSKonstantin Belousov IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti), 93bd50262fSKonstantin Belousov IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti); 9432580301SAttilio Rao 9532580301SAttilio Rao #define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 9632580301SAttilio Rao 9762a08214SJohn Baldwin #define ATPIC(io, base, eoi) { \ 9862a08214SJohn Baldwin .at_pic = { \ 99fd036deaSJohn Baldwin .pic_register_sources = atpic_register_sources, \ 10062a08214SJohn Baldwin .pic_enable_source = atpic_enable_source, \ 10162a08214SJohn Baldwin .pic_disable_source = atpic_disable_source, \ 10262a08214SJohn Baldwin .pic_eoi_source = (eoi), \ 10362a08214SJohn Baldwin .pic_enable_intr = atpic_enable_intr, \ 10462a08214SJohn Baldwin .pic_disable_intr = atpic_disable_intr, \ 10562a08214SJohn Baldwin .pic_vector = atpic_vector, \ 10662a08214SJohn Baldwin .pic_source_pending = atpic_source_pending, \ 10762a08214SJohn Baldwin .pic_resume = atpic_resume, \ 10862a08214SJohn Baldwin .pic_config_intr = atpic_config_intr, \ 10962a08214SJohn Baldwin .pic_assign_cpu = atpic_assign_cpu \ 11062a08214SJohn Baldwin }, \ 11162a08214SJohn Baldwin .at_ioaddr = (io), \ 11262a08214SJohn Baldwin .at_irqbase = (base), \ 11362a08214SJohn Baldwin .at_intbase = IDT_IO_INTS + (base), \ 11462a08214SJohn Baldwin .at_imen = 0xff, \ 11562a08214SJohn Baldwin } 11632580301SAttilio Rao 11732580301SAttilio Rao #define INTSRC(irq) \ 11832580301SAttilio Rao { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 119bd50262fSKonstantin Belousov IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 } 12032580301SAttilio Rao 12132580301SAttilio Rao struct atpic { 12232580301SAttilio Rao struct pic at_pic; 12332580301SAttilio Rao int at_ioaddr; 12432580301SAttilio Rao int at_irqbase; 12532580301SAttilio Rao uint8_t at_intbase; 12662a08214SJohn Baldwin uint8_t at_imen; 12732580301SAttilio Rao }; 12832580301SAttilio Rao 12932580301SAttilio Rao struct atpic_intsrc { 13032580301SAttilio Rao struct intsrc at_intsrc; 131bd50262fSKonstantin Belousov inthand_t *at_intr, *at_intr_pti; 13232580301SAttilio Rao int at_irq; /* Relative to PIC base. */ 13332580301SAttilio Rao enum intr_trigger at_trigger; 13432580301SAttilio Rao u_long at_count; 13532580301SAttilio Rao u_long at_straycount; 13632580301SAttilio Rao }; 13732580301SAttilio Rao 138fd036deaSJohn Baldwin static void atpic_register_sources(struct pic *pic); 13932580301SAttilio Rao static void atpic_enable_source(struct intsrc *isrc); 14032580301SAttilio Rao static void atpic_disable_source(struct intsrc *isrc, int eoi); 14132580301SAttilio Rao static void atpic_eoi_master(struct intsrc *isrc); 14232580301SAttilio Rao static void atpic_eoi_slave(struct intsrc *isrc); 14332580301SAttilio Rao static void atpic_enable_intr(struct intsrc *isrc); 14432580301SAttilio Rao static void atpic_disable_intr(struct intsrc *isrc); 14532580301SAttilio Rao static int atpic_vector(struct intsrc *isrc); 146428b7ca2SJustin T. Gibbs static void atpic_resume(struct pic *pic, bool suspend_cancelled); 14732580301SAttilio Rao static int atpic_source_pending(struct intsrc *isrc); 14832580301SAttilio Rao static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 14932580301SAttilio Rao enum intr_polarity pol); 15032580301SAttilio Rao static int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id); 15132580301SAttilio Rao static void i8259_init(struct atpic *pic, int slave); 15232580301SAttilio Rao 15332580301SAttilio Rao static struct atpic atpics[] = { 15462a08214SJohn Baldwin ATPIC(IO_ICU1, 0, atpic_eoi_master), 15562a08214SJohn Baldwin ATPIC(IO_ICU2, 8, atpic_eoi_slave) 15632580301SAttilio Rao }; 15732580301SAttilio Rao 15832580301SAttilio Rao static struct atpic_intsrc atintrs[] = { 15932580301SAttilio Rao INTSRC(0), 16032580301SAttilio Rao INTSRC(1), 16132580301SAttilio Rao INTSRC(2), 16232580301SAttilio Rao INTSRC(3), 16332580301SAttilio Rao INTSRC(4), 16432580301SAttilio Rao INTSRC(5), 16532580301SAttilio Rao INTSRC(6), 16632580301SAttilio Rao INTSRC(7), 16732580301SAttilio Rao INTSRC(8), 16832580301SAttilio Rao INTSRC(9), 16932580301SAttilio Rao INTSRC(10), 17032580301SAttilio Rao INTSRC(11), 17132580301SAttilio Rao INTSRC(12), 17232580301SAttilio Rao INTSRC(13), 17332580301SAttilio Rao INTSRC(14), 17432580301SAttilio Rao INTSRC(15), 17532580301SAttilio Rao }; 17632580301SAttilio Rao 177ea24b056SPedro F. Giffuni CTASSERT(nitems(atintrs) == NUM_ISA_IRQS); 17832580301SAttilio Rao 17932580301SAttilio Rao static __inline void 18032580301SAttilio Rao _atpic_eoi_master(struct intsrc *isrc) 18132580301SAttilio Rao { 18232580301SAttilio Rao 18332580301SAttilio Rao KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 18432580301SAttilio Rao ("%s: mismatched pic", __func__)); 18532580301SAttilio Rao #ifndef AUTO_EOI_1 18632580301SAttilio Rao outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 18732580301SAttilio Rao #endif 18832580301SAttilio Rao } 18932580301SAttilio Rao 19032580301SAttilio Rao /* 19132580301SAttilio Rao * The data sheet says no auto-EOI on slave, but it sometimes works. 19232580301SAttilio Rao * So, if AUTO_EOI_2 is enabled, we use it. 19332580301SAttilio Rao */ 19432580301SAttilio Rao static __inline void 19532580301SAttilio Rao _atpic_eoi_slave(struct intsrc *isrc) 19632580301SAttilio Rao { 19732580301SAttilio Rao 19832580301SAttilio Rao KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 19932580301SAttilio Rao ("%s: mismatched pic", __func__)); 20032580301SAttilio Rao #ifndef AUTO_EOI_2 20132580301SAttilio Rao outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 20232580301SAttilio Rao #ifndef AUTO_EOI_1 20332580301SAttilio Rao outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 20432580301SAttilio Rao #endif 20532580301SAttilio Rao #endif 20632580301SAttilio Rao } 20732580301SAttilio Rao 20832580301SAttilio Rao static void 209fd036deaSJohn Baldwin atpic_register_sources(struct pic *pic) 210fd036deaSJohn Baldwin { 211fd036deaSJohn Baldwin struct atpic *ap = (struct atpic *)pic; 212fd036deaSJohn Baldwin struct atpic_intsrc *ai; 213fd036deaSJohn Baldwin int i; 214fd036deaSJohn Baldwin 215fd036deaSJohn Baldwin /* 216fd036deaSJohn Baldwin * If any of the ISA IRQs have an interrupt source already, then 217fd036deaSJohn Baldwin * assume that the I/O APICs are being used and don't register any 218fd036deaSJohn Baldwin * of our interrupt sources. This makes sure we don't accidentally 219fd036deaSJohn Baldwin * use mixed mode. The "accidental" use could otherwise occur on 220fd036deaSJohn Baldwin * machines that route the ACPI SCI interrupt to a different ISA 221fd036deaSJohn Baldwin * IRQ (at least one machine routes it to IRQ 13) thus disabling 222fd036deaSJohn Baldwin * that APIC ISA routing and allowing the ATPIC source for that IRQ 223fd036deaSJohn Baldwin * to leak through. We used to depend on this feature for routing 224fd036deaSJohn Baldwin * IRQ0 via mixed mode, but now we don't use mixed mode at all. 22587bdca82SJohn Baldwin * 22687bdca82SJohn Baldwin * To avoid the slave not register sources after the master 22787bdca82SJohn Baldwin * registers its sources, register all IRQs when this function is 22887bdca82SJohn Baldwin * called on the master. 229fd036deaSJohn Baldwin */ 23087bdca82SJohn Baldwin if (ap != &atpics[MASTER]) 23187bdca82SJohn Baldwin return; 232fd036deaSJohn Baldwin for (i = 0; i < NUM_ISA_IRQS; i++) 233fd036deaSJohn Baldwin if (intr_lookup_source(i) != NULL) 234fd036deaSJohn Baldwin return; 235fd036deaSJohn Baldwin 236fd036deaSJohn Baldwin /* Loop through all interrupt sources and add them. */ 23787bdca82SJohn Baldwin for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 23887bdca82SJohn Baldwin if (i == ICU_SLAVEID) 239fd036deaSJohn Baldwin continue; 240fd036deaSJohn Baldwin intr_register_source(&ai->at_intsrc); 241fd036deaSJohn Baldwin } 242fd036deaSJohn Baldwin } 243fd036deaSJohn Baldwin 244fd036deaSJohn Baldwin static void 24532580301SAttilio Rao atpic_enable_source(struct intsrc *isrc) 24632580301SAttilio Rao { 24732580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 24832580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 24932580301SAttilio Rao 25032580301SAttilio Rao spinlock_enter(); 25162a08214SJohn Baldwin if (ap->at_imen & IMEN_MASK(ai)) { 25262a08214SJohn Baldwin ap->at_imen &= ~IMEN_MASK(ai); 25362a08214SJohn Baldwin outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen); 25432580301SAttilio Rao } 25532580301SAttilio Rao spinlock_exit(); 25632580301SAttilio Rao } 25732580301SAttilio Rao 25832580301SAttilio Rao static void 25932580301SAttilio Rao atpic_disable_source(struct intsrc *isrc, int eoi) 26032580301SAttilio Rao { 26132580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 26232580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 26332580301SAttilio Rao 26432580301SAttilio Rao spinlock_enter(); 26532580301SAttilio Rao if (ai->at_trigger != INTR_TRIGGER_EDGE) { 26662a08214SJohn Baldwin ap->at_imen |= IMEN_MASK(ai); 26762a08214SJohn Baldwin outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen); 26832580301SAttilio Rao } 26932580301SAttilio Rao 27032580301SAttilio Rao /* 27132580301SAttilio Rao * Take care to call these functions directly instead of through 27232580301SAttilio Rao * a function pointer. All of the referenced variables should 27332580301SAttilio Rao * still be hot in the cache. 27432580301SAttilio Rao */ 27532580301SAttilio Rao if (eoi == PIC_EOI) { 27632580301SAttilio Rao if (isrc->is_pic == &atpics[MASTER].at_pic) 27732580301SAttilio Rao _atpic_eoi_master(isrc); 27832580301SAttilio Rao else 27932580301SAttilio Rao _atpic_eoi_slave(isrc); 28032580301SAttilio Rao } 28132580301SAttilio Rao 28232580301SAttilio Rao spinlock_exit(); 28332580301SAttilio Rao } 28432580301SAttilio Rao 28532580301SAttilio Rao static void 28632580301SAttilio Rao atpic_eoi_master(struct intsrc *isrc) 28732580301SAttilio Rao { 28832580301SAttilio Rao #ifndef AUTO_EOI_1 28932580301SAttilio Rao spinlock_enter(); 29032580301SAttilio Rao _atpic_eoi_master(isrc); 29132580301SAttilio Rao spinlock_exit(); 29232580301SAttilio Rao #endif 29332580301SAttilio Rao } 29432580301SAttilio Rao 29532580301SAttilio Rao static void 29632580301SAttilio Rao atpic_eoi_slave(struct intsrc *isrc) 29732580301SAttilio Rao { 29832580301SAttilio Rao #ifndef AUTO_EOI_2 29932580301SAttilio Rao spinlock_enter(); 30032580301SAttilio Rao _atpic_eoi_slave(isrc); 30132580301SAttilio Rao spinlock_exit(); 30232580301SAttilio Rao #endif 30332580301SAttilio Rao } 30432580301SAttilio Rao 30532580301SAttilio Rao static void 30632580301SAttilio Rao atpic_enable_intr(struct intsrc *isrc) 30732580301SAttilio Rao { 30832580301SAttilio Rao } 30932580301SAttilio Rao 31032580301SAttilio Rao static void 31132580301SAttilio Rao atpic_disable_intr(struct intsrc *isrc) 31232580301SAttilio Rao { 31332580301SAttilio Rao } 31432580301SAttilio Rao 31532580301SAttilio Rao static int 31632580301SAttilio Rao atpic_vector(struct intsrc *isrc) 31732580301SAttilio Rao { 31832580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 31932580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 32032580301SAttilio Rao 32132580301SAttilio Rao return (IRQ(ap, ai)); 32232580301SAttilio Rao } 32332580301SAttilio Rao 32432580301SAttilio Rao static int 32532580301SAttilio Rao atpic_source_pending(struct intsrc *isrc) 32632580301SAttilio Rao { 32732580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 32832580301SAttilio Rao struct atpic *ap = (struct atpic *)isrc->is_pic; 32932580301SAttilio Rao 33032580301SAttilio Rao return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 33132580301SAttilio Rao } 33232580301SAttilio Rao 33332580301SAttilio Rao static void 334428b7ca2SJustin T. Gibbs atpic_resume(struct pic *pic, bool suspend_cancelled) 33532580301SAttilio Rao { 33632580301SAttilio Rao struct atpic *ap = (struct atpic *)pic; 33732580301SAttilio Rao 33832580301SAttilio Rao i8259_init(ap, ap == &atpics[SLAVE]); 33932580301SAttilio Rao if (ap == &atpics[SLAVE] && elcr_found) 34032580301SAttilio Rao elcr_resume(); 34132580301SAttilio Rao } 34232580301SAttilio Rao 34332580301SAttilio Rao static int 34432580301SAttilio Rao atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 34532580301SAttilio Rao enum intr_polarity pol) 34632580301SAttilio Rao { 34732580301SAttilio Rao struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 34832580301SAttilio Rao u_int vector; 34932580301SAttilio Rao 35032580301SAttilio Rao /* Map conforming values to edge/hi and sanity check the values. */ 35132580301SAttilio Rao if (trig == INTR_TRIGGER_CONFORM) 35232580301SAttilio Rao trig = INTR_TRIGGER_EDGE; 35332580301SAttilio Rao if (pol == INTR_POLARITY_CONFORM) 35432580301SAttilio Rao pol = INTR_POLARITY_HIGH; 35532580301SAttilio Rao vector = atpic_vector(isrc); 35632580301SAttilio Rao if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 35732580301SAttilio Rao (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 35832580301SAttilio Rao printf( 35932580301SAttilio Rao "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 36032580301SAttilio Rao vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 36132580301SAttilio Rao pol == INTR_POLARITY_HIGH ? "high" : "low"); 36232580301SAttilio Rao return (EINVAL); 36332580301SAttilio Rao } 36432580301SAttilio Rao 36532580301SAttilio Rao /* If there is no change, just return. */ 36632580301SAttilio Rao if (ai->at_trigger == trig) 36732580301SAttilio Rao return (0); 36832580301SAttilio Rao 36932580301SAttilio Rao /* 37032580301SAttilio Rao * Certain IRQs can never be level/lo, so don't try to set them 37132580301SAttilio Rao * that way if asked. At least some ELCR registers ignore setting 37232580301SAttilio Rao * these bits as well. 37332580301SAttilio Rao */ 37432580301SAttilio Rao if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 37532580301SAttilio Rao trig == INTR_TRIGGER_LEVEL) { 37632580301SAttilio Rao if (bootverbose) 37732580301SAttilio Rao printf( 37832580301SAttilio Rao "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 37932580301SAttilio Rao vector); 38032580301SAttilio Rao return (EINVAL); 38132580301SAttilio Rao } 38232580301SAttilio Rao if (!elcr_found) { 38332580301SAttilio Rao if (bootverbose) 38432580301SAttilio Rao printf("atpic: No ELCR to configure IRQ%u as %s\n", 38532580301SAttilio Rao vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 38632580301SAttilio Rao "level/low"); 38732580301SAttilio Rao return (ENXIO); 38832580301SAttilio Rao } 38932580301SAttilio Rao if (bootverbose) 39032580301SAttilio Rao printf("atpic: Programming IRQ%u as %s\n", vector, 39132580301SAttilio Rao trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 39232580301SAttilio Rao spinlock_enter(); 39332580301SAttilio Rao elcr_write_trigger(atpic_vector(isrc), trig); 39432580301SAttilio Rao ai->at_trigger = trig; 39532580301SAttilio Rao spinlock_exit(); 39632580301SAttilio Rao return (0); 39732580301SAttilio Rao } 39832580301SAttilio Rao 39932580301SAttilio Rao static int 40032580301SAttilio Rao atpic_assign_cpu(struct intsrc *isrc, u_int apic_id) 40132580301SAttilio Rao { 40232580301SAttilio Rao 40332580301SAttilio Rao /* 40432580301SAttilio Rao * 8259A's are only used in UP in which case all interrupts always 40532580301SAttilio Rao * go to the sole CPU and this function shouldn't even be called. 40632580301SAttilio Rao */ 40732580301SAttilio Rao panic("%s: bad cookie", __func__); 40832580301SAttilio Rao } 40932580301SAttilio Rao 41032580301SAttilio Rao static void 41132580301SAttilio Rao i8259_init(struct atpic *pic, int slave) 41232580301SAttilio Rao { 41332580301SAttilio Rao int imr_addr; 41432580301SAttilio Rao 41532580301SAttilio Rao /* Reset the PIC and program with next four bytes. */ 41632580301SAttilio Rao spinlock_enter(); 41732580301SAttilio Rao outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 41832580301SAttilio Rao imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 41932580301SAttilio Rao 42032580301SAttilio Rao /* Start vector. */ 42132580301SAttilio Rao outb(imr_addr, pic->at_intbase); 42232580301SAttilio Rao 42332580301SAttilio Rao /* 42432580301SAttilio Rao * Setup slave links. For the master pic, indicate what line 42532580301SAttilio Rao * the slave is configured on. For the slave indicate 42632580301SAttilio Rao * which line on the master we are connected to. 42732580301SAttilio Rao */ 42832580301SAttilio Rao if (slave) 42932580301SAttilio Rao outb(imr_addr, ICU_SLAVEID); 43032580301SAttilio Rao else 43132580301SAttilio Rao outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 43232580301SAttilio Rao 43332580301SAttilio Rao /* Set mode. */ 43432580301SAttilio Rao if (slave) 43532580301SAttilio Rao outb(imr_addr, SLAVE_MODE); 43632580301SAttilio Rao else 43732580301SAttilio Rao outb(imr_addr, MASTER_MODE); 43832580301SAttilio Rao 43932580301SAttilio Rao /* Set interrupt enable mask. */ 44062a08214SJohn Baldwin outb(imr_addr, pic->at_imen); 44132580301SAttilio Rao 44232580301SAttilio Rao /* Reset is finished, default to IRR on read. */ 44332580301SAttilio Rao outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 44432580301SAttilio Rao 44532580301SAttilio Rao /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 44632580301SAttilio Rao if (!slave) 44732580301SAttilio Rao outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 4482b375b4eSYoshihiro Takahashi 44932580301SAttilio Rao spinlock_exit(); 45032580301SAttilio Rao } 45132580301SAttilio Rao 45232580301SAttilio Rao void 45332580301SAttilio Rao atpic_startup(void) 45432580301SAttilio Rao { 45532580301SAttilio Rao struct atpic_intsrc *ai; 45632580301SAttilio Rao int i; 45732580301SAttilio Rao 45832580301SAttilio Rao /* Start off with all interrupts disabled. */ 45932580301SAttilio Rao i8259_init(&atpics[MASTER], 0); 46032580301SAttilio Rao i8259_init(&atpics[SLAVE], 1); 46132580301SAttilio Rao atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 46232580301SAttilio Rao 46332580301SAttilio Rao /* Install low-level interrupt handlers for all of our IRQs. */ 46432580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 46532580301SAttilio Rao if (i == ICU_SLAVEID) 46632580301SAttilio Rao continue; 46732580301SAttilio Rao ai->at_intsrc.is_count = &ai->at_count; 46832580301SAttilio Rao ai->at_intsrc.is_straycount = &ai->at_straycount; 46932580301SAttilio Rao setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 470bd50262fSKonstantin Belousov ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC, 471bd50262fSKonstantin Belousov SEL_KPL, GSEL_ATPIC); 47232580301SAttilio Rao } 47332580301SAttilio Rao 47432580301SAttilio Rao /* 47532580301SAttilio Rao * Look for an ELCR. If we find one, update the trigger modes. 47632580301SAttilio Rao * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 47732580301SAttilio Rao * edge triggered and that everything else is level triggered. 47832580301SAttilio Rao * We only use the trigger information to reprogram the ELCR if 47932580301SAttilio Rao * we have one and as an optimization to avoid masking edge 48032580301SAttilio Rao * triggered interrupts. For the case that we don't have an ELCR, 48132580301SAttilio Rao * it doesn't hurt to mask an edge triggered interrupt, so we 48232580301SAttilio Rao * assume level trigger for any interrupt that we aren't sure is 48332580301SAttilio Rao * edge triggered. 48432580301SAttilio Rao */ 48532580301SAttilio Rao if (elcr_found) { 48632580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 48732580301SAttilio Rao ai->at_trigger = elcr_read_trigger(i); 48832580301SAttilio Rao } else { 48932580301SAttilio Rao for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 49032580301SAttilio Rao switch (i) { 49132580301SAttilio Rao case 0: 49232580301SAttilio Rao case 1: 49332580301SAttilio Rao case 2: 49432580301SAttilio Rao case 8: 49532580301SAttilio Rao case 13: 49632580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_EDGE; 49732580301SAttilio Rao break; 49832580301SAttilio Rao default: 49932580301SAttilio Rao ai->at_trigger = INTR_TRIGGER_LEVEL; 50032580301SAttilio Rao break; 50132580301SAttilio Rao } 50232580301SAttilio Rao } 50332580301SAttilio Rao } 50432580301SAttilio Rao 50532580301SAttilio Rao static void 50632580301SAttilio Rao atpic_init(void *dummy __unused) 50732580301SAttilio Rao { 50832580301SAttilio Rao 50932580301SAttilio Rao /* 51032580301SAttilio Rao * Register our PICs, even if we aren't going to use any of their 51132580301SAttilio Rao * pins so that they are suspended and resumed. 51232580301SAttilio Rao */ 51332580301SAttilio Rao if (intr_register_pic(&atpics[0].at_pic) != 0 || 51432580301SAttilio Rao intr_register_pic(&atpics[1].at_pic) != 0) 51532580301SAttilio Rao panic("Unable to register ATPICs"); 51632580301SAttilio Rao 517fd036deaSJohn Baldwin if (num_io_irqs == 0) 518fd036deaSJohn Baldwin num_io_irqs = NUM_ISA_IRQS; 51932580301SAttilio Rao } 520e68c8d7fSRoger Pau Monné SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL); 52132580301SAttilio Rao 52232580301SAttilio Rao void 52332580301SAttilio Rao atpic_handle_intr(u_int vector, struct trapframe *frame) 52432580301SAttilio Rao { 52532580301SAttilio Rao struct intsrc *isrc; 52632580301SAttilio Rao 527f115c061SMark Johnston kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); 528b0f71f1bSMark Johnston kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); 529f115c061SMark Johnston 53032580301SAttilio Rao KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector)); 53132580301SAttilio Rao isrc = &atintrs[vector].at_intsrc; 53232580301SAttilio Rao 53332580301SAttilio Rao /* 53432580301SAttilio Rao * If we don't have an event, see if this is a spurious 53532580301SAttilio Rao * interrupt. 53632580301SAttilio Rao */ 53732580301SAttilio Rao if (isrc->is_event == NULL && (vector == 7 || vector == 15)) { 53832580301SAttilio Rao int port, isr; 53932580301SAttilio Rao 54032580301SAttilio Rao /* 54132580301SAttilio Rao * Read the ISR register to see if IRQ 7/15 is really 54232580301SAttilio Rao * pending. Reset read register back to IRR when done. 54332580301SAttilio Rao */ 54432580301SAttilio Rao port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 54532580301SAttilio Rao spinlock_enter(); 54632580301SAttilio Rao outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 54732580301SAttilio Rao isr = inb(port); 54832580301SAttilio Rao outb(port, OCW3_SEL | OCW3_RR); 54932580301SAttilio Rao spinlock_exit(); 55032580301SAttilio Rao if ((isr & IRQ_MASK(7)) == 0) 55132580301SAttilio Rao return; 55232580301SAttilio Rao } 55332580301SAttilio Rao intr_execute_handlers(isrc, frame); 55432580301SAttilio Rao } 55532580301SAttilio Rao 55632580301SAttilio Rao #ifdef DEV_ISA 55732580301SAttilio Rao /* 55832580301SAttilio Rao * Bus attachment for the ISA PIC. 55932580301SAttilio Rao */ 56032580301SAttilio Rao static struct isa_pnp_id atpic_ids[] = { 56132580301SAttilio Rao { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 56232580301SAttilio Rao { 0 } 56332580301SAttilio Rao }; 56432580301SAttilio Rao 56532580301SAttilio Rao static int 56632580301SAttilio Rao atpic_probe(device_t dev) 56732580301SAttilio Rao { 56832580301SAttilio Rao int result; 56932580301SAttilio Rao 57032580301SAttilio Rao result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 57132580301SAttilio Rao if (result <= 0) 57232580301SAttilio Rao device_quiet(dev); 57332580301SAttilio Rao return (result); 57432580301SAttilio Rao } 57532580301SAttilio Rao 57632580301SAttilio Rao /* 57732580301SAttilio Rao * We might be granted IRQ 2, as this is typically consumed by chaining 57832580301SAttilio Rao * between the two PIC components. If we're using the APIC, however, 57932580301SAttilio Rao * this may not be the case, and as such we should free the resource. 58032580301SAttilio Rao * (XXX untested) 58132580301SAttilio Rao * 58232580301SAttilio Rao * The generic ISA attachment code will handle allocating any other resources 58332580301SAttilio Rao * that we don't explicitly claim here. 58432580301SAttilio Rao */ 58532580301SAttilio Rao static int 58632580301SAttilio Rao atpic_attach(device_t dev) 58732580301SAttilio Rao { 58832580301SAttilio Rao struct resource *res; 58932580301SAttilio Rao int rid; 59032580301SAttilio Rao 59132580301SAttilio Rao /* Try to allocate our IRQ and then free it. */ 59232580301SAttilio Rao rid = 0; 59332580301SAttilio Rao res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 59432580301SAttilio Rao if (res != NULL) 59532580301SAttilio Rao bus_release_resource(dev, SYS_RES_IRQ, rid, res); 59632580301SAttilio Rao return (0); 59732580301SAttilio Rao } 59832580301SAttilio Rao 59932580301SAttilio Rao static device_method_t atpic_methods[] = { 60032580301SAttilio Rao /* Device interface */ 60132580301SAttilio Rao DEVMETHOD(device_probe, atpic_probe), 60232580301SAttilio Rao DEVMETHOD(device_attach, atpic_attach), 60332580301SAttilio Rao DEVMETHOD(device_detach, bus_generic_detach), 60432580301SAttilio Rao DEVMETHOD(device_shutdown, bus_generic_shutdown), 60532580301SAttilio Rao DEVMETHOD(device_suspend, bus_generic_suspend), 60632580301SAttilio Rao DEVMETHOD(device_resume, bus_generic_resume), 60732580301SAttilio Rao { 0, 0 } 60832580301SAttilio Rao }; 60932580301SAttilio Rao 61032580301SAttilio Rao static driver_t atpic_driver = { 61132580301SAttilio Rao "atpic", 61232580301SAttilio Rao atpic_methods, 61332580301SAttilio Rao 1, /* no softc */ 61432580301SAttilio Rao }; 61532580301SAttilio Rao 616*80d2b3deSJohn Baldwin DRIVER_MODULE(atpic, isa, atpic_driver, 0, 0); 617*80d2b3deSJohn Baldwin DRIVER_MODULE(atpic, acpi, atpic_driver, 0, 0); 618d6b66397SWarner Losh ISA_PNP_INFO(atpic_ids); 61932580301SAttilio Rao #endif /* DEV_ISA */ 620