2 * Copyright (c) 1996, by Steve Passe
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
25 * $FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.115.2.15 2003/03/14 21:22:35 jhb Exp $
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>
39 #include <sys/mplock2.h>
42 #include <vm/vm_param.h>
44 #include <vm/vm_kern.h>
45 #include <vm/vm_extern.h>
47 #include <vm/vm_map.h>
49 #include <machine/smp.h>
50 #include <machine_base/isa/isa_intr.h>
51 #include <machine_base/apic/apicreg.h>
52 #include <machine_base/apic/apicvar.h>
53 #include <machine/atomic.h>
54 #include <machine/cpufunc.h>
55 #include <machine/cputypes.h>
56 #include <machine_base/apic/lapic.h>
57 #include <machine_base/apic/ioapic.h>
58 #include <machine/psl.h>
59 #include <machine/segments.h>
60 #include <machine/tss.h>
61 #include <machine/specialreg.h>
62 #include <machine/globaldata.h>
63 #include <machine/pmap_inval.h>
64 #include <machine/mptable.h>
66 #include <machine/md_var.h> /* setidt() */
67 #include <machine_base/icu/icu.h> /* IPIs */
68 #include <machine_base/apic/ioapic_abi.h>
69 #include <machine/intr_machdep.h> /* IPIs */
71 extern u_int base_memory;
72 extern u_long ebda_addr;
73 extern int imcr_present;
76 static int force_enable = 0;
77 TUNABLE_INT("hw.lapic_force_enable", &force_enable);
79 #define BIOS_BASE (0xf0000)
80 #define BIOS_BASE2 (0xe0000)
81 #define BIOS_SIZE (0x10000)
82 #define BIOS_COUNT (BIOS_SIZE/4)
84 #define PROCENTRY_FLAG_EN 0x01
85 #define PROCENTRY_FLAG_BP 0x02
86 #define IOAPICENTRY_FLAG_EN 0x01
89 /* MP Floating Pointer Structure */
90 typedef struct MPFPS {
103 /* MP Configuration Table Header */
104 typedef struct MPCTH {
106 u_short base_table_length;
110 u_char product_id[12];
111 u_int32_t oem_table_pointer;
112 u_short oem_table_size;
114 u_int32_t apic_address;
115 u_short extended_table_length;
116 u_char extended_table_checksum;
121 typedef struct PROCENTRY {
126 u_int32_t cpu_signature;
127 u_int32_t feature_flags;
132 typedef struct BUSENTRY {
138 typedef struct IOAPICENTRY {
143 u_int32_t apic_address;
144 } *io_apic_entry_ptr;
146 typedef struct INTENTRY {
156 /* descriptions of MP basetable entries */
157 typedef struct BASETABLE_ENTRY {
166 vm_size_t mp_cth_mapsz;
169 #define MPTABLE_POS_USE_DEFAULT(mpt) \
170 ((mpt)->mp_fps->mpfb1 != 0 || (mpt)->mp_cth == NULL)
174 int mb_type; /* MPTABLE_BUS_ */
175 TAILQ_ENTRY(mptable_bus) mb_link;
178 #define MPTABLE_BUS_ISA 0
179 #define MPTABLE_BUS_PCI 1
181 struct mptable_bus_info {
182 TAILQ_HEAD(, mptable_bus) mbi_list;
185 struct mptable_pci_int {
192 TAILQ_ENTRY(mptable_pci_int) mpci_link;
195 struct mptable_ioapic {
201 TAILQ_ENTRY(mptable_ioapic) mio_link;
204 typedef int (*mptable_iter_func)(void *, const void *, int);
206 static int mptable_iterate_entries(const mpcth_t,
207 mptable_iter_func, void *);
208 static int mptable_search(void);
209 static long mptable_search_sig(u_int32_t target, int count);
210 static int mptable_hyperthread_fixup(cpumask_t, int);
211 static int mptable_map(struct mptable_pos *);
212 static void mptable_unmap(struct mptable_pos *);
213 static void mptable_bus_info_alloc(const mpcth_t,
214 struct mptable_bus_info *);
215 static void mptable_bus_info_free(struct mptable_bus_info *);
217 static int mptable_lapic_probe(struct lapic_enumerator *);
218 static int mptable_lapic_enumerate(struct lapic_enumerator *);
219 static void mptable_lapic_default(void);
221 static int mptable_ioapic_probe(struct ioapic_enumerator *);
222 static void mptable_ioapic_enumerate(struct ioapic_enumerator *);
224 static basetable_entry basetable_entry_types[] =
226 {0, 20, "Processor"},
233 static vm_paddr_t mptable_fps_phyaddr;
234 static int mptable_use_default;
235 static TAILQ_HEAD(mptable_pci_int_list, mptable_pci_int) mptable_pci_int_list =
236 TAILQ_HEAD_INITIALIZER(mptable_pci_int_list);
237 static TAILQ_HEAD(mptable_ioapic_list, mptable_ioapic) mptable_ioapic_list =
238 TAILQ_HEAD_INITIALIZER(mptable_ioapic_list);
243 struct mptable_pos mpt;
246 KKASSERT(mptable_fps_phyaddr == 0);
248 mptable_fps_phyaddr = mptable_search();
249 if (mptable_fps_phyaddr == 0)
252 error = mptable_map(&mpt);
254 mptable_fps_phyaddr = 0;
258 if (MPTABLE_POS_USE_DEFAULT(&mpt)) {
259 kprintf("MPTABLE: use default configuration\n");
260 mptable_use_default = 1;
262 if (mpt.mp_fps->mpfb2 & 0x80)
267 SYSINIT(mptable_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, mptable_probe, 0);
270 * Look for an Intel MP spec table (ie, SMP capable hardware).
278 /* see if EBDA exists */
279 if (ebda_addr != 0) {
280 /* search first 1K of EBDA */
281 target = (u_int32_t)ebda_addr;
282 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
285 /* last 1K of base memory, effective 'top of base' passed in */
286 target = (u_int32_t)(base_memory - 0x400);
287 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
291 /* search the BIOS */
292 target = (u_int32_t)BIOS_BASE;
293 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
296 /* search the extended BIOS */
297 target = (u_int32_t)BIOS_BASE2;
298 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
306 mptable_iterate_entries(const mpcth_t cth, mptable_iter_func func, void *arg)
308 int count, total_size;
309 const void *position;
311 KKASSERT(cth->base_table_length >= sizeof(struct MPCTH));
312 total_size = cth->base_table_length - sizeof(struct MPCTH);
313 position = (const uint8_t *)cth + sizeof(struct MPCTH);
314 count = cth->entry_count;
319 KKASSERT(total_size >= 0);
320 if (total_size == 0) {
321 kprintf("invalid base MP table, "
322 "entry count and length mismatch\n");
326 type = *(const uint8_t *)position;
328 case 0: /* processor_entry */
329 case 1: /* bus_entry */
330 case 2: /* io_apic_entry */
331 case 3: /* int_entry */
332 case 4: /* int_entry */
335 kprintf("unknown base MP table entry type %d\n", type);
339 if (total_size < basetable_entry_types[type].length) {
340 kprintf("invalid base MP table length, "
341 "does not contain all entries\n");
344 total_size -= basetable_entry_types[type].length;
346 error = func(arg, position, type);
350 position = (const uint8_t *)position +
351 basetable_entry_types[type].length;
357 * look for the MP spec signature
360 /* string defined by the Intel MP Spec as identifying the MP table */
361 #define MP_SIG 0x5f504d5f /* _MP_ */
362 #define NEXT(X) ((X) += 4)
364 mptable_search_sig(u_int32_t target, int count)
370 KKASSERT(target != 0);
372 map_size = count * sizeof(u_int32_t);
373 addr = pmap_mapdev((vm_paddr_t)target, map_size);
376 for (x = 0; x < count; NEXT(x)) {
377 if (addr[x] == MP_SIG) {
378 /* make array index a byte index */
379 ret = target + (x * sizeof(u_int32_t));
384 pmap_unmapdev((vm_offset_t)addr, map_size);
388 static int processor_entry (const struct PROCENTRY *entry, int cpu);
391 * Check if we should perform a hyperthreading "fix-up" to
392 * enumerate any logical CPU's that aren't already listed
395 * XXX: We assume that all of the physical CPUs in the
396 * system have the same number of logical CPUs.
398 * XXX: We assume that APIC ID's are allocated such that
399 * the APIC ID's for a physical processor are aligned
400 * with the number of logical CPU's in the processor.
403 mptable_hyperthread_fixup(cpumask_t id_mask, int cpu_count)
405 int i, id, lcpus_max, logical_cpus;
407 if ((cpu_feature & CPUID_HTT) == 0)
410 lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
414 if (cpu_vendor_id == CPU_VENDOR_INTEL) {
416 * INSTRUCTION SET REFERENCE, A-M (#253666)
417 * Page 3-181, Table 3-20
418 * "The nearest power-of-2 integer that is not smaller
419 * than EBX[23:16] is the number of unique initial APIC
420 * IDs reserved for addressing different logical
421 * processors in a physical package."
424 if ((1 << i) >= lcpus_max) {
431 KKASSERT(cpu_count != 0);
432 if (cpu_count == lcpus_max) {
433 /* We have nothing to fix */
435 } else if (cpu_count == 1) {
436 /* XXX this may be incorrect */
437 logical_cpus = lcpus_max;
442 * Calculate the distances between two nearest
443 * APIC IDs. If all such distances are same,
444 * then it is the number of missing cpus that
445 * we are going to fill later.
447 dist = cur = prev = -1;
448 for (id = 0; id < MAXCPU; ++id) {
449 if (CPUMASK_TESTBIT(id_mask, id) == 0)
454 int new_dist = cur - prev;
460 * Make sure that all distances
461 * between two nearest APIC IDs
464 if (dist != new_dist)
472 /* Must be power of 2 */
473 if (dist & (dist - 1))
476 /* Can't exceed CPU package capacity */
477 if (dist > lcpus_max)
478 logical_cpus = lcpus_max;
484 * For each APIC ID of a CPU that is set in the mask,
485 * scan the other candidate APIC ID's for this
486 * physical processor. If any of those ID's are
487 * already in the table, then kill the fixup.
489 for (id = 0; id < MAXCPU; id++) {
490 if (CPUMASK_TESTBIT(id_mask, id) == 0)
492 /* First, make sure we are on a logical_cpus boundary. */
493 if (id % logical_cpus != 0)
495 for (i = id + 1; i < id + logical_cpus; i++)
496 if (CPUMASK_TESTBIT(id_mask, i) != 0)
503 mptable_map(struct mptable_pos *mpt)
507 vm_size_t cth_mapsz = 0;
509 KKASSERT(mptable_fps_phyaddr != 0);
511 bzero(mpt, sizeof(*mpt));
513 fps = pmap_mapdev(mptable_fps_phyaddr, sizeof(*fps));
516 * Map configuration table header to get
517 * the base table size
519 cth = pmap_mapdev(fps->pap, sizeof(*cth));
520 cth_mapsz = cth->base_table_length;
521 pmap_unmapdev((vm_offset_t)cth, sizeof(*cth));
523 if (cth_mapsz < sizeof(*cth)) {
524 kprintf("invalid base MP table length %d\n",
526 pmap_unmapdev((vm_offset_t)fps, sizeof(*fps));
533 cth = pmap_mapdev(fps->pap, cth_mapsz);
538 mpt->mp_cth_mapsz = cth_mapsz;
544 mptable_unmap(struct mptable_pos *mpt)
546 if (mpt->mp_cth != NULL) {
547 pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz);
549 mpt->mp_cth_mapsz = 0;
551 if (mpt->mp_fps != NULL) {
552 pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps));
558 processor_entry(const struct PROCENTRY *entry, int cpu)
562 /* check for usability */
563 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
566 /* check for BSP flag */
567 if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
568 lapic_set_cpuid(0, entry->apic_id);
569 return 0; /* its already been counted */
572 /* add another AP to list, if less than max number of CPUs */
573 else if (cpu < MAXCPU) {
574 lapic_set_cpuid(cpu, entry->apic_id);
582 mptable_bus_info_callback(void *xarg, const void *pos, int type)
584 struct mptable_bus_info *bus_info = xarg;
585 const struct BUSENTRY *ent;
586 struct mptable_bus *bus;
592 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
593 if (bus->mb_id == ent->bus_id) {
594 kprintf("mptable_bus_info_alloc: duplicated bus id "
595 "(%d)\n", bus->mb_id);
601 if (strncmp(ent->bus_type, "PCI", 3) == 0) {
602 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
603 bus->mb_type = MPTABLE_BUS_PCI;
604 } else if (strncmp(ent->bus_type, "ISA", 3) == 0) {
605 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
606 bus->mb_type = MPTABLE_BUS_ISA;
610 bus->mb_id = ent->bus_id;
611 TAILQ_INSERT_TAIL(&bus_info->mbi_list, bus, mb_link);
617 mptable_bus_info_alloc(const mpcth_t cth, struct mptable_bus_info *bus_info)
621 bzero(bus_info, sizeof(*bus_info));
622 TAILQ_INIT(&bus_info->mbi_list);
624 error = mptable_iterate_entries(cth, mptable_bus_info_callback, bus_info);
626 mptable_bus_info_free(bus_info);
630 mptable_bus_info_free(struct mptable_bus_info *bus_info)
632 struct mptable_bus *bus;
634 while ((bus = TAILQ_FIRST(&bus_info->mbi_list)) != NULL) {
635 TAILQ_REMOVE(&bus_info->mbi_list, bus, mb_link);
640 struct mptable_lapic_cbarg1 {
643 u_int ht_apicid_mask;
647 mptable_lapic_pass1_callback(void *xarg, const void *pos, int type)
649 const struct PROCENTRY *ent;
650 struct mptable_lapic_cbarg1 *arg = xarg;
656 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
660 if (ent->apic_id < 64) {
661 arg->ht_apicid_mask |= 1UL << ent->apic_id;
662 } else if (arg->ht_fixup) {
663 kprintf("MPTABLE: lapic id > 64, disable HTT fixup\n");
669 struct mptable_lapic_cbarg2 {
676 mptable_lapic_pass2_callback(void *xarg, const void *pos, int type)
678 const struct PROCENTRY *ent;
679 struct mptable_lapic_cbarg2 *arg = xarg;
685 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
686 KKASSERT(!arg->found_bsp);
690 if (processor_entry(ent, arg->cpu))
693 if (arg->logical_cpus) {
694 struct PROCENTRY proc;
698 * Create fake mptable processor entries
699 * and feed them to processor_entry() to
700 * enumerate the logical CPUs.
702 bzero(&proc, sizeof(proc));
704 proc.cpu_flags = (force_enable) ? PROCENTRY_FLAG_EN : ent->cpu_flags;
705 proc.apic_id = ent->apic_id;
707 for (i = 1; i < arg->logical_cpus; i++) {
709 processor_entry(&proc, arg->cpu);
717 mptable_lapic_default(void)
719 int ap_apicid, bsp_apicid;
721 naps = 1; /* exclude BSP */
723 /* Map local apic before the id field is accessed */
724 lapic_map(DEFAULT_APIC_BASE);
726 bsp_apicid = LAPIC_READID;
727 ap_apicid = (bsp_apicid == 0) ? 1 : 0;
730 lapic_set_cpuid(0, bsp_apicid);
731 /* one and only AP */
732 lapic_set_cpuid(1, ap_apicid);
738 * APIC ID <-> CPU ID mappings
741 mptable_lapic_enumerate(struct lapic_enumerator *e)
743 struct mptable_pos mpt;
744 struct mptable_lapic_cbarg1 arg1;
745 struct mptable_lapic_cbarg2 arg2;
747 int error, logical_cpus = 0;
748 vm_paddr_t lapic_addr;
750 if (mptable_use_default) {
751 mptable_lapic_default();
755 error = mptable_map(&mpt);
757 panic("mptable_lapic_enumerate mptable_map failed");
758 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
762 /* Save local apic address */
763 lapic_addr = cth->apic_address;
764 KKASSERT(lapic_addr != 0);
767 * Find out how many CPUs do we have
769 bzero(&arg1, sizeof(arg1));
770 arg1.ht_fixup = 1; /* Apply ht fixup by default */
772 error = mptable_iterate_entries(cth,
773 mptable_lapic_pass1_callback, &arg1);
775 panic("mptable_iterate_entries(lapic_pass1) failed");
776 KKASSERT(arg1.cpu_count != 0);
778 /* See if we need to fixup HT logical CPUs. */
780 * XXX fixup for cpus >= 32 ? XXX
785 CPUMASK_ASSZERO(mask);
786 mask.ary[0] = arg1.ht_apicid_mask;
787 logical_cpus = mptable_hyperthread_fixup(mask, arg1.cpu_count);
788 if (logical_cpus != 0)
789 arg1.cpu_count *= logical_cpus;
791 naps = arg1.cpu_count - 1; /* subtract the BSP */
794 * Link logical CPU id to local apic id
796 bzero(&arg2, sizeof(arg2));
798 arg2.logical_cpus = logical_cpus;
800 error = mptable_iterate_entries(cth,
801 mptable_lapic_pass2_callback, &arg2);
803 panic("mptable_iterate_entries(lapic_pass2) failed");
804 KKASSERT(arg2.found_bsp);
807 lapic_map(lapic_addr);
814 struct mptable_lapic_probe_cbarg {
820 mptable_lapic_probe_callback(void *xarg, const void *pos, int type)
822 const struct PROCENTRY *ent;
823 struct mptable_lapic_probe_cbarg *arg = xarg;
829 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
833 if (ent->apic_id == APICID_MAX) {
834 kprintf("MPTABLE: invalid LAPIC apic id %d\n",
839 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
840 if (arg->found_bsp) {
841 kprintf("more than one BSP in base MP table\n");
850 mptable_lapic_probe(struct lapic_enumerator *e)
852 struct mptable_pos mpt;
853 struct mptable_lapic_probe_cbarg arg;
857 if (mptable_fps_phyaddr == 0)
860 if (mptable_use_default)
863 error = mptable_map(&mpt);
866 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
871 if (cth->apic_address == 0)
874 bzero(&arg, sizeof(arg));
875 error = mptable_iterate_entries(cth,
876 mptable_lapic_probe_callback, &arg);
878 if (arg.cpu_count == 0) {
879 kprintf("MP table contains no processor entries\n");
881 } else if (!arg.found_bsp) {
882 kprintf("MP table does not contains BSP entry\n");
891 static struct lapic_enumerator mptable_lapic_enumerator = {
892 .lapic_prio = LAPIC_ENUM_PRIO_MPTABLE,
893 .lapic_probe = mptable_lapic_probe,
894 .lapic_enumerate = mptable_lapic_enumerate
898 mptable_lapic_enum_register(void)
900 lapic_enumerator_register(&mptable_lapic_enumerator);
902 SYSINIT(mptable_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
903 mptable_lapic_enum_register, 0);
906 mptable_ioapic_list_callback(void *xarg, const void *pos, int type)
908 const struct IOAPICENTRY *ent;
909 struct mptable_ioapic *nioapic, *ioapic;
915 if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0)
918 if (ent->apic_address == 0) {
919 kprintf("mptable_ioapic_create_list: zero IOAPIC addr\n");
922 if (ent->apic_id == APICID_MAX) {
923 kprintf("mptable_ioapic_create_list: "
924 "invalid IOAPIC apic id %d\n", ent->apic_id);
928 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
929 if (ioapic->mio_apic_id == ent->apic_id) {
930 kprintf("mptable_ioapic_create_list: duplicated "
931 "apic id %d\n", ioapic->mio_apic_id);
934 if (ioapic->mio_addr == ent->apic_address) {
935 kprintf("mptable_ioapic_create_list: overlapped "
936 "IOAPIC addr 0x%08x", ioapic->mio_addr);
941 nioapic = kmalloc(sizeof(*nioapic), M_DEVBUF, M_WAITOK | M_ZERO);
942 nioapic->mio_apic_id = ent->apic_id;
943 nioapic->mio_addr = ent->apic_address;
946 * Create IOAPIC list in ascending order of APIC ID
948 TAILQ_FOREACH_REVERSE(ioapic, &mptable_ioapic_list,
949 mptable_ioapic_list, mio_link) {
950 if (nioapic->mio_apic_id > ioapic->mio_apic_id) {
951 TAILQ_INSERT_AFTER(&mptable_ioapic_list,
952 ioapic, nioapic, mio_link);
957 TAILQ_INSERT_HEAD(&mptable_ioapic_list, nioapic, mio_link);
963 mptable_ioapic_create_list(void)
965 struct mptable_ioapic *ioapic;
966 struct mptable_pos mpt;
969 if (mptable_fps_phyaddr == 0)
972 if (mptable_use_default) {
973 ioapic = kmalloc(sizeof(*ioapic), M_DEVBUF, M_WAITOK | M_ZERO);
975 ioapic->mio_apic_id = 0; /* NOTE: any value is ok here */
976 ioapic->mio_addr = 0xfec00000; /* XXX magic number */
978 TAILQ_INSERT_HEAD(&mptable_ioapic_list, ioapic, mio_link);
982 error = mptable_map(&mpt);
984 panic("mptable_ioapic_create_list: mptable_map failed");
985 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
987 error = mptable_iterate_entries(mpt.mp_cth,
988 mptable_ioapic_list_callback, NULL);
990 while ((ioapic = TAILQ_FIRST(&mptable_ioapic_list)) != NULL) {
991 TAILQ_REMOVE(&mptable_ioapic_list, ioapic, mio_link);
992 kfree(ioapic, M_DEVBUF);
998 * Assign index number for each IOAPIC
1001 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1002 ioapic->mio_idx = idx;
1006 mptable_unmap(&mpt);
1008 SYSINIT(mptable_ioapic_list, SI_BOOT2_PRESMP, SI_ORDER_SECOND,
1009 mptable_ioapic_create_list, 0);
1012 mptable_pci_int_callback(void *xarg, const void *pos, int type)
1014 const struct mptable_bus_info *bus_info = xarg;
1015 const struct mptable_ioapic *ioapic;
1016 const struct mptable_bus *bus;
1017 struct mptable_pci_int *pci_int;
1018 const struct INTENTRY *ent;
1019 int pci_pin, pci_dev;
1025 if (ent->int_type != 0)
1028 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
1029 if (bus->mb_type == MPTABLE_BUS_PCI &&
1030 bus->mb_id == ent->src_bus_id)
1036 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1037 if (ioapic->mio_apic_id == ent->dst_apic_id)
1040 if (ioapic == NULL) {
1042 static char intdis_warned[64];
1043 int apic_id = ent->dst_apic_id;
1046 if (apic_id < 0 || apic_id >= sizeof(intdis_warned)) {
1048 } else if (intdis_warned[apic_id] == 0) {
1049 intdis_warned[apic_id] = 1;
1053 kprintf("MPTABLE: warning PCI int dst apic id "
1054 "%d does not exist\n", apic_id);
1060 pci_pin = ent->src_bus_irq & 0x3;
1061 pci_dev = (ent->src_bus_irq >> 2) & 0x1f;
1063 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1064 if (pci_int->mpci_bus == ent->src_bus_id &&
1065 pci_int->mpci_dev == pci_dev &&
1066 pci_int->mpci_pin == pci_pin) {
1067 if (pci_int->mpci_ioapic_idx == ioapic->mio_idx &&
1068 pci_int->mpci_ioapic_pin == ent->dst_apic_int) {
1069 kprintf("MPTABLE: warning duplicated "
1070 "PCI int entry for "
1071 "bus %d, dev %d, pin %d\n",
1077 kprintf("mptable_pci_int_register: "
1078 "conflict PCI int entry for "
1079 "bus %d, dev %d, pin %d, "
1080 "IOAPIC %d.%d -> %d.%d\n",
1084 pci_int->mpci_ioapic_idx,
1085 pci_int->mpci_ioapic_pin,
1093 pci_int = kmalloc(sizeof(*pci_int), M_DEVBUF, M_WAITOK | M_ZERO);
1095 pci_int->mpci_bus = ent->src_bus_id;
1096 pci_int->mpci_dev = pci_dev;
1097 pci_int->mpci_pin = pci_pin;
1098 pci_int->mpci_ioapic_idx = ioapic->mio_idx;
1099 pci_int->mpci_ioapic_pin = ent->dst_apic_int;
1101 TAILQ_INSERT_TAIL(&mptable_pci_int_list, pci_int, mpci_link);
1107 mptable_pci_int_register(void)
1109 struct mptable_bus_info bus_info;
1110 const struct mptable_bus *bus;
1111 struct mptable_pci_int *pci_int;
1112 struct mptable_pos mpt;
1113 int error, force_pci0, npcibus;
1116 if (mptable_fps_phyaddr == 0)
1119 if (mptable_use_default)
1122 if (TAILQ_EMPTY(&mptable_ioapic_list))
1125 error = mptable_map(&mpt);
1127 panic("mptable_pci_int_register: mptable_map failed");
1128 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1132 mptable_bus_info_alloc(cth, &bus_info);
1133 if (TAILQ_EMPTY(&bus_info.mbi_list))
1138 TAILQ_FOREACH(bus, &bus_info.mbi_list, mb_link) {
1139 if (bus->mb_type == MPTABLE_BUS_PCI)
1143 mptable_bus_info_free(&bus_info);
1145 } else if (npcibus == 1) {
1149 error = mptable_iterate_entries(cth,
1150 mptable_pci_int_callback, &bus_info);
1152 mptable_bus_info_free(&bus_info);
1155 while ((pci_int = TAILQ_FIRST(&mptable_pci_int_list)) != NULL) {
1156 TAILQ_REMOVE(&mptable_pci_int_list, pci_int, mpci_link);
1157 kfree(pci_int, M_DEVBUF);
1163 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link)
1164 pci_int->mpci_bus = 0;
1167 mptable_unmap(&mpt);
1169 SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1170 mptable_pci_int_register, 0);
1172 struct mptable_ioapic_probe_cbarg {
1173 const struct mptable_bus_info *bus_info;
1177 mptable_ioapic_probe_callback(void *xarg, const void *pos, int type)
1179 struct mptable_ioapic_probe_cbarg *arg = xarg;
1180 const struct mptable_ioapic *ioapic;
1181 const struct mptable_bus *bus;
1182 const struct INTENTRY *ent;
1188 if (ent->int_type != 0)
1191 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1192 if (bus->mb_type == MPTABLE_BUS_ISA &&
1193 bus->mb_id == ent->src_bus_id)
1199 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1200 if (ioapic->mio_apic_id == ent->dst_apic_id)
1203 if (ioapic == NULL) {
1204 kprintf("MPTABLE: warning ISA int dst apic id %d "
1205 "does not exist\n", ent->dst_apic_id);
1209 /* XXX magic number */
1210 if (ent->src_bus_irq >= ISA_IRQ_CNT) {
1211 kprintf("mptable_ioapic_probe: invalid ISA irq (%d)\n",
1219 mptable_ioapic_probe(struct ioapic_enumerator *e)
1221 struct mptable_ioapic_probe_cbarg arg;
1222 struct mptable_bus_info bus_info;
1223 struct mptable_pos mpt;
1227 if (mptable_fps_phyaddr == 0)
1230 if (mptable_use_default)
1233 if (TAILQ_EMPTY(&mptable_ioapic_list))
1236 error = mptable_map(&mpt);
1238 panic("mptable_ioapic_probe: mptable_map failed");
1239 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1243 mptable_bus_info_alloc(cth, &bus_info);
1245 bzero(&arg, sizeof(arg));
1246 arg.bus_info = &bus_info;
1248 error = mptable_iterate_entries(cth,
1249 mptable_ioapic_probe_callback, &arg);
1251 mptable_bus_info_free(&bus_info);
1252 mptable_unmap(&mpt);
1257 struct mptable_ioapic_int_cbarg {
1258 const struct mptable_bus_info *bus_info;
1263 mptable_ioapic_int_callback(void *xarg, const void *pos, int type)
1265 struct mptable_ioapic_int_cbarg *arg = xarg;
1266 const struct mptable_ioapic *ioapic;
1267 const struct mptable_bus *bus;
1268 const struct INTENTRY *ent;
1277 if (ent->int_type != 0)
1280 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1281 if (bus->mb_type == MPTABLE_BUS_ISA &&
1282 bus->mb_id == ent->src_bus_id)
1288 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1289 if (ioapic->mio_apic_id == ent->dst_apic_id)
1292 if (ioapic == NULL) {
1293 kprintf("MPTABLE: warning ISA int dst apic id %d "
1294 "does not exist\n", ent->dst_apic_id);
1298 if (ent->dst_apic_int >= ioapic->mio_npin) {
1299 panic("mptable_ioapic_enumerate: invalid I/O APIC "
1300 "pin %d, should be < %d",
1301 ent->dst_apic_int, ioapic->mio_npin);
1303 gsi = ioapic->mio_gsi_base + ent->dst_apic_int;
1305 if (ent->src_bus_irq != gsi) {
1307 kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n",
1308 ent->src_bus_irq, gsi);
1310 ioapic_intsrc(ent->src_bus_irq, gsi,
1311 INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1317 mptable_ioapic_enumerate(struct ioapic_enumerator *e)
1319 struct mptable_bus_info bus_info;
1320 struct mptable_ioapic *ioapic;
1321 struct mptable_pos mpt;
1325 KKASSERT(mptable_fps_phyaddr != 0);
1326 KKASSERT(!TAILQ_EMPTY(&mptable_ioapic_list));
1328 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1329 const struct mptable_ioapic *prev_ioapic;
1333 addr = ioapic_map(ioapic->mio_addr);
1335 ver = ioapic_read(addr, IOAPIC_VER);
1336 ioapic->mio_npin = ((ver & IOART_VER_MAXREDIR)
1337 >> MAXREDIRSHIFT) + 1;
1339 prev_ioapic = TAILQ_PREV(ioapic,
1340 mptable_ioapic_list, mio_link);
1341 if (prev_ioapic == NULL) {
1342 ioapic->mio_gsi_base = 0;
1344 ioapic->mio_gsi_base =
1345 prev_ioapic->mio_gsi_base +
1346 prev_ioapic->mio_npin;
1348 ioapic_add(addr, ioapic->mio_gsi_base, ioapic->mio_npin);
1351 kprintf("MPTABLE: IOAPIC addr 0x%08x, "
1352 "apic id %d, idx %d, gsi base %d, npin %d\n",
1354 ioapic->mio_apic_id,
1356 ioapic->mio_gsi_base,
1361 if (mptable_use_default) {
1363 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n");
1364 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1368 error = mptable_map(&mpt);
1370 panic("mptable_ioapic_probe: mptable_map failed");
1371 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1375 mptable_bus_info_alloc(cth, &bus_info);
1377 if (TAILQ_EMPTY(&bus_info.mbi_list)) {
1379 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n");
1380 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1382 struct mptable_ioapic_int_cbarg arg;
1384 bzero(&arg, sizeof(arg));
1385 arg.bus_info = &bus_info;
1387 error = mptable_iterate_entries(cth,
1388 mptable_ioapic_int_callback, &arg);
1390 panic("mptable_ioapic_int failed");
1392 if (arg.ioapic_nint == 0) {
1394 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 "
1397 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE,
1398 INTR_POLARITY_HIGH);
1402 mptable_bus_info_free(&bus_info);
1404 mptable_unmap(&mpt);
1407 static struct ioapic_enumerator mptable_ioapic_enumerator = {
1408 .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE,
1409 .ioapic_probe = mptable_ioapic_probe,
1410 .ioapic_enumerate = mptable_ioapic_enumerate
1414 mptable_ioapic_enum_register(void)
1416 ioapic_enumerator_register(&mptable_ioapic_enumerator);
1418 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1419 mptable_ioapic_enum_register, 0);
1422 mptable_pci_int_dump(void)
1424 const struct mptable_pci_int *pci_int;
1429 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1430 kprintf("MPTABLE: %d:%d INT%c -> IOAPIC %d.%d\n",
1433 pci_int->mpci_pin + 'A',
1434 pci_int->mpci_ioapic_idx,
1435 pci_int->mpci_ioapic_pin);
1440 mptable_pci_int_route(int bus, int dev, int pin, int intline)
1442 const struct mptable_pci_int *pci_int;
1446 --pin; /* zero based */
1448 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1449 if (pci_int->mpci_bus == bus &&
1450 pci_int->mpci_dev == dev &&
1451 pci_int->mpci_pin == pin)
1454 if (pci_int != NULL) {
1457 gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
1458 pci_int->mpci_ioapic_pin);
1460 irq = machintr_legacy_intr_find_bygsi(gsi,
1461 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1465 if (irq < 0 && intline >= 0) {
1466 kprintf("MPTABLE: fixed interrupt routing "
1467 "for %d:%d INT%c\n", bus, dev, pin + 'A');
1468 irq = machintr_legacy_intr_find(intline,
1469 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1472 if (irq >= 0 && bootverbose) {
1473 kprintf("MPTABLE: %d:%d INT%c routed to irq %d\n",
1474 bus, dev, pin + 'A', irq);