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