irqmap: Consume the syscall entry in irqmap
[dragonfly.git] / sys / platform / pc32 / icu / icu_abi.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
3 * Copyright (c) 1991 The Regents of the University of California.
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/pc32/icu/icu_abi.c,v 1.14 2007/07/07 12:13:47 sephe 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/intr_machdep.h>
52#include <machine/globaldata.h>
53#include <machine/smp.h>
54
55#include <sys/thread2.h>
56
57#include <machine_base/apic/ioapic_abi.h>
58#include <machine_base/isa/elcr_var.h>
59
60#include "icu.h"
61#include "icu_ipl.h"
62
63extern inthand_t
64 IDTVEC(icu_intr0), IDTVEC(icu_intr1),
65 IDTVEC(icu_intr2), IDTVEC(icu_intr3),
66 IDTVEC(icu_intr4), IDTVEC(icu_intr5),
67 IDTVEC(icu_intr6), IDTVEC(icu_intr7),
68 IDTVEC(icu_intr8), IDTVEC(icu_intr9),
69 IDTVEC(icu_intr10), IDTVEC(icu_intr11),
70 IDTVEC(icu_intr12), IDTVEC(icu_intr13),
71 IDTVEC(icu_intr14), IDTVEC(icu_intr15);
72
73static inthand_t *icu_intr[ICU_HWI_VECTORS] = {
74 &IDTVEC(icu_intr0), &IDTVEC(icu_intr1),
75 &IDTVEC(icu_intr2), &IDTVEC(icu_intr3),
76 &IDTVEC(icu_intr4), &IDTVEC(icu_intr5),
77 &IDTVEC(icu_intr6), &IDTVEC(icu_intr7),
78 &IDTVEC(icu_intr8), &IDTVEC(icu_intr9),
79 &IDTVEC(icu_intr10), &IDTVEC(icu_intr11),
80 &IDTVEC(icu_intr12), &IDTVEC(icu_intr13),
81 &IDTVEC(icu_intr14), &IDTVEC(icu_intr15)
82};
83
84static struct icu_irqmap {
85 int im_type; /* ICU_IMT_ */
86 enum intr_trigger im_trig;
87} icu_irqmaps[MAX_HARDINTS]; /* XXX MAX_HARDINTS may not be correct */
88
89#define ICU_IMT_UNUSED 0 /* KEEP THIS */
90#define ICU_IMT_RESERVED 1
91#define ICU_IMT_LINE 2
92#define ICU_IMT_SYSCALL 3
93
94extern void ICU_INTREN(int);
95extern void ICU_INTRDIS(int);
96
97static int icu_vectorctl(int, int, int);
98static int icu_setvar(int, const void *);
99static int icu_getvar(int, void *);
100static void icu_finalize(void);
101static void icu_cleanup(void);
102static void icu_setdefault(void);
103static void icu_stabilize(void);
104static void icu_initmap(void);
105
106struct machintr_abi MachIntrABI_ICU = {
107 MACHINTR_ICU,
108 .intrdis = ICU_INTRDIS,
109 .intren = ICU_INTREN,
110 .vectorctl = icu_vectorctl,
111 .setvar = icu_setvar,
112 .getvar = icu_getvar,
113 .finalize = icu_finalize,
114 .cleanup = icu_cleanup,
115 .setdefault = icu_setdefault,
116 .stabilize = icu_stabilize,
117 .initmap = icu_initmap
118};
119
120static int icu_imcr_present;
121
122/*
123 * WARNING! SMP builds can use the ICU now so this code must be MP safe.
124 */
125static int
126icu_setvar(int varid, const void *buf)
127{
128 int error = 0;
129
130 switch (varid) {
131 case MACHINTR_VAR_IMCR_PRESENT:
132 icu_imcr_present = *(const int *)buf;
133 break;
134
135 default:
136 error = ENOENT;
137 break;
138 }
139 return error;
140}
141
142static int
143icu_getvar(int varid, void *buf)
144{
145 int error = 0;
146
147 switch (varid) {
148 case MACHINTR_VAR_IMCR_PRESENT:
149 *(int *)buf = icu_imcr_present;
150 break;
151
152 default:
153 error = ENOENT;
154 break;
155 }
156 return error;
157}
158
159/*
160 * Called before interrupts are physically enabled
161 */
162static void
163icu_stabilize(void)
164{
165 int intr;
166
167 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr)
168 machintr_intrdis(intr);
169 machintr_intren(ICU_IRQ_SLAVE);
170}
171
172/*
173 * Called after interrupts physically enabled but before the
174 * critical section is released.
175 */
176static void
177icu_cleanup(void)
178{
179 bzero(mdcpu->gd_ipending, sizeof(mdcpu->gd_ipending));
180}
181
182/*
183 * Called after stablize and cleanup; critical section is not
184 * held and interrupts are not physically disabled.
185 *
186 * For SMP:
187 * Further delayed after BSP's LAPIC is initialized
188 */
189static void
190icu_finalize(void)
191{
192 KKASSERT(MachIntrABI.type == MACHINTR_ICU);
193
194#ifdef SMP
195 if (apic_io_enable) {
196 /*
197 * MachIntrABI switching will happen in
198 * MachIntrABI_IOAPIC.finalize()
199 */
200 MachIntrABI_IOAPIC.setvar(MACHINTR_VAR_IMCR_PRESENT,
201 &icu_imcr_present);
202 MachIntrABI_IOAPIC.finalize();
203 return;
204 }
205
206 /*
207 * If an IMCR is present, programming bit 0 disconnects the 8259
208 * from the BSP. The 8259 may still be connected to LINT0 on the
209 * BSP's LAPIC.
210 *
211 * If we are running SMP the LAPIC is active, try to use virtual
212 * wire mode so we can use other interrupt sources within the LAPIC
213 * in addition to the 8259.
214 */
215 if (icu_imcr_present) {
216 u_long ef;
217
218 crit_enter();
219
220 ef = read_eflags();
221 cpu_disable_intr();
222
223 outb(0x22, 0x70);
224 outb(0x23, 0x01);
225
226 write_eflags(ef);
227
228 crit_exit();
229 }
230#endif /* SMP */
231}
232
233static int
234icu_vectorctl(int op, int intr, int flags)
235{
236 int error;
237 u_long ef;
238
239 if (intr < 0 || intr >= ICU_HWI_VECTORS || intr == ICU_IRQ_SLAVE)
240 return EINVAL;
241
242 ef = read_eflags();
243 cpu_disable_intr();
244 error = 0;
245
246 switch (op) {
247 case MACHINTR_VECTOR_SETUP:
248 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYS386IGT,
249 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
250 machintr_intren(intr);
251 break;
252
253 case MACHINTR_VECTOR_TEARDOWN:
254 machintr_intrdis(intr);
255 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYS386IGT,
256 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
257 break;
258
259 default:
260 error = EOPNOTSUPP;
261 break;
262 }
263 write_eflags(ef);
264 return error;
265}
266
267static void
268icu_setdefault(void)
269{
270 int intr;
271
272 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) {
273 if (intr == ICU_IRQ_SLAVE)
274 continue;
275 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYS386IGT,
276 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
277 }
278}
279
280static void
281icu_initmap(void)
282{
283 int i;
284
285 for (i = 0; i < ICU_HWI_VECTORS; ++i)
286 icu_irqmaps[i].im_type = ICU_IMT_LINE;
287 icu_irqmaps[ICU_IRQ_SLAVE].im_type = ICU_IMT_RESERVED;
288
289 if (elcr_found) {
290 for (i = 0; i < ICU_HWI_VECTORS; ++i)
291 icu_irqmaps[i].im_trig = elcr_read_trigger(i);
292 } else {
293 for (i = 0; i < ICU_HWI_VECTORS; ++i) {
294 switch (i) {
295 case 0:
296 case 1:
297 case 2:
298 case 8:
299 case 13:
300 icu_irqmaps[i].im_trig = INTR_TRIGGER_EDGE;
301 break;
302
303 default:
304 icu_irqmaps[i].im_trig = INTR_TRIGGER_LEVEL;
305 break;
306 }
307 }
308 }
309 icu_irqmaps[IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type = ICU_IMT_SYSCALL;
310}