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