1 /* 2 * Copyright (c) 1991 The Regents of the University of California. 3 * Copyright (c) 2005,2008 The DragonFly Project. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@backplane.com> 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in 20 * the documentation and/or other materials provided with the 21 * distribution. 22 * 3. Neither the name of The DragonFly Project nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific, prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 34 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 36 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * $DragonFly: src/sys/platform/pc64/icu/icu_abi.c,v 1.1 2008/08/29 17:07:16 dillon Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/machintr.h> 46 #include <sys/interrupt.h> 47 #include <sys/bus.h> 48 49 #include <machine/segments.h> 50 #include <machine/md_var.h> 51 #include <machine_base/isa/intr_machdep.h> 52 #include <machine/globaldata.h> 53 54 #include <sys/thread2.h> 55 56 #include "icu.h" 57 #include "icu_ipl.h" 58 59 #ifndef APIC_IO 60 61 extern void ICU_INTREN(int); 62 extern void ICU_INTRDIS(int); 63 64 extern inthand_t 65 IDTVEC(icu_fastintr0), IDTVEC(icu_fastintr1), 66 IDTVEC(icu_fastintr2), IDTVEC(icu_fastintr3), 67 IDTVEC(icu_fastintr4), IDTVEC(icu_fastintr5), 68 IDTVEC(icu_fastintr6), IDTVEC(icu_fastintr7), 69 IDTVEC(icu_fastintr8), IDTVEC(icu_fastintr9), 70 IDTVEC(icu_fastintr10), IDTVEC(icu_fastintr11), 71 IDTVEC(icu_fastintr12), IDTVEC(icu_fastintr13), 72 IDTVEC(icu_fastintr14), IDTVEC(icu_fastintr15); 73 74 extern inthand_t 75 IDTVEC(icu_slowintr0), IDTVEC(icu_slowintr1), 76 IDTVEC(icu_slowintr2), IDTVEC(icu_slowintr3), 77 IDTVEC(icu_slowintr4), IDTVEC(icu_slowintr5), 78 IDTVEC(icu_slowintr6), IDTVEC(icu_slowintr7), 79 IDTVEC(icu_slowintr8), IDTVEC(icu_slowintr9), 80 IDTVEC(icu_slowintr10), IDTVEC(icu_slowintr11), 81 IDTVEC(icu_slowintr12), IDTVEC(icu_slowintr13), 82 IDTVEC(icu_slowintr14), IDTVEC(icu_slowintr15); 83 84 static int icu_vectorctl(int, int, int); 85 static int icu_setvar(int, const void *); 86 static int icu_getvar(int, void *); 87 static void icu_finalize(void); 88 static void icu_cleanup(void); 89 90 static inthand_t *icu_fastintr[ICU_HWI_VECTORS] = { 91 &IDTVEC(icu_fastintr0), &IDTVEC(icu_fastintr1), 92 &IDTVEC(icu_fastintr2), &IDTVEC(icu_fastintr3), 93 &IDTVEC(icu_fastintr4), &IDTVEC(icu_fastintr5), 94 &IDTVEC(icu_fastintr6), &IDTVEC(icu_fastintr7), 95 &IDTVEC(icu_fastintr8), &IDTVEC(icu_fastintr9), 96 &IDTVEC(icu_fastintr10), &IDTVEC(icu_fastintr11), 97 &IDTVEC(icu_fastintr12), &IDTVEC(icu_fastintr13), 98 &IDTVEC(icu_fastintr14), &IDTVEC(icu_fastintr15) 99 }; 100 101 static inthand_t *icu_slowintr[ICU_HWI_VECTORS] = { 102 &IDTVEC(icu_slowintr0), &IDTVEC(icu_slowintr1), 103 &IDTVEC(icu_slowintr2), &IDTVEC(icu_slowintr3), 104 &IDTVEC(icu_slowintr4), &IDTVEC(icu_slowintr5), 105 &IDTVEC(icu_slowintr6), &IDTVEC(icu_slowintr7), 106 &IDTVEC(icu_slowintr8), &IDTVEC(icu_slowintr9), 107 &IDTVEC(icu_slowintr10), &IDTVEC(icu_slowintr11), 108 &IDTVEC(icu_slowintr12), &IDTVEC(icu_slowintr13), 109 &IDTVEC(icu_slowintr14), &IDTVEC(icu_slowintr15) 110 }; 111 112 struct machintr_abi MachIntrABI = { 113 MACHINTR_ICU, 114 .intrdis = ICU_INTRDIS, 115 .intren = ICU_INTREN, 116 .vectorctl =icu_vectorctl, 117 .setvar = icu_setvar, 118 .getvar = icu_getvar, 119 .finalize = icu_finalize, 120 .cleanup = icu_cleanup 121 }; 122 123 static int icu_imcr_present; 124 125 /* 126 * WARNING! SMP builds can use the ICU now so this code must be MP safe. 127 */ 128 static 129 int 130 icu_setvar(int varid, const void *buf) 131 { 132 int error = 0; 133 134 switch(varid) { 135 case MACHINTR_VAR_IMCR_PRESENT: 136 icu_imcr_present = *(const int *)buf; 137 break; 138 default: 139 error = ENOENT; 140 break; 141 } 142 return (error); 143 } 144 145 static 146 int 147 icu_getvar(int varid, void *buf) 148 { 149 int error = 0; 150 151 switch(varid) { 152 case MACHINTR_VAR_IMCR_PRESENT: 153 *(int *)buf = icu_imcr_present; 154 break; 155 default: 156 error = ENOENT; 157 break; 158 } 159 return (error); 160 } 161 162 /* 163 * Called before interrupts are physically enabled 164 */ 165 static void 166 icu_finalize(void) 167 { 168 int intr; 169 170 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) { 171 machintr_intrdis(intr); 172 } 173 machintr_intren(ICU_IRQ_SLAVE); 174 175 /* 176 * If an IMCR is present, programming bit 0 disconnects the 8259 177 * from the BSP. The 8259 may still be connected to LINT0 on the BSP's 178 * LAPIC. 179 * 180 * If we are running SMP the LAPIC is active, try to use virtual wire 181 * mode so we can use other interrupt sources within the LAPIC in 182 * addition to the 8259. 183 */ 184 if (icu_imcr_present) { 185 #if defined(SMP) 186 outb(0x22, 0x70); 187 outb(0x23, 0x01); 188 #endif 189 } 190 } 191 192 /* 193 * Called after interrupts physically enabled but before the 194 * critical section is released. 195 */ 196 static 197 void 198 icu_cleanup(void) 199 { 200 mdcpu->gd_fpending = 0; 201 mdcpu->gd_ipending = 0; 202 } 203 204 205 static 206 int 207 icu_vectorctl(int op, int intr, int flags) 208 { 209 int error; 210 register_t ef; 211 212 if (intr < 0 || intr >= ICU_HWI_VECTORS || intr == ICU_IRQ_SLAVE) 213 return (EINVAL); 214 215 ef = read_rflags(); 216 cpu_disable_intr(); 217 error = 0; 218 219 switch(op) { 220 case MACHINTR_VECTOR_SETUP: 221 setidt(IDT_OFFSET + intr, 222 flags & INTR_FAST ? icu_fastintr[intr] : icu_slowintr[intr], 223 SDT_SYSIGT, SEL_KPL, 0); 224 machintr_intren(intr); 225 break; 226 case MACHINTR_VECTOR_TEARDOWN: 227 case MACHINTR_VECTOR_SETDEFAULT: 228 setidt(IDT_OFFSET + intr, icu_slowintr[intr], 229 SDT_SYSIGT, SEL_KPL, 0); 230 machintr_intrdis(intr); 231 break; 232 default: 233 error = EOPNOTSUPP; 234 break; 235 } 236 write_rflags(ef); 237 return (error); 238 } 239 240 #endif 241