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