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 extern void ICU_INTREN(int); 60 extern void ICU_INTRDIS(int); 61 62 extern inthand_t 63 IDTVEC(icu_intr0), IDTVEC(icu_intr1), 64 IDTVEC(icu_intr2), IDTVEC(icu_intr3), 65 IDTVEC(icu_intr4), IDTVEC(icu_intr5), 66 IDTVEC(icu_intr6), IDTVEC(icu_intr7), 67 IDTVEC(icu_intr8), IDTVEC(icu_intr9), 68 IDTVEC(icu_intr10), IDTVEC(icu_intr11), 69 IDTVEC(icu_intr12), IDTVEC(icu_intr13), 70 IDTVEC(icu_intr14), IDTVEC(icu_intr15); 71 72 static int icu_vectorctl(int, int, int); 73 static int icu_setvar(int, const void *); 74 static int icu_getvar(int, void *); 75 static void icu_finalize(void); 76 static void icu_cleanup(void); 77 78 static inthand_t *icu_intr[ICU_HWI_VECTORS] = { 79 &IDTVEC(icu_intr0), &IDTVEC(icu_intr1), 80 &IDTVEC(icu_intr2), &IDTVEC(icu_intr3), 81 &IDTVEC(icu_intr4), &IDTVEC(icu_intr5), 82 &IDTVEC(icu_intr6), &IDTVEC(icu_intr7), 83 &IDTVEC(icu_intr8), &IDTVEC(icu_intr9), 84 &IDTVEC(icu_intr10), &IDTVEC(icu_intr11), 85 &IDTVEC(icu_intr12), &IDTVEC(icu_intr13), 86 &IDTVEC(icu_intr14), &IDTVEC(icu_intr15) 87 }; 88 89 struct machintr_abi MachIntrABI_ICU = { 90 MACHINTR_ICU, 91 .intrdis = ICU_INTRDIS, 92 .intren = ICU_INTREN, 93 .vectorctl = icu_vectorctl, 94 .setvar = icu_setvar, 95 .getvar = icu_getvar, 96 .finalize = icu_finalize, 97 .cleanup = icu_cleanup 98 }; 99 100 static int icu_imcr_present; 101 102 /* 103 * WARNING! SMP builds can use the ICU now so this code must be MP safe. 104 */ 105 static int 106 icu_setvar(int varid, const void *buf) 107 { 108 int error = 0; 109 110 switch(varid) { 111 case MACHINTR_VAR_IMCR_PRESENT: 112 icu_imcr_present = *(const int *)buf; 113 break; 114 115 default: 116 error = ENOENT; 117 break; 118 } 119 return error; 120 } 121 122 static int 123 icu_getvar(int varid, void *buf) 124 { 125 int error = 0; 126 127 switch(varid) { 128 case MACHINTR_VAR_IMCR_PRESENT: 129 *(int *)buf = icu_imcr_present; 130 break; 131 132 default: 133 error = ENOENT; 134 break; 135 } 136 return error; 137 } 138 139 /* 140 * Called before interrupts are physically enabled 141 */ 142 static void 143 icu_finalize(void) 144 { 145 int intr; 146 147 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) 148 machintr_intrdis(intr); 149 machintr_intren(ICU_IRQ_SLAVE); 150 151 #if defined(SMP) 152 /* 153 * If an IMCR is present, programming bit 0 disconnects the 8259 154 * from the BSP. The 8259 may still be connected to LINT0 on the 155 * BSP's LAPIC. 156 * 157 * If we are running SMP the LAPIC is active, try to use virtual 158 * wire mode so we can use other interrupt sources within the LAPIC 159 * in addition to the 8259. 160 */ 161 if (icu_imcr_present) { 162 outb(0x22, 0x70); 163 outb(0x23, 0x01); 164 } 165 #endif 166 } 167 168 /* 169 * Called after interrupts physically enabled but before the 170 * critical section is released. 171 */ 172 static void 173 icu_cleanup(void) 174 { 175 mdcpu->gd_fpending = 0; 176 } 177 178 179 static int 180 icu_vectorctl(int op, int intr, int flags) 181 { 182 int error; 183 register_t ef; 184 185 if (intr < 0 || intr >= ICU_HWI_VECTORS || intr == ICU_IRQ_SLAVE) 186 return EINVAL; 187 188 ef = read_rflags(); 189 cpu_disable_intr(); 190 error = 0; 191 192 switch(op) { 193 case MACHINTR_VECTOR_SETUP: 194 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYSIGT, 195 SEL_KPL, 0); 196 machintr_intren(intr); 197 break; 198 199 case MACHINTR_VECTOR_TEARDOWN: 200 case MACHINTR_VECTOR_SETDEFAULT: 201 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYSIGT, 202 SEL_KPL, 0); 203 machintr_intrdis(intr); 204 break; 205 206 default: 207 error = EOPNOTSUPP; 208 break; 209 } 210 write_rflags(ef); 211 return error; 212 } 213