MachIntr: Add two methods to find IRQ
[dragonfly.git] / sys / platform / pc64 / icu / icu_abi.c
CommitLineData
c8fe38ae
MD
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.
c8fe38ae
MD
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/machintr.h>
44#include <sys/interrupt.h>
b3cf468e 45#include <sys/rman.h>
c8fe38ae
MD
46#include <sys/bus.h>
47
48#include <machine/segments.h>
49#include <machine/md_var.h>
57a9c56b 50#include <machine/intr_machdep.h>
c8fe38ae 51#include <machine/globaldata.h>
10db3cc6 52#include <machine/smp.h>
759fc533 53#include <machine/msi_var.h>
c8fe38ae
MD
54
55#include <sys/thread2.h>
56
7265a4fe 57#include <machine_base/icu/elcr_var.h>
9e0e3f85 58
7265a4fe
SZ
59#include <machine_base/icu/icu.h>
60#include <machine_base/icu/icu_ipl.h>
ed4d621d 61#include <machine_base/apic/ioapic.h>
c8fe38ae 62
c8fe38ae 63extern inthand_t
35e45e47
SZ
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);
c8fe38ae 72
35e45e47
SZ
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)
c8fe38ae
MD
82};
83
a3dd9120
SZ
84static struct icu_irqmap {
85 int im_type; /* ICU_IMT_ */
86 enum intr_trigger im_trig;
759fc533 87 int im_msi_base;
86d692fe 88 uint32_t im_flags; /* ICU_IMF_ */
b3cf468e 89} icu_irqmaps[MAXCPU][IDT_HWI_VECTORS];
a3dd9120 90
759fc533
SZ
91static struct lwkt_token icu_irqmap_tok =
92 LWKT_TOKEN_INITIALIZER(icu_irqmap_token);
93
a3dd9120
SZ
94#define ICU_IMT_UNUSED 0 /* KEEP THIS */
95#define ICU_IMT_RESERVED 1
f9593a5d 96#define ICU_IMT_LEGACY 2
474ba684 97#define ICU_IMT_SYSCALL 3
759fc533 98#define ICU_IMT_MSI 4
dad1b17f 99#define ICU_IMT_MSIX 5
a3dd9120 100
b3cf468e
SZ
101#define ICU_IMT_ISHWI(map) ((map)->im_type != ICU_IMT_RESERVED && \
102 (map)->im_type != ICU_IMT_SYSCALL)
103
86d692fe
SZ
104#define ICU_IMF_CONF 0x1
105
10db3cc6
SZ
106extern void ICU_INTREN(int);
107extern void ICU_INTRDIS(int);
108
85bcaa51
SZ
109extern int imcr_present;
110
1967234a
SZ
111static void icu_abi_intr_enable(int);
112static void icu_abi_intr_disable(int);
f416026e
SZ
113static void icu_abi_intr_setup(int, int);
114static void icu_abi_intr_teardown(int);
bec969af
SZ
115
116static void icu_abi_legacy_intr_config(int, enum intr_trigger,
117 enum intr_polarity);
118static int icu_abi_legacy_intr_cpuid(int);
86d692fe
SZ
119static int icu_abi_legacy_intr_find(int, enum intr_trigger,
120 enum intr_polarity);
121static int icu_abi_legacy_intr_find_bygsi(int, enum intr_trigger,
122 enum intr_polarity);
aea76754 123
759fc533
SZ
124static int icu_abi_msi_alloc(int [], int, int);
125static void icu_abi_msi_release(const int [], int, int);
126static void icu_abi_msi_map(int, uint64_t *, uint32_t *, int);
dad1b17f
SZ
127static int icu_abi_msix_alloc(int *, int);
128static void icu_abi_msix_release(int, int);
129
130static int icu_abi_msi_alloc_intern(int, const char *,
131 int [], int, int);
132static void icu_abi_msi_release_intern(int, const char *,
133 const int [], int, int);
759fc533 134
aea76754
SZ
135static void icu_abi_finalize(void);
136static void icu_abi_cleanup(void);
137static void icu_abi_setdefault(void);
138static void icu_abi_stabilize(void);
139static void icu_abi_initmap(void);
b3cf468e 140static void icu_abi_rman_setup(struct rman *);
10db3cc6 141
faaf4131 142struct machintr_abi MachIntrABI_ICU = {
339478ac 143 MACHINTR_ICU,
1967234a
SZ
144 .intr_disable = icu_abi_intr_disable,
145 .intr_enable = icu_abi_intr_enable,
f416026e
SZ
146 .intr_setup = icu_abi_intr_setup,
147 .intr_teardown = icu_abi_intr_teardown,
bec969af
SZ
148
149 .legacy_intr_config = icu_abi_legacy_intr_config,
150 .legacy_intr_cpuid = icu_abi_legacy_intr_cpuid,
86d692fe
SZ
151 .legacy_intr_find = icu_abi_legacy_intr_find,
152 .legacy_intr_find_bygsi = icu_abi_legacy_intr_find_bygsi,
35b2edcb 153
759fc533
SZ
154 .msi_alloc = icu_abi_msi_alloc,
155 .msi_release = icu_abi_msi_release,
156 .msi_map = icu_abi_msi_map,
dad1b17f
SZ
157 .msix_alloc = icu_abi_msix_alloc,
158 .msix_release = icu_abi_msix_release,
759fc533 159
aea76754
SZ
160 .finalize = icu_abi_finalize,
161 .cleanup = icu_abi_cleanup,
162 .setdefault = icu_abi_setdefault,
163 .stabilize = icu_abi_stabilize,
b3cf468e
SZ
164 .initmap = icu_abi_initmap,
165 .rman_setup = icu_abi_rman_setup
c8fe38ae
MD
166};
167
759fc533
SZ
168static int icu_abi_msi_start; /* NOTE: for testing only */
169
c8fe38ae
MD
170/*
171 * WARNING! SMP builds can use the ICU now so this code must be MP safe.
172 */
c8fe38ae 173
1967234a
SZ
174static void
175icu_abi_intr_enable(int irq)
176{
177 const struct icu_irqmap *map;
178
179 KASSERT(irq >= 0 && irq < IDT_HWI_VECTORS,
ed20d0e3 180 ("icu enable, invalid irq %d", irq));
1967234a
SZ
181
182 map = &icu_irqmaps[mycpuid][irq];
183 KASSERT(ICU_IMT_ISHWI(map),
ed20d0e3 184 ("icu enable, not hwi irq %d, type %d, cpu%d",
1967234a 185 irq, map->im_type, mycpuid));
f9593a5d 186 if (map->im_type != ICU_IMT_LEGACY)
1967234a 187 return;
1967234a
SZ
188
189 ICU_INTREN(irq);
190}
191
192static void
193icu_abi_intr_disable(int irq)
194{
195 const struct icu_irqmap *map;
196
197 KASSERT(irq >= 0 && irq < IDT_HWI_VECTORS,
ed20d0e3 198 ("icu disable, invalid irq %d", irq));
1967234a
SZ
199
200 map = &icu_irqmaps[mycpuid][irq];
201 KASSERT(ICU_IMT_ISHWI(map),
ed20d0e3 202 ("icu disable, not hwi irq %d, type %d, cpu%d",
1967234a 203 irq, map->im_type, mycpuid));
f9593a5d 204 if (map->im_type != ICU_IMT_LEGACY)
1967234a 205 return;
1967234a
SZ
206
207 ICU_INTRDIS(irq);
208}
209
c8fe38ae
MD
210/*
211 * Called before interrupts are physically enabled
212 */
213static void
aea76754 214icu_abi_stabilize(void)
c8fe38ae 215{
339478ac
SZ
216 int intr;
217
7bf5fa56 218 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr)
1967234a
SZ
219 ICU_INTRDIS(intr);
220 ICU_INTREN(ICU_IRQ_SLAVE);
7bf5fa56
SZ
221}
222
223/*
224 * Called after interrupts physically enabled but before the
225 * critical section is released.
226 */
227static void
aea76754 228icu_abi_cleanup(void)
7bf5fa56
SZ
229{
230 bzero(mdcpu->gd_ipending, sizeof(mdcpu->gd_ipending));
231}
232
233/*
234 * Called after stablize and cleanup; critical section is not
235 * held and interrupts are not physically disabled.
7bf5fa56
SZ
236 */
237static void
aea76754 238icu_abi_finalize(void)
7bf5fa56
SZ
239{
240 KKASSERT(MachIntrABI.type == MACHINTR_ICU);
f45bfca0 241 KKASSERT(!ioapic_enable);
339478ac 242
339478ac
SZ
243 /*
244 * If an IMCR is present, programming bit 0 disconnects the 8259
245 * from the BSP. The 8259 may still be connected to LINT0 on the
246 * BSP's LAPIC.
247 *
248 * If we are running SMP the LAPIC is active, try to use virtual
249 * wire mode so we can use other interrupt sources within the LAPIC
250 * in addition to the 8259.
251 */
9d758cc4 252 if (imcr_present) {
339478ac
SZ
253 outb(0x22, 0x70);
254 outb(0x23, 0x01);
7bf5fa56 255 }
c8fe38ae
MD
256}
257
f416026e
SZ
258static void
259icu_abi_intr_setup(int intr, int flags)
c8fe38ae 260{
1967234a 261 const struct icu_irqmap *map;
339478ac
SZ
262 register_t ef;
263
1967234a 264 KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
ed20d0e3 265 ("icu setup, invalid irq %d", intr));
1967234a
SZ
266
267 map = &icu_irqmaps[mycpuid][intr];
268 KASSERT(ICU_IMT_ISHWI(map),
ed20d0e3 269 ("icu setup, not hwi irq %d, type %d, cpu%d",
1967234a 270 intr, map->im_type, mycpuid));
f9593a5d 271 if (map->im_type != ICU_IMT_LEGACY)
1967234a 272 return;
339478ac
SZ
273
274 ef = read_rflags();
275 cpu_disable_intr();
339478ac 276
26cf64b2 277 ICU_INTREN(intr);
339478ac 278
f416026e
SZ
279 write_rflags(ef);
280}
281
282static void
283icu_abi_intr_teardown(int intr)
284{
1967234a 285 const struct icu_irqmap *map;
f416026e
SZ
286 register_t ef;
287
1967234a 288 KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
ed20d0e3 289 ("icu teardown, invalid irq %d", intr));
1967234a
SZ
290
291 map = &icu_irqmaps[mycpuid][intr];
292 KASSERT(ICU_IMT_ISHWI(map),
ed20d0e3 293 ("icu teardown, not hwi irq %d, type %d, cpu%d",
1967234a 294 intr, map->im_type, mycpuid));
f9593a5d 295 if (map->im_type != ICU_IMT_LEGACY)
1967234a 296 return;
f416026e
SZ
297
298 ef = read_rflags();
299 cpu_disable_intr();
300
26cf64b2 301 ICU_INTRDIS(intr);
339478ac 302
339478ac 303 write_rflags(ef);
c8fe38ae 304}
10db3cc6
SZ
305
306static void
aea76754 307icu_abi_setdefault(void)
10db3cc6
SZ
308{
309 int intr;
310
311 for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) {
312 if (intr == ICU_IRQ_SLAVE)
313 continue;
8a06c6ee
SZ
314 setidt_global(IDT_OFFSET + intr, icu_intr[intr],
315 SDT_SYSIGT, SEL_KPL, 0);
10db3cc6
SZ
316 }
317}
a3dd9120
SZ
318
319static void
aea76754 320icu_abi_initmap(void)
a3dd9120 321{
b3cf468e
SZ
322 int cpu;
323
759fc533
SZ
324 kgetenv_int("hw.icu.msi_start", &icu_abi_msi_start);
325 icu_abi_msi_start &= ~0x1f; /* MUST be 32 aligned */
326
b3cf468e
SZ
327 /*
328 * NOTE: ncpus is not ready yet
329 */
330 for (cpu = 0; cpu < MAXCPU; ++cpu) {
331 int i;
332
333 if (cpu != 0) {
334 for (i = 0; i < ICU_HWI_VECTORS; ++i)
335 icu_irqmaps[cpu][i].im_type = ICU_IMT_RESERVED;
336 } else {
337 for (i = 0; i < ICU_HWI_VECTORS; ++i)
f9593a5d 338 icu_irqmaps[cpu][i].im_type = ICU_IMT_LEGACY;
b3cf468e
SZ
339 icu_irqmaps[cpu][ICU_IRQ_SLAVE].im_type =
340 ICU_IMT_RESERVED;
341
342 if (elcr_found) {
343 for (i = 0; i < ICU_HWI_VECTORS; ++i) {
344 icu_irqmaps[cpu][i].im_trig =
345 elcr_read_trigger(i);
346 }
347 } else {
348 /*
349 * NOTE: Trigger mode does not matter at all
350 */
351 for (i = 0; i < ICU_HWI_VECTORS; ++i) {
352 icu_irqmaps[cpu][i].im_trig =
353 INTR_TRIGGER_EDGE;
354 }
355 }
356 }
759fc533
SZ
357
358 for (i = 0; i < IDT_HWI_VECTORS; ++i)
359 icu_irqmaps[cpu][i].im_msi_base = -1;
360
b3cf468e
SZ
361 icu_irqmaps[cpu][IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type =
362 ICU_IMT_SYSCALL;
a3dd9120
SZ
363 }
364}
d1ae7328
SZ
365
366static void
bec969af 367icu_abi_legacy_intr_config(int irq, enum intr_trigger trig,
d1ae7328
SZ
368 enum intr_polarity pola __unused)
369{
16437a92
SZ
370 struct icu_irqmap *map;
371
372 KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
373
451af8d9 374 KKASSERT(irq >= 0 && irq < IDT_HWI_VECTORS);
b3cf468e 375 map = &icu_irqmaps[0][irq];
16437a92 376
f9593a5d 377 KKASSERT(map->im_type == ICU_IMT_LEGACY);
16437a92
SZ
378
379 /* TODO: Check whether it is configured or not */
86d692fe 380 map->im_flags |= ICU_IMF_CONF;
16437a92
SZ
381
382 if (trig == map->im_trig)
383 return;
384
385 if (bootverbose) {
386 kprintf("ICU: irq %d, %s -> %s\n", irq,
387 intr_str_trigger(map->im_trig),
388 intr_str_trigger(trig));
389 }
390 map->im_trig = trig;
391
392 if (!elcr_found) {
393 if (bootverbose)
394 kprintf("ICU: no ELCR, skip irq %d config\n", irq);
395 return;
396 }
397 elcr_write_trigger(irq, map->im_trig);
d1ae7328 398}
a05c798c
SZ
399
400static int
bec969af 401icu_abi_legacy_intr_cpuid(int irq __unused)
a05c798c
SZ
402{
403 return 0;
404}
b3cf468e
SZ
405
406static void
407icu_abi_rman_setup(struct rman *rm)
408{
409 int start, end, i;
410
411 KASSERT(rm->rm_cpuid >= 0 && rm->rm_cpuid < MAXCPU,
412 ("invalid rman cpuid %d", rm->rm_cpuid));
413
414 start = end = -1;
415 for (i = 0; i < IDT_HWI_VECTORS; ++i) {
416 const struct icu_irqmap *map = &icu_irqmaps[rm->rm_cpuid][i];
417
418 if (start < 0) {
419 if (ICU_IMT_ISHWI(map))
420 start = end = i;
421 } else {
422 if (ICU_IMT_ISHWI(map)) {
423 end = i;
424 } else {
425 KKASSERT(end >= 0);
426 if (bootverbose) {
427 kprintf("ICU: rman cpu%d %d - %d\n",
428 rm->rm_cpuid, start, end);
429 }
430 if (rman_manage_region(rm, start, end)) {
431 panic("rman_manage_region"
432 "(cpu%d %d - %d)", rm->rm_cpuid,
433 start, end);
434 }
435 start = end = -1;
436 }
437 }
438 }
439 if (start >= 0) {
440 KKASSERT(end >= 0);
441 if (bootverbose) {
442 kprintf("ICU: rman cpu%d %d - %d\n",
443 rm->rm_cpuid, start, end);
444 }
445 if (rman_manage_region(rm, start, end)) {
446 panic("rman_manage_region(cpu%d %d - %d)",
447 rm->rm_cpuid, start, end);
448 }
449 }
450}
759fc533
SZ
451
452static int
dad1b17f
SZ
453icu_abi_msi_alloc_intern(int type, const char *desc,
454 int intrs[], int count, int cpuid)
759fc533
SZ
455{
456 int i, error;
457
458 KASSERT(cpuid >= 0 && cpuid < ncpus,
459 ("invalid cpuid %d", cpuid));
460
ed20d0e3 461 KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
759fc533 462 KASSERT((count & (count - 1)) == 0,
ed20d0e3 463 ("count %d is not power of 2", count));
759fc533
SZ
464
465 lwkt_gettoken(&icu_irqmap_tok);
466
467 /*
468 * NOTE:
469 * Since IDT_OFFSET is 32, which is the maximum valid 'count',
470 * we do not need to find out the first properly aligned
471 * interrupt vector.
472 */
473
474 error = EMSGSIZE;
475 for (i = icu_abi_msi_start; i < IDT_HWI_VECTORS; i += count) {
476 int j;
477
478 if (icu_irqmaps[cpuid][i].im_type != ICU_IMT_UNUSED)
479 continue;
480
481 for (j = 1; j < count; ++j) {
482 if (icu_irqmaps[cpuid][i + j].im_type != ICU_IMT_UNUSED)
483 break;
484 }
485 if (j != count)
486 continue;
487
488 for (j = 0; j < count; ++j) {
489 struct icu_irqmap *map;
490 int intr = i + j;
491
492 map = &icu_irqmaps[cpuid][intr];
493 KASSERT(map->im_msi_base < 0,
ed20d0e3 494 ("intr %d, stale %s-base %d",
dad1b17f 495 intr, desc, map->im_msi_base));
759fc533 496
dad1b17f 497 map->im_type = type;
759fc533
SZ
498 map->im_msi_base = i;
499
500 intrs[j] = intr;
501 msi_setup(intr, cpuid);
502
503 if (bootverbose) {
dad1b17f
SZ
504 kprintf("alloc %s intr %d on cpu%d\n",
505 desc, intr, cpuid);
759fc533 506 }
759fc533
SZ
507 }
508 error = 0;
509 break;
510 }
511
512 lwkt_reltoken(&icu_irqmap_tok);
513
514 return error;
515}
516
517static void
dad1b17f
SZ
518icu_abi_msi_release_intern(int type, const char *desc,
519 const int intrs[], int count, int cpuid)
759fc533
SZ
520{
521 int i, msi_base = -1, intr_next = -1, mask;
522
523 KASSERT(cpuid >= 0 && cpuid < ncpus,
524 ("invalid cpuid %d", cpuid));
525
ed20d0e3 526 KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
759fc533
SZ
527
528 mask = count - 1;
ed20d0e3 529 KASSERT((count & mask) == 0, ("count %d is not power of 2", count));
759fc533
SZ
530
531 lwkt_gettoken(&icu_irqmap_tok);
532
533 for (i = 0; i < count; ++i) {
534 struct icu_irqmap *map;
535 int intr = intrs[i];
536
537 KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
ed20d0e3 538 ("invalid intr %d", intr));
759fc533
SZ
539
540 map = &icu_irqmaps[cpuid][intr];
dad1b17f 541 KASSERT(map->im_type == type,
ed20d0e3 542 ("trying to release non-%s intr %d, type %d", desc,
759fc533
SZ
543 intr, map->im_type));
544 KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr,
ed20d0e3 545 ("intr %d, invalid %s-base %d", intr, desc,
dad1b17f 546 map->im_msi_base));
759fc533 547 KASSERT((map->im_msi_base & mask) == 0,
ed20d0e3 548 ("intr %d, %s-base %d is not properly aligned %d",
dad1b17f 549 intr, desc, map->im_msi_base, count));
759fc533
SZ
550
551 if (msi_base < 0) {
552 msi_base = map->im_msi_base;
553 } else {
554 KASSERT(map->im_msi_base == msi_base,
dad1b17f 555 ("intr %d, inconsistent %s-base, "
ed20d0e3 556 "was %d, now %d",
dad1b17f 557 intr, desc, msi_base, map->im_msi_base));
759fc533
SZ
558 }
559
560 if (intr_next < intr)
561 intr_next = intr;
562
563 map->im_type = ICU_IMT_UNUSED;
564 map->im_msi_base = -1;
565
dad1b17f
SZ
566 if (bootverbose) {
567 kprintf("release %s intr %d on cpu%d\n",
568 desc, intr, cpuid);
569 }
759fc533
SZ
570 }
571
572 KKASSERT(intr_next > 0);
573 KKASSERT(msi_base >= 0);
574
575 ++intr_next;
576 if (intr_next < IDT_HWI_VECTORS) {
577 const struct icu_irqmap *map = &icu_irqmaps[cpuid][intr_next];
578
dad1b17f 579 if (map->im_type == type) {
759fc533 580 KASSERT(map->im_msi_base != msi_base,
ed20d0e3 581 ("more than %d %s was allocated", count, desc));
759fc533
SZ
582 }
583 }
584
585 lwkt_reltoken(&icu_irqmap_tok);
586}
587
dad1b17f
SZ
588static int
589icu_abi_msi_alloc(int intrs[], int count, int cpuid)
590{
591 return icu_abi_msi_alloc_intern(ICU_IMT_MSI, "MSI",
592 intrs, count, cpuid);
593}
594
595static void
596icu_abi_msi_release(const int intrs[], int count, int cpuid)
597{
fd20246e 598 icu_abi_msi_release_intern(ICU_IMT_MSI, "MSI",
dad1b17f
SZ
599 intrs, count, cpuid);
600}
601
602static int
603icu_abi_msix_alloc(int *intr, int cpuid)
604{
605 return icu_abi_msi_alloc_intern(ICU_IMT_MSIX, "MSI-X",
606 intr, 1, cpuid);
607}
608
609static void
610icu_abi_msix_release(int intr, int cpuid)
611{
fd20246e 612 icu_abi_msi_release_intern(ICU_IMT_MSIX, "MXI-X",
dad1b17f
SZ
613 &intr, 1, cpuid);
614}
615
759fc533
SZ
616static void
617icu_abi_msi_map(int intr, uint64_t *addr, uint32_t *data, int cpuid)
618{
619 const struct icu_irqmap *map;
620
621 KASSERT(cpuid >= 0 && cpuid < ncpus,
622 ("invalid cpuid %d", cpuid));
623
624 KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
ed20d0e3 625 ("invalid intr %d", intr));
759fc533
SZ
626
627 lwkt_gettoken(&icu_irqmap_tok);
628
629 map = &icu_irqmaps[cpuid][intr];
dad1b17f
SZ
630 KASSERT(map->im_type == ICU_IMT_MSI ||
631 map->im_type == ICU_IMT_MSIX,
ed20d0e3 632 ("trying to map non-MSI/MSI-X intr %d, type %d", intr, map->im_type));
759fc533 633 KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr,
ed20d0e3 634 ("intr %d, invalid %s-base %d", intr,
dad1b17f
SZ
635 map->im_type == ICU_IMT_MSI ? "MSI" : "MSI-X",
636 map->im_msi_base));
759fc533
SZ
637
638 msi_map(map->im_msi_base, addr, data, cpuid);
639
dad1b17f
SZ
640 if (bootverbose) {
641 kprintf("map %s intr %d on cpu%d\n",
642 map->im_type == ICU_IMT_MSI ? "MSI" : "MSI-X",
643 intr, cpuid);
644 }
759fc533
SZ
645
646 lwkt_reltoken(&icu_irqmap_tok);
647}
86d692fe
SZ
648
649static int
650icu_abi_legacy_intr_find(int irq, enum intr_trigger trig,
651 enum intr_polarity pola __unused)
652{
653 const struct icu_irqmap *map;
654
655#ifdef INVARIANTS
656 if (trig == INTR_TRIGGER_CONFORM) {
657 KKASSERT(pola == INTR_POLARITY_CONFORM);
658 } else {
659 KKASSERT(trig == INTR_TRIGGER_EDGE ||
660 trig == INTR_TRIGGER_LEVEL);
661 KKASSERT(pola == INTR_POLARITY_HIGH ||
662 pola == INTR_POLARITY_LOW);
663 }
664#endif
665
666 if (irq < 0 || irq >= ICU_HWI_VECTORS)
667 return -1;
668
669 map = &icu_irqmaps[0][irq];
670 if (map->im_type == ICU_IMT_LEGACY) {
671 if ((map->im_flags & ICU_IMF_CONF) &&
672 trig != INTR_TRIGGER_CONFORM) {
673 if (map->im_trig != trig)
674 return -1;
675 }
676 return irq;
677 }
678 return -1;
679}
680
681static int
682icu_abi_legacy_intr_find_bygsi(int gsi, enum intr_trigger trig,
683 enum intr_polarity pola)
684{
685 /* GSI and IRQ has 1:1 mapping */
686 return icu_abi_legacy_intr_find(gsi, trig, pola);
687}