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