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