MachIntr: Add two methods to find IRQ
[dragonfly.git] / sys / platform / pc32 / icu / icu_abi.c
1 /*
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  * Copyright (c) 1991 The Regents of the University of California.
4  * All rights reserved.
5  * 
6  * This code is derived from software contributed to The DragonFly Project
7  * by Matthew Dillon <dillon@backplane.com>
8  *
9  * This code is derived from software contributed to Berkeley by
10  * William Jolitz.
11  * 
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in
20  *    the documentation and/or other materials provided with the
21  *    distribution.
22  * 3. Neither the name of The DragonFly Project nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific, prior written permission.
25  * 
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
30  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
32  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
36  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  */
39
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>
45 #include <sys/rman.h>
46 #include <sys/bus.h>
47
48 #include <machine/segments.h>
49 #include <machine/md_var.h>
50 #include <machine/intr_machdep.h>
51 #include <machine/globaldata.h>
52 #include <machine/smp.h>
53 #include <machine/msi_var.h>
54
55 #include <sys/thread2.h>
56
57 #include <machine_base/icu/elcr_var.h>
58
59 #include <machine_base/icu/icu.h>
60 #include <machine_base/icu/icu_ipl.h>
61 #include <machine_base/apic/ioapic.h>
62
63 extern inthand_t
64         IDTVEC(icu_intr0),      IDTVEC(icu_intr1),
65         IDTVEC(icu_intr2),      IDTVEC(icu_intr3),
66         IDTVEC(icu_intr4),      IDTVEC(icu_intr5),
67         IDTVEC(icu_intr6),      IDTVEC(icu_intr7),
68         IDTVEC(icu_intr8),      IDTVEC(icu_intr9),
69         IDTVEC(icu_intr10),     IDTVEC(icu_intr11),
70         IDTVEC(icu_intr12),     IDTVEC(icu_intr13),
71         IDTVEC(icu_intr14),     IDTVEC(icu_intr15);
72
73 static inthand_t *icu_intr[ICU_HWI_VECTORS] = {
74         &IDTVEC(icu_intr0),     &IDTVEC(icu_intr1),
75         &IDTVEC(icu_intr2),     &IDTVEC(icu_intr3),
76         &IDTVEC(icu_intr4),     &IDTVEC(icu_intr5),
77         &IDTVEC(icu_intr6),     &IDTVEC(icu_intr7),
78         &IDTVEC(icu_intr8),     &IDTVEC(icu_intr9),
79         &IDTVEC(icu_intr10),    &IDTVEC(icu_intr11),
80         &IDTVEC(icu_intr12),    &IDTVEC(icu_intr13),
81         &IDTVEC(icu_intr14),    &IDTVEC(icu_intr15)
82 };
83
84 static struct icu_irqmap {
85         int                     im_type;        /* ICU_IMT_ */
86         enum intr_trigger       im_trig;
87         int                     im_msi_base;
88         uint32_t                im_flags;
89 } icu_irqmaps[MAXCPU][IDT_HWI_VECTORS];
90
91 static struct lwkt_token icu_irqmap_tok =
92         LWKT_TOKEN_INITIALIZER(icu_irqmap_token);
93
94 #define ICU_IMT_UNUSED          0       /* KEEP THIS */
95 #define ICU_IMT_RESERVED        1
96 #define ICU_IMT_LEGACY          2
97 #define ICU_IMT_SYSCALL         3
98 #define ICU_IMT_SHADOW          4
99 #define ICU_IMT_MSI             5
100 #define ICU_IMT_MSIX            6
101
102 #define ICU_IMT_ISHWI(map)      ((map)->im_type != ICU_IMT_RESERVED && \
103                                  (map)->im_type != ICU_IMT_SYSCALL && \
104                                  (map)->im_type != ICU_IMT_SHADOW)
105
106 #define ICU_IMF_CONF            0x1
107
108 extern void     ICU_INTREN(int);
109 extern void     ICU_INTRDIS(int);
110
111 extern int      imcr_present;
112
113 static void     icu_abi_intr_enable(int);
114 static void     icu_abi_intr_disable(int);
115 static void     icu_abi_intr_setup(int, int);
116 static void     icu_abi_intr_teardown(int);
117
118 static void     icu_abi_legacy_intr_config(int, enum intr_trigger,
119                     enum intr_polarity);
120 static int      icu_abi_legacy_intr_cpuid(int);
121 static int      icu_abi_legacy_intr_find(int, enum intr_trigger,
122                     enum intr_polarity);
123 static int      icu_abi_legacy_intr_find_bygsi(int, enum intr_trigger,
124                     enum intr_polarity);
125
126 static int      icu_abi_msi_alloc(int [], int, int);
127 static void     icu_abi_msi_release(const int [], int, int);
128 static void     icu_abi_msi_map(int, uint64_t *, uint32_t *, int);
129 static int      icu_abi_msix_alloc(int *, int);
130 static void     icu_abi_msix_release(int, int);
131
132 static int      icu_abi_msi_alloc_intern(int, const char *,
133                     int [], int, int);
134 static void     icu_abi_msi_release_intern(int, const char *,
135                     const int [], int, int);
136
137 static void     icu_abi_finalize(void);
138 static void     icu_abi_cleanup(void);
139 static void     icu_abi_setdefault(void);
140 static void     icu_abi_stabilize(void);
141 static void     icu_abi_initmap(void);
142 static void     icu_abi_rman_setup(struct rman *);
143
144 struct machintr_abi MachIntrABI_ICU = {
145         MACHINTR_ICU,
146         .intr_disable   = icu_abi_intr_disable,
147         .intr_enable    = icu_abi_intr_enable,
148         .intr_setup     = icu_abi_intr_setup,
149         .intr_teardown  = icu_abi_intr_teardown,
150
151         .legacy_intr_config = icu_abi_legacy_intr_config,
152         .legacy_intr_cpuid = icu_abi_legacy_intr_cpuid,
153         .legacy_intr_find = icu_abi_legacy_intr_find,
154         .legacy_intr_find_bygsi = icu_abi_legacy_intr_find_bygsi,
155
156         .msi_alloc      = icu_abi_msi_alloc,
157         .msi_release    = icu_abi_msi_release,
158         .msi_map        = icu_abi_msi_map,
159         .msix_alloc     = icu_abi_msix_alloc,
160         .msix_release   = icu_abi_msix_release,
161
162         .finalize       = icu_abi_finalize,
163         .cleanup        = icu_abi_cleanup,
164         .setdefault     = icu_abi_setdefault,
165         .stabilize      = icu_abi_stabilize,
166         .initmap        = icu_abi_initmap,
167         .rman_setup     = icu_abi_rman_setup
168 };
169
170 static int      icu_abi_msi_start;      /* NOTE: for testing only */
171
172 /*
173  * WARNING!  SMP builds can use the ICU now so this code must be MP safe.
174  */
175
176 static void
177 icu_abi_intr_enable(int irq)
178 {
179         const struct icu_irqmap *map;
180
181         KASSERT(irq >= 0 && irq < IDT_HWI_VECTORS,
182             ("icu enable, invalid irq %d", irq));
183
184         map = &icu_irqmaps[mycpuid][irq];
185         KASSERT(ICU_IMT_ISHWI(map),
186             ("icu enable, not hwi irq %d, type %d, cpu%d",
187              irq, map->im_type, mycpuid));
188         if (map->im_type != ICU_IMT_LEGACY)
189                 return;
190
191         ICU_INTREN(irq);
192 }
193
194 static void
195 icu_abi_intr_disable(int irq)
196 {
197         const struct icu_irqmap *map;
198
199         KASSERT(irq >= 0 && irq < IDT_HWI_VECTORS,
200             ("icu disable, invalid irq %d", irq));
201
202         map = &icu_irqmaps[mycpuid][irq];
203         KASSERT(ICU_IMT_ISHWI(map),
204             ("icu disable, not hwi irq %d, type %d, cpu%d",
205              irq, map->im_type, mycpuid));
206         if (map->im_type != ICU_IMT_LEGACY)
207                 return;
208
209         ICU_INTRDIS(irq);
210 }
211
212 /*
213  * Called before interrupts are physically enabled
214  */
215 static void
216 icu_abi_stabilize(void)
217 {
218         int intr;
219
220         for (intr = 0; intr < ICU_HWI_VECTORS; ++intr)
221                 ICU_INTRDIS(intr);
222         ICU_INTREN(ICU_IRQ_SLAVE);
223 }
224
225 /*
226  * Called after interrupts physically enabled but before the
227  * critical section is released.
228  */
229 static void
230 icu_abi_cleanup(void)
231 {
232         bzero(mdcpu->gd_ipending, sizeof(mdcpu->gd_ipending));
233 }
234
235 /*
236  * Called after stablize and cleanup; critical section is not
237  * held and interrupts are not physically disabled.
238  */
239 static void
240 icu_abi_finalize(void)
241 {
242         KKASSERT(MachIntrABI.type == MACHINTR_ICU);
243         KKASSERT(!ioapic_enable);
244
245         /*
246          * If an IMCR is present, programming bit 0 disconnects the 8259
247          * from the BSP.  The 8259 may still be connected to LINT0 on the
248          * BSP's LAPIC.
249          *
250          * If we are running SMP the LAPIC is active, try to use virtual
251          * wire mode so we can use other interrupt sources within the LAPIC
252          * in addition to the 8259.
253          */
254         if (imcr_present) {
255                 outb(0x22, 0x70);
256                 outb(0x23, 0x01);
257         }
258 }
259
260 static void
261 icu_abi_intr_setup(int intr, int flags __unused)
262 {
263         const struct icu_irqmap *map;
264         u_long ef;
265
266         KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
267             ("icu setup, invalid irq %d", intr));
268
269         map = &icu_irqmaps[mycpuid][intr];
270         KASSERT(ICU_IMT_ISHWI(map),
271             ("icu setup, not hwi irq %d, type %d, cpu%d",
272              intr, map->im_type, mycpuid));
273         if (map->im_type != ICU_IMT_LEGACY)
274                 return;
275
276         ef = read_eflags();
277         cpu_disable_intr();
278
279         ICU_INTREN(intr);
280
281         write_eflags(ef);
282 }
283
284 static void
285 icu_abi_intr_teardown(int intr)
286 {
287         const struct icu_irqmap *map;
288         u_long ef;
289
290         KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
291             ("icu teardown, invalid irq %d", intr));
292
293         map = &icu_irqmaps[mycpuid][intr];
294         KASSERT(ICU_IMT_ISHWI(map),
295             ("icu teardown, not hwi irq %d, type %d, cpu%d",
296              intr, map->im_type, mycpuid));
297         if (map->im_type != ICU_IMT_LEGACY)
298                 return;
299
300         ef = read_eflags();
301         cpu_disable_intr();
302
303         ICU_INTRDIS(intr);
304
305         write_eflags(ef);
306 }
307
308 static void
309 icu_abi_setdefault(void)
310 {
311         int intr;
312
313         for (intr = 0; intr < ICU_HWI_VECTORS; ++intr) {
314                 if (intr == ICU_IRQ_SLAVE)
315                         continue;
316                 setidt(IDT_OFFSET + intr, icu_intr[intr], SDT_SYS386IGT,
317                        SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
318         }
319 }
320
321 static void
322 icu_abi_initmap(void)
323 {
324         int cpu;
325
326         kgetenv_int("hw.icu.msi_start", &icu_abi_msi_start);
327         icu_abi_msi_start &= ~0x1f;     /* MUST be 32 aligned */
328
329         /*
330          * NOTE: ncpus is not ready yet
331          */
332         for (cpu = 0; cpu < MAXCPU; ++cpu) {
333                 int i;
334
335                 if (cpu != 0) {
336                         for (i = 0; i < ICU_HWI_VECTORS; ++i)
337                                 icu_irqmaps[cpu][i].im_type = ICU_IMT_RESERVED;
338                 } else {
339                         for (i = 0; i < ICU_HWI_VECTORS; ++i)
340                                 icu_irqmaps[cpu][i].im_type = ICU_IMT_LEGACY;
341                         icu_irqmaps[cpu][ICU_IRQ_SLAVE].im_type =
342                             ICU_IMT_RESERVED;
343
344                         if (elcr_found) {
345                                 for (i = 0; i < ICU_HWI_VECTORS; ++i) {
346                                         icu_irqmaps[cpu][i].im_trig =
347                                             elcr_read_trigger(i);
348                                 }
349                         } else {
350                                 /*
351                                  * NOTE: Trigger mode does not matter at all
352                                  */
353                                 for (i = 0; i < ICU_HWI_VECTORS; ++i) {
354                                         icu_irqmaps[cpu][i].im_trig =
355                                             INTR_TRIGGER_EDGE;
356                                 }
357                         }
358                 }
359
360                 for (i = 0; i < IDT_HWI_VECTORS; ++i)
361                         icu_irqmaps[cpu][i].im_msi_base = -1;
362
363                 icu_irqmaps[cpu][IDT_OFFSET_SYSCALL - IDT_OFFSET].im_type =
364                     ICU_IMT_SYSCALL;
365         }
366 }
367
368 static void
369 icu_abi_legacy_intr_config(int irq, enum intr_trigger trig,
370     enum intr_polarity pola __unused)
371 {
372         struct icu_irqmap *map;
373
374         KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
375
376         KKASSERT(irq >= 0 && irq < IDT_HWI_VECTORS);
377         map = &icu_irqmaps[0][irq];
378
379         KKASSERT(map->im_type == ICU_IMT_LEGACY);
380
381         /* TODO: Check whether it is configured or not */
382         map->im_flags |= ICU_IMF_CONF;
383
384         if (trig == map->im_trig)
385                 return;
386
387         if (bootverbose) {
388                 kprintf("ICU: irq %d, %s -> %s\n", irq,
389                         intr_str_trigger(map->im_trig),
390                         intr_str_trigger(trig));
391         }
392         map->im_trig = trig;
393
394         if (!elcr_found) {
395                 if (bootverbose)
396                         kprintf("ICU: no ELCR, skip irq %d config\n", irq);
397                 return;
398         }
399         elcr_write_trigger(irq, map->im_trig);
400 }
401
402 static int
403 icu_abi_legacy_intr_cpuid(int irq __unused)
404 {
405         return 0;
406 }
407
408 static void
409 icu_abi_rman_setup(struct rman *rm)
410 {
411         int start, end, i;
412
413         KASSERT(rm->rm_cpuid >= 0 && rm->rm_cpuid < MAXCPU,
414             ("invalid rman cpuid %d", rm->rm_cpuid));
415
416         start = end = -1;
417         for (i = 0; i < IDT_HWI_VECTORS; ++i) {
418                 const struct icu_irqmap *map = &icu_irqmaps[rm->rm_cpuid][i];
419
420                 if (start < 0) {
421                         if (ICU_IMT_ISHWI(map))
422                                 start = end = i;
423                 } else {
424                         if (ICU_IMT_ISHWI(map)) {
425                                 end = i;
426                         } else {
427                                 KKASSERT(end >= 0);
428                                 if (bootverbose) {
429                                         kprintf("ICU: rman cpu%d %d - %d\n",
430                                             rm->rm_cpuid, start, end);
431                                 }
432                                 if (rman_manage_region(rm, start, end)) {
433                                         panic("rman_manage_region"
434                                             "(cpu%d %d - %d)", rm->rm_cpuid,
435                                             start, end);
436                                 }
437                                 start = end = -1;
438                         }
439                 }
440         }
441         if (start >= 0) {
442                 KKASSERT(end >= 0);
443                 if (bootverbose) {
444                         kprintf("ICU: rman cpu%d %d - %d\n",
445                             rm->rm_cpuid, start, end);
446                 }
447                 if (rman_manage_region(rm, start, end)) {
448                         panic("rman_manage_region(cpu%d %d - %d)",
449                             rm->rm_cpuid, start, end);
450                 }
451         }
452 }
453
454 static int
455 icu_abi_msi_alloc_intern(int type, const char *desc,
456     int intrs[], int count, int cpuid)
457 {
458         int i, error;
459
460         KASSERT(cpuid >= 0 && cpuid < ncpus,
461             ("invalid cpuid %d", cpuid));
462
463         KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
464         KASSERT((count & (count - 1)) == 0,
465             ("count %d is not power of 2", count));
466
467         lwkt_gettoken(&icu_irqmap_tok);
468
469         /*
470          * NOTE:
471          * Since IDT_OFFSET is 32, which is the maximum valid 'count',
472          * we do not need to find out the first properly aligned
473          * interrupt vector.
474          */
475
476         error = EMSGSIZE;
477         for (i = icu_abi_msi_start; i < IDT_HWI_VECTORS; i += count) {
478                 int j;
479
480                 if (icu_irqmaps[cpuid][i].im_type != ICU_IMT_UNUSED)
481                         continue;
482
483                 for (j = 1; j < count; ++j) {
484                         if (icu_irqmaps[cpuid][i + j].im_type != ICU_IMT_UNUSED)
485                                 break;
486                 }
487                 if (j != count)
488                         continue;
489
490                 for (j = 0; j < count; ++j) {
491                         int intr = i + j, cpu;
492
493                         for (cpu = 0; cpu < ncpus; ++cpu) {
494                                 struct icu_irqmap *map;
495
496                                 map = &icu_irqmaps[cpu][intr];
497                                 KASSERT(map->im_msi_base < 0,
498                                     ("intr %d cpu%d, stale %s-base %d",
499                                      intr, cpu, desc, map->im_msi_base));
500                                 KASSERT(map->im_type == ICU_IMT_UNUSED,
501                                     ("intr %d cpu%d, already allocated",
502                                      intr, cpu));
503
504                                 if (cpu == cpuid) {
505                                         map->im_type = type;
506                                         map->im_msi_base = i;
507                                 } else {
508                                         map->im_type = ICU_IMT_SHADOW;
509                                 }
510                         }
511
512                         intrs[j] = intr;
513                         msi_setup(intr);
514
515                         if (bootverbose) {
516                                 kprintf("alloc %s intr %d on cpu%d\n",
517                                     desc, intr, cpuid);
518                         }
519                 }
520                 error = 0;
521                 break;
522         }
523
524         lwkt_reltoken(&icu_irqmap_tok);
525
526         return error;
527 }
528
529 static void
530 icu_abi_msi_release_intern(int type, const char *desc,
531     const int intrs[], int count, int cpuid)
532 {
533         int i, msi_base = -1, intr_next = -1, mask;
534
535         KASSERT(cpuid >= 0 && cpuid < ncpus,
536             ("invalid cpuid %d", cpuid));
537
538         KASSERT(count > 0 && count <= 32, ("invalid count %d", count));
539
540         mask = count - 1;
541         KASSERT((count & mask) == 0, ("count %d is not power of 2", count));
542
543         lwkt_gettoken(&icu_irqmap_tok);
544
545         for (i = 0; i < count; ++i) {
546                 int intr = intrs[i], cpu;
547
548                 KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
549                     ("invalid intr %d", intr));
550
551                 for (cpu = 0; cpu < ncpus; ++cpu) {
552                         struct icu_irqmap *map;
553
554                         map = &icu_irqmaps[cpu][intr];
555
556                         if (cpu == cpuid) {
557                                 KASSERT(map->im_type == type,
558                                     ("trying to release non-%s intr %d cpu%d, "
559                                      "type %d", desc, intr, cpu,
560                                      map->im_type));
561                                 KASSERT(map->im_msi_base >= 0 &&
562                                     map->im_msi_base <= intr,
563                                     ("intr %d cpu%d, invalid %s-base %d",
564                                      intr, cpu, desc, map->im_msi_base));
565                                 KASSERT((map->im_msi_base & mask) == 0,
566                                     ("intr %d cpu%d, %s-base %d is "
567                                      "not properly aligned %d",
568                                      intr, cpu, desc, map->im_msi_base, count));
569
570                                 if (msi_base < 0) {
571                                         msi_base = map->im_msi_base;
572                                 } else {
573                                         KASSERT(map->im_msi_base == msi_base,
574                                             ("intr %d cpu%d, "
575                                              "inconsistent %s-base, "
576                                              "was %d, now %d",
577                                              intr, cpu, desc,
578                                              msi_base, map->im_msi_base));
579                                 }
580                                 map->im_msi_base = -1;
581                         } else {
582                                 KASSERT(map->im_type == ICU_IMT_SHADOW,
583                                     ("trying to release non-%ssh intr %d cpu%d, "
584                                      "type %d", desc, intr, cpu,
585                                      map->im_type));
586                                 KASSERT(map->im_msi_base < 0,
587                                     ("intr %d cpu%d, invalid %ssh-base %d",
588                                      intr, cpu, desc, map->im_msi_base));
589                         }
590                         map->im_type = ICU_IMT_UNUSED;
591                 }
592
593                 if (intr_next < intr)
594                         intr_next = intr;
595
596                 if (bootverbose) {
597                         kprintf("release %s intr %d on cpu%d\n",
598                             desc, intr, cpuid);
599                 }
600         }
601
602         KKASSERT(intr_next > 0);
603         KKASSERT(msi_base >= 0);
604
605         ++intr_next;
606         if (intr_next < IDT_HWI_VECTORS) {
607                 int cpu;
608
609                 for (cpu = 0; cpu < ncpus; ++cpu) {
610                         const struct icu_irqmap *map =
611                             &icu_irqmaps[cpu][intr_next];
612
613                         if (map->im_type == type) {
614                                 KASSERT(map->im_msi_base != msi_base,
615                                     ("more than %d %s was allocated",
616                                      count, desc));
617                         }
618                 }
619         }
620
621         lwkt_reltoken(&icu_irqmap_tok);
622 }
623
624 static int
625 icu_abi_msi_alloc(int intrs[], int count, int cpuid)
626 {
627         return icu_abi_msi_alloc_intern(ICU_IMT_MSI, "MSI",
628             intrs, count, cpuid);
629 }
630
631 static void
632 icu_abi_msi_release(const int intrs[], int count, int cpuid)
633 {
634         icu_abi_msi_release_intern(ICU_IMT_MSI, "MSI",
635             intrs, count, cpuid);
636 }
637
638 static int
639 icu_abi_msix_alloc(int *intr, int cpuid)
640 {
641         return icu_abi_msi_alloc_intern(ICU_IMT_MSIX, "MSI-X",
642             intr, 1, cpuid);
643 }
644
645 static void
646 icu_abi_msix_release(int intr, int cpuid)
647 {
648         icu_abi_msi_release_intern(ICU_IMT_MSIX, "MSI-X",
649             &intr, 1, cpuid);
650 }
651
652 static void
653 icu_abi_msi_map(int intr, uint64_t *addr, uint32_t *data, int cpuid)
654 {
655         const struct icu_irqmap *map;
656
657         KASSERT(cpuid >= 0 && cpuid < ncpus,
658             ("invalid cpuid %d", cpuid));
659
660         KASSERT(intr >= 0 && intr < IDT_HWI_VECTORS,
661             ("invalid intr %d", intr));
662
663         lwkt_gettoken(&icu_irqmap_tok);
664
665         map = &icu_irqmaps[cpuid][intr];
666         KASSERT(map->im_type == ICU_IMT_MSI ||
667             map->im_type == ICU_IMT_MSIX,
668             ("trying to map non-MSI/MSI-X intr %d, type %d", intr, map->im_type));
669         KASSERT(map->im_msi_base >= 0 && map->im_msi_base <= intr,
670             ("intr %d, invalid %s-base %d", intr,
671              map->im_type == ICU_IMT_MSI ? "MSI" : "MSI-X",
672              map->im_msi_base));
673
674         msi_map(map->im_msi_base, addr, data, cpuid);
675
676         if (bootverbose) {
677                 kprintf("map %s intr %d on cpu%d\n",
678                     map->im_type == ICU_IMT_MSI ? "MSI" : "MSI-X",
679                     intr, cpuid);
680         }
681
682         lwkt_reltoken(&icu_irqmap_tok);
683 }
684
685 static int
686 icu_abi_legacy_intr_find(int irq, enum intr_trigger trig,
687     enum intr_polarity pola __unused)
688 {
689         const struct icu_irqmap *map;
690
691 #ifdef INVARIANTS
692         if (trig == INTR_TRIGGER_CONFORM) {
693                 KKASSERT(pola == INTR_POLARITY_CONFORM);
694         } else {
695                 KKASSERT(trig == INTR_TRIGGER_EDGE ||
696                     trig == INTR_TRIGGER_LEVEL);
697                 KKASSERT(pola == INTR_POLARITY_HIGH ||
698                     pola == INTR_POLARITY_LOW);
699         }
700 #endif
701
702         if (irq < 0 || irq >= ICU_HWI_VECTORS)
703                 return -1;
704
705         map = &icu_irqmaps[0][irq];
706         if (map->im_type == ICU_IMT_LEGACY) {
707                 if ((map->im_flags & ICU_IMF_CONF) &&
708                     trig != INTR_TRIGGER_CONFORM) {
709                         if (map->im_trig != trig)
710                                 return -1;
711                 }
712                 return irq;
713         }
714         return -1;
715 }
716
717 static int
718 icu_abi_legacy_intr_find_bygsi(int gsi, enum intr_trigger trig,
719     enum intr_polarity pola)
720 {
721         /* GSI and IRQ has 1:1 mapping */
722         return icu_abi_legacy_intr_find(gsi, trig, pola);
723 }