MachIntr: Add two methods to find IRQ
[dragonfly.git] / sys / platform / pc64 / apic / ioapic_abi.c
CommitLineData
c8fe38ae
MD
1/*
2 * Copyright (c) 1991 The Regents of the University of California.
3 * Copyright (c) 1996, by Steve Passe. All rights reserved.
4 * Copyright (c) 2005,2008 The DragonFly Project. All rights reserved.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The DragonFly Project
8 * by Matthew Dillon <dillon@backplane.com>
9 *
10 * This code is derived from software contributed to Berkeley by
11 * William Jolitz.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided with the
22 * distribution.
23 * 3. Neither the name of The DragonFly Project nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific, prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
c8fe38ae
MD
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/machintr.h>
45#include <sys/interrupt.h>
46#include <sys/bus.h>
981239a7 47#include <sys/rman.h>
95874ffd 48#include <sys/thread2.h>
c8fe38ae
MD
49
50#include <machine/smp.h>
51#include <machine/segments.h>
52#include <machine/md_var.h>
57a9c56b 53#include <machine/intr_machdep.h>
c8fe38ae 54#include <machine/globaldata.h>
4234567c 55#include <machine/msi_var.h>
c8fe38ae 56
104463f2 57#include <machine_base/isa/isa_intr.h>
61452645 58#include <machine_base/icu/icu.h>
6b809ec7 59#include <machine_base/icu/icu_var.h>
61452645 60#include <machine_base/apic/ioapic.h>
929c940f 61#include <machine_base/apic/ioapic_abi.h>
77f86d14 62#include <machine_base/apic/ioapic_ipl.h>
9a4bd8f3 63#include <machine_base/apic/apicreg.h>
c8fe38ae 64
95874ffd
SZ
65#include <dev/acpica5/acpi_sci_var.h>
66
451af8d9
SZ
67#define IOAPIC_HWI_VECTORS IDT_HWI_VECTORS
68
c8fe38ae 69extern inthand_t
9e0e3f85
SZ
70 IDTVEC(ioapic_intr0),
71 IDTVEC(ioapic_intr1),
72 IDTVEC(ioapic_intr2),
73 IDTVEC(ioapic_intr3),
74 IDTVEC(ioapic_intr4),
75 IDTVEC(ioapic_intr5),
76 IDTVEC(ioapic_intr6),
77 IDTVEC(ioapic_intr7),
78 IDTVEC(ioapic_intr8),
79 IDTVEC(ioapic_intr9),
80 IDTVEC(ioapic_intr10),
81 IDTVEC(ioapic_intr11),
82 IDTVEC(ioapic_intr12),
83 IDTVEC(ioapic_intr13),
84 IDTVEC(ioapic_intr14),
85 IDTVEC(ioapic_intr15),
86 IDTVEC(ioapic_intr16),
87 IDTVEC(ioapic_intr17),
88 IDTVEC(ioapic_intr18),
89 IDTVEC(ioapic_intr19),
90 IDTVEC(ioapic_intr20),
91 IDTVEC(ioapic_intr21),
92 IDTVEC(ioapic_intr22),
93 IDTVEC(ioapic_intr23),
94 IDTVEC(ioapic_intr24),
95 IDTVEC(ioapic_intr25),
96 IDTVEC(ioapic_intr26),
97 IDTVEC(ioapic_intr27),
98 IDTVEC(ioapic_intr28),
99 IDTVEC(ioapic_intr29),
100 IDTVEC(ioapic_intr30),
101 IDTVEC(ioapic_intr31),
102 IDTVEC(ioapic_intr32),
103 IDTVEC(ioapic_intr33),
104 IDTVEC(ioapic_intr34),
105 IDTVEC(ioapic_intr35),
106 IDTVEC(ioapic_intr36),
107 IDTVEC(ioapic_intr37),
108 IDTVEC(ioapic_intr38),
109 IDTVEC(ioapic_intr39),
110 IDTVEC(ioapic_intr40),
111 IDTVEC(ioapic_intr41),
112 IDTVEC(ioapic_intr42),
113 IDTVEC(ioapic_intr43),
114 IDTVEC(ioapic_intr44),
115 IDTVEC(ioapic_intr45),
116 IDTVEC(ioapic_intr46),
117 IDTVEC(ioapic_intr47),
118 IDTVEC(ioapic_intr48),
119 IDTVEC(ioapic_intr49),
120 IDTVEC(ioapic_intr50),
121 IDTVEC(ioapic_intr51),
122 IDTVEC(ioapic_intr52),
123 IDTVEC(ioapic_intr53),
124 IDTVEC(ioapic_intr54),
125 IDTVEC(ioapic_intr55),
126 IDTVEC(ioapic_intr56),
127 IDTVEC(ioapic_intr57),
128 IDTVEC(ioapic_intr58),
129 IDTVEC(ioapic_intr59),
130 IDTVEC(ioapic_intr60),
131 IDTVEC(ioapic_intr61),
132 IDTVEC(ioapic_intr62),
133 IDTVEC(ioapic_intr63),
134 IDTVEC(ioapic_intr64),
135 IDTVEC(ioapic_intr65),
136 IDTVEC(ioapic_intr66),
137 IDTVEC(ioapic_intr67),
138 IDTVEC(ioapic_intr68),
139 IDTVEC(ioapic_intr69),
140 IDTVEC(ioapic_intr70),
141 IDTVEC(ioapic_intr71),
142 IDTVEC(ioapic_intr72),
143 IDTVEC(ioapic_intr73),
144 IDTVEC(ioapic_intr74),
145 IDTVEC(ioapic_intr75),
146 IDTVEC(ioapic_intr76),
147 IDTVEC(ioapic_intr77),
148 IDTVEC(ioapic_intr78),
149 IDTVEC(ioapic_intr79),
150 IDTVEC(ioapic_intr80),
151 IDTVEC(ioapic_intr81),
152 IDTVEC(ioapic_intr82),
153 IDTVEC(ioapic_intr83),
154 IDTVEC(ioapic_intr84),
155 IDTVEC(ioapic_intr85),
156 IDTVEC(ioapic_intr86),
157 IDTVEC(ioapic_intr87),
158 IDTVEC(ioapic_intr88),
159 IDTVEC(ioapic_intr89),
160 IDTVEC(ioapic_intr90),
161 IDTVEC(ioapic_intr91),
162 IDTVEC(ioapic_intr92),
163 IDTVEC(ioapic_intr93),
164 IDTVEC(ioapic_intr94),
165 IDTVEC(ioapic_intr95),
166 IDTVEC(ioapic_intr96),
167 IDTVEC(ioapic_intr97),
168 IDTVEC(ioapic_intr98),
169 IDTVEC(ioapic_intr99),
170 IDTVEC(ioapic_intr100),
171 IDTVEC(ioapic_intr101),
172 IDTVEC(ioapic_intr102),
173 IDTVEC(ioapic_intr103),
174 IDTVEC(ioapic_intr104),
175 IDTVEC(ioapic_intr105),
176 IDTVEC(ioapic_intr106),
177 IDTVEC(ioapic_intr107),
178 IDTVEC(ioapic_intr108),
179 IDTVEC(ioapic_intr109),
180 IDTVEC(ioapic_intr110),
181 IDTVEC(ioapic_intr111),
182 IDTVEC(ioapic_intr112),
183 IDTVEC(ioapic_intr113),
184 IDTVEC(ioapic_intr114),
185 IDTVEC(ioapic_intr115),
186 IDTVEC(ioapic_intr116),
187 IDTVEC(ioapic_intr117),
188 IDTVEC(ioapic_intr118),
189 IDTVEC(ioapic_intr119),
190 IDTVEC(ioapic_intr120),
191 IDTVEC(ioapic_intr121),
192 IDTVEC(ioapic_intr122),
193 IDTVEC(ioapic_intr123),
194 IDTVEC(ioapic_intr124),
195 IDTVEC(ioapic_intr125),
196 IDTVEC(ioapic_intr126),
197 IDTVEC(ioapic_intr127),
198 IDTVEC(ioapic_intr128),
199 IDTVEC(ioapic_intr129),
200 IDTVEC(ioapic_intr130),
201 IDTVEC(ioapic_intr131),
202 IDTVEC(ioapic_intr132),
203 IDTVEC(ioapic_intr133),
204 IDTVEC(ioapic_intr134),
205 IDTVEC(ioapic_intr135),
206 IDTVEC(ioapic_intr136),
207 IDTVEC(ioapic_intr137),
208 IDTVEC(ioapic_intr138),
209 IDTVEC(ioapic_intr139),
210 IDTVEC(ioapic_intr140),
211 IDTVEC(ioapic_intr141),
212 IDTVEC(ioapic_intr142),
213 IDTVEC(ioapic_intr143),
214 IDTVEC(ioapic_intr144),
215 IDTVEC(ioapic_intr145),
216 IDTVEC(ioapic_intr146),
217 IDTVEC(ioapic_intr147),
218 IDTVEC(ioapic_intr148),
219 IDTVEC(ioapic_intr149),
220 IDTVEC(ioapic_intr150),
221 IDTVEC(ioapic_intr151),
222 IDTVEC(ioapic_intr152),
223 IDTVEC(ioapic_intr153),
224 IDTVEC(ioapic_intr154),
225 IDTVEC(ioapic_intr155),
226 IDTVEC(ioapic_intr156),
227 IDTVEC(ioapic_intr157),
228 IDTVEC(ioapic_intr158),
229 IDTVEC(ioapic_intr159),
230 IDTVEC(ioapic_intr160),
231 IDTVEC(ioapic_intr161),
232 IDTVEC(ioapic_intr162),
233 IDTVEC(ioapic_intr163),
234 IDTVEC(ioapic_intr164),
235 IDTVEC(ioapic_intr165),
236 IDTVEC(ioapic_intr166),
237 IDTVEC(ioapic_intr167),
238 IDTVEC(ioapic_intr168),
239 IDTVEC(ioapic_intr169),
240 IDTVEC(ioapic_intr170),
241 IDTVEC(ioapic_intr171),
242 IDTVEC(ioapic_intr172),
243 IDTVEC(ioapic_intr173),
244 IDTVEC(ioapic_intr174),
245 IDTVEC(ioapic_intr175),
246 IDTVEC(ioapic_intr176),
247 IDTVEC(ioapic_intr177),
248 IDTVEC(ioapic_intr178),
249 IDTVEC(ioapic_intr179),
250 IDTVEC(ioapic_intr180),
251 IDTVEC(ioapic_intr181),
252 IDTVEC(ioapic_intr182),
253 IDTVEC(ioapic_intr183),
254 IDTVEC(ioapic_intr184),
255 IDTVEC(ioapic_intr185),
256 IDTVEC(ioapic_intr186),
257 IDTVEC(ioapic_intr187),
258 IDTVEC(ioapic_intr188),
259 IDTVEC(ioapic_intr189),
260 IDTVEC(ioapic_intr190),
261 IDTVEC(ioapic_intr191);
262
263static inthand_t *ioapic_intr[IOAPIC_HWI_VECTORS] = {
264 &IDTVEC(ioapic_intr0),
265 &IDTVEC(ioapic_intr1),
266 &IDTVEC(ioapic_intr2),
267 &IDTVEC(ioapic_intr3),
268 &IDTVEC(ioapic_intr4),
269 &IDTVEC(ioapic_intr5),
270 &IDTVEC(ioapic_intr6),
271 &IDTVEC(ioapic_intr7),
272 &IDTVEC(ioapic_intr8),
273 &IDTVEC(ioapic_intr9),
274 &IDTVEC(ioapic_intr10),
275 &IDTVEC(ioapic_intr11),
276 &IDTVEC(ioapic_intr12),
277 &IDTVEC(ioapic_intr13),
278 &IDTVEC(ioapic_intr14),
279 &IDTVEC(ioapic_intr15),
280 &IDTVEC(ioapic_intr16),
281 &IDTVEC(ioapic_intr17),
282 &IDTVEC(ioapic_intr18),
283 &IDTVEC(ioapic_intr19),
284 &IDTVEC(ioapic_intr20),
285 &IDTVEC(ioapic_intr21),
286 &IDTVEC(ioapic_intr22),
287 &IDTVEC(ioapic_intr23),
288 &IDTVEC(ioapic_intr24),
289 &IDTVEC(ioapic_intr25),
290 &IDTVEC(ioapic_intr26),
291 &IDTVEC(ioapic_intr27),
292 &IDTVEC(ioapic_intr28),
293 &IDTVEC(ioapic_intr29),
294 &IDTVEC(ioapic_intr30),
295 &IDTVEC(ioapic_intr31),
296 &IDTVEC(ioapic_intr32),
297 &IDTVEC(ioapic_intr33),
298 &IDTVEC(ioapic_intr34),
299 &IDTVEC(ioapic_intr35),
300 &IDTVEC(ioapic_intr36),
301 &IDTVEC(ioapic_intr37),
302 &IDTVEC(ioapic_intr38),
303 &IDTVEC(ioapic_intr39),
304 &IDTVEC(ioapic_intr40),
305 &IDTVEC(ioapic_intr41),
306 &IDTVEC(ioapic_intr42),
307 &IDTVEC(ioapic_intr43),
308 &IDTVEC(ioapic_intr44),
309 &IDTVEC(ioapic_intr45),
310 &IDTVEC(ioapic_intr46),
311 &IDTVEC(ioapic_intr47),
312 &IDTVEC(ioapic_intr48),
313 &IDTVEC(ioapic_intr49),
314 &IDTVEC(ioapic_intr50),
315 &IDTVEC(ioapic_intr51),
316 &IDTVEC(ioapic_intr52),
317 &IDTVEC(ioapic_intr53),
318 &IDTVEC(ioapic_intr54),
319 &IDTVEC(ioapic_intr55),
320 &IDTVEC(ioapic_intr56),
321 &IDTVEC(ioapic_intr57),
322 &IDTVEC(ioapic_intr58),
323 &IDTVEC(ioapic_intr59),
324 &IDTVEC(ioapic_intr60),
325 &IDTVEC(ioapic_intr61),
326 &IDTVEC(ioapic_intr62),
327 &IDTVEC(ioapic_intr63),
328 &IDTVEC(ioapic_intr64),
329 &IDTVEC(ioapic_intr65),
330 &IDTVEC(ioapic_intr66),
331 &IDTVEC(ioapic_intr67),
332 &IDTVEC(ioapic_intr68),
333 &IDTVEC(ioapic_intr69),
334 &IDTVEC(ioapic_intr70),
335 &IDTVEC(ioapic_intr71),
336 &IDTVEC(ioapic_intr72),
337 &IDTVEC(ioapic_intr73),
338 &IDTVEC(ioapic_intr74),
339 &IDTVEC(ioapic_intr75),
340 &IDTVEC(ioapic_intr76),
341 &IDTVEC(ioapic_intr77),
342 &IDTVEC(ioapic_intr78),
343 &IDTVEC(ioapic_intr79),
344 &IDTVEC(ioapic_intr80),
345 &IDTVEC(ioapic_intr81),
346 &IDTVEC(ioapic_intr82),
347 &IDTVEC(ioapic_intr83),
348 &IDTVEC(ioapic_intr84),
349 &IDTVEC(ioapic_intr85),
350 &IDTVEC(ioapic_intr86),
351 &IDTVEC(ioapic_intr87),
352 &IDTVEC(ioapic_intr88),
353 &IDTVEC(ioapic_intr89),
354 &IDTVEC(ioapic_intr90),
355 &IDTVEC(ioapic_intr91),
356 &IDTVEC(ioapic_intr92),
357 &IDTVEC(ioapic_intr93),
358 &IDTVEC(ioapic_intr94),
359 &IDTVEC(ioapic_intr95),
360 &IDTVEC(ioapic_intr96),
361 &IDTVEC(ioapic_intr97),
362 &IDTVEC(ioapic_intr98),
363 &IDTVEC(ioapic_intr99),
364 &IDTVEC(ioapic_intr100),
365 &IDTVEC(ioapic_intr101),
366 &IDTVEC(ioapic_intr102),
367 &IDTVEC(ioapic_intr103),
368 &IDTVEC(ioapic_intr104),
369 &IDTVEC(ioapic_intr105),
370 &IDTVEC(ioapic_intr106),
371 &IDTVEC(ioapic_intr107),
372 &IDTVEC(ioapic_intr108),
373 &IDTVEC(ioapic_intr109),
374 &IDTVEC(ioapic_intr110),
375 &IDTVEC(ioapic_intr111),
376 &IDTVEC(ioapic_intr112),
377 &IDTVEC(ioapic_intr113),
378 &IDTVEC(ioapic_intr114),
379 &IDTVEC(ioapic_intr115),
380 &IDTVEC(ioapic_intr116),
381 &IDTVEC(ioapic_intr117),
382 &IDTVEC(ioapic_intr118),
383 &IDTVEC(ioapic_intr119),
384 &IDTVEC(ioapic_intr120),
385 &IDTVEC(ioapic_intr121),
386 &IDTVEC(ioapic_intr122),
387 &IDTVEC(ioapic_intr123),
388 &IDTVEC(ioapic_intr124),
389 &IDTVEC(ioapic_intr125),
390 &IDTVEC(ioapic_intr126),
391 &IDTVEC(ioapic_intr127),
392 &IDTVEC(ioapic_intr128),
393 &IDTVEC(ioapic_intr129),
394 &IDTVEC(ioapic_intr130),
395 &IDTVEC(ioapic_intr131),
396 &IDTVEC(ioapic_intr132),
397 &IDTVEC(ioapic_intr133),
398 &IDTVEC(ioapic_intr134),
399 &IDTVEC(ioapic_intr135),
400 &IDTVEC(ioapic_intr136),
401 &IDTVEC(ioapic_intr137),
402 &IDTVEC(ioapic_intr138),
403 &IDTVEC(ioapic_intr139),
404 &IDTVEC(ioapic_intr140),
405 &IDTVEC(ioapic_intr141),
406 &IDTVEC(ioapic_intr142),
407 &IDTVEC(ioapic_intr143),
408 &IDTVEC(ioapic_intr144),
409 &IDTVEC(ioapic_intr145),
410 &IDTVEC(ioapic_intr146),
411 &IDTVEC(ioapic_intr147),
412 &IDTVEC(ioapic_intr148),
413 &IDTVEC(ioapic_intr149),
414 &IDTVEC(ioapic_intr150),
415 &IDTVEC(ioapic_intr151),
416 &IDTVEC(ioapic_intr152),
417 &IDTVEC(ioapic_intr153),
418 &IDTVEC(ioapic_intr154),
419 &IDTVEC(ioapic_intr155),
420 &IDTVEC(ioapic_intr156),
421 &IDTVEC(ioapic_intr157),
422 &IDTVEC(ioapic_intr158),
423 &IDTVEC(ioapic_intr159),
424 &IDTVEC(ioapic_intr160),
425 &IDTVEC(ioapic_intr161),
426 &IDTVEC(ioapic_intr162),
427 &IDTVEC(ioapic_intr163),
428 &IDTVEC(ioapic_intr164),
429 &IDTVEC(ioapic_intr165),
430 &IDTVEC(ioapic_intr166),
431 &IDTVEC(ioapic_intr167),
432 &IDTVEC(ioapic_intr168),
433 &IDTVEC(ioapic_intr169),
434 &IDTVEC(ioapic_intr170),
435 &IDTVEC(ioapic_intr171),
436 &IDTVEC(ioapic_intr172),
437 &IDTVEC(ioapic_intr173),
438 &IDTVEC(ioapic_intr174),
439 &IDTVEC(ioapic_intr175),
440 &IDTVEC(ioapic_intr176),
441 &IDTVEC(ioapic_intr177),
442 &IDTVEC(ioapic_intr178),
443 &IDTVEC(ioapic_intr179),
444 &IDTVEC(ioapic_intr180),
445 &IDTVEC(ioapic_intr181),
446 &IDTVEC(ioapic_intr182),
447 &IDTVEC(ioapic_intr183),
448 &IDTVEC(ioapic_intr184),
449 &IDTVEC(ioapic_intr185),
450 &IDTVEC(ioapic_intr186),
451 &IDTVEC(ioapic_intr187),
452 &IDTVEC(ioapic_intr188),
453 &IDTVEC(ioapic_intr189),
454 &IDTVEC(ioapic_intr190),
455 &IDTVEC(ioapic_intr191)
c571da4a 456};
c8fe38ae 457
474ba684
SZ
458#define IOAPIC_HWI_SYSCALL (IDT_OFFSET_SYSCALL - IDT_OFFSET)
459
a3dd9120
SZ
460static struct ioapic_irqmap {
461 int im_type; /* IOAPIC_IMT_ */
462 enum intr_trigger im_trig;
f6915355 463 enum intr_polarity im_pola;
a3dd9120 464 int im_gsi;
4234567c 465 int im_msi_base;
d1ae7328 466 uint32_t im_flags; /* IOAPIC_IMF_ */
6f072945 467} ioapic_irqmaps[MAXCPU][IOAPIC_HWI_VECTORS];
a3dd9120 468
4234567c
SZ
469static struct lwkt_token ioapic_irqmap_tok =
470 LWKT_TOKEN_INITIALIZER(ioapic_irqmap_token);
471
a3dd9120
SZ
472#define IOAPIC_IMT_UNUSED 0
473#define IOAPIC_IMT_RESERVED 1
f9593a5d 474#define IOAPIC_IMT_LEGACY 2
474ba684 475#define IOAPIC_IMT_SYSCALL 3
4234567c 476#define IOAPIC_IMT_MSI 4
9dbe6e38 477#define IOAPIC_IMT_MSIX 5
a3dd9120 478
981239a7
SZ
479#define IOAPIC_IMT_ISHWI(map) ((map)->im_type != IOAPIC_IMT_RESERVED && \
480 (map)->im_type != IOAPIC_IMT_SYSCALL)
481
d1ae7328
SZ
482#define IOAPIC_IMF_CONF 0x1
483
9e0e3f85
SZ
484extern void IOAPIC_INTREN(int);
485extern void IOAPIC_INTRDIS(int);
486
85bcaa51
SZ
487extern int imcr_present;
488
35b2edcb
SZ
489static void ioapic_abi_intr_enable(int);
490static void ioapic_abi_intr_disable(int);
f416026e
SZ
491static void ioapic_abi_intr_setup(int, int);
492static void ioapic_abi_intr_teardown(int);
bec969af
SZ
493
494static void ioapic_abi_legacy_intr_config(int,
aea76754 495 enum intr_trigger, enum intr_polarity);
bec969af 496static int ioapic_abi_legacy_intr_cpuid(int);
86d692fe
SZ
497static int ioapic_abi_legacy_intr_find(int,
498 enum intr_trigger, enum intr_polarity);
499static int ioapic_abi_legacy_intr_find_bygsi(int,
500 enum intr_trigger, enum intr_polarity);
35b2edcb 501
4234567c
SZ
502static int ioapic_abi_msi_alloc(int [], int, int);
503static void ioapic_abi_msi_release(const int [], int, int);
504static void ioapic_abi_msi_map(int, uint64_t *, uint32_t *, int);
9dbe6e38
SZ
505static int ioapic_abi_msix_alloc(int *, int);
506static void ioapic_abi_msix_release(int, int);
507
508static int ioapic_abi_msi_alloc_intern(int, const char *,
509 int [], int, int);
510static void ioapic_abi_msi_release_intern(int, const char *,
511 const int [], int, int);
4234567c 512
aea76754
SZ
513static void ioapic_abi_finalize(void);
514static void ioapic_abi_cleanup(void);
515static void ioapic_abi_setdefault(void);
516static void ioapic_abi_stabilize(void);
517static void ioapic_abi_initmap(void);
981239a7 518static void ioapic_abi_rman_setup(struct rman *);
9e0e3f85 519
95874ffd
SZ
520static int ioapic_abi_gsi_cpuid(int, int);
521
9e0e3f85
SZ
522struct machintr_abi MachIntrABI_IOAPIC = {
523 MACHINTR_IOAPIC,
35b2edcb
SZ
524 .intr_disable = ioapic_abi_intr_disable,
525 .intr_enable = ioapic_abi_intr_enable,
f416026e
SZ
526 .intr_setup = ioapic_abi_intr_setup,
527 .intr_teardown = ioapic_abi_intr_teardown,
bec969af
SZ
528
529 .legacy_intr_config = ioapic_abi_legacy_intr_config,
530 .legacy_intr_cpuid = ioapic_abi_legacy_intr_cpuid,
86d692fe
SZ
531 .legacy_intr_find = ioapic_abi_legacy_intr_find,
532 .legacy_intr_find_bygsi = ioapic_abi_legacy_intr_find_bygsi,
35b2edcb 533
4234567c
SZ
534 .msi_alloc = ioapic_abi_msi_alloc,
535 .msi_release = ioapic_abi_msi_release,
536 .msi_map = ioapic_abi_msi_map,
9dbe6e38
SZ
537 .msix_alloc = ioapic_abi_msix_alloc,
538 .msix_release = ioapic_abi_msix_release,
4234567c 539
aea76754
SZ
540 .finalize = ioapic_abi_finalize,
541 .cleanup = ioapic_abi_cleanup,
542 .setdefault = ioapic_abi_setdefault,
543 .stabilize = ioapic_abi_stabilize,
981239a7
SZ
544 .initmap = ioapic_abi_initmap,
545 .rman_setup = ioapic_abi_rman_setup
c8fe38ae
MD
546};
547
6b809ec7 548static int ioapic_abi_extint_irq = -1;
f9593a5d 549static int ioapic_abi_legacy_irq_max;
2b195d6a 550static int ioapic_abi_gsi_balance;
7b87350b 551static int ioapic_abi_msi_start; /* NOTE: for testing only */
6b809ec7 552
5ac5ccd2 553struct ioapic_irqinfo ioapic_irqs[IOAPIC_HWI_VECTORS];
566d27d4
SZ
554
555static void
35b2edcb 556ioapic_abi_intr_enable(int irq)
566d27d4 557{
aef690c8
SZ
558 const struct ioapic_irqmap *map;
559
560 KASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS,
ed20d0e3 561 ("ioapic enable, invalid irq %d", irq));
aef690c8
SZ
562
563 map = &ioapic_irqmaps[mycpuid][irq];
564 KASSERT(IOAPIC_IMT_ISHWI(map),
ed20d0e3 565 ("ioapic enable, not hwi irq %d, type %d, cpu%d",
aef690c8 566 irq, map->im_type, mycpuid));
f9593a5d 567 if (map->im_type != IOAPIC_IMT_LEGACY)
566d27d4 568 return;
aef690c8 569
566d27d4
SZ
570 IOAPIC_INTREN(irq);
571}
572
573static void
35b2edcb 574ioapic_abi_intr_disable(int irq)
566d27d4 575{
aef690c8
SZ
576 const struct ioapic_irqmap *map;
577
578 KASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS,
ed20d0e3 579 ("ioapic disable, invalid irq %d", irq));
aef690c8
SZ
580
581 map = &ioapic_irqmaps[mycpuid][irq];
582 KASSERT(IOAPIC_IMT_ISHWI(map),
ed20d0e3 583 ("ioapic disable, not hwi irq %d, type %d, cpu%d",
aef690c8 584 irq, map->im_type, mycpuid));
f9593a5d 585 if (map->im_type != IOAPIC_IMT_LEGACY)
566d27d4 586 return;
aef690c8 587
566d27d4
SZ
588 IOAPIC_INTRDIS(irq);
589}
590
c8fe38ae 591static void
aea76754 592ioapic_abi_finalize(void)
c8fe38ae 593{
e0918665 594 KKASSERT(MachIntrABI.type == MACHINTR_IOAPIC);
f45bfca0 595 KKASSERT(ioapic_enable);
10db3cc6 596
339478ac
SZ
597 /*
598 * If an IMCR is present, program bit 0 to disconnect the 8259
e0918665 599 * from the BSP.
339478ac 600 */
9d758cc4 601 if (imcr_present) {
339478ac
SZ
602 outb(0x22, 0x70); /* select IMCR */
603 outb(0x23, 0x01); /* disconnect 8259 */
604 }
c8fe38ae
MD
605}
606
607/*
608 * This routine is called after physical interrupts are enabled but before
609 * the critical section is released. We need to clean out any interrupts
610 * that had already been posted to the cpu.
611 */
612static void
aea76754 613ioapic_abi_cleanup(void)
c8fe38ae 614{
9611ff20 615 bzero(mdcpu->gd_ipending, sizeof(mdcpu->gd_ipending));
c8fe38ae
MD
616}
617
7bf5fa56
SZ
618/* Must never be called */
619static void
aea76754 620ioapic_abi_stabilize(void)
7bf5fa56 621{
ed20d0e3 622 panic("ioapic_stabilize is called");
7bf5fa56
SZ
623}
624
f416026e
SZ
625static void
626ioapic_abi_intr_setup(int intr, int flags)
c8fe38ae 627{
88100cf6 628 const struct ioapic_irqmap *map;
f416026e 629 int vector, select;
339478ac 630 uint32_t value;
7bf5fa56 631 register_t ef;
c8fe38ae 632
88100cf6 633 KASSERT(intr >= 0 && intr < IOAPIC_HWI_VECTORS,
ed20d0e3 634 ("ioapic setup, invalid irq %d", intr));
88100cf6
SZ
635
636 map = &ioapic_irqmaps[mycpuid][intr];
637 KASSERT(IOAPIC_IMT_ISHWI(map),
638 ("ioapic setup, not hwi irq %d, type %d, cpu%d",
639 intr, map->im_type, mycpuid));
f9593a5d 640 if (map->im_type != IOAPIC_IMT_LEGACY)
88100cf6 641 return;
88100cf6
SZ
642
643 KASSERT(ioapic_irqs[intr].io_addr != NULL,
ed20d0e3 644 ("ioapic setup, no GSI information, irq %d", intr));
f416026e
SZ
645
646 ef = read_rflags();
647 cpu_disable_intr();
648
649 vector = IDT_OFFSET + intr;
f416026e
SZ
650
651 /*
652 * Now reprogram the vector in the IO APIC. In order to avoid
653 * losing an EOI for a level interrupt, which is vector based,
654 * make sure that the IO APIC is programmed for edge-triggering
655 * first, then reprogrammed with the new vector. This should
656 * clear the IRR bit.
657 */
658 imen_lock();
659
660 select = ioapic_irqs[intr].io_idx;
661 value = ioapic_read(ioapic_irqs[intr].io_addr, select);
662 value |= IOART_INTMSET;
663
664 ioapic_write(ioapic_irqs[intr].io_addr, select,
665 (value & ~APIC_TRIGMOD_MASK));
666 ioapic_write(ioapic_irqs[intr].io_addr, select,
667 (value & ~IOART_INTVEC) | vector);
668
669 imen_unlock();
670
26cf64b2 671 IOAPIC_INTREN(intr);
c8fe38ae 672
f416026e
SZ
673 write_rflags(ef);
674}
675
676static void
677ioapic_abi_intr_teardown(int intr)
678{
88100cf6 679 const struct ioapic_irqmap *map;
f416026e
SZ
680 int vector, select;
681 uint32_t value;
682 register_t ef;
683
88100cf6 684 KASSERT(intr >= 0 && intr < IOAPIC_HWI_VECTORS,
ed20d0e3 685 ("ioapic teardown, invalid irq %d", intr));
88100cf6
SZ
686
687 map = &ioapic_irqmaps[mycpuid][intr];
688 KASSERT(IOAPIC_IMT_ISHWI(map),
689 ("ioapic teardown, not hwi irq %d, type %d, cpu%d",
690 intr, map->im_type, mycpuid));
f9593a5d 691 if (map->im_type != IOAPIC_IMT_LEGACY)
88100cf6 692 return;
88100cf6
SZ
693
694 KASSERT(ioapic_irqs[intr].io_addr != NULL,
ed20d0e3 695 ("ioapic teardown, no GSI information, irq %d", intr));
5ac5ccd2 696
339478ac
SZ
697 ef = read_rflags();
698 cpu_disable_intr();
f416026e
SZ
699
700 /*
701 * Teardown an interrupt vector. The vector should already be
702 * installed in the cpu's IDT, but make sure.
703 */
26cf64b2 704 IOAPIC_INTRDIS(intr);
f416026e
SZ
705
706 vector = IDT_OFFSET + intr;
f416026e
SZ
707
708 /*
709 * In order to avoid losing an EOI for a level interrupt, which
710 * is vector based, make sure that the IO APIC is programmed for
711 * edge-triggering first, then reprogrammed with the new vector.
712 * This should clear the IRR bit.
713 */
714 imen_lock();
715
716 select = ioapic_irqs[intr].io_idx;
717 value = ioapic_read(ioapic_irqs[intr].io_addr, select);
718
719 ioapic_write(ioapic_irqs[intr].io_addr, select,
720 (value & ~APIC_TRIGMOD_MASK));
721 ioapic_write(ioapic_irqs[intr].io_addr, select,
722 (value & ~IOART_INTVEC) | vector);
723
724 imen_unlock();
c8fe38ae 725
339478ac 726 write_rflags(ef);
339478ac 727}
c8fe38ae 728
10db3cc6 729static void
aea76754 730ioapic_abi_setdefault(void)
10db3cc6
SZ
731{
732 int intr;
733
9e0e3f85 734 for (intr = 0; intr < IOAPIC_HWI_VECTORS; ++intr) {
474ba684 735 if (intr == IOAPIC_HWI_SYSCALL)
10db3cc6 736 continue;
8a06c6ee
SZ
737 setidt_global(IDT_OFFSET + intr, ioapic_intr[intr],
738 SDT_SYSIGT, SEL_KPL, 0);
10db3cc6
SZ
739 }
740}
741
a3dd9120 742static void
aea76754 743ioapic_abi_initmap(void)
a3dd9120 744{
6f072945 745 int cpu;
a3dd9120 746
2b195d6a
SZ
747 kgetenv_int("hw.ioapic.gsi.balance", &ioapic_abi_gsi_balance);
748
7b87350b
SZ
749 kgetenv_int("hw.ioapic.msi_start", &ioapic_abi_msi_start);
750 ioapic_abi_msi_start &= ~0x1f; /* MUST be 32 aligned */
751
6f072945
SZ
752 /*
753 * NOTE: ncpus is not ready yet
754 */
755 for (cpu = 0; cpu < MAXCPU; ++cpu) {
756 int i;
757
4234567c 758 for (i = 0; i < IOAPIC_HWI_VECTORS; ++i) {
6f072945 759 ioapic_irqmaps[cpu][i].im_gsi = -1;
4234567c
SZ
760 ioapic_irqmaps[cpu][i].im_msi_base = -1;
761 }
6f072945
SZ
762 ioapic_irqmaps[cpu][IOAPIC_HWI_SYSCALL].im_type =
763 IOAPIC_IMT_SYSCALL;
764 }
a3dd9120
SZ
765}
766
929c940f 767void
027bbbfe 768ioapic_set_legacy_irqmap(int irq, int gsi, enum intr_trigger trig,
929c940f
SZ
769 enum intr_polarity pola)
770{
5ac5ccd2 771 struct ioapic_irqinfo *info;
929c940f
SZ
772 struct ioapic_irqmap *map;
773 void *ioaddr;
95874ffd 774 int pin, cpuid;
929c940f
SZ
775
776 KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
777 KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
929c940f
SZ
778
779 KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS);
f9593a5d
SZ
780 if (irq > ioapic_abi_legacy_irq_max)
781 ioapic_abi_legacy_irq_max = irq;
bf2e6ffb 782
6f072945
SZ
783 cpuid = ioapic_abi_gsi_cpuid(irq, gsi);
784
785 map = &ioapic_irqmaps[cpuid][irq];
929c940f
SZ
786
787 KKASSERT(map->im_type == IOAPIC_IMT_UNUSED);
f9593a5d 788 map->im_type = IOAPIC_IMT_LEGACY;
929c940f
SZ
789
790 map->im_gsi = gsi;
791 map->im_trig = trig;
792 map->im_pola = pola;
793
794 if (bootverbose) {
4ecd5d4d
SZ
795 kprintf("IOAPIC: irq %d -> gsi %d %s/%s\n",
796 irq, map->im_gsi,
797 intr_str_trigger(map->im_trig),
798 intr_str_polarity(map->im_pola));
929c940f
SZ
799 }
800
d1ae7328
SZ
801 pin = ioapic_gsi_pin(map->im_gsi);
802 ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
929c940f 803
5ac5ccd2 804 info = &ioapic_irqs[irq];
929c940f 805
7bceaa10
SZ
806 imen_lock();
807
5ac5ccd2
SZ
808 info->io_addr = ioaddr;
809 info->io_idx = IOAPIC_REDTBL + (2 * pin);
810 info->io_flags = IOAPIC_IRQI_FLAG_MASKED;
d1ae7328 811 if (map->im_trig == INTR_TRIGGER_LEVEL)
5ac5ccd2 812 info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL;
d1ae7328
SZ
813
814 ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
95874ffd 815 map->im_trig, map->im_pola, cpuid);
7bceaa10
SZ
816
817 imen_unlock();
d1ae7328
SZ
818}
819
4a913811 820void
027bbbfe 821ioapic_fixup_legacy_irqmaps(void)
4a913811 822{
6f072945
SZ
823 int cpu;
824
825 for (cpu = 0; cpu < ncpus; ++cpu) {
826 int i;
4a913811 827
6f072945
SZ
828 for (i = 0; i < ISA_IRQ_CNT; ++i) {
829 struct ioapic_irqmap *map = &ioapic_irqmaps[cpu][i];
4a913811 830
6f072945
SZ
831 if (map->im_type == IOAPIC_IMT_UNUSED) {
832 map->im_type = IOAPIC_IMT_RESERVED;
833 if (bootverbose) {
834 kprintf("IOAPIC: "
835 "cpu%d irq %d reserved\n", cpu, i);
836 }
837 }
4a913811
SZ
838 }
839 }
6f072945 840
f9593a5d
SZ
841 ioapic_abi_legacy_irq_max += 1;
842 if (bootverbose) {
843 kprintf("IOAPIC: legacy irq max %d\n",
844 ioapic_abi_legacy_irq_max);
845 }
4a913811
SZ
846}
847
86d692fe
SZ
848static int
849ioapic_abi_legacy_intr_find_bygsi(int gsi, enum intr_trigger trig,
027bbbfe 850 enum intr_polarity pola)
e90e7ac4 851{
6f072945 852 int cpu;
e90e7ac4 853
86d692fe
SZ
854#ifdef INVARIANTS
855 if (trig == INTR_TRIGGER_CONFORM) {
856 KKASSERT(pola == INTR_POLARITY_CONFORM);
857 } else {
858 KKASSERT(trig == INTR_TRIGGER_EDGE ||
859 trig == INTR_TRIGGER_LEVEL);
860 KKASSERT(pola == INTR_POLARITY_HIGH ||
861 pola == INTR_POLARITY_LOW);
862 }
863#endif
e90e7ac4 864
6f072945
SZ
865 for (cpu = 0; cpu < ncpus; ++cpu) {
866 int irq;
e90e7ac4 867
f9593a5d 868 for (irq = 0; irq < ioapic_abi_legacy_irq_max; ++irq) {
6f072945
SZ
869 const struct ioapic_irqmap *map =
870 &ioapic_irqmaps[cpu][irq];
e90e7ac4 871
6f072945 872 if (map->im_gsi == gsi) {
f9593a5d 873 KKASSERT(map->im_type == IOAPIC_IMT_LEGACY);
6f072945 874
86d692fe
SZ
875 if ((map->im_flags & IOAPIC_IMF_CONF) &&
876 trig != INTR_TRIGGER_CONFORM &&
877 pola != INTR_POLARITY_CONFORM) {
6f072945
SZ
878 if (map->im_trig != trig ||
879 map->im_pola != pola)
880 return -1;
881 }
882 return irq;
e90e7ac4 883 }
e90e7ac4
SZ
884 }
885 }
886 return -1;
887}
888
86d692fe
SZ
889static int
890ioapic_abi_legacy_intr_find(int irq, enum intr_trigger trig,
027bbbfe 891 enum intr_polarity pola)
e90e7ac4 892{
6f072945 893 int cpu;
e90e7ac4 894
86d692fe
SZ
895#ifdef INVARIANTS
896 if (trig == INTR_TRIGGER_CONFORM) {
897 KKASSERT(pola == INTR_POLARITY_CONFORM);
898 } else {
899 KKASSERT(trig == INTR_TRIGGER_EDGE ||
900 trig == INTR_TRIGGER_LEVEL);
901 KKASSERT(pola == INTR_POLARITY_HIGH ||
902 pola == INTR_POLARITY_LOW);
903 }
904#endif
e90e7ac4 905
f9593a5d 906 if (irq < 0 || irq >= ioapic_abi_legacy_irq_max)
e90e7ac4 907 return -1;
e90e7ac4 908
6f072945
SZ
909 for (cpu = 0; cpu < ncpus; ++cpu) {
910 const struct ioapic_irqmap *map = &ioapic_irqmaps[cpu][irq];
e90e7ac4 911
f9593a5d 912 if (map->im_type == IOAPIC_IMT_LEGACY) {
86d692fe
SZ
913 if ((map->im_flags & IOAPIC_IMF_CONF) &&
914 trig != INTR_TRIGGER_CONFORM &&
915 pola != INTR_POLARITY_CONFORM) {
6f072945
SZ
916 if (map->im_trig != trig ||
917 map->im_pola != pola)
918 return -1;
919 }
920 return irq;
921 }
e90e7ac4 922 }
6f072945 923 return -1;
e90e7ac4
SZ
924}
925
d1ae7328 926static void
bec969af
SZ
927ioapic_abi_legacy_intr_config(int irq, enum intr_trigger trig,
928 enum intr_polarity pola)
d1ae7328 929{
5ac5ccd2 930 struct ioapic_irqinfo *info;
6f072945 931 struct ioapic_irqmap *map = NULL;
d1ae7328 932 void *ioaddr;
95874ffd 933 int pin, cpuid;
d1ae7328 934
d1ae7328
SZ
935 KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
936 KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
d1ae7328 937
f9593a5d 938 KKASSERT(irq >= 0 && irq < ioapic_abi_legacy_irq_max);
6f072945
SZ
939 for (cpuid = 0; cpuid < ncpus; ++cpuid) {
940 map = &ioapic_irqmaps[cpuid][irq];
f9593a5d 941 if (map->im_type == IOAPIC_IMT_LEGACY)
6f072945
SZ
942 break;
943 }
944 KKASSERT(cpuid < ncpus);
d1ae7328 945
7962296e 946#ifdef notyet
d1ae7328
SZ
947 if (map->im_flags & IOAPIC_IMF_CONF) {
948 if (trig != map->im_trig) {
ed20d0e3 949 panic("ioapic_intr_config: trig %s -> %s",
4ecd5d4d
SZ
950 intr_str_trigger(map->im_trig),
951 intr_str_trigger(trig));
d1ae7328
SZ
952 }
953 if (pola != map->im_pola) {
ed20d0e3 954 panic("ioapic_intr_config: pola %s -> %s",
4ecd5d4d
SZ
955 intr_str_polarity(map->im_pola),
956 intr_str_polarity(pola));
d1ae7328
SZ
957 }
958 return;
959 }
7962296e 960#endif
d1ae7328
SZ
961 map->im_flags |= IOAPIC_IMF_CONF;
962
963 if (trig == map->im_trig && pola == map->im_pola)
964 return;
965
966 if (bootverbose) {
4ecd5d4d
SZ
967 kprintf("IOAPIC: irq %d, gsi %d %s/%s -> %s/%s\n",
968 irq, map->im_gsi,
969 intr_str_trigger(map->im_trig),
970 intr_str_polarity(map->im_pola),
971 intr_str_trigger(trig),
972 intr_str_polarity(pola));
d1ae7328 973 }
d1ae7328
SZ
974 map->im_trig = trig;
975 map->im_pola = pola;
976
977 pin = ioapic_gsi_pin(map->im_gsi);
978 ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
979
5ac5ccd2 980 info = &ioapic_irqs[irq];
d1ae7328 981
7bceaa10
SZ
982 imen_lock();
983
5ac5ccd2 984 info->io_flags &= ~IOAPIC_IRQI_FLAG_LEVEL;
d1ae7328 985 if (map->im_trig == INTR_TRIGGER_LEVEL)
5ac5ccd2 986 info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL;
929c940f 987
ecec8ddc 988 ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq,
95874ffd 989 map->im_trig, map->im_pola, cpuid);
7bceaa10
SZ
990
991 imen_unlock();
929c940f
SZ
992}
993
6b809ec7 994int
027bbbfe 995ioapic_conf_legacy_extint(int irq)
6b809ec7 996{
5ac5ccd2 997 struct ioapic_irqinfo *info;
6b809ec7
SZ
998 struct ioapic_irqmap *map;
999 void *ioaddr;
1000 int pin, error, vec;
1001
95874ffd
SZ
1002 /* XXX only irq0 is allowed */
1003 KKASSERT(irq == 0);
1004
6b809ec7
SZ
1005 vec = IDT_OFFSET + irq;
1006
1007 if (ioapic_abi_extint_irq == irq)
1008 return 0;
1009 else if (ioapic_abi_extint_irq >= 0)
1010 return EEXIST;
1011
1012 error = icu_ioapic_extint(irq, vec);
1013 if (error)
1014 return error;
1015
6f072945
SZ
1016 /* ExtINT is always targeted to cpu0 */
1017 map = &ioapic_irqmaps[0][irq];
6b809ec7
SZ
1018
1019 KKASSERT(map->im_type == IOAPIC_IMT_RESERVED ||
f9593a5d
SZ
1020 map->im_type == IOAPIC_IMT_LEGACY);
1021 if (map->im_type == IOAPIC_IMT_LEGACY) {
6b809ec7
SZ
1022 if (map->im_flags & IOAPIC_IMF_CONF)
1023 return EEXIST;
1024 }
1025 ioapic_abi_extint_irq = irq;
1026
f9593a5d 1027 map->im_type = IOAPIC_IMT_LEGACY;
6b809ec7
SZ
1028 map->im_trig = INTR_TRIGGER_EDGE;
1029 map->im_pola = INTR_POLARITY_HIGH;
1030 map->im_flags = IOAPIC_IMF_CONF;
1031
1032 map->im_gsi = ioapic_extpin_gsi();
1033 KKASSERT(map->im_gsi >= 0);
1034
1035 if (bootverbose) {
4ecd5d4d
SZ
1036 kprintf("IOAPIC: irq %d -> extint gsi %d %s/%s\n",
1037 irq, map->im_gsi,
1038 intr_str_trigger(map->im_trig),
1039 intr_str_polarity(map->im_pola));
6b809ec7
SZ
1040 }
1041
1042 pin = ioapic_gsi_pin(map->im_gsi);
1043 ioaddr = ioapic_gsi_ioaddr(map->im_gsi);
1044
5ac5ccd2 1045 info = &ioapic_irqs[irq];
6b809ec7
SZ
1046
1047 imen_lock();
1048
5ac5ccd2
SZ
1049 info->io_addr = ioaddr;
1050 info->io_idx = IOAPIC_REDTBL + (2 * pin);
1051 info->io_flags = IOAPIC_IRQI_FLAG_MASKED;
6b809ec7
SZ
1052
1053 ioapic_extpin_setup(ioaddr, pin, vec);
1054
1055 imen_unlock();
1056
1057 return 0;
1058}
a05c798c
SZ
1059
1060static int
bec969af 1061ioapic_abi_legacy_intr_cpuid(int irq)
a05c798c 1062{
6f072945
SZ
1063 const struct ioapic_irqmap *map = NULL;
1064 int cpuid;
95874ffd 1065
f9593a5d 1066 KKASSERT(irq >= 0 && irq < ioapic_abi_legacy_irq_max);
95874ffd 1067
6f072945
SZ
1068 for (cpuid = 0; cpuid < ncpus; ++cpuid) {
1069 map = &ioapic_irqmaps[cpuid][irq];
f9593a5d 1070 if (map->im_type == IOAPIC_IMT_LEGACY)
6f072945 1071 return cpuid;
95874ffd
SZ
1072 }
1073
6f072945
SZ
1074 /* XXX some drivers tries to peek at reserved IRQs */
1075 for (cpuid = 0; cpuid < ncpus; ++cpuid) {
1076 map = &ioapic_irqmaps[cpuid][irq];
1077 KKASSERT(map->im_type == IOAPIC_IMT_RESERVED);
1078 }
1079 return 0;
95874ffd
SZ
1080}
1081
1082static int
1083ioapic_abi_gsi_cpuid(int irq, int gsi)
1084{
1085 char envpath[32];
1086 int cpuid = -1;
1087
1088 KKASSERT(gsi >= 0);
1089
1090 if (irq == 0 || gsi == 0) {
621d2ccf
SZ
1091 if (bootverbose) {
1092 kprintf("IOAPIC: irq %d, gsi %d -> cpu0 (0)\n",
1093 irq, gsi);
1094 }
95874ffd
SZ
1095 return 0;
1096 }
1097
1098 if (irq == acpi_sci_irqno()) {
621d2ccf
SZ
1099 if (bootverbose) {
1100 kprintf("IOAPIC: irq %d, gsi %d -> cpu0 (sci)\n",
1101 irq, gsi);
1102 }
95874ffd
SZ
1103 return 0;
1104 }
1105
1106 ksnprintf(envpath, sizeof(envpath), "hw.ioapic.gsi.%d.cpu", gsi);
1107 kgetenv_int(envpath, &cpuid);
1108
1109 if (cpuid < 0) {
b8dfb6b1
SZ
1110 if (!ioapic_abi_gsi_balance) {
1111 if (bootverbose) {
1112 kprintf("IOAPIC: irq %d, gsi %d -> cpu0 "
1113 "(fixed)\n", irq, gsi);
1114 }
1115 return 0;
1116 }
1117
95874ffd 1118 cpuid = gsi % ncpus;
621d2ccf
SZ
1119 if (bootverbose) {
1120 kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (auto)\n",
1121 irq, gsi, cpuid);
1122 }
95874ffd
SZ
1123 } else if (cpuid >= ncpus) {
1124 cpuid = ncpus - 1;
621d2ccf
SZ
1125 if (bootverbose) {
1126 kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (fixup)\n",
1127 irq, gsi, cpuid);
1128 }
95874ffd 1129 } else {
621d2ccf
SZ
1130 if (bootverbose) {
1131 kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (user)\n",
1132 irq, gsi, cpuid);
1133 }
95874ffd
SZ
1134 }
1135 return cpuid;
a05c798c 1136}
981239a7
SZ
1137
1138static void
1139ioapic_abi_rman_setup(struct rman *rm)
1140{
1141 int start, end, i;
1142
1143 KASSERT(rm->rm_cpuid >= 0 && rm->rm_cpuid < MAXCPU,
1144 ("invalid rman cpuid %d", rm->rm_cpuid));
1145
1146 start = end = -1;
1147 for (i = 0; i < IOAPIC_HWI_VECTORS; ++i) {
1148 const struct ioapic_irqmap *map =
1149 &ioapic_irqmaps[rm->rm_cpuid][i];
1150
1151 if (start < 0) {
1152 if (IOAPIC_IMT_ISHWI(map))
1153 start = end = i;
1154 } else {
1155 if (IOAPIC_IMT_ISHWI(map)) {
1156 end = i;
1157 } else {
1158 KKASSERT(end >= 0);
1159 if (bootverbose) {
1160 kprintf("IOAPIC: rman cpu%d %d - %d\n",
1161 rm->rm_cpuid, start, end);
1162 }
1163 if (rman_manage_region(rm, start, end)) {
1164 panic("rman_manage_region"
1165 "(cpu%d %d - %d)", rm->rm_cpuid,
1166 start, end);
1167 }
1168 start = end = -1;
1169 }
1170 }
1171 }
1172 if (start >= 0) {
1173 KKASSERT(end >= 0);
1174 if (bootverbose) {
1175 kprintf("IOAPIC: rman cpu%d %d - %d\n",
1176 rm->rm_cpuid, start, end);
1177 }
1178 if (rman_manage_region(rm, start, end)) {
1179 panic("rman_manage_region(cpu%d %d - %d)",
1180 rm->rm_cpuid, start, end);
1181 }
1182 }
1183}
4234567c
SZ
1184
1185static int
9dbe6e38
SZ
1186ioapic_abi_msi_alloc_intern(int type, const char *desc,
1187 int intrs[], int count, int cpuid)
4234567c
SZ
1188{
1189 int i, error;
1190
1191 KASSERT(cpuid >= 0 && cpuid < ncpus,
1192 ("invalid cpuid %d", cpuid));
1193
ed20d0e3 1194 KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
4234567c 1195 KASSERT((count & (count - 1)) == 0,
ed20d0e3 1196 ("count %d is not power of 2", count));
4234567c
SZ
1197
1198 lwkt_gettoken(&ioapic_irqmap_tok);
1199
1200 /*
1201 * NOTE:
1202 * Since IDT_OFFSET is 32, which is the maximum valid 'count',
1203 * we do not need to find out the first properly aligned
1204 * interrupt vector.
1205 */
1206
2c3d7ac8 1207 error = EMSGSIZE;
7b87350b 1208 for (i = ioapic_abi_msi_start; i < IOAPIC_HWI_VECTORS; i += count) {
4234567c
SZ
1209 int j;
1210
1211 if (ioapic_irqmaps[cpuid][i].im_type != IOAPIC_IMT_UNUSED)
1212 continue;
1213
1214 for (j = 1; j < count; ++j) {
1215 if (ioapic_irqmaps[cpuid][i + j].im_type !=
1216 IOAPIC_IMT_UNUSED)
1217 break;
1218 }
1219 if (j != count)
1220 continue;
1221
1222 for (j = 0; j < count; ++j) {
1223 struct ioapic_irqmap *map;
1224 int intr = i + j;
1225
1226 map = &ioapic_irqmaps[cpuid][intr];
1227 KASSERT(map->im_msi_base < 0,
ed20d0e3 1228 ("intr %d, stale %s-base %d",
9dbe6e38 1229 intr, desc, map->im_msi_base));
4234567c 1230
9dbe6e38 1231 map->im_type = type;
4234567c
SZ
1232 map->im_msi_base = i;
1233
1234 intrs[j] = intr;
1235 msi_setup(intr, cpuid);
1236
1237 if (bootverbose) {
9dbe6e38
SZ
1238 kprintf("alloc %s intr %d on cpu%d\n",
1239 desc, intr, cpuid);
4234567c 1240 }
4234567c
SZ
1241 }
1242 error = 0;
1243 break;
1244 }
1245
1246 lwkt_reltoken(&ioapic_irqmap_tok);
1247
1248 return error;
1249}
1250
1251static void
9dbe6e38
SZ
1252ioapic_abi_msi_release_intern(int type, const char *desc,
1253 const int intrs[], int count, int cpuid)
4234567c
SZ
1254{
1255 int i, msi_base = -1, intr_next = -1, mask;
1256
1257 KASSERT(cpuid >= 0 && cpuid < ncpus,
1258 ("invalid cpuid %d", cpuid));
1259
ed20d0e3 1260 KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
4234567c
SZ
1261
1262 mask = count - 1;
ed20d0e3 1263 KASSERT((count & mask) == 0, ("count %d is not power of 2", count));
4234567c
SZ
1264
1265 lwkt_gettoken(&ioapic_irqmap_tok);
1266
1267 for (i = 0; i < count; ++i) {
1268 struct ioapic_irqmap *map;
1269 int intr = intrs[i];
1270
1271 KASSERT(intr >= 0 && intr < IOAPIC_HWI_VECTORS,
ed20d0e3 1272 ("invalid intr %d", intr));
4234567c
SZ
1273
1274 map = &ioapic_irqmaps[cpuid][intr];
9dbe6e38 1275 KASSERT(map->im_type == type,
ed20d0e3 1276 ("trying to release non-%s intr %d, type %d", desc,
4234567c
SZ
1277 intr, map->im_type));
1278 KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr,
ed20d0e3 1279 ("intr %d, invalid %s-base %d", intr, desc,
9dbe6e38 1280 map->im_msi_base));
4234567c 1281 KASSERT((map->im_msi_base & mask) == 0,
ed20d0e3 1282 ("intr %d, %s-base %d is not properly aligned %d",
9dbe6e38 1283 intr, desc, map->im_msi_base, count));
4234567c
SZ
1284
1285 if (msi_base < 0) {
1286 msi_base = map->im_msi_base;
1287 } else {
1288 KASSERT(map->im_msi_base == msi_base,
9dbe6e38 1289 ("intr %d, inconsistent %s-base, "
ed20d0e3 1290 "was %d, now %d",
9dbe6e38 1291 intr, desc, msi_base, map->im_msi_base));
4234567c
SZ
1292 }
1293
1294 if (intr_next < intr)
1295 intr_next = intr;
1296
1297 map->im_type = IOAPIC_IMT_UNUSED;
1298 map->im_msi_base = -1;
1299
9dbe6e38
SZ
1300 if (bootverbose) {
1301 kprintf("release %s intr %d on cpu%d\n",
1302 desc, intr, cpuid);
1303 }
4234567c
SZ
1304 }
1305
1306 KKASSERT(intr_next > 0);
1307 KKASSERT(msi_base >= 0);
1308
1309 ++intr_next;
1310 if (intr_next < IOAPIC_HWI_VECTORS) {
1311 const struct ioapic_irqmap *map =
1312 &ioapic_irqmaps[cpuid][intr_next];
1313
9dbe6e38 1314 if (map->im_type == type) {
4234567c 1315 KASSERT(map->im_msi_base != msi_base,
ed20d0e3 1316 ("more than %d %s was allocated", count, desc));
4234567c
SZ
1317 }
1318 }
1319
1320 lwkt_reltoken(&ioapic_irqmap_tok);
1321}
1322
9dbe6e38
SZ
1323static int
1324ioapic_abi_msi_alloc(int intrs[], int count, int cpuid)
1325{
1326 return ioapic_abi_msi_alloc_intern(IOAPIC_IMT_MSI, "MSI",
1327 intrs, count, cpuid);
1328}
1329
1330static void
1331ioapic_abi_msi_release(const int intrs[], int count, int cpuid)
1332{
1333 ioapic_abi_msi_release_intern(IOAPIC_IMT_MSI, "MSI",
1334 intrs, count, cpuid);
1335}
1336
1337static int
1338ioapic_abi_msix_alloc(int *intr, int cpuid)
1339{
1340 return ioapic_abi_msi_alloc_intern(IOAPIC_IMT_MSIX, "MSI-X",
1341 intr, 1, cpuid);
1342}
1343
1344static void
1345ioapic_abi_msix_release(int intr, int cpuid)
1346{
1347 ioapic_abi_msi_release_intern(IOAPIC_IMT_MSIX, "MSI-X",
1348 &intr, 1, cpuid);
1349}
1350
4234567c
SZ
1351static void
1352ioapic_abi_msi_map(int intr, uint64_t *addr, uint32_t *data, int cpuid)
1353{
1354 const struct ioapic_irqmap *map;
1355
1356 KASSERT(cpuid >= 0 && cpuid < ncpus,
1357 ("invalid cpuid %d", cpuid));
1358
1359 KASSERT(intr >= 0 && intr < IOAPIC_HWI_VECTORS,
ed20d0e3 1360 ("invalid intr %d", intr));
4234567c
SZ
1361
1362 lwkt_gettoken(&ioapic_irqmap_tok);
1363
1364 map = &ioapic_irqmaps[cpuid][intr];
9dbe6e38
SZ
1365 KASSERT(map->im_type == IOAPIC_IMT_MSI ||
1366 map->im_type == IOAPIC_IMT_MSIX,
ed20d0e3 1367 ("trying to map non-MSI/MSI-X intr %d, type %d", intr, map->im_type));
4234567c 1368 KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr,
ed20d0e3 1369 ("intr %d, invalid %s-base %d", intr,
9dbe6e38
SZ
1370 map->im_type == IOAPIC_IMT_MSI ? "MSI" : "MSI-X",
1371 map->im_msi_base));
4234567c
SZ
1372
1373 msi_map(map->im_msi_base, addr, data, cpuid);
1374
9dbe6e38
SZ
1375 if (bootverbose) {
1376 kprintf("map %s intr %d on cpu%d\n",
1377 map->im_type == IOAPIC_IMT_MSI ? "MSI" : "MSI-X",
1378 intr, cpuid);
1379 }
4234567c
SZ
1380
1381 lwkt_reltoken(&ioapic_irqmap_tok);
1382}