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