kernel: Remove kernel profiling bits.
[dragonfly.git] / sys / platform / pc64 / x86_64 / mptable.c
blob141a1d79f927299d937f1b65217ef45f2399cf2f
1 /*
2 * Copyright (c) 1996, by Steve Passe
3 * All rights reserved.
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.
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.
25 * $FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.115.2.15 2003/03/14 21:22:35 jhb Exp $
28 #include "opt_cpu.h"
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>
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>
50 #include <machine/smp.h>
51 #include <machine_base/isa/isa_intr.h>
52 #include <machine_base/apic/apicreg.h>
53 #include <machine_base/apic/apicvar.h>
54 #include <machine/atomic.h>
55 #include <machine/cpufunc.h>
56 #include <machine/cputypes.h>
57 #include <machine_base/apic/lapic.h>
58 #include <machine_base/apic/ioapic.h>
59 #include <machine/psl.h>
60 #include <machine/segments.h>
61 #include <machine/tss.h>
62 #include <machine/specialreg.h>
63 #include <machine/globaldata.h>
64 #include <machine/pmap_inval.h>
65 #include <machine/mptable.h>
67 #include <machine/md_var.h> /* setidt() */
68 #include <machine_base/icu/icu.h> /* IPIs */
69 #include <machine_base/apic/ioapic_abi.h>
70 #include <machine/intr_machdep.h> /* IPIs */
72 extern u_int base_memory;
73 extern u_long ebda_addr;
74 extern int imcr_present;
75 extern int naps;
77 static int force_enable = 0;
78 TUNABLE_INT("hw.lapic_force_enable", &force_enable);
80 #define BIOS_BASE (0xf0000)
81 #define BIOS_BASE2 (0xe0000)
82 #define BIOS_SIZE (0x10000)
83 #define BIOS_COUNT (BIOS_SIZE/4)
85 #define PROCENTRY_FLAG_EN 0x01
86 #define PROCENTRY_FLAG_BP 0x02
87 #define IOAPICENTRY_FLAG_EN 0x01
90 /* MP Floating Pointer Structure */
91 typedef struct MPFPS {
92 char signature[4];
93 u_int32_t pap;
94 u_char length;
95 u_char spec_rev;
96 u_char checksum;
97 u_char mpfb1;
98 u_char mpfb2;
99 u_char mpfb3;
100 u_char mpfb4;
101 u_char mpfb5;
102 } *mpfps_t;
104 /* MP Configuration Table Header */
105 typedef struct MPCTH {
106 char signature[4];
107 u_short base_table_length;
108 u_char spec_rev;
109 u_char checksum;
110 u_char oem_id[8];
111 u_char product_id[12];
112 u_int32_t oem_table_pointer;
113 u_short oem_table_size;
114 u_short entry_count;
115 u_int32_t apic_address;
116 u_short extended_table_length;
117 u_char extended_table_checksum;
118 u_char reserved;
119 } *mpcth_t;
122 typedef struct PROCENTRY {
123 u_char type;
124 u_char apic_id;
125 u_char apic_version;
126 u_char cpu_flags;
127 u_int32_t cpu_signature;
128 u_int32_t feature_flags;
129 u_int32_t reserved1;
130 u_int32_t reserved2;
131 } *proc_entry_ptr;
133 typedef struct BUSENTRY {
134 u_char type;
135 u_char bus_id;
136 char bus_type[6];
137 } *bus_entry_ptr;
139 typedef struct IOAPICENTRY {
140 u_char type;
141 u_char apic_id;
142 u_char apic_version;
143 u_char apic_flags;
144 u_int32_t apic_address;
145 } *io_apic_entry_ptr;
147 typedef struct INTENTRY {
148 u_char type;
149 u_char int_type;
150 u_short int_flags;
151 u_char src_bus_id;
152 u_char src_bus_irq;
153 u_char dst_apic_id;
154 u_char dst_apic_int;
155 } *int_entry_ptr;
157 /* descriptions of MP basetable entries */
158 typedef struct BASETABLE_ENTRY {
159 u_char type;
160 u_char length;
161 char name[16];
162 } basetable_entry;
164 struct mptable_pos {
165 mpfps_t mp_fps;
166 mpcth_t mp_cth;
167 vm_size_t mp_cth_mapsz;
170 #define MPTABLE_POS_USE_DEFAULT(mpt) \
171 ((mpt)->mp_fps->mpfb1 != 0 || (mpt)->mp_cth == NULL)
173 struct mptable_bus {
174 int mb_id;
175 int mb_type; /* MPTABLE_BUS_ */
176 TAILQ_ENTRY(mptable_bus) mb_link;
179 #define MPTABLE_BUS_ISA 0
180 #define MPTABLE_BUS_PCI 1
182 struct mptable_bus_info {
183 TAILQ_HEAD(, mptable_bus) mbi_list;
186 struct mptable_pci_int {
187 int mpci_bus;
188 int mpci_dev;
189 int mpci_pin;
191 int mpci_ioapic_idx;
192 int mpci_ioapic_pin;
193 TAILQ_ENTRY(mptable_pci_int) mpci_link;
196 struct mptable_ioapic {
197 int mio_idx;
198 int mio_apic_id;
199 uint32_t mio_addr;
200 int mio_gsi_base;
201 int mio_npin;
202 TAILQ_ENTRY(mptable_ioapic) mio_link;
205 typedef int (*mptable_iter_func)(void *, const void *, int);
207 static int mptable_iterate_entries(const mpcth_t,
208 mptable_iter_func, void *);
209 static int mptable_search(void);
210 static long mptable_search_sig(u_int32_t target, int count);
211 static int mptable_hyperthread_fixup(cpumask_t, int);
212 static int mptable_map(struct mptable_pos *);
213 static void mptable_unmap(struct mptable_pos *);
214 static void mptable_bus_info_alloc(const mpcth_t,
215 struct mptable_bus_info *);
216 static void mptable_bus_info_free(struct mptable_bus_info *);
218 static int mptable_lapic_probe(struct lapic_enumerator *);
219 static int mptable_lapic_enumerate(struct lapic_enumerator *);
220 static void mptable_lapic_default(void);
222 static int mptable_ioapic_probe(struct ioapic_enumerator *);
223 static void mptable_ioapic_enumerate(struct ioapic_enumerator *);
225 static basetable_entry basetable_entry_types[] =
227 {0, 20, "Processor"},
228 {1, 8, "Bus"},
229 {2, 8, "I/O APIC"},
230 {3, 8, "I/O INT"},
231 {4, 8, "Local INT"}
234 static vm_paddr_t mptable_fps_phyaddr;
235 static int mptable_use_default;
236 static TAILQ_HEAD(mptable_pci_int_list, mptable_pci_int) mptable_pci_int_list =
237 TAILQ_HEAD_INITIALIZER(mptable_pci_int_list);
238 static TAILQ_HEAD(mptable_ioapic_list, mptable_ioapic) mptable_ioapic_list =
239 TAILQ_HEAD_INITIALIZER(mptable_ioapic_list);
241 static void
242 mptable_probe(void)
244 struct mptable_pos mpt;
245 int error;
247 KKASSERT(mptable_fps_phyaddr == 0);
249 mptable_fps_phyaddr = mptable_search();
250 if (mptable_fps_phyaddr == 0)
251 return;
253 error = mptable_map(&mpt);
254 if (error) {
255 mptable_fps_phyaddr = 0;
256 return;
259 if (MPTABLE_POS_USE_DEFAULT(&mpt)) {
260 kprintf("MPTABLE: use default configuration\n");
261 mptable_use_default = 1;
263 if (mpt.mp_fps->mpfb2 & 0x80)
264 imcr_present = 1;
266 mptable_unmap(&mpt);
268 SYSINIT(mptable_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, mptable_probe, 0);
271 * Look for an Intel MP spec table (ie, SMP capable hardware).
273 static int
274 mptable_search(void)
276 long x;
277 u_int32_t target;
279 /* see if EBDA exists */
280 if (ebda_addr != 0) {
281 /* search first 1K of EBDA */
282 target = (u_int32_t)ebda_addr;
283 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
284 return x;
285 } else {
286 /* last 1K of base memory, effective 'top of base' passed in */
287 target = (u_int32_t)(base_memory - 0x400);
288 if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
289 return x;
292 /* search the BIOS */
293 target = (u_int32_t)BIOS_BASE;
294 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
295 return x;
297 /* search the extended BIOS */
298 target = (u_int32_t)BIOS_BASE2;
299 if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0)
300 return x;
302 /* nothing found */
303 return 0;
306 static int
307 mptable_iterate_entries(const mpcth_t cth, mptable_iter_func func, void *arg)
309 int count, total_size;
310 const void *position;
312 KKASSERT(cth->base_table_length >= sizeof(struct MPCTH));
313 total_size = cth->base_table_length - sizeof(struct MPCTH);
314 position = (const uint8_t *)cth + sizeof(struct MPCTH);
315 count = cth->entry_count;
317 while (count--) {
318 int type, error;
320 KKASSERT(total_size >= 0);
321 if (total_size == 0) {
322 kprintf("invalid base MP table, "
323 "entry count and length mismatch\n");
324 return EINVAL;
327 type = *(const uint8_t *)position;
328 switch (type) {
329 case 0: /* processor_entry */
330 case 1: /* bus_entry */
331 case 2: /* io_apic_entry */
332 case 3: /* int_entry */
333 case 4: /* int_entry */
334 break;
335 default:
336 kprintf("unknown base MP table entry type %d\n", type);
337 return EINVAL;
340 if (total_size < basetable_entry_types[type].length) {
341 kprintf("invalid base MP table length, "
342 "does not contain all entries\n");
343 return EINVAL;
345 total_size -= basetable_entry_types[type].length;
347 error = func(arg, position, type);
348 if (error)
349 return error;
351 position = (const uint8_t *)position +
352 basetable_entry_types[type].length;
354 return 0;
358 * look for the MP spec signature
361 /* string defined by the Intel MP Spec as identifying the MP table */
362 #define MP_SIG 0x5f504d5f /* _MP_ */
363 #define NEXT(X) ((X) += 4)
364 static long
365 mptable_search_sig(u_int32_t target, int count)
367 vm_size_t map_size;
368 u_int32_t *addr;
369 int x, ret;
371 KKASSERT(target != 0);
373 map_size = count * sizeof(u_int32_t);
374 addr = pmap_mapdev((vm_paddr_t)target, map_size);
376 ret = 0;
377 for (x = 0; x < count; NEXT(x)) {
378 if (addr[x] == MP_SIG) {
379 /* make array index a byte index */
380 ret = target + (x * sizeof(u_int32_t));
381 break;
385 pmap_unmapdev((vm_offset_t)addr, map_size);
386 return ret;
389 static int processor_entry (const struct PROCENTRY *entry, int cpu);
392 * Check if we should perform a hyperthreading "fix-up" to
393 * enumerate any logical CPU's that aren't already listed
394 * in the table.
396 * XXX: We assume that all of the physical CPUs in the
397 * system have the same number of logical CPUs.
399 * XXX: We assume that APIC ID's are allocated such that
400 * the APIC ID's for a physical processor are aligned
401 * with the number of logical CPU's in the processor.
403 static int
404 mptable_hyperthread_fixup(cpumask_t id_mask, int cpu_count)
406 int i, id, lcpus_max, logical_cpus;
408 if ((cpu_feature & CPUID_HTT) == 0)
409 return 0;
411 lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
412 if (lcpus_max <= 1)
413 return 0;
415 if (cpu_vendor_id == CPU_VENDOR_INTEL) {
417 * INSTRUCTION SET REFERENCE, A-M (#253666)
418 * Page 3-181, Table 3-20
419 * "The nearest power-of-2 integer that is not smaller
420 * than EBX[23:16] is the number of unique initial APIC
421 * IDs reserved for addressing different logical
422 * processors in a physical package."
424 for (i = 0; ; ++i) {
425 if ((1 << i) >= lcpus_max) {
426 lcpus_max = 1 << i;
427 break;
432 KKASSERT(cpu_count != 0);
433 if (cpu_count == lcpus_max) {
434 /* We have nothing to fix */
435 return 0;
436 } else if (cpu_count == 1) {
437 /* XXX this may be incorrect */
438 logical_cpus = lcpus_max;
439 } else {
440 int cur, prev, dist;
443 * Calculate the distances between two nearest
444 * APIC IDs. If all such distances are same,
445 * then it is the number of missing cpus that
446 * we are going to fill later.
448 dist = cur = prev = -1;
449 for (id = 0; id < MAXCPU; ++id) {
450 if (CPUMASK_TESTBIT(id_mask, id) == 0)
451 continue;
453 cur = id;
454 if (prev >= 0) {
455 int new_dist = cur - prev;
457 if (dist < 0)
458 dist = new_dist;
461 * Make sure that all distances
462 * between two nearest APIC IDs
463 * are same.
465 if (dist != new_dist)
466 return 0;
468 prev = cur;
470 if (dist == 1)
471 return 0;
473 /* Must be power of 2 */
474 if (dist & (dist - 1))
475 return 0;
477 /* Can't exceed CPU package capacity */
478 if (dist > lcpus_max)
479 logical_cpus = lcpus_max;
480 else
481 logical_cpus = dist;
485 * For each APIC ID of a CPU that is set in the mask,
486 * scan the other candidate APIC ID's for this
487 * physical processor. If any of those ID's are
488 * already in the table, then kill the fixup.
490 for (id = 0; id < MAXCPU; id++) {
491 if (CPUMASK_TESTBIT(id_mask, id) == 0)
492 continue;
493 /* First, make sure we are on a logical_cpus boundary. */
494 if (id % logical_cpus != 0)
495 return 0;
496 for (i = id + 1; i < id + logical_cpus; i++)
497 if (CPUMASK_TESTBIT(id_mask, i) != 0)
498 return 0;
500 return logical_cpus;
503 static int
504 mptable_map(struct mptable_pos *mpt)
506 mpfps_t fps = NULL;
507 mpcth_t cth = NULL;
508 vm_size_t cth_mapsz = 0;
510 KKASSERT(mptable_fps_phyaddr != 0);
512 bzero(mpt, sizeof(*mpt));
514 fps = pmap_mapdev(mptable_fps_phyaddr, sizeof(*fps));
515 if (fps->pap != 0) {
517 * Map configuration table header to get
518 * the base table size
520 cth = pmap_mapdev(fps->pap, sizeof(*cth));
521 cth_mapsz = cth->base_table_length;
522 pmap_unmapdev((vm_offset_t)cth, sizeof(*cth));
524 if (cth_mapsz < sizeof(*cth)) {
525 kprintf("invalid base MP table length %d\n",
526 (int)cth_mapsz);
527 pmap_unmapdev((vm_offset_t)fps, sizeof(*fps));
528 return EINVAL;
532 * Map the base table
534 cth = pmap_mapdev(fps->pap, cth_mapsz);
537 mpt->mp_fps = fps;
538 mpt->mp_cth = cth;
539 mpt->mp_cth_mapsz = cth_mapsz;
541 return 0;
544 static void
545 mptable_unmap(struct mptable_pos *mpt)
547 if (mpt->mp_cth != NULL) {
548 pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz);
549 mpt->mp_cth = NULL;
550 mpt->mp_cth_mapsz = 0;
552 if (mpt->mp_fps != NULL) {
553 pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps));
554 mpt->mp_fps = NULL;
558 static int
559 processor_entry(const struct PROCENTRY *entry, int cpu)
561 KKASSERT(cpu > 0);
563 /* check for usability */
564 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
565 return 0;
567 /* check for BSP flag */
568 if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
569 lapic_set_cpuid(0, entry->apic_id);
570 return 0; /* its already been counted */
573 /* add another AP to list, if less than max number of CPUs */
574 else if (cpu < MAXCPU) {
575 lapic_set_cpuid(cpu, entry->apic_id);
576 return 1;
579 return 0;
582 static int
583 mptable_bus_info_callback(void *xarg, const void *pos, int type)
585 struct mptable_bus_info *bus_info = xarg;
586 const struct BUSENTRY *ent;
587 struct mptable_bus *bus;
589 if (type != 1)
590 return 0;
592 ent = pos;
593 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
594 if (bus->mb_id == ent->bus_id) {
595 kprintf("mptable_bus_info_alloc: duplicated bus id "
596 "(%d)\n", bus->mb_id);
597 return EINVAL;
601 bus = NULL;
602 if (strncmp(ent->bus_type, "PCI", 3) == 0) {
603 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
604 bus->mb_type = MPTABLE_BUS_PCI;
605 } else if (strncmp(ent->bus_type, "ISA", 3) == 0) {
606 bus = kmalloc(sizeof(*bus), M_TEMP, M_WAITOK | M_ZERO);
607 bus->mb_type = MPTABLE_BUS_ISA;
610 if (bus != NULL) {
611 bus->mb_id = ent->bus_id;
612 TAILQ_INSERT_TAIL(&bus_info->mbi_list, bus, mb_link);
614 return 0;
617 static void
618 mptable_bus_info_alloc(const mpcth_t cth, struct mptable_bus_info *bus_info)
620 int error;
622 bzero(bus_info, sizeof(*bus_info));
623 TAILQ_INIT(&bus_info->mbi_list);
625 error = mptable_iterate_entries(cth, mptable_bus_info_callback, bus_info);
626 if (error)
627 mptable_bus_info_free(bus_info);
630 static void
631 mptable_bus_info_free(struct mptable_bus_info *bus_info)
633 struct mptable_bus *bus;
635 while ((bus = TAILQ_FIRST(&bus_info->mbi_list)) != NULL) {
636 TAILQ_REMOVE(&bus_info->mbi_list, bus, mb_link);
637 kfree(bus, M_TEMP);
641 struct mptable_lapic_cbarg1 {
642 int cpu_count;
643 int ht_fixup;
644 u_int ht_apicid_mask;
647 static int
648 mptable_lapic_pass1_callback(void *xarg, const void *pos, int type)
650 const struct PROCENTRY *ent;
651 struct mptable_lapic_cbarg1 *arg = xarg;
653 if (type != 0)
654 return 0;
655 ent = pos;
657 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
658 return 0;
660 arg->cpu_count++;
661 if (ent->apic_id < 64) {
662 arg->ht_apicid_mask |= 1UL << ent->apic_id;
663 } else if (arg->ht_fixup) {
664 kprintf("MPTABLE: lapic id > 64, disable HTT fixup\n");
665 arg->ht_fixup = 0;
667 return 0;
670 struct mptable_lapic_cbarg2 {
671 int cpu;
672 int logical_cpus;
673 int found_bsp;
676 static int
677 mptable_lapic_pass2_callback(void *xarg, const void *pos, int type)
679 const struct PROCENTRY *ent;
680 struct mptable_lapic_cbarg2 *arg = xarg;
682 if (type != 0)
683 return 0;
684 ent = pos;
686 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
687 KKASSERT(!arg->found_bsp);
688 arg->found_bsp = 1;
691 if (processor_entry(ent, arg->cpu))
692 arg->cpu++;
694 if (arg->logical_cpus) {
695 struct PROCENTRY proc;
696 int i;
699 * Create fake mptable processor entries
700 * and feed them to processor_entry() to
701 * enumerate the logical CPUs.
703 bzero(&proc, sizeof(proc));
704 proc.type = 0;
705 proc.cpu_flags = (force_enable) ? PROCENTRY_FLAG_EN : ent->cpu_flags;
706 proc.apic_id = ent->apic_id;
708 for (i = 1; i < arg->logical_cpus; i++) {
709 proc.apic_id++;
710 processor_entry(&proc, arg->cpu);
711 arg->cpu++;
714 return 0;
717 static void
718 mptable_lapic_default(void)
720 int ap_apicid, bsp_apicid;
722 naps = 1; /* exclude BSP */
724 /* Map local apic before the id field is accessed */
725 lapic_map(DEFAULT_APIC_BASE);
727 bsp_apicid = LAPIC_READID;
728 ap_apicid = (bsp_apicid == 0) ? 1 : 0;
730 /* BSP */
731 lapic_set_cpuid(0, bsp_apicid);
732 /* one and only AP */
733 lapic_set_cpuid(1, ap_apicid);
737 * Configure:
738 * naps
739 * APIC ID <-> CPU ID mappings
741 static int
742 mptable_lapic_enumerate(struct lapic_enumerator *e)
744 struct mptable_pos mpt;
745 struct mptable_lapic_cbarg1 arg1;
746 struct mptable_lapic_cbarg2 arg2;
747 mpcth_t cth;
748 int error, logical_cpus = 0;
749 vm_paddr_t lapic_addr;
751 if (mptable_use_default) {
752 mptable_lapic_default();
753 return 0;
756 error = mptable_map(&mpt);
757 if (error)
758 panic("mptable_lapic_enumerate mptable_map failed");
759 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
761 cth = mpt.mp_cth;
763 /* Save local apic address */
764 lapic_addr = cth->apic_address;
765 KKASSERT(lapic_addr != 0);
768 * Find out how many CPUs do we have
770 bzero(&arg1, sizeof(arg1));
771 arg1.ht_fixup = 1; /* Apply ht fixup by default */
773 error = mptable_iterate_entries(cth,
774 mptable_lapic_pass1_callback, &arg1);
775 if (error)
776 panic("mptable_iterate_entries(lapic_pass1) failed");
777 KKASSERT(arg1.cpu_count != 0);
779 /* See if we need to fixup HT logical CPUs. */
781 * XXX fixup for cpus >= 32 ? XXX
783 if (arg1.ht_fixup) {
784 cpumask_t mask;
786 CPUMASK_ASSZERO(mask);
787 mask.ary[0] = arg1.ht_apicid_mask;
788 logical_cpus = mptable_hyperthread_fixup(mask, arg1.cpu_count);
789 if (logical_cpus != 0)
790 arg1.cpu_count *= logical_cpus;
792 naps = arg1.cpu_count - 1; /* subtract the BSP */
795 * Link logical CPU id to local apic id
797 bzero(&arg2, sizeof(arg2));
798 arg2.cpu = 1;
799 arg2.logical_cpus = logical_cpus;
801 error = mptable_iterate_entries(cth,
802 mptable_lapic_pass2_callback, &arg2);
803 if (error)
804 panic("mptable_iterate_entries(lapic_pass2) failed");
805 KKASSERT(arg2.found_bsp);
807 /* Map local apic */
808 lapic_map(lapic_addr);
810 mptable_unmap(&mpt);
812 return 0;
815 struct mptable_lapic_probe_cbarg {
816 int cpu_count;
817 int found_bsp;
820 static int
821 mptable_lapic_probe_callback(void *xarg, const void *pos, int type)
823 const struct PROCENTRY *ent;
824 struct mptable_lapic_probe_cbarg *arg = xarg;
826 if (type != 0)
827 return 0;
828 ent = pos;
830 if ((ent->cpu_flags & PROCENTRY_FLAG_EN) == 0)
831 return 0;
832 arg->cpu_count++;
834 if (ent->apic_id == APICID_MAX) {
835 kprintf("MPTABLE: invalid LAPIC apic id %d\n",
836 ent->apic_id);
837 return EINVAL;
840 if (ent->cpu_flags & PROCENTRY_FLAG_BP) {
841 if (arg->found_bsp) {
842 kprintf("more than one BSP in base MP table\n");
843 return EINVAL;
845 arg->found_bsp = 1;
847 return 0;
850 static int
851 mptable_lapic_probe(struct lapic_enumerator *e)
853 struct mptable_pos mpt;
854 struct mptable_lapic_probe_cbarg arg;
855 mpcth_t cth;
856 int error;
858 if (mptable_fps_phyaddr == 0)
859 return ENXIO;
861 if (mptable_use_default)
862 return 0;
864 error = mptable_map(&mpt);
865 if (error)
866 return error;
867 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
869 error = EINVAL;
870 cth = mpt.mp_cth;
872 if (cth->apic_address == 0)
873 goto done;
875 bzero(&arg, sizeof(arg));
876 error = mptable_iterate_entries(cth,
877 mptable_lapic_probe_callback, &arg);
878 if (!error) {
879 if (arg.cpu_count == 0) {
880 kprintf("MP table contains no processor entries\n");
881 error = EINVAL;
882 } else if (!arg.found_bsp) {
883 kprintf("MP table does not contains BSP entry\n");
884 error = EINVAL;
887 done:
888 mptable_unmap(&mpt);
889 return error;
892 static struct lapic_enumerator mptable_lapic_enumerator = {
893 .lapic_prio = LAPIC_ENUM_PRIO_MPTABLE,
894 .lapic_probe = mptable_lapic_probe,
895 .lapic_enumerate = mptable_lapic_enumerate
898 static void
899 mptable_lapic_enum_register(void)
901 lapic_enumerator_register(&mptable_lapic_enumerator);
903 SYSINIT(mptable_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
904 mptable_lapic_enum_register, 0);
906 static int
907 mptable_ioapic_list_callback(void *xarg, const void *pos, int type)
909 const struct IOAPICENTRY *ent;
910 struct mptable_ioapic *nioapic, *ioapic;
912 if (type != 2)
913 return 0;
914 ent = pos;
916 if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0)
917 return 0;
919 if (ent->apic_address == 0) {
920 kprintf("mptable_ioapic_create_list: zero IOAPIC addr\n");
921 return EINVAL;
923 if (ent->apic_id == APICID_MAX) {
924 kprintf("mptable_ioapic_create_list: "
925 "invalid IOAPIC apic id %d\n", ent->apic_id);
926 return EINVAL;
929 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
930 if (ioapic->mio_apic_id == ent->apic_id) {
931 kprintf("mptable_ioapic_create_list: duplicated "
932 "apic id %d\n", ioapic->mio_apic_id);
933 return EINVAL;
935 if (ioapic->mio_addr == ent->apic_address) {
936 kprintf("mptable_ioapic_create_list: overlapped "
937 "IOAPIC addr 0x%08x", ioapic->mio_addr);
938 return EINVAL;
942 nioapic = kmalloc(sizeof(*nioapic), M_DEVBUF, M_WAITOK | M_ZERO);
943 nioapic->mio_apic_id = ent->apic_id;
944 nioapic->mio_addr = ent->apic_address;
947 * Create IOAPIC list in ascending order of APIC ID
949 TAILQ_FOREACH_REVERSE(ioapic, &mptable_ioapic_list,
950 mptable_ioapic_list, mio_link) {
951 if (nioapic->mio_apic_id > ioapic->mio_apic_id) {
952 TAILQ_INSERT_AFTER(&mptable_ioapic_list,
953 ioapic, nioapic, mio_link);
954 break;
957 if (ioapic == NULL)
958 TAILQ_INSERT_HEAD(&mptable_ioapic_list, nioapic, mio_link);
960 return 0;
963 static void
964 mptable_ioapic_create_list(void)
966 struct mptable_ioapic *ioapic;
967 struct mptable_pos mpt;
968 int idx, error;
970 if (mptable_fps_phyaddr == 0)
971 return;
973 if (mptable_use_default) {
974 ioapic = kmalloc(sizeof(*ioapic), M_DEVBUF, M_WAITOK | M_ZERO);
975 ioapic->mio_idx = 0;
976 ioapic->mio_apic_id = 0; /* NOTE: any value is ok here */
977 ioapic->mio_addr = 0xfec00000; /* XXX magic number */
979 TAILQ_INSERT_HEAD(&mptable_ioapic_list, ioapic, mio_link);
980 return;
983 error = mptable_map(&mpt);
984 if (error)
985 panic("mptable_ioapic_create_list: mptable_map failed");
986 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
988 error = mptable_iterate_entries(mpt.mp_cth,
989 mptable_ioapic_list_callback, NULL);
990 if (error) {
991 while ((ioapic = TAILQ_FIRST(&mptable_ioapic_list)) != NULL) {
992 TAILQ_REMOVE(&mptable_ioapic_list, ioapic, mio_link);
993 kfree(ioapic, M_DEVBUF);
995 goto done;
999 * Assign index number for each IOAPIC
1001 idx = 0;
1002 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1003 ioapic->mio_idx = idx;
1004 ++idx;
1006 done:
1007 mptable_unmap(&mpt);
1009 SYSINIT(mptable_ioapic_list, SI_BOOT2_PRESMP, SI_ORDER_SECOND,
1010 mptable_ioapic_create_list, 0);
1012 static int
1013 mptable_pci_int_callback(void *xarg, const void *pos, int type)
1015 const struct mptable_bus_info *bus_info = xarg;
1016 const struct mptable_ioapic *ioapic;
1017 const struct mptable_bus *bus;
1018 struct mptable_pci_int *pci_int;
1019 const struct INTENTRY *ent;
1020 int pci_pin, pci_dev;
1022 if (type != 3)
1023 return 0;
1024 ent = pos;
1026 if (ent->int_type != 0)
1027 return 0;
1029 TAILQ_FOREACH(bus, &bus_info->mbi_list, mb_link) {
1030 if (bus->mb_type == MPTABLE_BUS_PCI &&
1031 bus->mb_id == ent->src_bus_id)
1032 break;
1034 if (bus == NULL)
1035 return 0;
1037 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1038 if (ioapic->mio_apic_id == ent->dst_apic_id)
1039 break;
1041 if (ioapic == NULL) {
1042 if (bootverbose) {
1043 static char intdis_warned[64];
1044 int apic_id = ent->dst_apic_id;
1045 int warn = 0;
1047 if (apic_id < 0 || apic_id >= sizeof(intdis_warned)) {
1048 warn = 1;
1049 } else if (intdis_warned[apic_id] == 0) {
1050 intdis_warned[apic_id] = 1;
1051 warn = 1;
1053 if (warn) {
1054 kprintf("MPTABLE: warning PCI int dst apic id "
1055 "%d does not exist\n", apic_id);
1058 return 0;
1061 pci_pin = ent->src_bus_irq & 0x3;
1062 pci_dev = (ent->src_bus_irq >> 2) & 0x1f;
1064 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1065 if (pci_int->mpci_bus == ent->src_bus_id &&
1066 pci_int->mpci_dev == pci_dev &&
1067 pci_int->mpci_pin == pci_pin) {
1068 if (pci_int->mpci_ioapic_idx == ioapic->mio_idx &&
1069 pci_int->mpci_ioapic_pin == ent->dst_apic_int) {
1070 kprintf("MPTABLE: warning duplicated "
1071 "PCI int entry for "
1072 "bus %d, dev %d, pin %d\n",
1073 pci_int->mpci_bus,
1074 pci_int->mpci_dev,
1075 pci_int->mpci_pin);
1076 return 0;
1077 } else {
1078 kprintf("mptable_pci_int_register: "
1079 "conflict PCI int entry for "
1080 "bus %d, dev %d, pin %d, "
1081 "IOAPIC %d.%d -> %d.%d\n",
1082 pci_int->mpci_bus,
1083 pci_int->mpci_dev,
1084 pci_int->mpci_pin,
1085 pci_int->mpci_ioapic_idx,
1086 pci_int->mpci_ioapic_pin,
1087 ioapic->mio_idx,
1088 ent->dst_apic_int);
1089 return EINVAL;
1094 pci_int = kmalloc(sizeof(*pci_int), M_DEVBUF, M_WAITOK | M_ZERO);
1096 pci_int->mpci_bus = ent->src_bus_id;
1097 pci_int->mpci_dev = pci_dev;
1098 pci_int->mpci_pin = pci_pin;
1099 pci_int->mpci_ioapic_idx = ioapic->mio_idx;
1100 pci_int->mpci_ioapic_pin = ent->dst_apic_int;
1102 TAILQ_INSERT_TAIL(&mptable_pci_int_list, pci_int, mpci_link);
1104 return 0;
1107 static void
1108 mptable_pci_int_register(void)
1110 struct mptable_bus_info bus_info;
1111 const struct mptable_bus *bus;
1112 struct mptable_pci_int *pci_int;
1113 struct mptable_pos mpt;
1114 int error, force_pci0, npcibus;
1115 mpcth_t cth;
1117 if (mptable_fps_phyaddr == 0)
1118 return;
1120 if (mptable_use_default)
1121 return;
1123 if (TAILQ_EMPTY(&mptable_ioapic_list))
1124 return;
1126 error = mptable_map(&mpt);
1127 if (error)
1128 panic("mptable_pci_int_register: mptable_map failed");
1129 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1131 cth = mpt.mp_cth;
1133 mptable_bus_info_alloc(cth, &bus_info);
1134 if (TAILQ_EMPTY(&bus_info.mbi_list))
1135 goto done;
1137 force_pci0 = 0;
1138 npcibus = 0;
1139 TAILQ_FOREACH(bus, &bus_info.mbi_list, mb_link) {
1140 if (bus->mb_type == MPTABLE_BUS_PCI)
1141 ++npcibus;
1143 if (npcibus == 0) {
1144 mptable_bus_info_free(&bus_info);
1145 goto done;
1146 } else if (npcibus == 1) {
1147 force_pci0 = 1;
1150 error = mptable_iterate_entries(cth,
1151 mptable_pci_int_callback, &bus_info);
1153 mptable_bus_info_free(&bus_info);
1155 if (error) {
1156 while ((pci_int = TAILQ_FIRST(&mptable_pci_int_list)) != NULL) {
1157 TAILQ_REMOVE(&mptable_pci_int_list, pci_int, mpci_link);
1158 kfree(pci_int, M_DEVBUF);
1160 goto done;
1163 if (force_pci0) {
1164 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link)
1165 pci_int->mpci_bus = 0;
1167 done:
1168 mptable_unmap(&mpt);
1170 SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1171 mptable_pci_int_register, 0);
1173 struct mptable_ioapic_probe_cbarg {
1174 const struct mptable_bus_info *bus_info;
1177 static int
1178 mptable_ioapic_probe_callback(void *xarg, const void *pos, int type)
1180 struct mptable_ioapic_probe_cbarg *arg = xarg;
1181 const struct mptable_ioapic *ioapic;
1182 const struct mptable_bus *bus;
1183 const struct INTENTRY *ent;
1185 if (type != 3)
1186 return 0;
1187 ent = pos;
1189 if (ent->int_type != 0)
1190 return 0;
1192 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1193 if (bus->mb_type == MPTABLE_BUS_ISA &&
1194 bus->mb_id == ent->src_bus_id)
1195 break;
1197 if (bus == NULL)
1198 return 0;
1200 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1201 if (ioapic->mio_apic_id == ent->dst_apic_id)
1202 break;
1204 if (ioapic == NULL) {
1205 kprintf("MPTABLE: warning ISA int dst apic id %d "
1206 "does not exist\n", ent->dst_apic_id);
1207 return 0;
1210 /* XXX magic number */
1211 if (ent->src_bus_irq >= ISA_IRQ_CNT) {
1212 kprintf("mptable_ioapic_probe: invalid ISA irq (%d)\n",
1213 ent->src_bus_irq);
1214 return EINVAL;
1216 return 0;
1219 static int
1220 mptable_ioapic_probe(struct ioapic_enumerator *e)
1222 struct mptable_ioapic_probe_cbarg arg;
1223 struct mptable_bus_info bus_info;
1224 struct mptable_pos mpt;
1225 mpcth_t cth;
1226 int error;
1228 if (mptable_fps_phyaddr == 0)
1229 return ENXIO;
1231 if (mptable_use_default)
1232 return 0;
1234 if (TAILQ_EMPTY(&mptable_ioapic_list))
1235 return ENXIO;
1237 error = mptable_map(&mpt);
1238 if (error)
1239 panic("mptable_ioapic_probe: mptable_map failed");
1240 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1242 cth = mpt.mp_cth;
1244 mptable_bus_info_alloc(cth, &bus_info);
1246 bzero(&arg, sizeof(arg));
1247 arg.bus_info = &bus_info;
1249 error = mptable_iterate_entries(cth,
1250 mptable_ioapic_probe_callback, &arg);
1252 mptable_bus_info_free(&bus_info);
1253 mptable_unmap(&mpt);
1255 return error;
1258 struct mptable_ioapic_int_cbarg {
1259 const struct mptable_bus_info *bus_info;
1260 int ioapic_nint;
1263 static int
1264 mptable_ioapic_int_callback(void *xarg, const void *pos, int type)
1266 struct mptable_ioapic_int_cbarg *arg = xarg;
1267 const struct mptable_ioapic *ioapic;
1268 const struct mptable_bus *bus;
1269 const struct INTENTRY *ent;
1270 int gsi;
1272 if (type != 3)
1273 return 0;
1275 arg->ioapic_nint++;
1277 ent = pos;
1278 if (ent->int_type != 0)
1279 return 0;
1281 TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) {
1282 if (bus->mb_type == MPTABLE_BUS_ISA &&
1283 bus->mb_id == ent->src_bus_id)
1284 break;
1286 if (bus == NULL)
1287 return 0;
1289 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1290 if (ioapic->mio_apic_id == ent->dst_apic_id)
1291 break;
1293 if (ioapic == NULL) {
1294 kprintf("MPTABLE: warning ISA int dst apic id %d "
1295 "does not exist\n", ent->dst_apic_id);
1296 return 0;
1299 if (ent->dst_apic_int >= ioapic->mio_npin) {
1300 panic("mptable_ioapic_enumerate: invalid I/O APIC "
1301 "pin %d, should be < %d",
1302 ent->dst_apic_int, ioapic->mio_npin);
1304 gsi = ioapic->mio_gsi_base + ent->dst_apic_int;
1306 if (ent->src_bus_irq != gsi) {
1307 if (bootverbose) {
1308 kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n",
1309 ent->src_bus_irq, gsi);
1311 ioapic_intsrc(ent->src_bus_irq, gsi,
1312 INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1314 return 0;
1317 static void
1318 mptable_ioapic_enumerate(struct ioapic_enumerator *e)
1320 struct mptable_bus_info bus_info;
1321 struct mptable_ioapic *ioapic;
1322 struct mptable_pos mpt;
1323 mpcth_t cth;
1324 int error;
1326 KKASSERT(mptable_fps_phyaddr != 0);
1327 KKASSERT(!TAILQ_EMPTY(&mptable_ioapic_list));
1329 TAILQ_FOREACH(ioapic, &mptable_ioapic_list, mio_link) {
1330 const struct mptable_ioapic *prev_ioapic;
1331 uint32_t ver;
1332 void *addr;
1334 addr = ioapic_map(ioapic->mio_addr);
1336 ver = ioapic_read(addr, IOAPIC_VER);
1337 ioapic->mio_npin = ((ver & IOART_VER_MAXREDIR)
1338 >> MAXREDIRSHIFT) + 1;
1340 prev_ioapic = TAILQ_PREV(ioapic,
1341 mptable_ioapic_list, mio_link);
1342 if (prev_ioapic == NULL) {
1343 ioapic->mio_gsi_base = 0;
1344 } else {
1345 ioapic->mio_gsi_base =
1346 prev_ioapic->mio_gsi_base +
1347 prev_ioapic->mio_npin;
1349 ioapic_add(addr, ioapic->mio_gsi_base, ioapic->mio_npin);
1351 if (bootverbose) {
1352 kprintf("MPTABLE: IOAPIC addr 0x%08x, "
1353 "apic id %d, idx %d, gsi base %d, npin %d\n",
1354 ioapic->mio_addr,
1355 ioapic->mio_apic_id,
1356 ioapic->mio_idx,
1357 ioapic->mio_gsi_base,
1358 ioapic->mio_npin);
1362 if (mptable_use_default) {
1363 if (bootverbose)
1364 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n");
1365 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1366 return;
1369 error = mptable_map(&mpt);
1370 if (error)
1371 panic("mptable_ioapic_probe: mptable_map failed");
1372 KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt));
1374 cth = mpt.mp_cth;
1376 mptable_bus_info_alloc(cth, &bus_info);
1378 if (TAILQ_EMPTY(&bus_info.mbi_list)) {
1379 if (bootverbose)
1380 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n");
1381 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
1382 } else {
1383 struct mptable_ioapic_int_cbarg arg;
1385 bzero(&arg, sizeof(arg));
1386 arg.bus_info = &bus_info;
1388 error = mptable_iterate_entries(cth,
1389 mptable_ioapic_int_callback, &arg);
1390 if (error)
1391 panic("mptable_ioapic_int failed");
1393 if (arg.ioapic_nint == 0) {
1394 if (bootverbose) {
1395 kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 "
1396 "(no int)\n");
1398 ioapic_intsrc(0, 2, INTR_TRIGGER_EDGE,
1399 INTR_POLARITY_HIGH);
1403 mptable_bus_info_free(&bus_info);
1405 mptable_unmap(&mpt);
1408 static struct ioapic_enumerator mptable_ioapic_enumerator = {
1409 .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE,
1410 .ioapic_probe = mptable_ioapic_probe,
1411 .ioapic_enumerate = mptable_ioapic_enumerate
1414 static void
1415 mptable_ioapic_enum_register(void)
1417 ioapic_enumerator_register(&mptable_ioapic_enumerator);
1419 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
1420 mptable_ioapic_enum_register, 0);
1422 void
1423 mptable_pci_int_dump(void)
1425 const struct mptable_pci_int *pci_int;
1427 if (!bootverbose)
1428 return;
1430 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1431 kprintf("MPTABLE: %d:%d INT%c -> IOAPIC %d.%d\n",
1432 pci_int->mpci_bus,
1433 pci_int->mpci_dev,
1434 pci_int->mpci_pin + 'A',
1435 pci_int->mpci_ioapic_idx,
1436 pci_int->mpci_ioapic_pin);
1441 mptable_pci_int_route(int bus, int dev, int pin, int intline)
1443 const struct mptable_pci_int *pci_int;
1444 int irq = -1;
1446 KKASSERT(pin >= 1);
1447 --pin; /* zero based */
1449 TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
1450 if (pci_int->mpci_bus == bus &&
1451 pci_int->mpci_dev == dev &&
1452 pci_int->mpci_pin == pin)
1453 break;
1455 if (pci_int != NULL) {
1456 int gsi;
1458 gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
1459 pci_int->mpci_ioapic_pin);
1460 if (gsi >= 0) {
1461 irq = machintr_legacy_intr_find_bygsi(gsi,
1462 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1466 if (irq < 0 && intline >= 0) {
1467 kprintf("MPTABLE: fixed interrupt routing "
1468 "for %d:%d INT%c\n", bus, dev, pin + 'A');
1469 irq = machintr_legacy_intr_find(intline,
1470 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
1473 if (irq >= 0 && bootverbose) {
1474 kprintf("MPTABLE: %d:%d INT%c routed to irq %d\n",
1475 bus, dev, pin + 'A', irq);
1477 return irq;