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/rman.h> 48 #include <sys/bus.h> 49 50 #include <machine/segments.h> 51 #include <machine/md_var.h> 52 #include <machine/intr_machdep.h> 53 #include <machine/globaldata.h> 54 #include <machine/smp.h> 55 56 #include <sys/thread2.h> 57 58 #include <machine_base/icu/elcr_var.h> 59 60 #include <machine_base/icu/icu.h> 61 #include <machine_base/icu/icu_ipl.h> 62 #include <machine_base/apic/ioapic.h> 63 64 extern inthand_t 65 IDTVEC(icu_intr0), IDTVEC(icu_intr1), 66 IDTVEC(icu_intr2), IDTVEC(icu_intr3), 67 IDTVEC(icu_intr4), IDTVEC(icu_intr5), 68 IDTVEC(icu_intr6), IDTVEC(icu_intr7), 69 IDTVEC(icu_intr8), IDTVEC(icu_intr9), 70 IDTVEC(icu_intr10), IDTVEC(icu_intr11), 71 IDTVEC(icu_intr12), IDTVEC(icu_intr13), 72 IDTVEC(icu_intr14), IDTVEC(icu_intr15); 73 74 static inthand_t *icu_intr[ICU_HWI_VECTORS] = { 75 &IDTVEC(icu_intr0), &IDTVEC(icu_intr1), 76 &IDTVEC(icu_intr2), &IDTVEC(icu_intr3), 77 &IDTVEC(icu_intr4), &IDTVEC(icu_intr5), 78 &IDTVEC(icu_intr6), &IDTVEC(icu_intr7), 79 &IDTVEC(icu_intr8), &IDTVEC(icu_intr9), 80 &IDTVEC(icu_intr10), &IDTVEC(icu_intr11), 81 &IDTVEC(icu_intr12), &IDTVEC(icu_intr13), 82 &IDTVEC(icu_intr14), &IDTVEC(icu_intr15) 83 }; 84 85 static struct icu_irqmap { 86 int im_type; /* ICU_IMT_ */ 87 enum intr_trigger im_trig; 88 } icu_irqmaps[MAXCPU][IDT_HWI_VECTORS]; 89 90 #define ICU_IMT_UNUSED 0 /* KEEP THIS */ 91 #define ICU_IMT_RESERVED 1 92 #define ICU_IMT_LINE 2 93 #define ICU_IMT_SYSCALL 3 94 95 #define ICU_IMT_ISHWI(map) ((map)->im_type != ICU_IMT_RESERVED && \ 96 (map)->im_type != ICU_IMT_SYSCALL) 97 98 extern void ICU_INTREN(int); 99 extern void ICU_INTRDIS(int); 100 101 extern int imcr_present; 102 103 static void icu_abi_intr_setup(int, int); 104 static void icu_abi_intr_teardown(int); 105 static void icu_abi_intr_config(int, enum intr_trigger, enum intr_polarity); 106 static int icu_abi_intr_cpuid(int); 107 108 static void icu_abi_finalize(void); 109 static void icu_abi_cleanup(void); 110 static void icu_abi_setdefault(void); 111 static void icu_abi_stabilize(void); 112 static void icu_abi_initmap(void); 113 static void icu_abi_rman_setup(struct rman *); 114 115 struct machintr_abi MachIntrABI_ICU = { 116 MACHINTR_ICU, 117 .intr_disable = ICU_INTRDIS, 118 .intr_enable = ICU_INTREN, 119 .intr_setup = icu_abi_intr_setup, 120 .intr_teardown = icu_abi_intr_teardown, 121 .intr_config = icu_abi_intr_config, 122 .intr_cpuid = icu_abi_intr_cpuid, 123 124 .finalize = icu_abi_finalize, 125 .cleanup = icu_abi_cleanup, 126 .setdefault = icu_abi_setdefault, 127 .stabilize = icu_abi_stabilize, 128 .initmap = icu_abi_initmap, 129 .rman_setup = icu_abi_rman_setup 130 }; 131 132 /* 133 * WARNING! SMP builds can use the ICU now so this code must be MP safe. 134 */ 135 136 /* 137 * Called before interrupts are physically enabled 138 */ 139 static void 140 icu_abi_stabilize(void) 141 { 142 int intr; 143 144 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) 145 machintr_intr_disable(intr); 146 machintr_intr_enable(ICU_IRQ_SLAVE); 147 } 148 149 /* 150 * Called after interrupts physically enabled but before the 151 * critical section is released. 152 */ 153 static void 154 icu_abi_cleanup(void) 155 { 156 bzero(mdcpu->gd_ipending, sizeof(mdcpu->gd_ipending)); 157 } 158 159 /* 160 * Called after stablize and cleanup; critical section is not 161 * held and interrupts are not physically disabled. 162 */ 163 static void 164 icu_abi_finalize(void) 165 { 166 KKASSERT(MachIntrABI.type == MACHINTR_ICU); 167 KKASSERT(!ioapic_enable); 168 169 /* 170 * If an IMCR is present, programming bit 0 disconnects the 8259 171 * from the BSP. The 8259 may still be connected to LINT0 on the 172 * BSP's LAPIC. 173 * 174 * If we are running SMP the LAPIC is active, try to use virtual 175 * wire mode so we can use other interrupt sources within the LAPIC 176 * in addition to the 8259. 177 */ 178 if (imcr_present) { 179 outb(0x22, 0x70); 180 outb(0x23, 0x01); 181 } 182 } 183 184 static void 185 icu_abi_intr_setup(int intr, int flags) 186 { 187 register_t ef; 188 189 KKASSERT(intr >= 0 && intr < ICU_HWI_VECTORS && intr != ICU_IRQ_SLAVE); 190 191 ef = read_rflags(); 192 cpu_disable_intr(); 193 194 machintr_intr_enable(intr); 195 196 write_rflags(ef); 197 } 198 199 static void 200 icu_abi_intr_teardown(int intr) 201 { 202 register_t ef; 203 204 KKASSERT(intr >= 0 && intr < ICU_HWI_VECTORS && intr != ICU_IRQ_SLAVE); 205 206 ef = read_rflags(); 207 cpu_disable_intr(); 208 209 machintr_intr_disable(intr); 210 211 write_rflags(ef); 212 } 213 214 static void 215 icu_abi_setdefault(void) 216 { 217 int intr; 218 219 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) { 220 if (intr == ICU_IRQ_SLAVE) 221 continue; 222 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYSIGT, 223 SEL_KPL, 0); 224 } 225 } 226 227 static void 228 icu_abi_initmap(void) 229 { 230 int cpu; 231 232 /* 233 * NOTE: ncpus is not ready yet 234 */ 235 for (cpu = 0; cpu < MAXCPU; ++cpu) { 236 int i; 237 238 if (cpu != 0) { 239 for (i = 0; i < ICU_HWI_VECTORS; ++i) 240 icu_irqmaps[cpu][i].im_type = ICU_IMT_RESERVED; 241 } else { 242 for (i = 0; i < ICU_HWI_VECTORS; ++i) 243 icu_irqmaps[cpu][i].im_type = ICU_IMT_LINE; 244 icu_irqmaps[cpu][ICU_IRQ_SLAVE].im_type = 245 ICU_IMT_RESERVED; 246 247 if (elcr_found) { 248 for (i = 0; i < ICU_HWI_VECTORS; ++i) { 249 icu_irqmaps[cpu][i].im_trig = 250 elcr_read_trigger(i); 251 } 252 } else { 253 /* 254 * NOTE: Trigger mode does not matter at all 255 */ 256 for (i = 0; i < ICU_HWI_VECTORS; ++i) { 257 icu_irqmaps[cpu][i].im_trig = 258 INTR_TRIGGER_EDGE; 259 } 260 } 261 } 262 icu_irqmaps[cpu][IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type = 263 ICU_IMT_SYSCALL; 264 } 265 } 266 267 static void 268 icu_abi_intr_config(int irq, enum intr_trigger trig, 269 enum intr_polarity pola __unused) 270 { 271 struct icu_irqmap *map; 272 273 KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL); 274 275 KKASSERT(irq >= 0 && irq < IDT_HWI_VECTORS); 276 map = &icu_irqmaps[0][irq]; 277 278 KKASSERT(map->im_type == ICU_IMT_LINE); 279 280 /* TODO: Check whether it is configured or not */ 281 282 if (trig == map->im_trig) 283 return; 284 285 if (bootverbose) { 286 kprintf("ICU: irq %d, %s -> %s\n", irq, 287 intr_str_trigger(map->im_trig), 288 intr_str_trigger(trig)); 289 } 290 map->im_trig = trig; 291 292 if (!elcr_found) { 293 if (bootverbose) 294 kprintf("ICU: no ELCR, skip irq %d config\n", irq); 295 return; 296 } 297 elcr_write_trigger(irq, map->im_trig); 298 } 299 300 static int 301 icu_abi_intr_cpuid(int irq __unused) 302 { 303 return 0; 304 } 305 306 static void 307 icu_abi_rman_setup(struct rman *rm) 308 { 309 int start, end, i; 310 311 KASSERT(rm->rm_cpuid >= 0 && rm->rm_cpuid < MAXCPU, 312 ("invalid rman cpuid %d", rm->rm_cpuid)); 313 314 start = end = -1; 315 for (i = 0; i < IDT_HWI_VECTORS; ++i) { 316 const struct icu_irqmap *map = &icu_irqmaps[rm->rm_cpuid][i]; 317 318 if (start < 0) { 319 if (ICU_IMT_ISHWI(map)) 320 start = end = i; 321 } else { 322 if (ICU_IMT_ISHWI(map)) { 323 end = i; 324 } else { 325 KKASSERT(end >= 0); 326 if (bootverbose) { 327 kprintf("ICU: rman cpu%d %d - %d\n", 328 rm->rm_cpuid, start, end); 329 } 330 if (rman_manage_region(rm, start, end)) { 331 panic("rman_manage_region" 332 "(cpu%d %d - %d)", rm->rm_cpuid, 333 start, end); 334 } 335 start = end = -1; 336 } 337 } 338 } 339 if (start >= 0) { 340 KKASSERT(end >= 0); 341 if (bootverbose) { 342 kprintf("ICU: rman cpu%d %d - %d\n", 343 rm->rm_cpuid, start, end); 344 } 345 if (rman_manage_region(rm, start, end)) { 346 panic("rman_manage_region(cpu%d %d - %d)", 347 rm->rm_cpuid, start, end); 348 } 349 } 350 } 351