ioapic_abi: More consistent function name w/ legacy interrupt
[dragonfly.git] / sys / platform / pc32 / i386 / mptable.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. The name of the developer may NOT be used to endorse or promote products
11  *    derived from this software without specific prior written permission.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.115.2.15 2003/03/14 21:22:35 jhb Exp $
26  */
27
28 #include "opt_cpu.h"
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/sysctl.h>
34 #include <sys/malloc.h>
35 #include <sys/memrange.h>
36 #include <sys/cons.h>   /* cngetc() */
37 #include <sys/machintr.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_param.h>
41 #include <vm/pmap.h>
42 #include <vm/vm_kern.h>
43 #include <vm/vm_extern.h>
44 #include <sys/lock.h>
45 #include <vm/vm_map.h>
46 #include <sys/user.h>
47 #ifdef GPROF 
48 #include <sys/gmon.h>
49 #endif
50
51 #include <sys/mplock2.h>
52
53 #include <machine/smp.h>
54 #include <machine_base/isa/isa_intr.h>
55 #include <machine_base/apic/apicreg.h>
56 #include <machine/atomic.h>
57 #include <machine/cpufunc.h>
58 #include <machine/cputypes.h>
59 #include <machine_base/apic/ioapic_abi.h>
60 #include <machine_base/apic/lapic.h>
61 #include <machine_base/apic/ioapic.h>
62 #include <machine/psl.h>
63 #include <machine/segments.h>
64 #include <machine/tss.h>
65 #include <machine/specialreg.h>
66 #include <machine/globaldata.h>
67 #include <machine/pmap_inval.h>
68 #include <machine/mptable.h>
69
70 #include <machine/md_var.h>             /* setidt() */
71 #include <machine_base/icu/icu.h>       /* IPIs */
72 #include <machine/intr_machdep.h>       /* IPIs */
73
74 extern u_long   ebda_addr;
75 extern u_int    base_memory;
76 extern int      imcr_present;
77 extern int      naps;
78
79 #define BIOS_BASE               (0xf0000)
80 #define BIOS_BASE2              (0xe0000)
81 #define BIOS_SIZE               (0x10000)
82 #define BIOS_COUNT              (BIOS_SIZE/4)
83
84 #define PROCENTRY_FLAG_EN       0x01
85 #define PROCENTRY_FLAG_BP       0x02
86 #define IOAPICENTRY_FLAG_EN     0x01
87
88 /* MP Floating Pointer Structure */
89 typedef struct MPFPS {
90         char    signature[4];
91         u_int32_t pap;
92         u_char  length;
93         u_char  spec_rev;
94         u_char  checksum;
95         u_char  mpfb1;
96         u_char  mpfb2;
97         u_char  mpfb3;
98         u_char  mpfb4;
99         u_char  mpfb5;
100 }      *mpfps_t;
101
102 /* MP Configuration Table Header */
103 typedef struct MPCTH {
104         char    signature[4];
105         u_short base_table_length;
106         u_char  spec_rev;
107         u_char  checksum;
108         u_char  oem_id[8];
109         u_char  product_id[12];
110         void   *oem_table_pointer;
111         u_short oem_table_size;
112         u_short entry_count;
113         void   *apic_address;
114         u_short extended_table_length;
115         u_char  extended_table_checksum;
116         u_char  reserved;
117 }      *mpcth_t;
118
119
120 typedef struct PROCENTRY {
121         u_char  type;
122         u_char  apic_id;
123         u_char  apic_version;
124         u_char  cpu_flags;
125         u_long  cpu_signature;
126         u_long  feature_flags;
127         u_long  reserved1;
128         u_long  reserved2;
129 }      *proc_entry_ptr;
130
131 typedef struct BUSENTRY {
132         u_char  type;
133         u_char  bus_id;
134         char    bus_type[6];
135 }      *bus_entry_ptr;
136
137 typedef struct IOAPICENTRY {
138         u_char  type;
139         u_char  apic_id;
140         u_char  apic_version;
141         u_char  apic_flags;
142         void   *apic_address;
143 }      *io_apic_entry_ptr;
144
145 typedef struct INTENTRY {
146         u_char  type;
147         u_char  int_type;
148         u_short int_flags;
149         u_char  src_bus_id;
150         u_char  src_bus_irq;
151         u_char  dst_apic_id;
152         u_char  dst_apic_int;
153 }      *int_entry_ptr;
154
155 /* descriptions of MP basetable entries */
156 typedef struct BASETABLE_ENTRY {
157         u_char  type;
158         u_char  length;
159         char    name[16];
160 }       basetable_entry;
161
162 struct mptable_pos {
163         mpfps_t         mp_fps;
164         mpcth_t         mp_cth;
165         vm_size_t       mp_cth_mapsz;
166 };
167
168 #define MPTABLE_POS_USE_DEFAULT(mpt) \
169         ((mpt)->mp_fps->mpfb1 != 0 || (mpt)->mp_cth == NULL)
170
171 struct mptable_bus {
172         int             mb_id;
173         int             mb_type;        /* MPTABLE_BUS_ */
174         TAILQ_ENTRY(mptable_bus) mb_link;
175 };
176
177 #define MPTABLE_BUS_ISA         0
178 #define MPTABLE_BUS_PCI         1
179
180 struct mptable_bus_info {
181         TAILQ_HEAD(, mptable_bus) mbi_list;
182 };
183
184 struct mptable_pci_int {
185         int             mpci_bus;
186         int             mpci_dev;
187         int             mpci_pin;
188
189         int             mpci_ioapic_idx;
190         int             mpci_ioapic_pin;
191         TAILQ_ENTRY(mptable_pci_int) mpci_link;
192 };
193
194 struct mptable_ioapic {
195         int             mio_idx;
196         int             mio_apic_id;
197         uint32_t        mio_addr;
198         int             mio_gsi_base;
199         int             mio_npin;
200         TAILQ_ENTRY(mptable_ioapic) mio_link;
201 };
202
203 typedef int     (*mptable_iter_func)(void *, const void *, int);
204
205 static int      mptable_iterate_entries(const mpcth_t,
206                     mptable_iter_func, void *);
207 static int      mptable_search(void);
208 static int      mptable_search_sig(u_int32_t target, int count);
209 static int      mptable_hyperthread_fixup(cpumask_t, int);
210 static int      mptable_map(struct mptable_pos *);
211 static void     mptable_unmap(struct mptable_pos *);
212 static void     mptable_bus_info_alloc(const mpcth_t,
213                     struct mptable_bus_info *);
214 static void     mptable_bus_info_free(struct mptable_bus_info *);
215
216 static int      mptable_lapic_probe(struct lapic_enumerator *);
217 static void     mptable_lapic_enumerate(struct lapic_enumerator *);
218 static void     mptable_lapic_default(void);
219
220 static int      mptable_ioapic_probe(struct ioapic_enumerator *);
221 static void     mptable_ioapic_enumerate(struct ioapic_enumerator *);
222
223 static basetable_entry basetable_entry_types[] =
224 {
225         {0, 20, "Processor"},
226         {1, 8, "Bus"},
227         {2, 8, "I/O APIC"},
228         {3, 8, "I/O INT"},
229         {4, 8, "Local INT"}
230 };
231
232 static vm_paddr_t       mptable_fps_phyaddr;
233 static int              mptable_use_default;
234 static TAILQ_HEAD(mptable_pci_int_list, mptable_pci_int) mptable_pci_int_list =
235         TAILQ_HEAD_INITIALIZER(mptable_pci_int_list);
236 static TAILQ_HEAD(mptable_ioapic_list, mptable_ioapic) mptable_ioapic_list =
237         TAILQ_HEAD_INITIALIZER(mptable_ioapic_list);
238
239 static void
240 mptable_probe(void)
241 {
242         struct mptable_pos mpt;
243         int error;
244
245         KKASSERT(mptable_fps_phyaddr == 0);
246
247         mptable_fps_phyaddr = mptable_search();
248         if (mptable_fps_phyaddr == 0)
249                 return;
250
251         error = mptable_map(&mpt);
252         if (error) {
253                 mptable_fps_phyaddr = 0;
254                 return;
255         }
256
257         if (MPTABLE_POS_USE_DEFAULT(&mpt)) {
258                 kprintf("MPTABLE: use default configuration\n");
259                 mptable_use_default = 1;
260         }
261         if (mpt.mp_fps->mpfb2 & 0x80)
262                 imcr_present = 1;
263
264         mptable_unmap(&mpt);
265 }
266 SYSINIT(mptable_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, mptable_probe, 0);
267
268 /*
269  * Look for an Intel MP spec table (ie, SMP capable hardware).
270  */
271 static int
272 mptable_search(void)
273 {
274         int     x;
275         u_int32_t target;
276  
277         /* see if EBDA exists */
278         if (ebda_addr != 0) {
279                 /* search first 1K of EBDA */
280                 target = (u_int32_t)ebda_addr;
281                 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
282                         return x;
283         } else {
284                 /* last 1K of base memory, effective 'top of base' passed in */
285                 target = (u_int32_t)(base_memory - 0x400);
286                 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
287                         return x;
288         }
289
290         /* search the BIOS */
291         target = (u_int32_t)BIOS_BASE;
292         if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
293                 return x;
294
295         /* search the extended BIOS */
296         target = (u_int32_t)BIOS_BASE2;
297         if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
298                 return x;
299
300         /* nothing found */
301         return 0;
302 }
303
304 static int
305 mptable_iterate_entries(const mpcth_t cth, mptable_iter_func func, void *arg)
306 {
307         int count, total_size;
308         const void *position;
309
310         KKASSERT(cth->base_table_length >= sizeof(struct MPCTH));
311         total_size = cth->base_table_length - sizeof(struct MPCTH);
312         position = (const uint8_t *)cth + sizeof(struct MPCTH);
313         count = cth->entry_count;
314
315         while (count--) {
316                 int type, error;
317
318                 KKASSERT(total_size >= 0);
319                 if (total_size == 0) {
320                         kprintf("invalid base MP table, "
321                                 "entry count and length mismatch\n");
322                         return EINVAL;
323                 }
324
325                 type = *(const uint8_t *)position;
326                 switch (type) {
327                 case 0: /* processor_entry */
328                 case 1: /* bus_entry */
329                 case 2: /* io_apic_entry */
330                 case 3: /* int_entry */
331                 case 4: /* int_entry */
332                         break;
333                 default:
334                         kprintf("unknown base MP table entry type %d\n", type);
335                         return EINVAL;
336                 }
337
338                 if (total_size < basetable_entry_types[type].length) {
339                         kprintf("invalid base MP table length, "
340                                 "does not contain all entries\n");
341                         return EINVAL;
342                 }
343                 total_size -= basetable_entry_types[type].length;
344
345                 error = func(arg, position, type);
346                 if (error)
347                         return error;
348
349                 position = (const uint8_t *)position +
350                     basetable_entry_types[type].length;
351         }
352         return 0;
353 }
354
355 /*
356  * look for the MP spec signature
357  */
358
359 /* string defined by the Intel MP Spec as identifying the MP table */
360 #define MP_SIG          0x5f504d5f      /* _MP_ */
361 #define NEXT(X)         ((X) += 4)
362 static int
363 mptable_search_sig(u_int32_t target, int count)
364 {
365         vm_size_t map_size;
366         u_int32_t *addr;
367         int x, ret;
368
369         KKASSERT(target != 0);
370
371         map_size = count * sizeof(u_int32_t);
372         addr = pmap_mapdev((vm_paddr_t)target, map_size);
373
374         ret = 0;
375         for (x = 0; x < count; NEXT(x)) {
376                 if (addr[x] == MP_SIG) {
377                         /* make array index a byte index */
378                         ret = target + (x * sizeof(u_int32_t));
379                         break;
380                 }
381         }
382
383         pmap_unmapdev((vm_offset_t)addr, map_size);
384         return ret;
385 }
386
387 static int processor_entry      (const struct PROCENTRY *entry, int cpu);
388
389 /*
390  * Check if we should perform a hyperthreading "fix-up" to
391  * enumerate any logical CPU's that aren't already listed
392  * in the table.
393  *
394  * XXX: We assume that all of the physical CPUs in the
395  * system have the same number of logical CPUs.
396  *
397  * XXX: We assume that APIC ID's are allocated such that
398  * the APIC ID's for a physical processor are aligned
399  * with the number of logical CPU's in the processor.
400  */
401 static int
402 mptable_hyperthread_fixup(cpumask_t id_mask, int cpu_count)
403 {
404         int i, id, lcpus_max, logical_cpus;
405
406         if ((cpu_feature & CPUID_HTT) == 0)
407                 return 0;
408
409         lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
410         if (lcpus_max <= 1)
411                 return 0;
412
413         if (cpu_vendor_id == CPU_VENDOR_INTEL) {
414                 /*
415                  * INSTRUCTION SET REFERENCE, A-M (#253666)
416                  * Page 3-181, Table 3-20
417                  * "The nearest power-of-2 integer that is not smaller
418                  *  than EBX[23:16] is the number of unique initial APIC
419                  *  IDs reserved for addressing different logical
420                  *  processors in a physical package."
421                  */
422                 for (i = 0; ; ++i) {
423                         if ((1 << i) >= lcpus_max) {
424                                 lcpus_max = 1 << i;
425                                 break;
426                         }
427                 }
428         }
429
430         KKASSERT(cpu_count != 0);
431         if (cpu_count == lcpus_max) {
432                 /* We have nothing to fix */
433                 return 0;
434         } else if (cpu_count == 1) {
435                 /* XXX this may be incorrect */
436                 logical_cpus = lcpus_max;
437         } else {
438                 int cur, prev, dist;
439
440                 /*
441                  * Calculate the distances between two nearest
442                  * APIC IDs.  If all such distances are same,
443                  * then it is the number of missing cpus that
444                  * we are going to fill later.
445                  */
446                 dist = cur = prev = -1;
447                 for (id = 0; id < MAXCPU; ++id) {
448                         if ((id_mask & CPUMASK(id)) == 0)
449                                 continue;
450
451                         cur = id;
452                         if (prev >= 0) {
453                                 int new_dist = cur - prev;
454
455                                 if (dist < 0)
456                                         dist = new_dist;
457
458                                 /*
459                                  * Make sure that all distances
460                                  * between two nearest APIC IDs
461                                  * are same.
462                                  */
463                                 if (dist != new_dist)
464                                         return 0;
465                         }
466                         prev = cur;
467                 }
468                 if (dist == 1)
469                         return 0;
470
471                 /* Must be power of 2 */
472                 if (dist & (dist - 1))
473                         return 0;
474
475                 /* Can't exceed CPU package capacity */
476                 if (dist > lcpus_max)
477                         logical_cpus = lcpus_max;
478                 else
479                         logical_cpus = dist;
480         }
481
482         /*
483          * For each APIC ID of a CPU that is set in the mask,
484          * scan the other candidate APIC ID's for this
485          * physical processor.  If any of those ID's are
486          * already in the table, then kill the fixup.
487          */
488         for (id = 0; id < MAXCPU; id++) {
489                 if ((id_mask & CPUMASK(id)) == 0)
490                         continue;
491                 /* First, make sure we are on a logical_cpus boundary. */
492                 if (id % logical_cpus != 0)
493                         return 0;
494                 for (i = id + 1; i < id + logical_cpus; i++)
495                         if ((id_mask & CPUMASK(i)) != 0)
496                                 return 0;
497         }
498         return logical_cpus;
499 }
500
501 static int
502 mptable_map(struct mptable_pos *mpt)
503 {
504         mpfps_t fps = NULL;
505         mpcth_t cth = NULL;
506         vm_size_t cth_mapsz = 0;
507
508         KKASSERT(mptable_fps_phyaddr != 0);
509
510         bzero(mpt, sizeof(*mpt));
511
512         fps = pmap_mapdev(mptable_fps_phyaddr, sizeof(*fps));
513         if (fps->pap != 0) {
514                 /*
515                  * Map configuration table header to get
516                  * the base table size
517                  */
518                 cth = pmap_mapdev(fps->pap, sizeof(*cth));
519                 cth_mapsz = cth->base_table_length;
520                 pmap_unmapdev((vm_offset_t)cth, sizeof(*cth));
521
522                 if (cth_mapsz < sizeof(*cth)) {
523                         kprintf("invalid base MP table length %d\n",
524                                 (int)cth_mapsz);
525                         pmap_unmapdev((vm_offset_t)fps, sizeof(*fps));
526                         return EINVAL;
527                 }
528
529                 /*
530                  * Map the base table
531                  */
532                 cth = pmap_mapdev(fps->pap, cth_mapsz);
533         }
534
535         mpt->mp_fps = fps;
536         mpt->mp_cth = cth;
537         mpt->mp_cth_mapsz = cth_mapsz;
538
539         return 0;
540 }
541
542 static void
543 mptable_unmap(struct mptable_pos *mpt)
544 {
545         if (mpt->mp_cth != NULL) {
546                 pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz);
547                 mpt->mp_cth = NULL;
548                 mpt->mp_cth_mapsz = 0;
549         }
550         if (mpt->mp_fps != NULL) {
551                 pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps));
552                 mpt->mp_fps = NULL;
553         }
554 }
555
556 static int
557 processor_entry(const struct PROCENTRY *entry, int cpu)
558 {
559         KKASSERT(cpu > 0);
560
561         /* check for usability */
562         if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
563                 return 0;
564
565         /* check for BSP flag */
566         if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
567                 lapic_set_cpuid(0, entry->apic_id);
568                 return 0;       /* its already been counted */
569         }
570
571         /* add another AP to list, if less than max number of CPUs */
572         else if (cpu < MAXCPU) {
573                 lapic_set_cpuid(cpu, entry->apic_id);
574                 return 1;
575         }
576
577         return 0;
578 }
579
580 static int
581 mptable_bus_info_callback(void *xarg, const void *pos, int type)
582 {
583         struct mptable_bus_info *bus_info = xarg;
584         const struct BUSENTRY *ent;
585         struct mptable_bus *bus;
586
587         if (type != 1)
588                 return 0;
589
590         ent = pos;
591         TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
592                 if (bus->mb_id == ent->bus_id) {
593                         kprintf("mptable_bus_info_alloc: duplicated bus id "
594                                 "(%d)\n", bus->mb_id);
595                         return EINVAL;
596                 }
597         }
598
599         bus = NULL;
600         if (strncmp(ent->bus_type, "PCI", 3) == 0) {
601                 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
602                 bus->mb_type = MPTABLE_BUS_PCI;
603         } else if (strncmp(ent->bus_type, "ISA", 3) == 0) {
604                 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
605                 bus->mb_type = MPTABLE_BUS_ISA;
606         }
607
608         if (bus != NULL) {
609                 bus->mb_id = ent->bus_id;
610                 TAILQ_INSERT_TAIL(&bus_info->mbi_list, bus, mb_link);
611         }
612         return 0;
613 }
614
615 static void
616 mptable_bus_info_alloc(const mpcth_t cth, struct mptable_bus_info *bus_info)
617 {
618         int error;
619
620         bzero(bus_info, sizeof(*bus_info));
621         TAILQ_INIT(&bus_info->mbi_list);
622
623         error = mptable_iterate_entries(cth, mptable_bus_info_callback, bus_info);
624         if (error)
625                 mptable_bus_info_free(bus_info);
626 }
627
628 static void
629 mptable_bus_info_free(struct mptable_bus_info *bus_info)
630 {
631         struct mptable_bus *bus;
632
633         while ((bus = TAILQ_FIRST(&bus_info->mbi_list)) != NULL) {
634                 TAILQ_REMOVE(&bus_info->mbi_list, bus, mb_link);
635                 kfree(bus, M_TEMP);
636         }
637 }
638
639 struct mptable_lapic_cbarg1 {
640         int     cpu_count;
641         int     ht_fixup;
642         u_int   ht_apicid_mask;
643 };
644
645 static int
646 mptable_lapic_pass1_callback(void *xarg, const void *pos, int type)
647 {
648         const struct PROCENTRY *ent;
649         struct mptable_lapic_cbarg1 *arg = xarg;
650
651         if (type != 0)
652                 return 0;
653         ent = pos;
654
655         if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
656                 return 0;
657
658         arg->cpu_count++;
659         if (ent->apic_id < 32) {
660                 arg->ht_apicid_mask |= 1 << ent->apic_id;
661         } else if (arg->ht_fixup) {
662                 kprintf("MPTABLE: lapic id > 32, disable HTT fixup\n");
663                 arg->ht_fixup = 0;
664         }
665         return 0;
666 }
667
668 struct mptable_lapic_cbarg2 {
669         int     cpu;
670         int     logical_cpus;
671         int     found_bsp;
672 };
673
674 static int
675 mptable_lapic_pass2_callback(void *xarg, const void *pos, int type)
676 {
677         const struct PROCENTRY *ent;
678         struct mptable_lapic_cbarg2 *arg = xarg;
679
680         if (type != 0)
681                 return 0;
682         ent = pos;
683
684         if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
685                 KKASSERT(!arg->found_bsp);
686                 arg->found_bsp = 1;
687         }
688
689         if (processor_entry(ent, arg->cpu))
690                 arg->cpu++;
691
692         if (arg->logical_cpus) {
693                 struct PROCENTRY proc;
694                 int i;
695
696                 /*
697                  * Create fake mptable processor entries
698                  * and feed them to processor_entry() to
699                  * enumerate the logical CPUs.
700                  */
701                 bzero(&proc, sizeof(proc));
702                 proc.type = 0;
703                 proc.cpu_flags = PROCENTRY_FLAG_EN;
704                 proc.apic_id = ent->apic_id;
705
706                 for (i = 1; i < arg->logical_cpus; i++) {
707                         proc.apic_id++;
708                         processor_entry(&proc, arg->cpu);
709                         arg->cpu++;
710                 }
711         }
712         return 0;
713 }
714
715 static void
716 mptable_lapic_default(void)
717 {
718         int ap_apicid, bsp_apicid;
719
720         naps = 1; /* exclude BSP */
721
722         /* Map local apic before the id field is accessed */
723         lapic_map(DEFAULT_APIC_BASE);
724
725         bsp_apicid = APIC_ID(lapic->id);
726         ap_apicid = (bsp_apicid == 0) ? 1 : 0;
727
728         /* BSP */
729         lapic_set_cpuid(0, bsp_apicid);
730         /* one and only AP */
731         lapic_set_cpuid(1, ap_apicid);
732 }
733
734 /*
735  * Configure:
736  *     naps
737  *     APIC ID <-> CPU ID mappings
738  */
739 static void
740 mptable_lapic_enumerate(struct lapic_enumerator *e)
741 {
742         struct mptable_pos mpt;
743         struct mptable_lapic_cbarg1 arg1;
744         struct mptable_lapic_cbarg2 arg2;
745         mpcth_t cth;
746         int error, logical_cpus = 0;
747         vm_paddr_t lapic_addr;
748
749         if (mptable_use_default) {
750                 mptable_lapic_default();
751                 return;
752         }
753
754         error = mptable_map(&mpt);
755         if (error)
756                 panic("mptable_lapic_enumerate mptable_map failed\n");
757         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
758
759         cth = mpt.mp_cth;
760
761         /* Save local apic address */
762         lapic_addr = (vm_paddr_t)(uintptr_t)cth->apic_address;
763         KKASSERT(lapic_addr != 0);
764
765         /*
766          * Find out how many CPUs do we have
767          */
768         bzero(&arg1, sizeof(arg1));
769         arg1.ht_fixup = 1; /* Apply ht fixup by default */
770
771         error = mptable_iterate_entries(cth,
772                     mptable_lapic_pass1_callback, &arg1);
773         if (error)
774                 panic("mptable_iterate_entries(lapic_pass1) failed\n");
775         KKASSERT(arg1.cpu_count != 0);
776
777         /* See if we need to fixup HT logical CPUs. */
778         if (arg1.ht_fixup) {
779                 logical_cpus = mptable_hyperthread_fixup(arg1.ht_apicid_mask,
780                                                          arg1.cpu_count);
781                 if (logical_cpus != 0)
782                         arg1.cpu_count *= logical_cpus;
783         }
784         naps = arg1.cpu_count - 1;      /* subtract the BSP */
785
786         /*
787          * Link logical CPU id to local apic id
788          */
789         bzero(&arg2, sizeof(arg2));
790         arg2.cpu = 1;
791         arg2.logical_cpus = logical_cpus;
792
793         error = mptable_iterate_entries(cth,
794                     mptable_lapic_pass2_callback, &arg2);
795         if (error)
796                 panic("mptable_iterate_entries(lapic_pass2) failed\n");
797         KKASSERT(arg2.found_bsp);
798
799         /* Map local apic */
800         lapic_map(lapic_addr);
801
802         mptable_unmap(&mpt);
803 }
804
805 struct mptable_lapic_probe_cbarg {
806         int     cpu_count;
807         int     found_bsp;
808 };
809
810 static int
811 mptable_lapic_probe_callback(void *xarg, const void *pos, int type)
812 {
813         const struct PROCENTRY *ent;
814         struct mptable_lapic_probe_cbarg *arg = xarg;
815
816         if (type != 0)
817                 return 0;
818         ent = pos;
819
820         if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
821                 return 0;
822         arg->cpu_count++;
823
824         if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
825                 if (arg->found_bsp) {
826                         kprintf("more than one BSP in base MP table\n");
827                         return EINVAL;
828                 }
829                 arg->found_bsp = 1;
830         }
831         return 0;
832 }
833
834 static int
835 mptable_lapic_probe(struct lapic_enumerator *e)
836 {
837         struct mptable_pos mpt;
838         struct mptable_lapic_probe_cbarg arg;
839         mpcth_t cth;
840         int error;
841
842         if (mptable_fps_phyaddr == 0)
843                 return ENXIO;
844
845         if (mptable_use_default)
846                 return 0;
847
848         error = mptable_map(&mpt);
849         if (error)
850                 return error;
851         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
852
853         error = EINVAL;
854         cth = mpt.mp_cth;
855
856         if (cth->apic_address == NULL)
857                 goto done;
858
859         bzero(&arg, sizeof(arg));
860         error = mptable_iterate_entries(cth,
861                     mptable_lapic_probe_callback, &arg);
862         if (!error) {
863                 if (arg.cpu_count == 0) {
864                         kprintf("MP table contains no processor entries\n");
865                         error = EINVAL;
866                 } else if (!arg.found_bsp) {
867                         kprintf("MP table does not contains BSP entry\n");
868                         error = EINVAL;
869                 }
870         }
871 done:
872         mptable_unmap(&mpt);
873         return error;
874 }
875
876 static struct lapic_enumerator  mptable_lapic_enumerator = {
877         .lapic_prio = LAPIC_ENUM_PRIO_MPTABLE,
878         .lapic_probe = mptable_lapic_probe,
879         .lapic_enumerate = mptable_lapic_enumerate
880 };
881
882 static void
883 mptable_lapic_enum_register(void)
884 {
885         lapic_enumerator_register(&mptable_lapic_enumerator);
886 }
887 SYSINIT(mptable_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
888         mptable_lapic_enum_register, 0);
889
890 static int
891 mptable_ioapic_list_callback(void *xarg, const void *pos, int type)
892 {
893         const struct IOAPICENTRY *ent;
894         struct mptable_ioapic *nioapic, *ioapic;
895
896         if (type != 2)
897                 return 0;
898         ent = pos;
899
900         if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0)
901                 return 0;
902
903         if (ent->apic_address == NULL) {
904                 kprintf("mptable_ioapic_create_list: zero IOAPIC addr\n");
905                 return EINVAL;
906         }
907
908         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
909                 if (ioapic->mio_apic_id == ent->apic_id) {
910                         kprintf("mptable_ioapic_create_list: duplicated "
911                                 "apic id %d\n", ioapic->mio_apic_id);
912                         return EINVAL;
913                 }
914                 if (ioapic->mio_addr == (uint32_t)ent->apic_address) {
915                         kprintf("mptable_ioapic_create_list: overlapped "
916                                 "IOAPIC addr 0x%08x", ioapic->mio_addr);
917                         return EINVAL;
918                 }
919         }
920
921         nioapic = kmalloc(sizeof(*nioapic), M_DEVBUF, M_WAITOK | M_ZERO);
922         nioapic->mio_apic_id = ent->apic_id;
923         nioapic->mio_addr = (uint32_t)ent->apic_address;
924
925         /*
926          * Create IOAPIC list in ascending order of APIC ID
927          */
928         TAILQ_FOREACH_REVERSE(ioapic, &mptable_ioapic_list,
929             mptable_ioapic_list, mio_link) {
930                 if (nioapic->mio_apic_id > ioapic->mio_apic_id) {
931                         TAILQ_INSERT_AFTER(&mptable_ioapic_list,
932                             ioapic, nioapic, mio_link);
933                         break;
934                 }
935         }
936         if (ioapic == NULL)
937                 TAILQ_INSERT_HEAD(&mptable_ioapic_list, nioapic, mio_link);
938
939         return 0;
940 }
941
942 static void
943 mptable_ioapic_create_list(void)
944 {
945         struct mptable_ioapic *ioapic;
946         struct mptable_pos mpt;
947         int idx, error;
948
949         if (mptable_fps_phyaddr == 0)
950                 return;
951
952         if (mptable_use_default) {
953                 ioapic = kmalloc(sizeof(*ioapic), M_DEVBUF, M_WAITOK | M_ZERO);
954                 ioapic->mio_idx = 0;
955                 ioapic->mio_apic_id = 0;        /* NOTE: any value is ok here */
956                 ioapic->mio_addr = 0xfec00000;  /* XXX magic number */
957
958                 TAILQ_INSERT_HEAD(&mptable_ioapic_list, ioapic, mio_link);
959                 return;
960         }
961
962         error = mptable_map(&mpt);
963         if (error)
964                 panic("mptable_ioapic_create_list: mptable_map failed\n");
965         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
966
967         error = mptable_iterate_entries(mpt.mp_cth,
968                     mptable_ioapic_list_callback, NULL);
969         if (error) {
970                 while ((ioapic = TAILQ_FIRST(&mptable_ioapic_list)) != NULL) {
971                         TAILQ_REMOVE(&mptable_ioapic_list, ioapic, mio_link);
972                         kfree(ioapic, M_DEVBUF);
973                 }
974                 goto done;
975         }
976
977         /*
978          * Assign index number for each IOAPIC
979          */
980         idx = 0;
981         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
982                 ioapic->mio_idx = idx;
983                 ++idx;
984         }
985 done:
986         mptable_unmap(&mpt);
987 }
988 SYSINIT(mptable_ioapic_list, SI_BOOT2_PRESMP, SI_ORDER_SECOND,
989         mptable_ioapic_create_list, 0);
990
991 static int
992 mptable_pci_int_callback(void *xarg, const void *pos, int type)
993 {
994         const struct mptable_bus_info *bus_info = xarg;
995         const struct mptable_ioapic *ioapic;
996         const struct mptable_bus *bus;
997         struct mptable_pci_int *pci_int;
998         const struct INTENTRY *ent;
999         int pci_pin, pci_dev;
1000
1001         if (type != 3)
1002                 return 0;
1003         ent = pos;
1004
1005         if (ent->int_type != 0)
1006                 return 0;
1007
1008         TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
1009                 if (bus->mb_type == MPTABLE_BUS_PCI &&
1010                     bus->mb_id == ent->src_bus_id)
1011                         break;
1012         }
1013         if (bus == NULL)
1014                 return 0;
1015
1016         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1017                 if (ioapic->mio_apic_id == ent->dst_apic_id)
1018                         break;
1019         }
1020         if (ioapic == NULL) {
1021                 kprintf("MPTABLE: warning PCI int dst apic id %d "
1022                         "does not exist\n", ent->dst_apic_id);
1023                 return 0;
1024         }
1025
1026         pci_pin = ent->src_bus_irq & 0x3;
1027         pci_dev = (ent->src_bus_irq >> 2) & 0x1f;
1028
1029         TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1030                 if (pci_int->mpci_bus == ent->src_bus_id &&
1031                     pci_int->mpci_dev == pci_dev &&
1032                     pci_int->mpci_pin == pci_pin) {
1033                         if (pci_int->mpci_ioapic_idx == ioapic->mio_idx &&
1034                             pci_int->mpci_ioapic_pin == ent->dst_apic_int) {
1035                                 kprintf("MPTABLE: warning duplicated "
1036                                         "PCI int entry for "
1037                                         "bus %d, dev %d, pin %d\n",
1038                                         pci_int->mpci_bus,
1039                                         pci_int->mpci_dev,
1040                                         pci_int->mpci_pin);
1041                                 return 0;
1042                         } else {
1043                                 kprintf("mptable_pci_int_register: "
1044                                         "conflict PCI int entry for "
1045                                         "bus %d, dev %d, pin %d, "
1046                                         "IOAPIC %d.%d -> %d.%d\n",
1047                                         pci_int->mpci_bus,
1048                                         pci_int->mpci_dev,
1049                                         pci_int->mpci_pin,
1050                                         pci_int->mpci_ioapic_idx,
1051                                         pci_int->mpci_ioapic_pin,
1052                                         ioapic->mio_idx,
1053                                         ent->dst_apic_int);
1054                                 return EINVAL;
1055                         }
1056                 }
1057         }
1058
1059         pci_int = kmalloc(sizeof(*pci_int), M_DEVBUF, M_WAITOK | M_ZERO);
1060
1061         pci_int->mpci_bus = ent->src_bus_id;
1062         pci_int->mpci_dev = pci_dev;
1063         pci_int->mpci_pin = pci_pin;
1064         pci_int->mpci_ioapic_idx = ioapic->mio_idx;
1065         pci_int->mpci_ioapic_pin = ent->dst_apic_int;
1066
1067         TAILQ_INSERT_TAIL(&mptable_pci_int_list, pci_int, mpci_link);
1068
1069         return 0;
1070 }
1071
1072 static void
1073 mptable_pci_int_register(void)
1074 {
1075         struct mptable_bus_info bus_info;
1076         const struct mptable_bus *bus;
1077         struct mptable_pci_int *pci_int;
1078         struct mptable_pos mpt;
1079         int error, force_pci0, npcibus;
1080         mpcth_t cth;
1081
1082         if (mptable_fps_phyaddr == 0)
1083                 return;
1084
1085         if (mptable_use_default)
1086                 return;
1087
1088         if (TAILQ_EMPTY(&mptable_ioapic_list))
1089                 return;
1090
1091         error = mptable_map(&mpt);
1092         if (error)
1093                 panic("mptable_pci_int_register: mptable_map failed\n");
1094         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1095
1096         cth = mpt.mp_cth;
1097
1098         mptable_bus_info_alloc(cth, &bus_info);
1099         if (TAILQ_EMPTY(&bus_info.mbi_list))
1100                 goto done;
1101
1102         force_pci0 = 0;
1103         npcibus = 0;
1104         TAILQ_FOREACH(bus, &bus_info.mbi_list, mb_link) {
1105                 if (bus->mb_type == MPTABLE_BUS_PCI)
1106                         ++npcibus;
1107         }
1108         if (npcibus == 0) {
1109                 mptable_bus_info_free(&bus_info);
1110                 goto done;
1111         } else if (npcibus == 1) {
1112                 force_pci0 = 1;
1113         }
1114
1115         error = mptable_iterate_entries(cth,
1116                     mptable_pci_int_callback, &bus_info);
1117
1118         mptable_bus_info_free(&bus_info);
1119
1120         if (error) {
1121                 while ((pci_int = TAILQ_FIRST(&mptable_pci_int_list)) != NULL) {
1122                         TAILQ_REMOVE(&mptable_pci_int_list, pci_int, mpci_link);
1123                         kfree(pci_int, M_DEVBUF);
1124                 }
1125                 goto done;
1126         }
1127
1128         if (force_pci0) {
1129                 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link)
1130                         pci_int->mpci_bus = 0;
1131         }
1132 done:
1133         mptable_unmap(&mpt);
1134 }
1135 SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1136         mptable_pci_int_register, 0);
1137
1138 struct mptable_ioapic_probe_cbarg {
1139         const struct mptable_bus_info *bus_info;
1140 };
1141
1142 static int
1143 mptable_ioapic_probe_callback(void *xarg, const void *pos, int type)
1144 {
1145         struct mptable_ioapic_probe_cbarg *arg = xarg;
1146         const struct mptable_ioapic *ioapic;
1147         const struct mptable_bus *bus;
1148         const struct INTENTRY *ent;
1149
1150         if (type != 3)
1151                 return 0;
1152         ent = pos;
1153
1154         if (ent->int_type != 0)
1155                 return 0;
1156
1157         TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1158                 if (bus->mb_type == MPTABLE_BUS_ISA &&
1159                     bus->mb_id == ent->src_bus_id)
1160                         break;
1161         }
1162         if (bus == NULL)
1163                 return 0;
1164
1165         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1166                 if (ioapic->mio_apic_id == ent->dst_apic_id)
1167                         break;
1168         }
1169         if (ioapic == NULL) {
1170                 kprintf("MPTABLE: warning ISA int dst apic id %d "
1171                         "does not exist\n", ent->dst_apic_id);
1172                 return 0;
1173         }
1174
1175         /* XXX magic number */
1176         if (ent->src_bus_irq >= ISA_IRQ_CNT) {
1177                 kprintf("mptable_ioapic_probe: invalid ISA irq (%d)\n",
1178                         ent->src_bus_irq);
1179                 return EINVAL;
1180         }
1181         return 0;
1182 }
1183
1184 static int
1185 mptable_ioapic_probe(struct ioapic_enumerator *e)
1186 {
1187         struct mptable_ioapic_probe_cbarg arg;
1188         struct mptable_bus_info bus_info;
1189         struct mptable_pos mpt;
1190         mpcth_t cth;
1191         int error;
1192
1193         if (mptable_fps_phyaddr == 0)
1194                 return ENXIO;
1195
1196         if (mptable_use_default)
1197                 return 0;
1198
1199         if (TAILQ_EMPTY(&mptable_ioapic_list))
1200                 return ENXIO;
1201
1202         error = mptable_map(&mpt);
1203         if (error)
1204                 panic("mptable_ioapic_probe: mptable_map failed\n");
1205         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1206
1207         cth = mpt.mp_cth;
1208
1209         mptable_bus_info_alloc(cth, &bus_info);
1210
1211         bzero(&arg, sizeof(arg));
1212         arg.bus_info = &bus_info;
1213
1214         error = mptable_iterate_entries(cth,
1215                     mptable_ioapic_probe_callback, &arg);
1216
1217         mptable_bus_info_free(&bus_info);
1218         mptable_unmap(&mpt);
1219
1220         return error;
1221 }
1222
1223 struct mptable_ioapic_int_cbarg {
1224         const struct mptable_bus_info *bus_info;
1225         int     ioapic_nint;
1226 };
1227
1228 static int
1229 mptable_ioapic_int_callback(void *xarg, const void *pos, int type)
1230 {
1231         struct mptable_ioapic_int_cbarg *arg = xarg;
1232         const struct mptable_ioapic *ioapic;
1233         const struct mptable_bus *bus;
1234         const struct INTENTRY *ent;
1235         int gsi;
1236
1237         if (type != 3)
1238                 return 0;
1239
1240         arg->ioapic_nint++;
1241
1242         ent = pos;
1243         if (ent->int_type != 0)
1244                 return 0;
1245
1246         TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1247                 if (bus->mb_type == MPTABLE_BUS_ISA &&
1248                     bus->mb_id == ent->src_bus_id)
1249                         break;
1250         }
1251         if (bus == NULL)
1252                 return 0;
1253
1254         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1255                 if (ioapic->mio_apic_id == ent->dst_apic_id)
1256                         break;
1257         }
1258         if (ioapic == NULL) {
1259                 kprintf("MPTABLE: warning ISA int dst apic id %d "
1260                         "does not exist\n", ent->dst_apic_id);
1261                 return 0;
1262         }
1263
1264         if (ent->dst_apic_int >= ioapic->mio_npin) {
1265                 panic("mptable_ioapic_enumerate: invalid I/O APIC "
1266                       "pin %d, should be < %d",
1267                       ent->dst_apic_int, ioapic->mio_npin);
1268         }
1269         gsi = ioapic->mio_gsi_base + ent->dst_apic_int;
1270
1271         if (ent->src_bus_irq != gsi) {
1272                 if (bootverbose) {
1273                         kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n",
1274                                 ent->src_bus_irq, gsi);
1275                 }
1276                 ioapic_intsrc(ent->src_bus_irq, gsi,
1277                     INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1278         }
1279         return 0;
1280 }
1281
1282 static void
1283 mptable_ioapic_enumerate(struct ioapic_enumerator *e)
1284 {
1285         struct mptable_bus_info bus_info;
1286         struct mptable_ioapic *ioapic;
1287         struct mptable_pos mpt;
1288         mpcth_t cth;
1289         int error;
1290
1291         KKASSERT(mptable_fps_phyaddr != 0);
1292         KKASSERT(!TAILQ_EMPTY(&mptable_ioapic_list));
1293
1294         TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1295                 const struct mptable_ioapic *prev_ioapic;
1296                 uint32_t ver;
1297                 void *addr;
1298
1299                 addr = ioapic_map(ioapic->mio_addr);
1300
1301                 ver = ioapic_read(addr, IOAPIC_VER);
1302                 ioapic->mio_npin = ((ver & IOART_VER_MAXREDIR)
1303                                     >> MAXREDIRSHIFT) + 1;
1304
1305                 prev_ioapic = TAILQ_PREV(ioapic,
1306                                 mptable_ioapic_list, mio_link);
1307                 if (prev_ioapic == NULL) {
1308                         ioapic->mio_gsi_base = 0;
1309                 } else {
1310                         ioapic->mio_gsi_base =
1311                                 prev_ioapic->mio_gsi_base +
1312                                 prev_ioapic->mio_npin;
1313                 }
1314                 ioapic_add(addr, ioapic->mio_gsi_base,
1315                     ioapic->mio_npin);
1316
1317                 if (bootverbose) {
1318                         kprintf("MPTABLE: IOAPIC addr 0x%08x, "
1319                                 "apic id %d, idx %d, gsi base %d, npin %d\n",
1320                                 ioapic->mio_addr,
1321                                 ioapic->mio_apic_id,
1322                                 ioapic->mio_idx,
1323                                 ioapic->mio_gsi_base,
1324                                 ioapic->mio_npin);
1325                 }
1326         }
1327
1328         if (mptable_use_default) {
1329                 if (bootverbose)
1330                         kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n");
1331                 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1332                 return;
1333         }
1334
1335         error = mptable_map(&mpt);
1336         if (error)
1337                 panic("mptable_ioapic_probe: mptable_map failed\n");
1338         KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1339
1340         cth = mpt.mp_cth;
1341
1342         mptable_bus_info_alloc(cth, &bus_info);
1343
1344         if (TAILQ_EMPTY(&bus_info.mbi_list)) {
1345                 if (bootverbose)
1346                         kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n");
1347                 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1348         } else {
1349                 struct mptable_ioapic_int_cbarg arg;
1350
1351                 bzero(&arg, sizeof(arg));
1352                 arg.bus_info = &bus_info;
1353
1354                 error = mptable_iterate_entries(cth,
1355                             mptable_ioapic_int_callback, &arg);
1356                 if (error)
1357                         panic("mptable_ioapic_int failed\n");
1358
1359                 if (arg.ioapic_nint == 0) {
1360                         if (bootverbose) {
1361                                 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 "
1362                                         "(no int)\n");
1363                         }
1364                         ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE,
1365                             INTR_POLARITY_HIGH);
1366                 }
1367         }
1368
1369         mptable_bus_info_free(&bus_info);
1370
1371         mptable_unmap(&mpt);
1372 }
1373
1374 static struct ioapic_enumerator mptable_ioapic_enumerator = {
1375         .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE,
1376         .ioapic_probe = mptable_ioapic_probe,
1377         .ioapic_enumerate = mptable_ioapic_enumerate
1378 };
1379
1380 static void
1381 mptable_ioapic_enum_register(void)
1382 {
1383         ioapic_enumerator_register(&mptable_ioapic_enumerator);
1384 }
1385 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1386         mptable_ioapic_enum_register, 0);
1387
1388 void
1389 mptable_pci_int_dump(void)
1390 {
1391         const struct mptable_pci_int *pci_int;
1392
1393         if (!bootverbose)
1394                 return;
1395
1396         TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1397                 kprintf("MPTABLE: %d:%d INT%c -> IOAPIC %d.%d\n",
1398                         pci_int->mpci_bus,
1399                         pci_int->mpci_dev,
1400                         pci_int->mpci_pin + 'A',
1401                         pci_int->mpci_ioapic_idx,
1402                         pci_int->mpci_ioapic_pin);
1403         }
1404 }
1405
1406 int
1407 mptable_pci_int_route(int bus, int dev, int pin, int intline)
1408 {
1409         const struct mptable_pci_int *pci_int;
1410         int irq = -1;
1411
1412         KKASSERT(pin >= 1);
1413         --pin;  /* zero based */
1414
1415         TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1416                 if (pci_int->mpci_bus == bus &&
1417                     pci_int->mpci_dev == dev &&
1418                     pci_int->mpci_pin == pin)
1419                         break;
1420         }
1421         if (pci_int != NULL) {
1422                 int gsi;
1423
1424                 gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
1425                         pci_int->mpci_ioapic_pin);
1426                 if (gsi >= 0) {
1427                         irq = ioapic_find_legacy_by_gsi(gsi,
1428                                 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1429                 }
1430         }
1431
1432         if (irq < 0) {
1433                 if (bootverbose) {
1434                         kprintf("MPTABLE: fixed interrupt routing "
1435                                 "for %d:%d INT%c\n", bus, dev, pin + 'A');
1436                 }
1437
1438                 irq = ioapic_find_legacy_by_irq(intline,
1439                         INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1440         }
1441
1442         if (irq >= 0 && bootverbose) {
1443                 kprintf("MPTABLE: %d:%d INT%c routed to irq %d\n",
1444                         bus, dev, pin + 'A', irq);
1445         }
1446         return irq;
1447 }