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