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 $
26 * $DragonFly: src/sys/platform/pc32/i386/mp_machdep.c,v 1.60 2008/06/07 12:03:52 mneumann Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/sysctl.h>
35 #include <sys/malloc.h>
36 #include <sys/memrange.h>
37 #include <sys/cons.h> /* cngetc() */
38 #include <sys/machintr.h>
41 #include <vm/vm_param.h>
43 #include <vm/vm_kern.h>
44 #include <vm/vm_extern.h>
46 #include <vm/vm_map.h>
52 #include <sys/mplock2.h>
54 #include <machine/smp.h>
55 #include <machine_base/apic/apicreg.h>
56 #include <machine/atomic.h>
57 #include <machine/cpufunc.h>
58 #include <machine/cputypes.h>
59 #include <machine_base/apic/ioapic_abi.h>
60 #include <machine_base/apic/lapic.h>
61 #include <machine_base/apic/ioapic.h>
62 #include <machine/psl.h>
63 #include <machine/segments.h>
64 #include <machine/tss.h>
65 #include <machine/specialreg.h>
66 #include <machine/globaldata.h>
67 #include <machine/pmap_inval.h>
69 #include <machine/md_var.h> /* setidt() */
70 #include <machine_base/icu/icu.h> /* IPIs */
71 #include <machine/intr_machdep.h> /* IPIs */
73 extern u_long ebda_addr;
74 extern u_int base_memory;
76 #define BIOS_BASE (0xf0000)
77 #define BIOS_BASE2 (0xe0000)
78 #define BIOS_SIZE (0x10000)
79 #define BIOS_COUNT (BIOS_SIZE/4)
81 #define PROCENTRY_FLAG_EN 0x01
82 #define PROCENTRY_FLAG_BP 0x02
83 #define IOAPICENTRY_FLAG_EN 0x01
85 /* MP Floating Pointer Structure */
86 typedef struct MPFPS {
99 /* MP Configuration Table Header */
100 typedef struct MPCTH {
102 u_short base_table_length;
106 u_char product_id[12];
107 void *oem_table_pointer;
108 u_short oem_table_size;
111 u_short extended_table_length;
112 u_char extended_table_checksum;
117 typedef struct PROCENTRY {
122 u_long cpu_signature;
123 u_long feature_flags;
128 typedef struct BUSENTRY {
134 typedef struct IOAPICENTRY {
140 } *io_apic_entry_ptr;
142 typedef struct INTENTRY {
152 /* descriptions of MP basetable entries */
153 typedef struct BASETABLE_ENTRY {
162 vm_size_t mp_cth_mapsz;
165 #define MPTABLE_POS_USE_DEFAULT(mpt) \
166 ((mpt)->mp_fps->mpfb1 != 0 || (mpt)->mp_cth == NULL)
170 int mb_type; /* MPTABLE_BUS_ */
171 TAILQ_ENTRY(mptable_bus) mb_link;
174 #define MPTABLE_BUS_ISA 0
175 #define MPTABLE_BUS_PCI 1
177 struct mptable_bus_info {
178 TAILQ_HEAD(, mptable_bus) mbi_list;
181 struct mptable_pci_int {
188 TAILQ_ENTRY(mptable_pci_int) mpci_link;
191 struct mptable_ioapic {
197 TAILQ_ENTRY(mptable_ioapic) mio_link;
200 typedef int (*mptable_iter_func)(void *, const void *, int);
202 static int mptable_iterate_entries(const mpcth_t,
203 mptable_iter_func, void *);
204 static int mptable_search(void);
205 static int mptable_search_sig(u_int32_t target, int count);
206 static int mptable_hyperthread_fixup(cpumask_t, int);
207 static int mptable_map(struct mptable_pos *);
208 static void mptable_unmap(struct mptable_pos *);
209 static void mptable_bus_info_alloc(const mpcth_t,
210 struct mptable_bus_info *);
211 static void mptable_bus_info_free(struct mptable_bus_info *);
213 static int mptable_lapic_probe(struct lapic_enumerator *);
214 static void mptable_lapic_enumerate(struct lapic_enumerator *);
215 static void mptable_lapic_default(void);
217 static int mptable_ioapic_probe(struct ioapic_enumerator *);
218 static void mptable_ioapic_enumerate(struct ioapic_enumerator *);
220 static basetable_entry basetable_entry_types[] =
222 {0, 20, "Processor"},
229 static vm_paddr_t mptable_fps_phyaddr;
230 static int mptable_use_default;
231 static TAILQ_HEAD(mptable_pci_int_list, mptable_pci_int) mptable_pci_int_list =
232 TAILQ_HEAD_INITIALIZER(mptable_pci_int_list);
233 static TAILQ_HEAD(mptable_ioapic_list, mptable_ioapic) mptable_ioapic_list =
234 TAILQ_HEAD_INITIALIZER(mptable_ioapic_list);
239 struct mptable_pos mpt;
242 KKASSERT(mptable_fps_phyaddr == 0);
244 mptable_fps_phyaddr = mptable_search();
245 if (mptable_fps_phyaddr == 0)
248 error = mptable_map(&mpt);
250 mptable_fps_phyaddr = 0;
254 if (MPTABLE_POS_USE_DEFAULT(&mpt)) {
255 kprintf("MPTABLE: use default configuration\n");
256 mptable_use_default = 1;
258 if (mpt.mp_fps->mpfb2 & 0x80)
263 SYSINIT(mptable_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, mptable_probe, 0);
266 * Look for an Intel MP spec table (ie, SMP capable hardware).
274 /* see if EBDA exists */
275 if (ebda_addr != 0) {
276 /* search first 1K of EBDA */
277 target = (u_int32_t)ebda_addr;
278 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
281 /* last 1K of base memory, effective 'top of base' passed in */
282 target = (u_int32_t)(base_memory - 0x400);
283 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
287 /* search the BIOS */
288 target = (u_int32_t)BIOS_BASE;
289 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
292 /* search the extended BIOS */
293 target = (u_int32_t)BIOS_BASE2;
294 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
302 mptable_iterate_entries(const mpcth_t cth, mptable_iter_func func, void *arg)
304 int count, total_size;
305 const void *position;
307 KKASSERT(cth->base_table_length >= sizeof(struct MPCTH));
308 total_size = cth->base_table_length - sizeof(struct MPCTH);
309 position = (const uint8_t *)cth + sizeof(struct MPCTH);
310 count = cth->entry_count;
315 KKASSERT(total_size >= 0);
316 if (total_size == 0) {
317 kprintf("invalid base MP table, "
318 "entry count and length mismatch\n");
322 type = *(const uint8_t *)position;
324 case 0: /* processor_entry */
325 case 1: /* bus_entry */
326 case 2: /* io_apic_entry */
327 case 3: /* int_entry */
328 case 4: /* int_entry */
331 kprintf("unknown base MP table entry type %d\n", type);
335 if (total_size < basetable_entry_types[type].length) {
336 kprintf("invalid base MP table length, "
337 "does not contain all entries\n");
340 total_size -= basetable_entry_types[type].length;
342 error = func(arg, position, type);
346 position = (const uint8_t *)position +
347 basetable_entry_types[type].length;
353 * look for the MP spec signature
356 /* string defined by the Intel MP Spec as identifying the MP table */
357 #define MP_SIG 0x5f504d5f /* _MP_ */
358 #define NEXT(X) ((X) += 4)
360 mptable_search_sig(u_int32_t target, int count)
366 KKASSERT(target != 0);
368 map_size = count * sizeof(u_int32_t);
369 addr = pmap_mapdev((vm_paddr_t)target, map_size);
372 for (x = 0; x < count; NEXT(x)) {
373 if (addr[x] == MP_SIG) {
374 /* make array index a byte index */
375 ret = target + (x * sizeof(u_int32_t));
380 pmap_unmapdev((vm_offset_t)addr, map_size);
384 static int processor_entry (const struct PROCENTRY *entry, int cpu);
387 * Check if we should perform a hyperthreading "fix-up" to
388 * enumerate any logical CPU's that aren't already listed
391 * XXX: We assume that all of the physical CPUs in the
392 * system have the same number of logical CPUs.
394 * XXX: We assume that APIC ID's are allocated such that
395 * the APIC ID's for a physical processor are aligned
396 * with the number of logical CPU's in the processor.
399 mptable_hyperthread_fixup(cpumask_t id_mask, int cpu_count)
401 int i, id, lcpus_max, logical_cpus;
403 if ((cpu_feature & CPUID_HTT) == 0)
406 lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
410 if (cpu_vendor_id == CPU_VENDOR_INTEL) {
412 * INSTRUCTION SET REFERENCE, A-M (#253666)
413 * Page 3-181, Table 3-20
414 * "The nearest power-of-2 integer that is not smaller
415 * than EBX[23:16] is the number of unique initial APIC
416 * IDs reserved for addressing different logical
417 * processors in a physical package."
420 if ((1 << i) >= lcpus_max) {
427 KKASSERT(cpu_count != 0);
428 if (cpu_count == lcpus_max) {
429 /* We have nothing to fix */
431 } else if (cpu_count == 1) {
432 /* XXX this may be incorrect */
433 logical_cpus = lcpus_max;
438 * Calculate the distances between two nearest
439 * APIC IDs. If all such distances are same,
440 * then it is the number of missing cpus that
441 * we are going to fill later.
443 dist = cur = prev = -1;
444 for (id = 0; id < MAXCPU; ++id) {
445 if ((id_mask & CPUMASK(id)) == 0)
450 int new_dist = cur - prev;
456 * Make sure that all distances
457 * between two nearest APIC IDs
460 if (dist != new_dist)
468 /* Must be power of 2 */
469 if (dist & (dist - 1))
472 /* Can't exceed CPU package capacity */
473 if (dist > lcpus_max)
474 logical_cpus = lcpus_max;
480 * For each APIC ID of a CPU that is set in the mask,
481 * scan the other candidate APIC ID's for this
482 * physical processor. If any of those ID's are
483 * already in the table, then kill the fixup.
485 for (id = 0; id < MAXCPU; id++) {
486 if ((id_mask & CPUMASK(id)) == 0)
488 /* First, make sure we are on a logical_cpus boundary. */
489 if (id % logical_cpus != 0)
491 for (i = id + 1; i < id + logical_cpus; i++)
492 if ((id_mask & CPUMASK(i)) != 0)
499 mptable_map(struct mptable_pos *mpt)
503 vm_size_t cth_mapsz = 0;
505 KKASSERT(mptable_fps_phyaddr != 0);
507 bzero(mpt, sizeof(*mpt));
509 fps = pmap_mapdev(mptable_fps_phyaddr, sizeof(*fps));
512 * Map configuration table header to get
513 * the base table size
515 cth = pmap_mapdev(fps->pap, sizeof(*cth));
516 cth_mapsz = cth->base_table_length;
517 pmap_unmapdev((vm_offset_t)cth, sizeof(*cth));
519 if (cth_mapsz < sizeof(*cth)) {
520 kprintf("invalid base MP table length %d\n",
522 pmap_unmapdev((vm_offset_t)fps, sizeof(*fps));
529 cth = pmap_mapdev(fps->pap, cth_mapsz);
534 mpt->mp_cth_mapsz = cth_mapsz;
540 mptable_unmap(struct mptable_pos *mpt)
542 if (mpt->mp_cth != NULL) {
543 pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz);
545 mpt->mp_cth_mapsz = 0;
547 if (mpt->mp_fps != NULL) {
548 pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps));
554 processor_entry(const struct PROCENTRY *entry, int cpu)
558 /* check for usability */
559 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
562 /* check for BSP flag */
563 if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
564 lapic_set_cpuid(0, entry->apic_id);
565 return 0; /* its already been counted */
568 /* add another AP to list, if less than max number of CPUs */
569 else if (cpu < MAXCPU) {
570 lapic_set_cpuid(cpu, entry->apic_id);
578 mptable_bus_info_callback(void *xarg, const void *pos, int type)
580 struct mptable_bus_info *bus_info = xarg;
581 const struct BUSENTRY *ent;
582 struct mptable_bus *bus;
588 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
589 if (bus->mb_id == ent->bus_id) {
590 kprintf("mptable_bus_info_alloc: duplicated bus id "
591 "(%d)\n", bus->mb_id);
597 if (strncmp(ent->bus_type, "PCI", 3) == 0) {
598 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
599 bus->mb_type = MPTABLE_BUS_PCI;
600 } else if (strncmp(ent->bus_type, "ISA", 3) == 0) {
601 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
602 bus->mb_type = MPTABLE_BUS_ISA;
606 bus->mb_id = ent->bus_id;
607 TAILQ_INSERT_TAIL(&bus_info->mbi_list, bus, mb_link);
613 mptable_bus_info_alloc(const mpcth_t cth, struct mptable_bus_info *bus_info)
617 bzero(bus_info, sizeof(*bus_info));
618 TAILQ_INIT(&bus_info->mbi_list);
620 error = mptable_iterate_entries(cth, mptable_bus_info_callback, bus_info);
622 mptable_bus_info_free(bus_info);
626 mptable_bus_info_free(struct mptable_bus_info *bus_info)
628 struct mptable_bus *bus;
630 while ((bus = TAILQ_FIRST(&bus_info->mbi_list)) != NULL) {
631 TAILQ_REMOVE(&bus_info->mbi_list, bus, mb_link);
636 struct mptable_lapic_cbarg1 {
639 u_int ht_apicid_mask;
643 mptable_lapic_pass1_callback(void *xarg, const void *pos, int type)
645 const struct PROCENTRY *ent;
646 struct mptable_lapic_cbarg1 *arg = xarg;
652 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
656 if (ent->apic_id < 32) {
657 arg->ht_apicid_mask |= 1 << ent->apic_id;
658 } else if (arg->ht_fixup) {
659 kprintf("MPTABLE: lapic id > 32, disable HTT fixup\n");
665 struct mptable_lapic_cbarg2 {
672 mptable_lapic_pass2_callback(void *xarg, const void *pos, int type)
674 const struct PROCENTRY *ent;
675 struct mptable_lapic_cbarg2 *arg = xarg;
681 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
682 KKASSERT(!arg->found_bsp);
686 if (processor_entry(ent, arg->cpu))
689 if (arg->logical_cpus) {
690 struct PROCENTRY proc;
694 * Create fake mptable processor entries
695 * and feed them to processor_entry() to
696 * enumerate the logical CPUs.
698 bzero(&proc, sizeof(proc));
700 proc.cpu_flags = PROCENTRY_FLAG_EN;
701 proc.apic_id = ent->apic_id;
703 for (i = 1; i < arg->logical_cpus; i++) {
705 processor_entry(&proc, arg->cpu);
713 mptable_lapic_default(void)
715 int ap_apicid, bsp_apicid;
717 mp_naps = 1; /* exclude BSP */
719 /* Map local apic before the id field is accessed */
720 lapic_map(DEFAULT_APIC_BASE);
722 bsp_apicid = APIC_ID(lapic->id);
723 ap_apicid = (bsp_apicid == 0) ? 1 : 0;
726 lapic_set_cpuid(0, bsp_apicid);
727 /* one and only AP */
728 lapic_set_cpuid(1, ap_apicid);
734 * APIC ID <-> CPU ID mappings
737 mptable_lapic_enumerate(struct lapic_enumerator *e)
739 struct mptable_pos mpt;
740 struct mptable_lapic_cbarg1 arg1;
741 struct mptable_lapic_cbarg2 arg2;
743 int error, logical_cpus = 0;
744 vm_offset_t lapic_addr;
746 if (mptable_use_default) {
747 mptable_lapic_default();
751 error = mptable_map(&mpt);
753 panic("mptable_lapic_enumerate mptable_map failed\n");
754 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
758 /* Save local apic address */
759 lapic_addr = (vm_offset_t)cth->apic_address;
760 KKASSERT(lapic_addr != 0);
763 * Find out how many CPUs do we have
765 bzero(&arg1, sizeof(arg1));
766 arg1.ht_fixup = 1; /* Apply ht fixup by default */
768 error = mptable_iterate_entries(cth,
769 mptable_lapic_pass1_callback, &arg1);
771 panic("mptable_iterate_entries(lapic_pass1) failed\n");
772 KKASSERT(arg1.cpu_count != 0);
774 /* See if we need to fixup HT logical CPUs. */
776 logical_cpus = mptable_hyperthread_fixup(arg1.ht_apicid_mask,
778 if (logical_cpus != 0)
779 arg1.cpu_count *= logical_cpus;
781 mp_naps = arg1.cpu_count;
783 /* Qualify the numbers again, after possible HT fixup */
784 if (mp_naps > MAXCPU) {
785 kprintf("Warning: only using %d of %d available CPUs!\n",
790 --mp_naps; /* subtract the BSP */
793 * Link logical CPU id to local apic id
795 bzero(&arg2, sizeof(arg2));
797 arg2.logical_cpus = logical_cpus;
799 error = mptable_iterate_entries(cth,
800 mptable_lapic_pass2_callback, &arg2);
802 panic("mptable_iterate_entries(lapic_pass2) failed\n");
803 KKASSERT(arg2.found_bsp);
806 lapic_map(lapic_addr);
811 struct mptable_lapic_probe_cbarg {
817 mptable_lapic_probe_callback(void *xarg, const void *pos, int type)
819 const struct PROCENTRY *ent;
820 struct mptable_lapic_probe_cbarg *arg = xarg;
826 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
830 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
831 if (arg->found_bsp) {
832 kprintf("more than one BSP in base MP table\n");
841 mptable_lapic_probe(struct lapic_enumerator *e)
843 struct mptable_pos mpt;
844 struct mptable_lapic_probe_cbarg arg;
848 if (mptable_fps_phyaddr == 0)
851 if (mptable_use_default)
854 error = mptable_map(&mpt);
857 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
862 if (cth->apic_address == 0)
865 bzero(&arg, sizeof(arg));
866 error = mptable_iterate_entries(cth,
867 mptable_lapic_probe_callback, &arg);
869 if (arg.cpu_count == 0) {
870 kprintf("MP table contains no processor entries\n");
872 } else if (!arg.found_bsp) {
873 kprintf("MP table does not contains BSP entry\n");
882 static struct lapic_enumerator mptable_lapic_enumerator = {
883 .lapic_prio = LAPIC_ENUM_PRIO_MPTABLE,
884 .lapic_probe = mptable_lapic_probe,
885 .lapic_enumerate = mptable_lapic_enumerate
889 mptable_lapic_enum_register(void)
891 lapic_enumerator_register(&mptable_lapic_enumerator);
893 SYSINIT(mptable_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
894 mptable_lapic_enum_register, 0);
897 mptable_ioapic_list_callback(void *xarg, const void *pos, int type)
899 const struct IOAPICENTRY *ent;
900 struct mptable_ioapic *nioapic, *ioapic;
906 if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0)
909 if (ent->apic_address == 0) {
910 kprintf("mptable_ioapic_create_list: zero IOAPIC addr\n");
914 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
915 if (ioapic->mio_apic_id == ent->apic_id) {
916 kprintf("mptable_ioapic_create_list: duplicated "
917 "apic id %d\n", ioapic->mio_apic_id);
920 if (ioapic->mio_addr == (uint32_t)ent->apic_address) {
921 kprintf("mptable_ioapic_create_list: overlapped "
922 "IOAPIC addr 0x%08x", ioapic->mio_addr);
927 nioapic = kmalloc(sizeof(*nioapic), M_DEVBUF, M_WAITOK | M_ZERO);
928 nioapic->mio_apic_id = ent->apic_id;
929 nioapic->mio_addr = (uint32_t)ent->apic_address;
932 * Create IOAPIC list in ascending order of APIC ID
934 TAILQ_FOREACH_REVERSE(ioapic, &mptable_ioapic_list,
935 mptable_ioapic_list, mio_link) {
936 if (nioapic->mio_apic_id > ioapic->mio_apic_id) {
937 TAILQ_INSERT_AFTER(&mptable_ioapic_list,
938 ioapic, nioapic, mio_link);
943 TAILQ_INSERT_HEAD(&mptable_ioapic_list, nioapic, mio_link);
949 mptable_ioapic_create_list(void)
951 struct mptable_ioapic *ioapic;
952 struct mptable_pos mpt;
955 if (mptable_fps_phyaddr == 0)
958 if (mptable_use_default) {
959 ioapic = kmalloc(sizeof(*ioapic), M_DEVBUF, M_WAITOK | M_ZERO);
961 ioapic->mio_apic_id = 0; /* NOTE: any value is ok here */
962 ioapic->mio_addr = 0xfec00000; /* XXX magic number */
964 TAILQ_INSERT_HEAD(&mptable_ioapic_list, ioapic, mio_link);
968 error = mptable_map(&mpt);
970 panic("mptable_ioapic_create_list: mptable_map failed\n");
971 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
973 error = mptable_iterate_entries(mpt.mp_cth,
974 mptable_ioapic_list_callback, NULL);
976 while ((ioapic = TAILQ_FIRST(&mptable_ioapic_list)) != NULL) {
977 TAILQ_REMOVE(&mptable_ioapic_list, ioapic, mio_link);
978 kfree(ioapic, M_DEVBUF);
984 * Assign index number for each IOAPIC
987 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
988 ioapic->mio_idx = idx;
994 SYSINIT(mptable_ioapic_list, SI_BOOT2_PRESMP, SI_ORDER_SECOND,
995 mptable_ioapic_create_list, 0);
998 mptable_pci_int_callback(void *xarg, const void *pos, int type)
1000 const struct mptable_bus_info *bus_info = xarg;
1001 const struct mptable_ioapic *ioapic;
1002 const struct mptable_bus *bus;
1003 struct mptable_pci_int *pci_int;
1004 const struct INTENTRY *ent;
1005 int pci_pin, pci_dev;
1011 if (ent->int_type != 0)
1014 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
1015 if (bus->mb_type == MPTABLE_BUS_PCI &&
1016 bus->mb_id == ent->src_bus_id)
1022 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1023 if (ioapic->mio_apic_id == ent->dst_apic_id)
1026 if (ioapic == NULL) {
1027 kprintf("MPTABLE: warning PCI int dst apic id %d "
1028 "does not exist\n", ent->dst_apic_id);
1032 pci_pin = ent->src_bus_irq & 0x3;
1033 pci_dev = (ent->src_bus_irq >> 2) & 0x1f;
1035 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1036 if (pci_int->mpci_bus == ent->src_bus_id &&
1037 pci_int->mpci_dev == pci_dev &&
1038 pci_int->mpci_pin == pci_pin) {
1039 if (pci_int->mpci_ioapic_idx == ioapic->mio_idx &&
1040 pci_int->mpci_ioapic_pin == ent->dst_apic_int) {
1041 kprintf("MPTABLE: warning duplicated "
1042 "PCI int entry for "
1043 "bus %d, dev %d, pin %d\n",
1049 kprintf("mptable_pci_int_register: "
1050 "conflict PCI int entry for "
1051 "bus %d, dev %d, pin %d, "
1052 "IOAPIC %d.%d -> %d.%d\n",
1056 pci_int->mpci_ioapic_idx,
1057 pci_int->mpci_ioapic_pin,
1065 pci_int = kmalloc(sizeof(*pci_int), M_DEVBUF, M_WAITOK | M_ZERO);
1067 pci_int->mpci_bus = ent->src_bus_id;
1068 pci_int->mpci_dev = pci_dev;
1069 pci_int->mpci_pin = pci_pin;
1070 pci_int->mpci_ioapic_idx = ioapic->mio_idx;
1071 pci_int->mpci_ioapic_pin = ent->dst_apic_int;
1073 TAILQ_INSERT_TAIL(&mptable_pci_int_list, pci_int, mpci_link);
1079 mptable_pci_int_register(void)
1081 struct mptable_bus_info bus_info;
1082 const struct mptable_bus *bus;
1083 struct mptable_pci_int *pci_int;
1084 struct mptable_pos mpt;
1085 int error, force_pci0, npcibus;
1088 if (mptable_fps_phyaddr == 0)
1091 if (mptable_use_default)
1094 if (TAILQ_EMPTY(&mptable_ioapic_list))
1097 error = mptable_map(&mpt);
1099 panic("mptable_pci_int_register: mptable_map failed\n");
1100 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1104 mptable_bus_info_alloc(cth, &bus_info);
1105 if (TAILQ_EMPTY(&bus_info.mbi_list))
1110 TAILQ_FOREACH(bus, &bus_info.mbi_list, mb_link) {
1111 if (bus->mb_type == MPTABLE_BUS_PCI)
1115 mptable_bus_info_free(&bus_info);
1117 } else if (npcibus == 1) {
1121 error = mptable_iterate_entries(cth,
1122 mptable_pci_int_callback, &bus_info);
1124 mptable_bus_info_free(&bus_info);
1127 while ((pci_int = TAILQ_FIRST(&mptable_pci_int_list)) != NULL) {
1128 TAILQ_REMOVE(&mptable_pci_int_list, pci_int, mpci_link);
1129 kfree(pci_int, M_DEVBUF);
1135 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link)
1136 pci_int->mpci_bus = 0;
1139 mptable_unmap(&mpt);
1141 SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1142 mptable_pci_int_register, 0);
1144 struct mptable_ioapic_probe_cbarg {
1145 const struct mptable_bus_info *bus_info;
1149 mptable_ioapic_probe_callback(void *xarg, const void *pos, int type)
1151 struct mptable_ioapic_probe_cbarg *arg = xarg;
1152 const struct mptable_ioapic *ioapic;
1153 const struct mptable_bus *bus;
1154 const struct INTENTRY *ent;
1160 if (ent->int_type != 0)
1163 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1164 if (bus->mb_type == MPTABLE_BUS_ISA &&
1165 bus->mb_id == ent->src_bus_id)
1171 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1172 if (ioapic->mio_apic_id == ent->dst_apic_id)
1175 if (ioapic == NULL) {
1176 kprintf("MPTABLE: warning ISA int dst apic id %d "
1177 "does not exist\n", ent->dst_apic_id);
1181 /* XXX magic number */
1182 if (ent->src_bus_irq >= 16) {
1183 kprintf("mptable_ioapic_probe: invalid ISA irq (%d)\n",
1191 mptable_ioapic_probe(struct ioapic_enumerator *e)
1193 struct mptable_ioapic_probe_cbarg arg;
1194 struct mptable_bus_info bus_info;
1195 struct mptable_pos mpt;
1199 if (mptable_fps_phyaddr == 0)
1202 if (mptable_use_default)
1205 if (TAILQ_EMPTY(&mptable_ioapic_list))
1208 error = mptable_map(&mpt);
1210 panic("mptable_ioapic_probe: mptable_map failed\n");
1211 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1215 mptable_bus_info_alloc(cth, &bus_info);
1217 bzero(&arg, sizeof(arg));
1218 arg.bus_info = &bus_info;
1220 error = mptable_iterate_entries(cth,
1221 mptable_ioapic_probe_callback, &arg);
1223 mptable_bus_info_free(&bus_info);
1224 mptable_unmap(&mpt);
1229 struct mptable_ioapic_int_cbarg {
1230 const struct mptable_bus_info *bus_info;
1235 mptable_ioapic_int_callback(void *xarg, const void *pos, int type)
1237 struct mptable_ioapic_int_cbarg *arg = xarg;
1238 const struct mptable_ioapic *ioapic;
1239 const struct mptable_bus *bus;
1240 const struct INTENTRY *ent;
1249 if (ent->int_type != 0)
1252 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1253 if (bus->mb_type == MPTABLE_BUS_ISA &&
1254 bus->mb_id == ent->src_bus_id)
1260 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1261 if (ioapic->mio_apic_id == ent->dst_apic_id)
1264 if (ioapic == NULL) {
1265 kprintf("MPTABLE: warning ISA int dst apic id %d "
1266 "does not exist\n", ent->dst_apic_id);
1270 if (ent->dst_apic_int >= ioapic->mio_npin) {
1271 panic("mptable_ioapic_enumerate: invalid I/O APIC "
1272 "pin %d, should be < %d",
1273 ent->dst_apic_int, ioapic->mio_npin);
1275 gsi = ioapic->mio_gsi_base + ent->dst_apic_int;
1277 if (ent->src_bus_irq != gsi) {
1279 kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n",
1280 ent->src_bus_irq, gsi);
1282 ioapic_intsrc(ent->src_bus_irq, gsi,
1283 INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1289 mptable_ioapic_enumerate(struct ioapic_enumerator *e)
1291 struct mptable_bus_info bus_info;
1292 struct mptable_ioapic *ioapic;
1293 struct mptable_pos mpt;
1297 KKASSERT(mptable_fps_phyaddr != 0);
1298 KKASSERT(!TAILQ_EMPTY(&mptable_ioapic_list));
1300 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1301 const struct mptable_ioapic *prev_ioapic;
1305 addr = ioapic_map(ioapic->mio_addr);
1307 ver = ioapic_read(addr, IOAPIC_VER);
1308 ioapic->mio_npin = ((ver & IOART_VER_MAXREDIR)
1309 >> MAXREDIRSHIFT) + 1;
1311 prev_ioapic = TAILQ_PREV(ioapic,
1312 mptable_ioapic_list, mio_link);
1313 if (prev_ioapic == NULL) {
1314 ioapic->mio_gsi_base = 0;
1316 ioapic->mio_gsi_base =
1317 prev_ioapic->mio_gsi_base +
1318 prev_ioapic->mio_npin;
1320 ioapic_add(addr, ioapic->mio_gsi_base,
1324 kprintf("MPTABLE: IOAPIC addr 0x%08x, "
1325 "apic id %d, idx %d, gsi base %d, npin %d\n",
1327 ioapic->mio_apic_id,
1329 ioapic->mio_gsi_base,
1334 if (mptable_use_default) {
1336 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n");
1337 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1341 error = mptable_map(&mpt);
1343 panic("mptable_ioapic_probe: mptable_map failed\n");
1344 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1348 mptable_bus_info_alloc(cth, &bus_info);
1350 if (TAILQ_EMPTY(&bus_info.mbi_list)) {
1352 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n");
1353 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1355 struct mptable_ioapic_int_cbarg arg;
1357 bzero(&arg, sizeof(arg));
1358 arg.bus_info = &bus_info;
1360 error = mptable_iterate_entries(cth,
1361 mptable_ioapic_int_callback, &arg);
1363 panic("mptable_ioapic_int failed\n");
1365 if (arg.ioapic_nint == 0) {
1367 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 "
1370 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE,
1371 INTR_POLARITY_HIGH);
1375 mptable_bus_info_free(&bus_info);
1377 mptable_unmap(&mpt);
1380 static struct ioapic_enumerator mptable_ioapic_enumerator = {
1381 .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE,
1382 .ioapic_probe = mptable_ioapic_probe,
1383 .ioapic_enumerate = mptable_ioapic_enumerate
1387 mptable_ioapic_enum_register(void)
1389 ioapic_enumerator_register(&mptable_ioapic_enumerator);
1391 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1392 mptable_ioapic_enum_register, 0);
1395 mptable_pci_int_dump(void)
1397 const struct mptable_pci_int *pci_int;
1399 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1400 kprintf("MPTABLE: %d:%d INT%c -> IOAPIC %d.%d\n",
1403 pci_int->mpci_pin + 'A',
1404 pci_int->mpci_ioapic_idx,
1405 pci_int->mpci_ioapic_pin);
1410 mptable_pci_int_route(int bus, int dev, int pin, int intline)
1412 const struct mptable_pci_int *pci_int;
1416 --pin; /* zero based */
1418 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1419 if (pci_int->mpci_bus == bus &&
1420 pci_int->mpci_dev == dev &&
1421 pci_int->mpci_pin == pin)
1424 if (pci_int != NULL) {
1427 gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
1428 pci_int->mpci_ioapic_pin);
1430 irq = ioapic_abi_find_gsi(gsi,
1431 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1437 kprintf("MPTABLE: fixed interrupt routing "
1438 "for %d:%d INT%c\n", bus, dev, pin + 'A');
1441 irq = ioapic_abi_find_irq(intline,
1442 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1445 if (irq >= 0 && bootverbose) {
1446 kprintf("MPTABLE: %d:%d INT%c routed to irq %d\n",
1447 bus, dev, pin + 'A', irq);