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