xref: /dragonfly/sys/platform/pc64/acpica/acpi_madt.c (revision abba2c19)
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