1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/bus.h>
31#include <sys/kernel.h>
32#include <sys/limits.h>
33#include <sys/malloc.h>
34#include <sys/smp.h>
35#include <vm/vm.h>
36#include <vm/pmap.h>
37
38#include <x86/apicreg.h>
39#include <machine/intr_machdep.h>
40#include <x86/apicvar.h>
41#include <machine/md_var.h>
42#include <x86/vmware.h>
43
44#include <contrib/dev/acpica/include/acpi.h>
45#include <contrib/dev/acpica/include/aclocal.h>
46#include <contrib/dev/acpica/include/actables.h>
47
48#include <dev/acpica/acpivar.h>
49#include <dev/pci/pcivar.h>
50
51/* These two arrays are indexed by APIC IDs. */
52static struct {
53	void *io_apic;
54	UINT32 io_vector;
55} *ioapics;
56
57static struct lapic_info {
58	u_int la_enabled;
59	u_int la_acpi_id;
60} *lapics;
61
62int madt_found_sci_override;
63static ACPI_TABLE_MADT *madt;
64static vm_paddr_t madt_physaddr;
65static vm_offset_t madt_length;
66
67static MALLOC_DEFINE(M_MADT, "madt_table", "ACPI MADT Table Items");
68
69static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source);
70static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
71static int	madt_find_cpu(u_int acpi_id, u_int *apic_id);
72static int	madt_find_interrupt(int intr, void **apic, u_int *pin);
73static void	madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
74static void	madt_parse_interrupt_override(
75		    ACPI_MADT_INTERRUPT_OVERRIDE *intr);
76static void	madt_parse_ints(ACPI_SUBTABLE_HEADER *entry,
77		    void *arg __unused);
78static void	madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi);
79static void	madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi);
80static int	madt_probe(void);
81static int	madt_probe_cpus(void);
82static void	madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
83		    void *arg __unused);
84static void	madt_setup_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
85		    void *arg __unused);
86static void	madt_register(void *dummy);
87static int	madt_setup_local(void);
88static int	madt_setup_io(void);
89static void	madt_walk_table(acpi_subtable_handler *handler, void *arg);
90
91static struct apic_enumerator madt_enumerator = {
92	.apic_name = "MADT",
93	.apic_probe = madt_probe,
94	.apic_probe_cpus = madt_probe_cpus,
95	.apic_setup_local = madt_setup_local,
96	.apic_setup_io = madt_setup_io
97};
98
99/*
100 * Look for an ACPI Multiple APIC Description Table ("APIC")
101 */
102static int
103madt_probe(void)
104{
105
106	madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
107	if (madt_physaddr == 0)
108		return (ENXIO);
109	return (-50);
110}
111
112/*
113 * Run through the MP table enumerating CPUs.
114 */
115static int
116madt_probe_cpus(void)
117{
118
119	madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
120	madt_length = madt->Header.Length;
121	KASSERT(madt != NULL, ("Unable to re-map MADT"));
122	madt_walk_table(madt_probe_cpus_handler, NULL);
123	acpi_unmap_table(madt);
124	madt = NULL;
125	return (0);
126}
127
128static const char *x2apic_sandy_dis[] = {
129	"LENOVO",
130	"ASUSTeK Computer Inc.",
131	"SAMSUNG ELECTRONICS CO., LTD.",
132};
133
134/*
135 * Automatically detect several configurations where x2APIC mode is
136 * known to cause troubles.  User can override the setting with
137 * hw.x2apic_enable tunable.
138 */
139static const char *
140madt_x2apic_disable_reason(void)
141{
142	ACPI_TABLE_DMAR *dmartbl;
143	vm_paddr_t dmartbl_physaddr;
144	const char *reason;
145	char *hw_vendor;
146	u_int p[4];
147	int i;
148
149	reason = NULL;
150
151	dmartbl_physaddr = acpi_find_table(ACPI_SIG_DMAR);
152	if (dmartbl_physaddr != 0) {
153		dmartbl = acpi_map_table(dmartbl_physaddr, ACPI_SIG_DMAR);
154		if ((dmartbl->Flags & ACPI_DMAR_X2APIC_OPT_OUT) != 0)
155			reason = "by DMAR table";
156		acpi_unmap_table(dmartbl);
157		if (reason != NULL)
158			return (reason);
159	}
160
161	if (vm_guest == VM_GUEST_VMWARE) {
162		vmware_hvcall(0, VMW_HVCMD_GETVCPU_INFO,
163		    VMW_HVCMD_DEFAULT_PARAM, p);
164		if ((p[0] & VMW_VCPUINFO_VCPU_RESERVED) != 0 ||
165		    (p[0] & VMW_VCPUINFO_LEGACY_X2APIC) == 0)
166			return ("inside VMWare without intr redirection");
167	}
168
169	if (vm_guest == VM_GUEST_NO &&
170	    CPUID_TO_FAMILY(cpu_id) == 0x6 &&
171	    CPUID_TO_MODEL(cpu_id) == 0x2a) {
172		hw_vendor = kern_getenv("smbios.planar.maker");
173		/*
174		 * It seems that some SandyBridge-based notebook
175		 * BIOSes have a bug which prevents booting AP in
176		 * x2APIC mode.  Since the only way to detect mobile
177		 * CPU is to check northbridge pci id, which cannot be
178		 * done that early, disable x2APIC for all such
179		 * machines.
180		 */
181		if (hw_vendor != NULL) {
182			for (i = 0; i < nitems(x2apic_sandy_dis); i++) {
183				if (strcmp(hw_vendor, x2apic_sandy_dis[i]) ==
184				    0) {
185					reason =
186				"for a suspected SandyBridge BIOS bug";
187					break;
188				}
189			}
190			freeenv(hw_vendor);
191		}
192		if (reason != NULL)
193			return (reason);
194	}
195
196	return (NULL);
197}
198
199/*
200 * Initialize the local APIC on the BSP.
201 */
202static int
203madt_setup_local(void)
204{
205	const char *reason;
206	int user_x2apic;
207	bool bios_x2apic;
208
209	if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
210		reason = madt_x2apic_disable_reason();
211		bios_x2apic = lapic_is_x2apic();
212		if (reason != NULL && bios_x2apic) {
213			if (bootverbose)
214				printf("x2APIC should be disabled %s but "
215				    "already enabled by BIOS; enabling.\n",
216				     reason);
217			reason = NULL;
218		}
219		if (reason == NULL)
220			x2apic_mode = 1;
221		else if (bootverbose)
222			printf("x2APIC available but disabled %s\n", reason);
223		user_x2apic = x2apic_mode;
224		TUNABLE_INT_FETCH("hw.apic.x2apic_mode", &user_x2apic);
225		if (user_x2apic != x2apic_mode) {
226			if (bios_x2apic && !user_x2apic)
227				printf("x2APIC disabled by tunable and "
228				    "enabled by BIOS; ignoring tunable.");
229			else
230				x2apic_mode = user_x2apic;
231		}
232	}
233
234	/*
235	 * Truncate max_apic_id if not in x2APIC mode. Some structures
236	 * will already be allocated with the previous max_apic_id, but
237	 * at least we can prevent wasting more memory elsewhere.
238	 */
239	if (!x2apic_mode)
240		max_apic_id = min(max_apic_id, xAPIC_MAX_APIC_ID);
241
242	madt = pmap_mapbios(madt_physaddr, madt_length);
243	lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_MADT,
244	    M_WAITOK | M_ZERO);
245	madt_walk_table(madt_setup_cpus_handler, NULL);
246
247	lapic_init(madt->Address);
248	printf("ACPI APIC Table: <%.*s %.*s>\n",
249	    (int)sizeof(madt->Header.OemId), madt->Header.OemId,
250	    (int)sizeof(madt->Header.OemTableId), madt->Header.OemTableId);
251
252	/*
253	 * We ignore 64-bit local APIC override entries.  Should we
254	 * perhaps emit a warning here if we find one?
255	 */
256	return (0);
257}
258
259/*
260 * Enumerate I/O APICs and setup interrupt sources.
261 */
262static int
263madt_setup_io(void)
264{
265	void *ioapic;
266	u_int pin;
267	int i;
268
269	KASSERT(lapics != NULL, ("local APICs not initialized"));
270
271	/* Try to initialize ACPI so that we can access the FADT. */
272	i = acpi_Startup();
273	if (ACPI_FAILURE(i)) {
274		printf("MADT: ACPI Startup failed with %s\n",
275		    AcpiFormatException(i));
276		printf("Try disabling either ACPI or apic support.\n");
277		panic("Using MADT but ACPI doesn't work");
278	}
279
280	ioapics = malloc(sizeof(*ioapics) * (IOAPIC_MAX_ID + 1), M_MADT,
281	    M_WAITOK | M_ZERO);
282
283	/* First, we run through adding I/O APIC's. */
284	madt_walk_table(madt_parse_apics, NULL);
285
286	/* Second, we run through the table tweaking interrupt sources. */
287	madt_walk_table(madt_parse_ints, NULL);
288
289	/*
290	 * If there was not an explicit override entry for the SCI,
291	 * force it to use level trigger and active-low polarity.
292	 */
293	if (!madt_found_sci_override) {
294		if (madt_find_interrupt(AcpiGbl_FADT.SciInterrupt, &ioapic,
295		    &pin) != 0)
296			printf("MADT: Could not find APIC for SCI IRQ %u\n",
297			    AcpiGbl_FADT.SciInterrupt);
298		else {
299			printf(
300	"MADT: Forcing active-low polarity and level trigger for SCI\n");
301			ioapic_set_polarity(ioapic, pin, INTR_POLARITY_LOW);
302			ioapic_set_triggermode(ioapic, pin, INTR_TRIGGER_LEVEL);
303		}
304	}
305
306	/* Third, we register all the I/O APIC's. */
307	for (i = 0; i <= IOAPIC_MAX_ID; i++)
308		if (ioapics[i].io_apic != NULL)
309			ioapic_register(ioapics[i].io_apic);
310
311	/* Finally, we throw the switch to enable the I/O APIC's. */
312	acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
313
314	free(ioapics, M_MADT);
315	ioapics = NULL;
316
317	/* NB: this is the last use of the lapics array. */
318	free(lapics, M_MADT);
319	lapics = NULL;
320
321	return (0);
322}
323
324static void
325madt_register(void *dummy __unused)
326{
327
328	apic_register_enumerator(&madt_enumerator);
329}
330SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, madt_register, NULL);
331
332/*
333 * Call the handler routine for each entry in the MADT table.
334 */
335static void
336madt_walk_table(acpi_subtable_handler *handler, void *arg)
337{
338
339	acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
340	    handler, arg);
341}
342
343static void
344madt_parse_cpu(unsigned int apic_id, unsigned int flags)
345{
346
347	if (!(flags & ACPI_MADT_ENABLED) ||
348#ifdef SMP
349	    mp_ncpus == MAXCPU ||
350#endif
351	    apic_id > MAX_APIC_ID)
352		return;
353
354#ifdef SMP
355	mp_ncpus++;
356	mp_maxid = mp_ncpus - 1;
357#endif
358	max_apic_id = max(apic_id, max_apic_id);
359}
360
361static void
362madt_add_cpu(u_int acpi_id, u_int apic_id, u_int flags)
363{
364	struct lapic_info *la;
365
366	/*
367	 * The MADT does not include a BSP flag, so we have to let the
368	 * MP code figure out which CPU is the BSP on its own.
369	 */
370	if (bootverbose)
371		printf("MADT: Found CPU APIC ID %d ACPI ID %u: %s\n",
372		    (int)apic_id, acpi_id, flags & ACPI_MADT_ENABLED ?
373		    "enabled" : "disabled");
374	if (!(flags & ACPI_MADT_ENABLED))
375		return;
376	if (apic_id > max_apic_id) {
377		printf("MADT: Ignoring local APIC ID %u (too high)\n",
378		    apic_id);
379		return;
380	}
381
382	la = &lapics[apic_id];
383	KASSERT(la->la_enabled == 0, ("Duplicate local APIC ID %u", apic_id));
384	la->la_enabled = 1;
385	la->la_acpi_id = acpi_id;
386	lapic_create(apic_id, 0);
387}
388
389static void
390madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
391{
392	ACPI_MADT_LOCAL_APIC *proc;
393	ACPI_MADT_LOCAL_X2APIC *x2apic;
394
395	switch (entry->Type) {
396	case ACPI_MADT_TYPE_LOCAL_APIC:
397		proc = (ACPI_MADT_LOCAL_APIC *)entry;
398		madt_parse_cpu(proc->Id, proc->LapicFlags);
399		break;
400	case ACPI_MADT_TYPE_LOCAL_X2APIC:
401		x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
402		madt_parse_cpu(x2apic->LocalApicId, x2apic->LapicFlags);
403		break;
404	}
405}
406
407static void
408madt_setup_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
409{
410	ACPI_MADT_LOCAL_APIC *proc;
411	ACPI_MADT_LOCAL_X2APIC *x2apic;
412
413	switch (entry->Type) {
414	case ACPI_MADT_TYPE_LOCAL_APIC:
415		proc = (ACPI_MADT_LOCAL_APIC *)entry;
416		madt_add_cpu(proc->ProcessorId, proc->Id, proc->LapicFlags);
417		break;
418	case ACPI_MADT_TYPE_LOCAL_X2APIC:
419		x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
420		madt_add_cpu(x2apic->Uid, x2apic->LocalApicId,
421		    x2apic->LapicFlags);
422		break;
423	}
424}
425
426/*
427 * Add an I/O APIC from an entry in the table.
428 */
429static void
430madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
431{
432	ACPI_MADT_IO_APIC *apic;
433
434	switch (entry->Type) {
435	case ACPI_MADT_TYPE_IO_APIC:
436		apic = (ACPI_MADT_IO_APIC *)entry;
437		if (bootverbose)
438			printf(
439			    "MADT: Found IO APIC ID %u, Interrupt %u at %p\n",
440			    apic->Id, apic->GlobalIrqBase,
441			    (void *)(uintptr_t)apic->Address);
442		if (apic->Id > IOAPIC_MAX_ID)
443			panic("%s: I/O APIC ID %u too high", __func__,
444			    apic->Id);
445		if (ioapics[apic->Id].io_apic != NULL)
446			panic("%s: Double APIC ID %u", __func__, apic->Id);
447		ioapics[apic->Id].io_apic = ioapic_create(apic->Address,
448		    apic->Id, apic->GlobalIrqBase);
449		ioapics[apic->Id].io_vector = apic->GlobalIrqBase;
450		break;
451	default:
452		break;
453	}
454}
455
456/*
457 * Determine properties of an interrupt source.  Note that for ACPI these
458 * functions are only used for ISA interrupts, so we assume ISA bus values
459 * (Active Hi, Edge Triggered) for conforming values except for the ACPI
460 * SCI for which we use Active Lo, Level Triggered.
461 */
462static enum intr_polarity
463interrupt_polarity(UINT16 IntiFlags, UINT8 Source)
464{
465
466	switch (IntiFlags & ACPI_MADT_POLARITY_MASK) {
467	default:
468		printf("WARNING: Bogus Interrupt Polarity. Assume CONFORMS\n");
469		/* FALLTHROUGH*/
470	case ACPI_MADT_POLARITY_CONFORMS:
471		if (Source == AcpiGbl_FADT.SciInterrupt)
472			return (INTR_POLARITY_LOW);
473		else
474			return (INTR_POLARITY_HIGH);
475	case ACPI_MADT_POLARITY_ACTIVE_HIGH:
476		return (INTR_POLARITY_HIGH);
477	case ACPI_MADT_POLARITY_ACTIVE_LOW:
478		return (INTR_POLARITY_LOW);
479	}
480}
481
482static enum intr_trigger
483interrupt_trigger(UINT16 IntiFlags, UINT8 Source)
484{
485
486	switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) {
487	default:
488		printf("WARNING: Bogus Interrupt Trigger Mode. Assume CONFORMS.\n");
489		/*FALLTHROUGH*/
490	case ACPI_MADT_TRIGGER_CONFORMS:
491		if (Source == AcpiGbl_FADT.SciInterrupt)
492			return (INTR_TRIGGER_LEVEL);
493		else
494			return (INTR_TRIGGER_EDGE);
495	case ACPI_MADT_TRIGGER_EDGE:
496		return (INTR_TRIGGER_EDGE);
497	case ACPI_MADT_TRIGGER_LEVEL:
498		return (INTR_TRIGGER_LEVEL);
499	}
500}
501
502/*
503 * Find the local APIC ID associated with a given ACPI Processor ID.
504 */
505static int
506madt_find_cpu(u_int acpi_id, u_int *apic_id)
507{
508	int i;
509
510	for (i = 0; i <= max_apic_id; i++) {
511		if (!lapics[i].la_enabled)
512			continue;
513		if (lapics[i].la_acpi_id != acpi_id)
514			continue;
515		*apic_id = i;
516		return (0);
517	}
518	return (ENOENT);
519}
520
521/*
522 * Find the IO APIC and pin on that APIC associated with a given global
523 * interrupt.
524 */
525static int
526madt_find_interrupt(int intr, void **apic, u_int *pin)
527{
528	int i, best;
529
530	best = -1;
531	for (i = 0; i <= IOAPIC_MAX_ID; i++) {
532		if (ioapics[i].io_apic == NULL ||
533		    ioapics[i].io_vector > intr)
534			continue;
535		if (best == -1 ||
536		    ioapics[best].io_vector < ioapics[i].io_vector)
537			best = i;
538	}
539	if (best == -1)
540		return (ENOENT);
541	*apic = ioapics[best].io_apic;
542	*pin = intr - ioapics[best].io_vector;
543	if (*pin > 32)
544		printf("WARNING: Found intpin of %u for vector %d\n", *pin,
545		    intr);
546	return (0);
547}
548
549void
550madt_parse_interrupt_values(void *entry,
551    enum intr_trigger *trig, enum intr_polarity *pol)
552{
553	ACPI_MADT_INTERRUPT_OVERRIDE *intr;
554	char buf[64];
555
556	intr = entry;
557
558	if (bootverbose)
559		printf("MADT: Interrupt override: source %u, irq %u\n",
560		    intr->SourceIrq, intr->GlobalIrq);
561	KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero"));
562
563	/*
564	 * Lookup the appropriate trigger and polarity modes for this
565	 * entry.
566	 */
567	*trig = interrupt_trigger(intr->IntiFlags, intr->SourceIrq);
568	*pol = interrupt_polarity(intr->IntiFlags, intr->SourceIrq);
569
570	/*
571	 * If the SCI is identity mapped but has edge trigger and
572	 * active-hi polarity or the force_sci_lo tunable is set,
573	 * force it to use level/lo.
574	 */
575	if (intr->SourceIrq == AcpiGbl_FADT.SciInterrupt) {
576		madt_found_sci_override = 1;
577		if (getenv_string("hw.acpi.sci.trigger", buf, sizeof(buf))) {
578			if (tolower(buf[0]) == 'e')
579				*trig = INTR_TRIGGER_EDGE;
580			else if (tolower(buf[0]) == 'l')
581				*trig = INTR_TRIGGER_LEVEL;
582			else
583				panic(
584				"Invalid trigger %s: must be 'edge' or 'level'",
585				    buf);
586			printf("MADT: Forcing SCI to %s trigger\n",
587			    *trig == INTR_TRIGGER_EDGE ? "edge" : "level");
588		}
589		if (getenv_string("hw.acpi.sci.polarity", buf, sizeof(buf))) {
590			if (tolower(buf[0]) == 'h')
591				*pol = INTR_POLARITY_HIGH;
592			else if (tolower(buf[0]) == 'l')
593				*pol = INTR_POLARITY_LOW;
594			else
595				panic(
596				"Invalid polarity %s: must be 'high' or 'low'",
597				    buf);
598			printf("MADT: Forcing SCI to active %s polarity\n",
599			    *pol == INTR_POLARITY_HIGH ? "high" : "low");
600		}
601	}
602}
603
604/*
605 * Parse an interrupt source override for an ISA interrupt.
606 */
607static void
608madt_parse_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *intr)
609{
610	void *new_ioapic, *old_ioapic;
611	u_int new_pin, old_pin;
612	enum intr_trigger trig;
613	enum intr_polarity pol;
614
615	if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
616	    intr->GlobalIrq == 2) {
617		if (bootverbose)
618			printf("MADT: Skipping timer override\n");
619		return;
620	}
621
622	if (madt_find_interrupt(intr->GlobalIrq, &new_ioapic, &new_pin) != 0) {
623		printf("MADT: Could not find APIC for vector %u (IRQ %u)\n",
624		    intr->GlobalIrq, intr->SourceIrq);
625		return;
626	}
627
628	madt_parse_interrupt_values(intr, &trig, &pol);
629
630	/* Remap the IRQ if it is mapped to a different interrupt vector. */
631	if (intr->SourceIrq != intr->GlobalIrq) {
632		/*
633		 * If the SCI is remapped to a non-ISA global interrupt,
634		 * then override the vector we use to setup and allocate
635		 * the interrupt.
636		 */
637		if (intr->GlobalIrq > 15 &&
638		    intr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
639			acpi_OverrideInterruptLevel(intr->GlobalIrq);
640		else
641			ioapic_remap_vector(new_ioapic, new_pin,
642			    intr->SourceIrq);
643		if (madt_find_interrupt(intr->SourceIrq, &old_ioapic,
644		    &old_pin) != 0)
645			printf("MADT: Could not find APIC for source IRQ %u\n",
646			    intr->SourceIrq);
647		else if (ioapic_get_vector(old_ioapic, old_pin) ==
648		    intr->SourceIrq)
649			ioapic_disable_pin(old_ioapic, old_pin);
650	}
651
652	/* Program the polarity and trigger mode. */
653	ioapic_set_triggermode(new_ioapic, new_pin, trig);
654	ioapic_set_polarity(new_ioapic, new_pin, pol);
655}
656
657/*
658 * Parse an entry for an NMI routed to an IO APIC.
659 */
660static void
661madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi)
662{
663	void *ioapic;
664	u_int pin;
665
666	if (madt_find_interrupt(nmi->GlobalIrq, &ioapic, &pin) != 0) {
667		printf("MADT: Could not find APIC for vector %u\n",
668		    nmi->GlobalIrq);
669		return;
670	}
671
672	ioapic_set_nmi(ioapic, pin);
673	if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
674		ioapic_set_triggermode(ioapic, pin,
675		    interrupt_trigger(nmi->IntiFlags, 0));
676	if (!(nmi->IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
677		ioapic_set_polarity(ioapic, pin,
678		    interrupt_polarity(nmi->IntiFlags, 0));
679}
680
681/*
682 * Parse an entry for an NMI routed to a local APIC LVT pin.
683 */
684static void
685madt_handle_local_nmi(u_int acpi_id, UINT8 Lint, UINT16 IntiFlags)
686{
687	u_int apic_id, pin;
688
689	if (acpi_id == 0xffffffff)
690		apic_id = APIC_ID_ALL;
691	else if (madt_find_cpu(acpi_id, &apic_id) != 0) {
692		if (bootverbose)
693			printf("MADT: Ignoring local NMI routed to "
694			    "ACPI CPU %u\n", acpi_id);
695		return;
696	}
697	if (Lint == 0)
698		pin = APIC_LVT_LINT0;
699	else
700		pin = APIC_LVT_LINT1;
701	lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
702	if (!(IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
703		lapic_set_lvt_triggermode(apic_id, pin,
704		    interrupt_trigger(IntiFlags, 0));
705	if (!(IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
706		lapic_set_lvt_polarity(apic_id, pin,
707		    interrupt_polarity(IntiFlags, 0));
708}
709
710static void
711madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
712{
713
714	madt_handle_local_nmi(nmi->ProcessorId == 0xff ? 0xffffffff :
715	    nmi->ProcessorId, nmi->Lint, nmi->IntiFlags);
716}
717
718static void
719madt_parse_local_x2apic_nmi(ACPI_MADT_LOCAL_X2APIC_NMI *nmi)
720{
721
722	madt_handle_local_nmi(nmi->Uid, nmi->Lint, nmi->IntiFlags);
723}
724
725/*
726 * Parse interrupt entries.
727 */
728static void
729madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
730{
731
732	switch (entry->Type) {
733	case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
734		madt_parse_interrupt_override(
735			(ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
736		break;
737	case ACPI_MADT_TYPE_NMI_SOURCE:
738		madt_parse_nmi((ACPI_MADT_NMI_SOURCE *)entry);
739		break;
740	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
741		madt_parse_local_nmi((ACPI_MADT_LOCAL_APIC_NMI *)entry);
742		break;
743	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
744		madt_parse_local_x2apic_nmi(
745		    (ACPI_MADT_LOCAL_X2APIC_NMI *)entry);
746		break;
747	}
748}
749
750/*
751 * Setup per-CPU ACPI IDs.
752 */
753static void
754madt_set_ids(void *dummy)
755{
756	struct lapic_info *la;
757	struct pcpu *pc;
758	u_int i;
759
760	if (madt == NULL)
761		return;
762
763	KASSERT(lapics != NULL, ("local APICs not initialized"));
764
765	CPU_FOREACH(i) {
766		pc = pcpu_find(i);
767		KASSERT(pc != NULL, ("no pcpu data for CPU %u", i));
768		la = &lapics[pc->pc_apic_id];
769		if (!la->la_enabled)
770			panic("APIC: CPU with APIC ID %u is not enabled",
771			    pc->pc_apic_id);
772		pc->pc_acpi_id = la->la_acpi_id;
773		if (bootverbose)
774			printf("APIC: CPU %u has ACPI ID %u\n", i,
775			    la->la_acpi_id);
776	}
777}
778SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_MIDDLE, madt_set_ids, NULL);
779