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