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