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