15db2f26eSSascha Wildner /*
25db2f26eSSascha Wildner * Copyright (c) 2009 The DragonFly Project. All rights reserved.
35db2f26eSSascha Wildner *
45db2f26eSSascha Wildner * This code is derived from software contributed to The DragonFly Project
55db2f26eSSascha Wildner * by Sepherosa Ziehau <sepherosa@gmail.com>
65db2f26eSSascha Wildner *
75db2f26eSSascha Wildner * Redistribution and use in source and binary forms, with or without
85db2f26eSSascha Wildner * modification, are permitted provided that the following conditions
95db2f26eSSascha Wildner * are met:
105db2f26eSSascha Wildner *
115db2f26eSSascha Wildner * 1. Redistributions of source code must retain the above copyright
125db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer.
135db2f26eSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
145db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer in
155db2f26eSSascha Wildner * the documentation and/or other materials provided with the
165db2f26eSSascha Wildner * distribution.
175db2f26eSSascha Wildner * 3. Neither the name of The DragonFly Project nor the names of its
185db2f26eSSascha Wildner * contributors may be used to endorse or promote products derived
195db2f26eSSascha Wildner * from this software without specific, prior written permission.
205db2f26eSSascha Wildner *
215db2f26eSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225db2f26eSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235db2f26eSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
245db2f26eSSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
255db2f26eSSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
265db2f26eSSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
275db2f26eSSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
285db2f26eSSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
295db2f26eSSascha Wildner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
305db2f26eSSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
315db2f26eSSascha Wildner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325db2f26eSSascha Wildner * SUCH DAMAGE.
335db2f26eSSascha Wildner */
345db2f26eSSascha Wildner
355db2f26eSSascha Wildner #include <sys/param.h>
365db2f26eSSascha Wildner #include <sys/bus.h>
375db2f26eSSascha Wildner #include <sys/kernel.h>
385db2f26eSSascha Wildner #include <sys/systm.h>
395db2f26eSSascha Wildner
405db2f26eSSascha Wildner #include <machine_base/isa/isa_intr.h>
415db2f26eSSascha Wildner #include <machine_base/apic/lapic.h>
425db2f26eSSascha Wildner #include <machine_base/apic/ioapic.h>
435db2f26eSSascha Wildner #include <machine_base/apic/apicvar.h>
448005c0c8SSepherosa Ziehau #include <machine_base/acpica/acpi_md_cpu.h>
45f89b4a45SSepherosa Ziehau #include <machine/specialreg.h>
465db2f26eSSascha Wildner
478d3ef488SSascha Wildner #include <contrib/dev/acpica/source/include/acpi.h>
488d3ef488SSascha Wildner
495db2f26eSSascha Wildner #include "acpi_sdt_var.h"
505db2f26eSSascha Wildner #include "acpi_sci_var.h"
515db2f26eSSascha Wildner
525db2f26eSSascha Wildner extern int naps;
535db2f26eSSascha Wildner
545db2f26eSSascha Wildner #define MADT_VPRINTF(fmt, arg...) \
555db2f26eSSascha Wildner do { \
565db2f26eSSascha Wildner if (bootverbose) \
575db2f26eSSascha Wildner kprintf("ACPI MADT: " fmt , ##arg); \
585db2f26eSSascha Wildner } while (0)
595db2f26eSSascha Wildner
605db2f26eSSascha Wildner #define MADT_INT_BUS_ISA 0
615db2f26eSSascha Wildner
625db2f26eSSascha Wildner typedef int (*madt_iter_t)(void *,
638d3ef488SSascha Wildner const ACPI_SUBTABLE_HEADER *);
645db2f26eSSascha Wildner
655db2f26eSSascha Wildner static int madt_check(vm_paddr_t);
668d3ef488SSascha Wildner static int madt_iterate_entries(ACPI_TABLE_MADT *,
675db2f26eSSascha Wildner madt_iter_t, void *);
685db2f26eSSascha Wildner
695db2f26eSSascha Wildner static vm_paddr_t madt_lapic_pass1(void);
705db2f26eSSascha Wildner static int madt_lapic_pass2(int);
715db2f26eSSascha Wildner
725db2f26eSSascha Wildner static int madt_lapic_enumerate(struct lapic_enumerator *);
735db2f26eSSascha Wildner static int madt_lapic_probe(struct lapic_enumerator *);
745db2f26eSSascha Wildner
755db2f26eSSascha Wildner static void madt_ioapic_enumerate(
765db2f26eSSascha Wildner struct ioapic_enumerator *);
775db2f26eSSascha Wildner static int madt_ioapic_probe(struct ioapic_enumerator *);
785db2f26eSSascha Wildner
795db2f26eSSascha Wildner static vm_paddr_t madt_phyaddr;
805db2f26eSSascha Wildner
8162571e42SSepherosa Ziehau static boolean_t madt_use_x2apic = FALSE;
8262571e42SSepherosa Ziehau
838005c0c8SSepherosa Ziehau u_int cpu_id_to_acpi_id[NAPICID];
848005c0c8SSepherosa Ziehau
855db2f26eSSascha Wildner static void
madt_probe(void)865db2f26eSSascha Wildner madt_probe(void)
875db2f26eSSascha Wildner {
885db2f26eSSascha Wildner vm_paddr_t madt_paddr;
898005c0c8SSepherosa Ziehau int i;
908005c0c8SSepherosa Ziehau
918005c0c8SSepherosa Ziehau for (i = 0; i < NAPICID; ++i)
928005c0c8SSepherosa Ziehau CPUID_TO_ACPIID(i) = (u_int)-1;
935db2f26eSSascha Wildner
945db2f26eSSascha Wildner KKASSERT(madt_phyaddr == 0);
955db2f26eSSascha Wildner
968d3ef488SSascha Wildner madt_paddr = sdt_search(ACPI_SIG_MADT);
975db2f26eSSascha Wildner if (madt_paddr == 0) {
985db2f26eSSascha Wildner kprintf("madt_probe: can't locate MADT\n");
995db2f26eSSascha Wildner return;
1005db2f26eSSascha Wildner }
1015db2f26eSSascha Wildner
1025db2f26eSSascha Wildner /* Preliminary checks */
1035db2f26eSSascha Wildner if (madt_check(madt_paddr)) {
1045db2f26eSSascha Wildner kprintf("madt_probe: madt_check failed\n");
1055db2f26eSSascha Wildner return;
1065db2f26eSSascha Wildner }
1075db2f26eSSascha Wildner
1085db2f26eSSascha Wildner madt_phyaddr = madt_paddr;
1095db2f26eSSascha Wildner }
1105db2f26eSSascha Wildner SYSINIT(madt_probe, SI_BOOT2_PRESMP, SI_ORDER_SECOND, madt_probe, 0);
1115db2f26eSSascha Wildner
1125db2f26eSSascha Wildner static int
madt_check(vm_paddr_t madt_paddr)1135db2f26eSSascha Wildner madt_check(vm_paddr_t madt_paddr)
1145db2f26eSSascha Wildner {
1158d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
1165db2f26eSSascha Wildner int error = 0;
1175db2f26eSSascha Wildner
1185db2f26eSSascha Wildner KKASSERT(madt_paddr != 0);
1195db2f26eSSascha Wildner
1205db2f26eSSascha Wildner madt = sdt_sdth_map(madt_paddr);
1215db2f26eSSascha Wildner KKASSERT(madt != NULL);
1225db2f26eSSascha Wildner
1235db2f26eSSascha Wildner /*
124*abba2c19SSascha Wildner * MADT in ACPI specification 1.0 - 6.4
1255db2f26eSSascha Wildner */
126*abba2c19SSascha Wildner if (madt->Header.Revision < 1 || madt->Header.Revision > 5) {
127fa90647aSSepherosa Ziehau kprintf("madt_check: unknown MADT revision %d\n",
1288d3ef488SSascha Wildner madt->Header.Revision);
1295db2f26eSSascha Wildner }
1305db2f26eSSascha Wildner
1318d3ef488SSascha Wildner if (madt->Header.Length < sizeof(*madt)) {
1325db2f26eSSascha Wildner kprintf("madt_check: invalid MADT length %u\n",
1338d3ef488SSascha Wildner madt->Header.Length);
1345db2f26eSSascha Wildner error = EINVAL;
1355db2f26eSSascha Wildner goto back;
1365db2f26eSSascha Wildner }
1375db2f26eSSascha Wildner back:
1388d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
1395db2f26eSSascha Wildner return error;
1405db2f26eSSascha Wildner }
1415db2f26eSSascha Wildner
1425db2f26eSSascha Wildner static int
madt_iterate_entries(ACPI_TABLE_MADT * madt,madt_iter_t func,void * arg)1438d3ef488SSascha Wildner madt_iterate_entries(ACPI_TABLE_MADT *madt, madt_iter_t func, void *arg)
1445db2f26eSSascha Wildner {
1455db2f26eSSascha Wildner int size, cur, error;
1465db2f26eSSascha Wildner
1478d3ef488SSascha Wildner size = madt->Header.Length - sizeof(*madt);
1485db2f26eSSascha Wildner cur = 0;
1495db2f26eSSascha Wildner error = 0;
1505db2f26eSSascha Wildner
1518d3ef488SSascha Wildner while (size - cur > sizeof(ACPI_SUBTABLE_HEADER)) {
1528d3ef488SSascha Wildner const ACPI_SUBTABLE_HEADER *ent;
1535db2f26eSSascha Wildner
1548d3ef488SSascha Wildner ent = (const ACPI_SUBTABLE_HEADER *)
1558d3ef488SSascha Wildner ((char *)madt + sizeof(*madt) + cur);
1568d3ef488SSascha Wildner if (ent->Length < sizeof(*ent)) {
1575db2f26eSSascha Wildner kprintf("madt_iterate_entries: invalid MADT "
1588d3ef488SSascha Wildner "entry len %d\n", ent->Length);
1595db2f26eSSascha Wildner error = EINVAL;
1605db2f26eSSascha Wildner break;
1615db2f26eSSascha Wildner }
1628d3ef488SSascha Wildner if (ent->Length > (size - cur)) {
1635db2f26eSSascha Wildner kprintf("madt_iterate_entries: invalid MADT "
1648d3ef488SSascha Wildner "entry len %d, > table length\n", ent->Length);
1655db2f26eSSascha Wildner error = EINVAL;
1665db2f26eSSascha Wildner break;
1675db2f26eSSascha Wildner }
1685db2f26eSSascha Wildner
1698d3ef488SSascha Wildner cur += ent->Length;
1705db2f26eSSascha Wildner
1715db2f26eSSascha Wildner /*
1725db2f26eSSascha Wildner * Only Local APIC, I/O APIC and Interrupt Source Override
173df362704SSepherosa Ziehau * are defined in ACPI specification 1.0 - 5.0
1745db2f26eSSascha Wildner */
1758d3ef488SSascha Wildner switch (ent->Type) {
1768d3ef488SSascha Wildner case ACPI_MADT_TYPE_LOCAL_APIC:
1778d3ef488SSascha Wildner if (ent->Length < sizeof(ACPI_MADT_LOCAL_APIC)) {
1785db2f26eSSascha Wildner kprintf("madt_iterate_entries: invalid MADT "
1798d3ef488SSascha Wildner "lapic entry len %d\n", ent->Length);
1805db2f26eSSascha Wildner error = EINVAL;
1815db2f26eSSascha Wildner }
1825db2f26eSSascha Wildner break;
1835db2f26eSSascha Wildner
18462571e42SSepherosa Ziehau case ACPI_MADT_TYPE_LOCAL_X2APIC:
18562571e42SSepherosa Ziehau if (ent->Length < sizeof(ACPI_MADT_LOCAL_X2APIC)) {
18662571e42SSepherosa Ziehau kprintf("madt_iterate_entries: invalid MADT "
18762571e42SSepherosa Ziehau "x2apic entry len %d\n", ent->Length);
18862571e42SSepherosa Ziehau error = EINVAL;
18962571e42SSepherosa Ziehau }
19062571e42SSepherosa Ziehau break;
19162571e42SSepherosa Ziehau
1928d3ef488SSascha Wildner case ACPI_MADT_TYPE_IO_APIC:
1938d3ef488SSascha Wildner if (ent->Length < sizeof(ACPI_MADT_IO_APIC)) {
1945db2f26eSSascha Wildner kprintf("madt_iterate_entries: invalid MADT "
1958d3ef488SSascha Wildner "ioapic entry len %d\n", ent->Length);
1965db2f26eSSascha Wildner error = EINVAL;
1975db2f26eSSascha Wildner }
1985db2f26eSSascha Wildner break;
1995db2f26eSSascha Wildner
2008d3ef488SSascha Wildner case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
2018d3ef488SSascha Wildner if (ent->Length < sizeof(ACPI_MADT_INTERRUPT_OVERRIDE)) {
2025db2f26eSSascha Wildner kprintf("madt_iterate_entries: invalid MADT "
2035db2f26eSSascha Wildner "intsrc entry len %d\n",
2048d3ef488SSascha Wildner ent->Length);
2055db2f26eSSascha Wildner error = EINVAL;
2065db2f26eSSascha Wildner }
2075db2f26eSSascha Wildner break;
2085db2f26eSSascha Wildner }
2095db2f26eSSascha Wildner if (error)
2105db2f26eSSascha Wildner break;
2115db2f26eSSascha Wildner
2125db2f26eSSascha Wildner error = func(arg, ent);
2135db2f26eSSascha Wildner if (error)
2145db2f26eSSascha Wildner break;
2158d3ef488SSascha Wildner
2168d3ef488SSascha Wildner ent = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, ent, ent->Length);
2175db2f26eSSascha Wildner }
2185db2f26eSSascha Wildner return error;
2195db2f26eSSascha Wildner }
2205db2f26eSSascha Wildner
2215db2f26eSSascha Wildner static int
madt_lapic_pass1_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)2228d3ef488SSascha Wildner madt_lapic_pass1_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
2235db2f26eSSascha Wildner {
2248d3ef488SSascha Wildner const ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_addr_ent;
2255db2f26eSSascha Wildner uint64_t *addr64 = xarg;
2265db2f26eSSascha Wildner
2278d3ef488SSascha Wildner if (ent->Type != ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE)
2285db2f26eSSascha Wildner return 0;
2298d3ef488SSascha Wildner if (ent->Length < sizeof(*lapic_addr_ent)) {
2305db2f26eSSascha Wildner kprintf("madt_lapic_pass1: "
2315db2f26eSSascha Wildner "invalid LAPIC address override length\n");
2325db2f26eSSascha Wildner return 0;
2335db2f26eSSascha Wildner }
2348d3ef488SSascha Wildner lapic_addr_ent = (const ACPI_MADT_LOCAL_APIC_OVERRIDE *)ent;
2355db2f26eSSascha Wildner
2368d3ef488SSascha Wildner *addr64 = lapic_addr_ent->Address;
2375db2f26eSSascha Wildner return 0;
2385db2f26eSSascha Wildner }
2395db2f26eSSascha Wildner
2405db2f26eSSascha Wildner static vm_paddr_t
madt_lapic_pass1(void)2415db2f26eSSascha Wildner madt_lapic_pass1(void)
2425db2f26eSSascha Wildner {
2438d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
2445db2f26eSSascha Wildner vm_paddr_t lapic_addr;
2455db2f26eSSascha Wildner uint64_t lapic_addr64;
2465db2f26eSSascha Wildner int error;
2475db2f26eSSascha Wildner
2485db2f26eSSascha Wildner KKASSERT(madt_phyaddr != 0);
2495db2f26eSSascha Wildner
2505db2f26eSSascha Wildner madt = sdt_sdth_map(madt_phyaddr);
2515db2f26eSSascha Wildner KKASSERT(madt != NULL);
2525db2f26eSSascha Wildner
2535db2f26eSSascha Wildner MADT_VPRINTF("LAPIC address 0x%x, flags %#x\n",
2548d3ef488SSascha Wildner madt->Address, madt->Flags);
2558d3ef488SSascha Wildner lapic_addr = madt->Address;
2565db2f26eSSascha Wildner
2575db2f26eSSascha Wildner lapic_addr64 = 0;
2585db2f26eSSascha Wildner error = madt_iterate_entries(madt, madt_lapic_pass1_callback,
2595db2f26eSSascha Wildner &lapic_addr64);
2605db2f26eSSascha Wildner if (error)
2615db2f26eSSascha Wildner panic("madt_iterate_entries(pass1) failed");
2625db2f26eSSascha Wildner
2635db2f26eSSascha Wildner if (lapic_addr64 != 0) {
2645db2f26eSSascha Wildner kprintf("ACPI MADT: 64bits lapic address 0x%lx\n",
2655db2f26eSSascha Wildner lapic_addr64);
2665db2f26eSSascha Wildner lapic_addr = lapic_addr64;
2675db2f26eSSascha Wildner }
2685db2f26eSSascha Wildner
2698d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
2705db2f26eSSascha Wildner
2715db2f26eSSascha Wildner return lapic_addr;
2725db2f26eSSascha Wildner }
2735db2f26eSSascha Wildner
2745db2f26eSSascha Wildner struct madt_lapic_pass2_cbarg {
2755db2f26eSSascha Wildner int cpu;
2765db2f26eSSascha Wildner int bsp_found;
2775db2f26eSSascha Wildner int bsp_apic_id;
2785db2f26eSSascha Wildner };
2795db2f26eSSascha Wildner
2805db2f26eSSascha Wildner static int
madt_lapic_pass2_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)2818d3ef488SSascha Wildner madt_lapic_pass2_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
2825db2f26eSSascha Wildner {
2838d3ef488SSascha Wildner const ACPI_MADT_LOCAL_APIC *lapic_ent;
2845db2f26eSSascha Wildner struct madt_lapic_pass2_cbarg *arg = xarg;
2855db2f26eSSascha Wildner
2868d3ef488SSascha Wildner if (ent->Type != ACPI_MADT_TYPE_LOCAL_APIC)
2875db2f26eSSascha Wildner return 0;
2885db2f26eSSascha Wildner
2898d3ef488SSascha Wildner lapic_ent = (const ACPI_MADT_LOCAL_APIC *)ent;
2908d3ef488SSascha Wildner if (lapic_ent->LapicFlags & ACPI_MADT_ENABLED) {
2918005c0c8SSepherosa Ziehau int cpu;
2928005c0c8SSepherosa Ziehau
2938d3ef488SSascha Wildner if (lapic_ent->Id == arg->bsp_apic_id) {
2948005c0c8SSepherosa Ziehau cpu = 0;
2959cd8f4f8SMatthew Dillon if (arg->bsp_found) {
2969cd8f4f8SMatthew Dillon kprintf("cpu id %d, duplicate BSP found\n",
2979cd8f4f8SMatthew Dillon arg->cpu);
2989cd8f4f8SMatthew Dillon }
2995db2f26eSSascha Wildner arg->bsp_found = 1;
3005db2f26eSSascha Wildner } else {
3018005c0c8SSepherosa Ziehau cpu = arg->cpu;
3025db2f26eSSascha Wildner arg->cpu++;
3035db2f26eSSascha Wildner }
30427acf54bSSepherosa Ziehau MADT_VPRINTF("cpu id %d, acpi id %d, apic id %d\n",
30527acf54bSSepherosa Ziehau cpu, lapic_ent->ProcessorId, lapic_ent->Id);
3069cd8f4f8SMatthew Dillon if (lapic_ent->Id >= 255) {
3079cd8f4f8SMatthew Dillon kprintf("cpu id %d, WARNING acpi id %d\n",
3089cd8f4f8SMatthew Dillon cpu, lapic_ent->Id);
3099cd8f4f8SMatthew Dillon }
3109cd8f4f8SMatthew Dillon if (lapic_ent->ProcessorId >= 255) {
3119cd8f4f8SMatthew Dillon kprintf("cpu id %d, WARNING acpi processorid %d\n",
3129cd8f4f8SMatthew Dillon cpu, lapic_ent->ProcessorId);
3139cd8f4f8SMatthew Dillon }
3148005c0c8SSepherosa Ziehau lapic_set_cpuid(cpu, lapic_ent->Id);
3158005c0c8SSepherosa Ziehau CPUID_TO_ACPIID(cpu) = lapic_ent->ProcessorId;
3165db2f26eSSascha Wildner }
3175db2f26eSSascha Wildner return 0;
3185db2f26eSSascha Wildner }
3195db2f26eSSascha Wildner
3205db2f26eSSascha Wildner static int
madt_x2apic_pass2_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)32162571e42SSepherosa Ziehau madt_x2apic_pass2_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
32262571e42SSepherosa Ziehau {
32362571e42SSepherosa Ziehau const ACPI_MADT_LOCAL_X2APIC *x2apic_ent;
32462571e42SSepherosa Ziehau struct madt_lapic_pass2_cbarg *arg = xarg;
32562571e42SSepherosa Ziehau
32662571e42SSepherosa Ziehau if (ent->Type != ACPI_MADT_TYPE_LOCAL_X2APIC)
32762571e42SSepherosa Ziehau return 0;
32862571e42SSepherosa Ziehau
32962571e42SSepherosa Ziehau x2apic_ent = (const ACPI_MADT_LOCAL_X2APIC *)ent;
33062571e42SSepherosa Ziehau if (x2apic_ent->LapicFlags & ACPI_MADT_ENABLED) {
33162571e42SSepherosa Ziehau int cpu;
33262571e42SSepherosa Ziehau
33362571e42SSepherosa Ziehau if (x2apic_ent->LocalApicId == arg->bsp_apic_id) {
33462571e42SSepherosa Ziehau cpu = 0;
33562571e42SSepherosa Ziehau arg->bsp_found = 1;
33662571e42SSepherosa Ziehau } else {
33762571e42SSepherosa Ziehau cpu = arg->cpu;
33862571e42SSepherosa Ziehau arg->cpu++;
33962571e42SSepherosa Ziehau }
34062571e42SSepherosa Ziehau MADT_VPRINTF("cpu id %d, acpi uid %u, apic id %d\n",
34162571e42SSepherosa Ziehau cpu, x2apic_ent->Uid, x2apic_ent->LocalApicId);
34262571e42SSepherosa Ziehau lapic_set_cpuid(cpu, x2apic_ent->LocalApicId);
34362571e42SSepherosa Ziehau CPUID_TO_ACPIID(cpu) = x2apic_ent->Uid;
34462571e42SSepherosa Ziehau }
34562571e42SSepherosa Ziehau return 0;
34662571e42SSepherosa Ziehau }
34762571e42SSepherosa Ziehau
34862571e42SSepherosa Ziehau static int
madt_lapic_pass2(int bsp_apic_id)3495db2f26eSSascha Wildner madt_lapic_pass2(int bsp_apic_id)
3505db2f26eSSascha Wildner {
3518d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
3525db2f26eSSascha Wildner struct madt_lapic_pass2_cbarg arg;
35362571e42SSepherosa Ziehau madt_iter_t func;
3545db2f26eSSascha Wildner int error;
3555db2f26eSSascha Wildner
3565db2f26eSSascha Wildner MADT_VPRINTF("BSP apic id %d\n", bsp_apic_id);
3575db2f26eSSascha Wildner
3585db2f26eSSascha Wildner KKASSERT(madt_phyaddr != 0);
3595db2f26eSSascha Wildner
3605db2f26eSSascha Wildner madt = sdt_sdth_map(madt_phyaddr);
3615db2f26eSSascha Wildner KKASSERT(madt != NULL);
3625db2f26eSSascha Wildner
3635db2f26eSSascha Wildner bzero(&arg, sizeof(arg));
3645db2f26eSSascha Wildner arg.cpu = 1;
3655db2f26eSSascha Wildner arg.bsp_apic_id = bsp_apic_id;
3665db2f26eSSascha Wildner
36762571e42SSepherosa Ziehau if (madt_use_x2apic)
36862571e42SSepherosa Ziehau func = madt_x2apic_pass2_callback;
36962571e42SSepherosa Ziehau else
37062571e42SSepherosa Ziehau func = madt_lapic_pass2_callback;
37162571e42SSepherosa Ziehau error = madt_iterate_entries(madt, func, &arg);
3725db2f26eSSascha Wildner if (error)
3735db2f26eSSascha Wildner panic("madt_iterate_entries(pass2) failed");
3745db2f26eSSascha Wildner
3755db2f26eSSascha Wildner KKASSERT(arg.bsp_found);
3765db2f26eSSascha Wildner naps = arg.cpu - 1; /* exclude BSP */
3779cd8f4f8SMatthew Dillon kprintf("ACPI CPUS = %d\n", arg.cpu);
3785db2f26eSSascha Wildner
3798d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
3805db2f26eSSascha Wildner
3815db2f26eSSascha Wildner return 0;
3825db2f26eSSascha Wildner }
3835db2f26eSSascha Wildner
3845db2f26eSSascha Wildner struct madt_lapic_probe_cbarg {
38562571e42SSepherosa Ziehau int x2apic_count;
38662571e42SSepherosa Ziehau int lapic_count;
3875db2f26eSSascha Wildner vm_paddr_t lapic_addr;
3885db2f26eSSascha Wildner };
3895db2f26eSSascha Wildner
3905db2f26eSSascha Wildner static int
madt_lapic_probe_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)3918d3ef488SSascha Wildner madt_lapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
3925db2f26eSSascha Wildner {
3935db2f26eSSascha Wildner struct madt_lapic_probe_cbarg *arg = xarg;
3945db2f26eSSascha Wildner
3958d3ef488SSascha Wildner if (ent->Type == ACPI_MADT_TYPE_LOCAL_APIC) {
3968d3ef488SSascha Wildner const ACPI_MADT_LOCAL_APIC *lapic_ent;
3975db2f26eSSascha Wildner
3988d3ef488SSascha Wildner lapic_ent = (const ACPI_MADT_LOCAL_APIC *)ent;
3998d3ef488SSascha Wildner if (lapic_ent->LapicFlags & ACPI_MADT_ENABLED) {
40062571e42SSepherosa Ziehau arg->lapic_count++;
4018d3ef488SSascha Wildner if (lapic_ent->Id == APICID_MAX) {
4025db2f26eSSascha Wildner kprintf("madt_lapic_probe: "
4035db2f26eSSascha Wildner "invalid LAPIC apic id %d\n",
4048d3ef488SSascha Wildner lapic_ent->Id);
4055db2f26eSSascha Wildner return EINVAL;
4065db2f26eSSascha Wildner }
4075db2f26eSSascha Wildner }
40862571e42SSepherosa Ziehau } else if (ent->Type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
40962571e42SSepherosa Ziehau const ACPI_MADT_LOCAL_X2APIC *x2apic_ent;
41062571e42SSepherosa Ziehau
41162571e42SSepherosa Ziehau x2apic_ent = (const ACPI_MADT_LOCAL_X2APIC *)ent;
41262571e42SSepherosa Ziehau if (x2apic_ent->LapicFlags & ACPI_MADT_ENABLED) {
41362571e42SSepherosa Ziehau if (x2apic_ent->LocalApicId < APICID_MAX) {
41462571e42SSepherosa Ziehau /*
41562571e42SSepherosa Ziehau * XXX we only support APIC ID 0~254 at
41662571e42SSepherosa Ziehau * the moment.
41762571e42SSepherosa Ziehau */
41862571e42SSepherosa Ziehau arg->x2apic_count++;
41962571e42SSepherosa Ziehau }
42062571e42SSepherosa Ziehau }
4218d3ef488SSascha Wildner } else if (ent->Type == ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE) {
4228d3ef488SSascha Wildner const ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_addr_ent;
4235db2f26eSSascha Wildner
4248d3ef488SSascha Wildner if (ent->Length < sizeof(*lapic_addr_ent)) {
4255db2f26eSSascha Wildner kprintf("madt_lapic_probe: "
4265db2f26eSSascha Wildner "invalid LAPIC address override length\n");
4275db2f26eSSascha Wildner return 0;
4285db2f26eSSascha Wildner }
4298d3ef488SSascha Wildner lapic_addr_ent = (const ACPI_MADT_LOCAL_APIC_OVERRIDE *)ent;
4305db2f26eSSascha Wildner
4318d3ef488SSascha Wildner if (lapic_addr_ent->Address != 0)
4328d3ef488SSascha Wildner arg->lapic_addr = lapic_addr_ent->Address;
4335db2f26eSSascha Wildner }
4345db2f26eSSascha Wildner return 0;
4355db2f26eSSascha Wildner }
4365db2f26eSSascha Wildner
4375db2f26eSSascha Wildner static int
madt_lapic_probe(struct lapic_enumerator * e)4385db2f26eSSascha Wildner madt_lapic_probe(struct lapic_enumerator *e)
4395db2f26eSSascha Wildner {
4405db2f26eSSascha Wildner struct madt_lapic_probe_cbarg arg;
4418d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
4425db2f26eSSascha Wildner int error;
4435db2f26eSSascha Wildner
4445db2f26eSSascha Wildner if (madt_phyaddr == 0)
4455db2f26eSSascha Wildner return ENXIO;
4465db2f26eSSascha Wildner
4475db2f26eSSascha Wildner madt = sdt_sdth_map(madt_phyaddr);
4485db2f26eSSascha Wildner KKASSERT(madt != NULL);
4495db2f26eSSascha Wildner
4505db2f26eSSascha Wildner bzero(&arg, sizeof(arg));
4518d3ef488SSascha Wildner arg.lapic_addr = madt->Address;
4525db2f26eSSascha Wildner
4535db2f26eSSascha Wildner error = madt_iterate_entries(madt, madt_lapic_probe_callback, &arg);
4545db2f26eSSascha Wildner if (!error) {
4559cd8f4f8SMatthew Dillon kprintf("madt_lapic_probe: lapic_count=%d x2apic_count=%d\n",
4569cd8f4f8SMatthew Dillon arg.lapic_count, arg.x2apic_count);
45762571e42SSepherosa Ziehau if (arg.lapic_count == 0 && arg.x2apic_count == 0) {
4585db2f26eSSascha Wildner kprintf("madt_lapic_probe: no CPU is found\n");
4595db2f26eSSascha Wildner error = EOPNOTSUPP;
46062571e42SSepherosa Ziehau } else if (arg.lapic_count == 0) {
46162571e42SSepherosa Ziehau /*
46262571e42SSepherosa Ziehau * ACPI 5.1 says that LOCAL_X2APIC entry should
46362571e42SSepherosa Ziehau * be used only if APIC ID > 255. While ACPI 6.2
46462571e42SSepherosa Ziehau * removes that constraint, which means that
46562571e42SSepherosa Ziehau * LOCAL_X2APIC entry could be used for any APIC
46662571e42SSepherosa Ziehau * ID.
46762571e42SSepherosa Ziehau *
46862571e42SSepherosa Ziehau * XXX
46962571e42SSepherosa Ziehau * In DragonFlyBSD, we don't support APIC ID >=
47062571e42SSepherosa Ziehau * 255, so LOCAL_X2APIC entries should be ignored,
47162571e42SSepherosa Ziehau * if LOCAL_X2APIC entries are mixed with
47262571e42SSepherosa Ziehau * LOCAL_APIC entries. LOCAL_X2APIC entries are
47362571e42SSepherosa Ziehau * used, iff only LOCAL_X2APIC entries exist.
47462571e42SSepherosa Ziehau */
47562571e42SSepherosa Ziehau madt_use_x2apic = TRUE;
47662571e42SSepherosa Ziehau kprintf("MADT: use X2APIC entries\n");
4775db2f26eSSascha Wildner }
47862571e42SSepherosa Ziehau
4795db2f26eSSascha Wildner if (arg.lapic_addr == 0) {
48062571e42SSepherosa Ziehau /*
481f89b4a45SSepherosa Ziehau * The LAPIC address does not matter in X2APIC mode.
48262571e42SSepherosa Ziehau */
483f89b4a45SSepherosa Ziehau if ((cpu_feature2 & CPUID2_X2APIC) == 0) {
4845db2f26eSSascha Wildner kprintf("madt_lapic_probe: zero LAPIC address\n");
4855db2f26eSSascha Wildner error = EOPNOTSUPP;
4865db2f26eSSascha Wildner }
4875db2f26eSSascha Wildner }
488f89b4a45SSepherosa Ziehau }
4895db2f26eSSascha Wildner
4908d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
4915db2f26eSSascha Wildner return error;
4925db2f26eSSascha Wildner }
4935db2f26eSSascha Wildner
4945db2f26eSSascha Wildner static int
madt_lapic_enumerate(struct lapic_enumerator * e)4955db2f26eSSascha Wildner madt_lapic_enumerate(struct lapic_enumerator *e)
4965db2f26eSSascha Wildner {
497f89b4a45SSepherosa Ziehau vm_paddr_t lapic_addr = 0;
4985db2f26eSSascha Wildner int bsp_apic_id;
4995db2f26eSSascha Wildner
5005db2f26eSSascha Wildner KKASSERT(madt_phyaddr != 0);
5015db2f26eSSascha Wildner
502f89b4a45SSepherosa Ziehau if (!x2apic_enable) {
5035db2f26eSSascha Wildner lapic_addr = madt_lapic_pass1();
504f89b4a45SSepherosa Ziehau if (lapic_addr == 0) {
505f89b4a45SSepherosa Ziehau /*
506f89b4a45SSepherosa Ziehau * No LAPIC address.
507f89b4a45SSepherosa Ziehau */
508f89b4a45SSepherosa Ziehau if (cpu_feature2 & CPUID2_X2APIC) {
509f89b4a45SSepherosa Ziehau /*
510f89b4a45SSepherosa Ziehau * X2APIC mode is not enabled, but the CPU supports
511f89b4a45SSepherosa Ziehau * it. Forcefully enable X2APIC mode, which nullifies
512f89b4a45SSepherosa Ziehau * the requirement of the LAPIC address.
513f89b4a45SSepherosa Ziehau */
514f89b4a45SSepherosa Ziehau kprintf("MADT: no LAPIC address, force X2APIC mode\n");
515f89b4a45SSepherosa Ziehau KKASSERT(!x2apic_enable);
516f89b4a45SSepherosa Ziehau x2apic_enable = 1;
517f89b4a45SSepherosa Ziehau lapic_x2apic_enter(TRUE);
518f89b4a45SSepherosa Ziehau } else {
519f89b4a45SSepherosa Ziehau /*
520f89b4a45SSepherosa Ziehau * We should not reach here, madt_lapic_probe() must
521f89b4a45SSepherosa Ziehau * have failed.
522f89b4a45SSepherosa Ziehau */
5235db2f26eSSascha Wildner panic("madt_lapic_enumerate: no local apic");
524f89b4a45SSepherosa Ziehau }
525f89b4a45SSepherosa Ziehau }
526f89b4a45SSepherosa Ziehau }
5275db2f26eSSascha Wildner
528f89b4a45SSepherosa Ziehau if (!x2apic_enable) {
529f89b4a45SSepherosa Ziehau KASSERT(lapic_addr != 0, ("madt_lapic_enumerate: zero LAPIC address"));
5305db2f26eSSascha Wildner lapic_map(lapic_addr);
531f89b4a45SSepherosa Ziehau }
5325db2f26eSSascha Wildner
5338afc0c3dSSepherosa Ziehau bsp_apic_id = LAPIC_READID;
5345db2f26eSSascha Wildner if (bsp_apic_id == APICID_MAX) {
5355db2f26eSSascha Wildner /*
5365db2f26eSSascha Wildner * XXX
5375db2f26eSSascha Wildner * Some old brain dead BIOS will set BSP's LAPIC apic id
5385db2f26eSSascha Wildner * to 255, though all LAPIC entries in MADT are valid.
5395db2f26eSSascha Wildner */
5405db2f26eSSascha Wildner kprintf("%s invalid BSP LAPIC apic id %d\n", __func__,
5415db2f26eSSascha Wildner bsp_apic_id);
5425db2f26eSSascha Wildner return EINVAL;
5435db2f26eSSascha Wildner }
5445db2f26eSSascha Wildner
5455db2f26eSSascha Wildner if (madt_lapic_pass2(bsp_apic_id))
5465db2f26eSSascha Wildner panic("madt_lapic_enumerate: madt_lapic_pass2 failed");
5475db2f26eSSascha Wildner
5485db2f26eSSascha Wildner return 0;
5495db2f26eSSascha Wildner }
5505db2f26eSSascha Wildner
5515db2f26eSSascha Wildner static struct lapic_enumerator madt_lapic_enumerator = {
5525db2f26eSSascha Wildner .lapic_prio = LAPIC_ENUM_PRIO_MADT,
5535db2f26eSSascha Wildner .lapic_probe = madt_lapic_probe,
5545db2f26eSSascha Wildner .lapic_enumerate = madt_lapic_enumerate
5555db2f26eSSascha Wildner };
5565db2f26eSSascha Wildner
5575db2f26eSSascha Wildner static void
madt_lapic_enum_register(void)5585db2f26eSSascha Wildner madt_lapic_enum_register(void)
5595db2f26eSSascha Wildner {
5605db2f26eSSascha Wildner int prio;
5615db2f26eSSascha Wildner
5625db2f26eSSascha Wildner prio = LAPIC_ENUM_PRIO_MADT;
5635db2f26eSSascha Wildner kgetenv_int("hw.madt_lapic_prio", &prio);
5645db2f26eSSascha Wildner madt_lapic_enumerator.lapic_prio = prio;
5655db2f26eSSascha Wildner
5665db2f26eSSascha Wildner lapic_enumerator_register(&madt_lapic_enumerator);
5675db2f26eSSascha Wildner }
5685db2f26eSSascha Wildner SYSINIT(madt_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY, madt_lapic_enum_register, 0);
5695db2f26eSSascha Wildner
5705db2f26eSSascha Wildner struct madt_ioapic_probe_cbarg {
5715db2f26eSSascha Wildner int ioapic_cnt;
5725db2f26eSSascha Wildner int gsi_base0;
5735db2f26eSSascha Wildner };
5745db2f26eSSascha Wildner
5755db2f26eSSascha Wildner static int
madt_ioapic_probe_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)5768d3ef488SSascha Wildner madt_ioapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
5775db2f26eSSascha Wildner {
5785db2f26eSSascha Wildner struct madt_ioapic_probe_cbarg *arg = xarg;
5795db2f26eSSascha Wildner
5808d3ef488SSascha Wildner if (ent->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
5818d3ef488SSascha Wildner const ACPI_MADT_INTERRUPT_OVERRIDE *intsrc_ent;
5825db2f26eSSascha Wildner int trig, pola;
5835db2f26eSSascha Wildner
5848d3ef488SSascha Wildner intsrc_ent = (const ACPI_MADT_INTERRUPT_OVERRIDE *)ent;
5855db2f26eSSascha Wildner
5868d3ef488SSascha Wildner if (intsrc_ent->SourceIrq >= ISA_IRQ_CNT) {
5875db2f26eSSascha Wildner kprintf("madt_ioapic_probe: invalid intsrc irq (%d)\n",
5888d3ef488SSascha Wildner intsrc_ent->SourceIrq);
5895db2f26eSSascha Wildner return EINVAL;
5905db2f26eSSascha Wildner }
5915db2f26eSSascha Wildner
5928d3ef488SSascha Wildner if (intsrc_ent->Bus != MADT_INT_BUS_ISA) {
5935db2f26eSSascha Wildner kprintf("ACPI MADT: warning intsrc irq %d "
5945db2f26eSSascha Wildner "bus is not ISA (%d)\n",
5958d3ef488SSascha Wildner intsrc_ent->SourceIrq, intsrc_ent->Bus);
5965db2f26eSSascha Wildner }
5975db2f26eSSascha Wildner
5988d3ef488SSascha Wildner trig = intsrc_ent->IntiFlags & ACPI_MADT_TRIGGER_MASK;
5998d3ef488SSascha Wildner if (trig == ACPI_MADT_TRIGGER_RESERVED) {
6005db2f26eSSascha Wildner kprintf("ACPI MADT: warning invalid intsrc irq %d "
6018d3ef488SSascha Wildner "trig, reserved\n", intsrc_ent->SourceIrq);
6028d3ef488SSascha Wildner } else if (trig == ACPI_MADT_TRIGGER_LEVEL) {
6035db2f26eSSascha Wildner MADT_VPRINTF("warning invalid intsrc irq %d "
6048d3ef488SSascha Wildner "trig, level\n", intsrc_ent->SourceIrq);
6055db2f26eSSascha Wildner }
6065db2f26eSSascha Wildner
6078d3ef488SSascha Wildner pola = intsrc_ent->IntiFlags & ACPI_MADT_POLARITY_MASK;
6088d3ef488SSascha Wildner if (pola == ACPI_MADT_POLARITY_RESERVED) {
6095db2f26eSSascha Wildner kprintf("ACPI MADT: warning invalid intsrc irq %d "
6108d3ef488SSascha Wildner "pola, reserved\n", intsrc_ent->SourceIrq);
6118d3ef488SSascha Wildner } else if (pola == ACPI_MADT_POLARITY_ACTIVE_LOW) {
6125db2f26eSSascha Wildner MADT_VPRINTF("warning invalid intsrc irq %d "
6138d3ef488SSascha Wildner "pola, low\n", intsrc_ent->SourceIrq);
6145db2f26eSSascha Wildner }
6158d3ef488SSascha Wildner } else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) {
6168d3ef488SSascha Wildner const ACPI_MADT_IO_APIC *ioapic_ent;
6175db2f26eSSascha Wildner
6188d3ef488SSascha Wildner ioapic_ent = (const ACPI_MADT_IO_APIC *)ent;
6198d3ef488SSascha Wildner if (ioapic_ent->Address == 0) {
6205db2f26eSSascha Wildner kprintf("madt_ioapic_probe: zero IOAPIC address\n");
6215db2f26eSSascha Wildner return EINVAL;
6225db2f26eSSascha Wildner }
6238d3ef488SSascha Wildner if (ioapic_ent->Id == APICID_MAX) {
6245db2f26eSSascha Wildner kprintf("madt_ioapic_probe: "
6255db2f26eSSascha Wildner "invalid IOAPIC apic id %d\n",
6268d3ef488SSascha Wildner ioapic_ent->Id);
6275db2f26eSSascha Wildner return EINVAL;
6285db2f26eSSascha Wildner }
6295db2f26eSSascha Wildner
6305db2f26eSSascha Wildner arg->ioapic_cnt++;
6318d3ef488SSascha Wildner if (ioapic_ent->GlobalIrqBase == 0)
6325db2f26eSSascha Wildner arg->gsi_base0 = 1;
6335db2f26eSSascha Wildner }
6345db2f26eSSascha Wildner return 0;
6355db2f26eSSascha Wildner }
6365db2f26eSSascha Wildner
6375db2f26eSSascha Wildner static int
madt_ioapic_probe(struct ioapic_enumerator * e)6385db2f26eSSascha Wildner madt_ioapic_probe(struct ioapic_enumerator *e)
6395db2f26eSSascha Wildner {
6405db2f26eSSascha Wildner struct madt_ioapic_probe_cbarg arg;
6418d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
6425db2f26eSSascha Wildner int error;
6435db2f26eSSascha Wildner
6445db2f26eSSascha Wildner if (madt_phyaddr == 0)
6455db2f26eSSascha Wildner return ENXIO;
6465db2f26eSSascha Wildner
6475db2f26eSSascha Wildner madt = sdt_sdth_map(madt_phyaddr);
6485db2f26eSSascha Wildner KKASSERT(madt != NULL);
6495db2f26eSSascha Wildner
6505db2f26eSSascha Wildner bzero(&arg, sizeof(arg));
6515db2f26eSSascha Wildner
6525db2f26eSSascha Wildner error = madt_iterate_entries(madt, madt_ioapic_probe_callback, &arg);
6535db2f26eSSascha Wildner if (!error) {
6545db2f26eSSascha Wildner if (arg.ioapic_cnt == 0) {
6555db2f26eSSascha Wildner kprintf("madt_ioapic_probe: no IOAPIC\n");
6565db2f26eSSascha Wildner error = ENXIO;
6575db2f26eSSascha Wildner }
6585db2f26eSSascha Wildner if (!arg.gsi_base0) {
6595db2f26eSSascha Wildner kprintf("madt_ioapic_probe: no GSI base 0\n");
6605db2f26eSSascha Wildner error = EINVAL;
6615db2f26eSSascha Wildner }
6625db2f26eSSascha Wildner }
6635db2f26eSSascha Wildner
6648d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
6655db2f26eSSascha Wildner return error;
6665db2f26eSSascha Wildner }
6675db2f26eSSascha Wildner
6685db2f26eSSascha Wildner static int
madt_ioapic_enum_callback(void * xarg,const ACPI_SUBTABLE_HEADER * ent)6698d3ef488SSascha Wildner madt_ioapic_enum_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
6705db2f26eSSascha Wildner {
6718d3ef488SSascha Wildner if (ent->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
6728d3ef488SSascha Wildner const ACPI_MADT_INTERRUPT_OVERRIDE *intsrc_ent;
6735db2f26eSSascha Wildner enum intr_trigger trig;
6745db2f26eSSascha Wildner enum intr_polarity pola;
6755db2f26eSSascha Wildner int ent_trig, ent_pola;
6765db2f26eSSascha Wildner
6778d3ef488SSascha Wildner intsrc_ent = (const ACPI_MADT_INTERRUPT_OVERRIDE *)ent;
6785db2f26eSSascha Wildner
6798d3ef488SSascha Wildner KKASSERT(intsrc_ent->SourceIrq < ISA_IRQ_CNT);
6808d3ef488SSascha Wildner if (intsrc_ent->Bus != MADT_INT_BUS_ISA)
6815db2f26eSSascha Wildner return 0;
6825db2f26eSSascha Wildner
6838d3ef488SSascha Wildner ent_trig = intsrc_ent->IntiFlags & ACPI_MADT_TRIGGER_MASK;
6848d3ef488SSascha Wildner if (ent_trig == ACPI_MADT_TRIGGER_RESERVED)
6855db2f26eSSascha Wildner return 0;
6868d3ef488SSascha Wildner else if (ent_trig == ACPI_MADT_TRIGGER_LEVEL)
6875db2f26eSSascha Wildner trig = INTR_TRIGGER_LEVEL;
6885db2f26eSSascha Wildner else
6895db2f26eSSascha Wildner trig = INTR_TRIGGER_EDGE;
6905db2f26eSSascha Wildner
6918d3ef488SSascha Wildner ent_pola = intsrc_ent->IntiFlags & ACPI_MADT_POLARITY_MASK;
6928d3ef488SSascha Wildner if (ent_pola == ACPI_MADT_POLARITY_RESERVED)
6935db2f26eSSascha Wildner return 0;
6948d3ef488SSascha Wildner else if (ent_pola == ACPI_MADT_POLARITY_ACTIVE_LOW)
6955db2f26eSSascha Wildner pola = INTR_POLARITY_LOW;
6965db2f26eSSascha Wildner else
6975db2f26eSSascha Wildner pola = INTR_POLARITY_HIGH;
6985db2f26eSSascha Wildner
6998d3ef488SSascha Wildner if (intsrc_ent->SourceIrq == acpi_sci_irqno()) {
7005db2f26eSSascha Wildner acpi_sci_setmode1(trig, pola);
7015db2f26eSSascha Wildner MADT_VPRINTF("SCI irq %d, first test %s/%s\n",
7028d3ef488SSascha Wildner intsrc_ent->SourceIrq,
7035db2f26eSSascha Wildner intr_str_trigger(trig), intr_str_polarity(pola));
7045db2f26eSSascha Wildner }
7055db2f26eSSascha Wildner
7065db2f26eSSascha Wildner /*
7075db2f26eSSascha Wildner * We ignore the polarity and trigger changes, since
7085db2f26eSSascha Wildner * most of them are wrong or useless at best.
7095db2f26eSSascha Wildner */
7108d3ef488SSascha Wildner if (intsrc_ent->SourceIrq == intsrc_ent->GlobalIrq) {
7115db2f26eSSascha Wildner /* Nothing changed */
7125db2f26eSSascha Wildner return 0;
7135db2f26eSSascha Wildner }
7145db2f26eSSascha Wildner trig = INTR_TRIGGER_EDGE;
7155db2f26eSSascha Wildner pola = INTR_POLARITY_HIGH;
7165db2f26eSSascha Wildner
7175db2f26eSSascha Wildner MADT_VPRINTF("INTSRC irq %d -> gsi %u %s/%s\n",
7188d3ef488SSascha Wildner intsrc_ent->SourceIrq, intsrc_ent->GlobalIrq,
7195db2f26eSSascha Wildner intr_str_trigger(trig), intr_str_polarity(pola));
7208d3ef488SSascha Wildner ioapic_intsrc(intsrc_ent->SourceIrq, intsrc_ent->GlobalIrq,
7215db2f26eSSascha Wildner trig, pola);
7228d3ef488SSascha Wildner } else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) {
7238d3ef488SSascha Wildner const ACPI_MADT_IO_APIC *ioapic_ent;
7245db2f26eSSascha Wildner uint32_t ver;
7255db2f26eSSascha Wildner void *addr;
7265db2f26eSSascha Wildner int npin;
7275db2f26eSSascha Wildner
7288d3ef488SSascha Wildner ioapic_ent = (const ACPI_MADT_IO_APIC *)ent;
7295db2f26eSSascha Wildner MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n",
7308d3ef488SSascha Wildner ioapic_ent->Address, ioapic_ent->Id,
7318d3ef488SSascha Wildner ioapic_ent->GlobalIrqBase);
7325db2f26eSSascha Wildner
7338d3ef488SSascha Wildner addr = ioapic_map(ioapic_ent->Address);
7345db2f26eSSascha Wildner
7355db2f26eSSascha Wildner ver = ioapic_read(addr, IOAPIC_VER);
7365db2f26eSSascha Wildner npin = ((ver & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
7375db2f26eSSascha Wildner
7388d3ef488SSascha Wildner ioapic_add(addr, ioapic_ent->GlobalIrqBase, npin);
7395db2f26eSSascha Wildner }
7405db2f26eSSascha Wildner return 0;
7415db2f26eSSascha Wildner }
7425db2f26eSSascha Wildner
7435db2f26eSSascha Wildner static void
madt_ioapic_enumerate(struct ioapic_enumerator * e)7445db2f26eSSascha Wildner madt_ioapic_enumerate(struct ioapic_enumerator *e)
7455db2f26eSSascha Wildner {
7468d3ef488SSascha Wildner ACPI_TABLE_MADT *madt;
7475db2f26eSSascha Wildner int error;
7485db2f26eSSascha Wildner
7495db2f26eSSascha Wildner KKASSERT(madt_phyaddr != 0);
7505db2f26eSSascha Wildner
7515db2f26eSSascha Wildner madt = sdt_sdth_map(madt_phyaddr);
7525db2f26eSSascha Wildner KKASSERT(madt != NULL);
7535db2f26eSSascha Wildner
7545db2f26eSSascha Wildner error = madt_iterate_entries(madt, madt_ioapic_enum_callback, NULL);
7555db2f26eSSascha Wildner if (error)
7565db2f26eSSascha Wildner panic("madt_ioapic_enumerate failed");
7575db2f26eSSascha Wildner
7588d3ef488SSascha Wildner sdt_sdth_unmap(&madt->Header);
7595db2f26eSSascha Wildner }
7605db2f26eSSascha Wildner
7615db2f26eSSascha Wildner static struct ioapic_enumerator madt_ioapic_enumerator = {
7625db2f26eSSascha Wildner .ioapic_prio = IOAPIC_ENUM_PRIO_MADT,
7635db2f26eSSascha Wildner .ioapic_probe = madt_ioapic_probe,
7645db2f26eSSascha Wildner .ioapic_enumerate = madt_ioapic_enumerate
7655db2f26eSSascha Wildner };
7665db2f26eSSascha Wildner
7675db2f26eSSascha Wildner static void
madt_ioapic_enum_register(void)7685db2f26eSSascha Wildner madt_ioapic_enum_register(void)
7695db2f26eSSascha Wildner {
7705db2f26eSSascha Wildner int prio;
7715db2f26eSSascha Wildner
7725db2f26eSSascha Wildner prio = IOAPIC_ENUM_PRIO_MADT;
7735db2f26eSSascha Wildner kgetenv_int("hw.madt_ioapic_prio", &prio);
7745db2f26eSSascha Wildner madt_ioapic_enumerator.ioapic_prio = prio;
7755db2f26eSSascha Wildner
7765db2f26eSSascha Wildner ioapic_enumerator_register(&madt_ioapic_enumerator);
7775db2f26eSSascha Wildner }
7785db2f26eSSascha Wildner SYSINIT(madt_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
7795db2f26eSSascha Wildner madt_ioapic_enum_register, 0);
780