madt.c revision 125048
1/*-
2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/i386/acpica/madt.c 125048 2004-01-26 19:34:24Z jhb $");
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/smp.h>
39
40#include <vm/vm.h>
41#include <vm/vm_param.h>
42#include <vm/pmap.h>
43
44#include <machine/apicreg.h>
45#include <machine/frame.h>
46#include <machine/intr_machdep.h>
47#include <machine/apicvar.h>
48#include <machine/md_var.h>
49#include <machine/specialreg.h>
50
51#include "acpi.h"
52#include <dev/acpica/acpivar.h>
53#include <dev/pci/pcivar.h>
54
55#define	NIOAPICS		32	/* Max number of I/O APICs */
56#define	NLAPICS			32	/* Max number of local APICs */
57
58typedef	void madt_entry_handler(APIC_HEADER *entry, void *arg);
59
60/* These two arrays are indexed by APIC IDs. */
61struct ioapic_info {
62	void *io_apic;
63	UINT32 io_vector;
64} ioapics[NIOAPICS];
65
66struct lapic_info {
67	u_int la_present:1;
68	u_int la_enabled:1;
69	u_int la_apic_id:8;
70} lapics[NLAPICS + 1];
71
72static MULTIPLE_APIC_TABLE *madt;
73static vm_paddr_t madt_physaddr;
74static vm_offset_t madt_length;
75
76MALLOC_DEFINE(M_MADT, "MADT Table", "ACPI MADT Table Items");
77
78static u_char	interrupt_polarity(UINT16 Polarity);
79static u_char	interrupt_trigger(UINT16 TriggerMode);
80static int	madt_find_cpu(u_int acpi_id, u_int *apic_id);
81static int	madt_find_interrupt(int intr, void **apic, u_int *pin);
82static void	*madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
83static void	*madt_map_table(vm_paddr_t pa, int offset, const char *sig);
84static void	madt_parse_apics(APIC_HEADER *entry, void *arg);
85static void	madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr);
86static void	madt_parse_ints(APIC_HEADER *entry, void *arg __unused);
87static void	madt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi);
88static void	madt_parse_nmi(MADT_NMI_SOURCE *nmi);
89static int	madt_probe(void);
90static int	madt_probe_cpus(void);
91static void	madt_probe_cpus_handler(APIC_HEADER *entry, void *arg __unused);
92static int	madt_probe_table(vm_paddr_t address);
93static void	madt_register(void *dummy);
94static int	madt_setup_local(void);
95static int	madt_setup_io(void);
96static void	madt_unmap(void *data, vm_offset_t length);
97static void	madt_unmap_table(void *table);
98static void	madt_walk_table(madt_entry_handler *handler, void *arg);
99
100static struct apic_enumerator madt_enumerator = {
101	"MADT",
102	madt_probe,
103	madt_probe_cpus,
104	madt_setup_local,
105	madt_setup_io
106};
107
108/*
109 * Code to abuse the crashdump map to map in the tables for the early
110 * probe.  We cheat and make the following assumptions about how we
111 * use this KVA: page 0 is used to map in the first page of each table
112 * found via the RSDT or XSDT and pages 1 to n are used to map in the
113 * RSDT or XSDT.  The offset is in pages; the length is in bytes.
114 */
115static void *
116madt_map(vm_paddr_t pa, int offset, vm_offset_t length)
117{
118	vm_offset_t va, off;
119	void *data;
120
121	off = pa & PAGE_MASK;
122	length = roundup(length + off, PAGE_SIZE);
123	pa = pa & PG_FRAME;
124	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
125	    (offset * PAGE_SIZE);
126	data = (void *)(va + off);
127	length -= PAGE_SIZE;
128	while (length > 0) {
129		va += PAGE_SIZE;
130		pa += PAGE_SIZE;
131		length -= PAGE_SIZE;
132		pmap_kenter(va, pa);
133		invlpg(va);
134	}
135	return (data);
136}
137
138static void
139madt_unmap(void *data, vm_offset_t length)
140{
141	vm_offset_t va, off;
142
143	va = (vm_offset_t)data;
144	off = va & PAGE_MASK;
145	length = roundup(length + off, PAGE_SIZE);
146	va &= ~PAGE_MASK;
147	while (length > 0) {
148		pmap_kremove(va);
149		invlpg(va);
150		va += PAGE_SIZE;
151		length -= PAGE_SIZE;
152	}
153}
154
155static void *
156madt_map_table(vm_paddr_t pa, int offset, const char *sig)
157{
158	ACPI_TABLE_HEADER *header;
159	vm_offset_t length;
160
161	header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
162	if (strncmp(header->Signature, sig, 4) != 0) {
163		madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
164		return (NULL);
165	}
166	length = header->Length;
167	madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
168	return (madt_map(pa, offset, length));
169}
170
171static void
172madt_unmap_table(void *table)
173{
174	ACPI_TABLE_HEADER *header;
175
176	header = (ACPI_TABLE_HEADER *)table;
177	madt_unmap(table, header->Length);
178}
179
180/*
181 * Look for an ACPI Multiple APIC Description Table ("APIC")
182 */
183static int
184madt_probe(void)
185{
186	ACPI_POINTER rsdp_ptr;
187	RSDP_DESCRIPTOR *rsdp;
188	RSDT_DESCRIPTOR *rsdt;
189	XSDT_DESCRIPTOR *xsdt;
190	int i, count;
191
192	if (resource_disabled("acpi", 0))
193		return (ENXIO);
194
195	/*
196	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
197	 * calls pmap_mapdev() to find the RSDP, we assume that we can use
198	 * pmap_mapdev() to map the RSDP.
199	 */
200	if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
201		return (ENXIO);
202#ifdef __i386__
203	KASSERT(rsdp_ptr.Pointer.Physical < KERNLOAD, ("RSDP too high"));
204#endif
205	rsdp = pmap_mapdev(rsdp_ptr.Pointer.Physical, sizeof(RSDP_DESCRIPTOR));
206	if (rsdp == NULL) {
207		if (bootverbose)
208			printf("MADT: Failed to map RSDP\n");
209		return (ENXIO);
210	}
211
212	/*
213	 * For ACPI < 2.0, use the RSDT.  For ACPI >= 2.0, use the XSDT.
214	 * We map the XSDT and RSDT at page 1 in the crashdump area.
215	 * Page 0 is used to map in the headers of candidate ACPI tables.
216	 */
217	if (rsdp->Revision >= 2) {
218		xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG);
219		if (xsdt == NULL) {
220			if (bootverbose)
221				printf("MADT: Failed to map XSDT\n");
222			return (ENXIO);
223		}
224		count = (xsdt->Length - sizeof(ACPI_TABLE_HEADER)) /
225		    sizeof(UINT64);
226		for (i = 0; i < count; i++)
227			if (madt_probe_table(xsdt->TableOffsetEntry[i]))
228				break;
229		madt_unmap_table(xsdt);
230	} else {
231		rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1, RSDT_SIG);
232		if (rsdt == NULL) {
233			if (bootverbose)
234				printf("MADT: Failed to map RSDT\n");
235			return (ENXIO);
236		}
237		count = (rsdt->Length - sizeof(ACPI_TABLE_HEADER)) /
238		    sizeof(UINT32);
239		for (i = 0; i < count; i++)
240			if (madt_probe_table(rsdt->TableOffsetEntry[i]))
241				break;
242		madt_unmap_table(rsdt);
243	}
244	pmap_unmapdev((vm_offset_t)rsdp, sizeof(RSDP_DESCRIPTOR));
245	if (madt_physaddr == 0) {
246		if (bootverbose)
247			printf("MADT: No MADT table found\n");
248		return (ENXIO);
249	}
250	if (bootverbose)
251		printf("MADT: Found table at 0x%jx\n",
252		    (uintmax_t)madt_physaddr);
253
254	return (0);
255}
256
257/*
258 * See if a given ACPI table is the MADT.
259 */
260static int
261madt_probe_table(vm_paddr_t address)
262{
263	ACPI_TABLE_HEADER *table;
264
265	table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER));
266	if (table == NULL) {
267		if (bootverbose)
268			printf("MADT: Failed to map table at 0x%jx\n",
269			    (uintmax_t)address);
270		return (0);
271	}
272	if (bootverbose)
273		printf("Table '%.4s' at 0x%jx\n", table->Signature,
274		    (uintmax_t)address);
275
276	/* XXX: Verify checksum? */
277	if (strncmp(table->Signature, APIC_SIG, 4) != 0) {
278		madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
279		return (0);
280	}
281	madt_physaddr = address;
282	madt_length = table->Length;
283	madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
284	return (1);
285}
286
287/*
288 * Run through the MP table enumerating CPUs.
289 */
290static int
291madt_probe_cpus(void)
292{
293
294	madt = madt_map_table(madt_physaddr, 0, APIC_SIG);
295	KASSERT(madt != NULL, ("Unable to re-map MADT"));
296	madt_walk_table(madt_probe_cpus_handler, NULL);
297	madt_unmap_table(madt);
298	madt = NULL;
299	return (0);
300}
301
302/*
303 * Initialize the local APIC on the BSP.
304 */
305static int
306madt_setup_local(void)
307{
308
309	madt = pmap_mapdev(madt_physaddr, madt_length);
310	lapic_init((uintptr_t)madt->LocalApicAddress);
311	printf("ACPI APIC Table: <%.*s %.*s>\n",
312	    (int)sizeof(madt->OemId), madt->OemId,
313	    (int)sizeof(madt->OemTableId), madt->OemTableId);
314
315	/*
316	 * We ignore 64-bit local APIC override entries.  Should we
317	 * perhaps emit a warning here if we find one?
318	 */
319	return (0);
320}
321
322/*
323 * Enumerate I/O APICs and setup interrupt sources.
324 */
325static int
326madt_setup_io(void)
327{
328	int i;
329
330	/* Try to initialize ACPI so that we can access the FADT. */
331	i = acpi_Startup();
332	if (ACPI_FAILURE(i)) {
333		printf("MADT: ACPI Startup failed with %s\n",
334		    AcpiFormatException(i));
335		printf("Try disabling either ACPI or apic support.\n");
336		panic("Using MADT but ACPI doesn't work");
337	}
338
339	/* First, we run through adding I/O APIC's. */
340	madt_walk_table(madt_parse_apics, NULL);
341
342	/* Second, we run through the table tweaking interrupt sources. */
343	madt_walk_table(madt_parse_ints, NULL);
344
345	/* Third, we register all the I/O APIC's. */
346	for (i = 0; i < NIOAPICS; i++)
347		if (ioapics[i].io_apic != NULL)
348			ioapic_register(ioapics[i].io_apic);
349
350	/* Finally, we throw the switch to enable the I/O APIC's. */
351	acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
352
353	return (0);
354}
355
356static void
357madt_register(void *dummy __unused)
358{
359
360	apic_register_enumerator(&madt_enumerator);
361}
362SYSINIT(madt_register, SI_SUB_CPU - 1, SI_ORDER_FIRST, madt_register, NULL)
363
364/*
365 * Call the handler routine for each entry in the MADT table.
366 */
367static void
368madt_walk_table(madt_entry_handler *handler, void *arg)
369{
370	APIC_HEADER *entry;
371	u_char *p, *end;
372
373	end = (u_char *)(madt) + madt->Length;
374	for (p = (u_char *)(madt + 1); p < end; ) {
375		entry = (APIC_HEADER *)p;
376		handler(entry, arg);
377		p += entry->Length;
378	}
379}
380
381static void
382madt_probe_cpus_handler(APIC_HEADER *entry, void *arg)
383{
384	MADT_PROCESSOR_APIC *proc;
385	struct lapic_info *la;
386
387	switch (entry->Type) {
388	case APIC_PROCESSOR:
389		/*
390		 * The MADT does not include a BSP flag, so we have to
391		 * let the MP code figure out which CPU is the BSP on
392		 * its own.
393		 */
394		proc = (MADT_PROCESSOR_APIC *)entry;
395		if (bootverbose)
396			printf("MADT: Found CPU APIC ID %d ACPI ID %d: %s\n",
397			    proc->LocalApicId, proc->ProcessorId,
398			    proc->ProcessorEnabled ? "enabled" : "disabled");
399		if (proc->ProcessorId > NLAPICS)
400			panic("%s: CPU ID %d too high", __func__,
401			    proc->ProcessorId);
402		la = &lapics[proc->ProcessorId];
403		KASSERT(la->la_present == 0,
404		    ("Duplicate local ACPI ID %d", proc->ProcessorId));
405		la->la_present = 1;
406		la->la_apic_id = proc->LocalApicId;
407		if (proc->ProcessorEnabled) {
408			la->la_enabled = 1;
409			lapic_create(proc->LocalApicId, 0);
410		}
411		break;
412	}
413}
414
415
416/*
417 * Add an I/O APIC from an entry in the table.
418 */
419static void
420madt_parse_apics(APIC_HEADER *entry, void *arg __unused)
421{
422	MADT_IO_APIC *apic;
423
424	switch (entry->Type) {
425	case APIC_IO:
426		apic = (MADT_IO_APIC *)entry;
427		if (bootverbose)
428			printf("MADT: Found IO APIC ID %d, Interrupt %d at %p\n",
429			    apic->IoApicId, apic->Interrupt,
430			    (void *)(uintptr_t)apic->Address);
431		if (apic->IoApicId >= NIOAPICS)
432			panic("%s: I/O APIC ID %d too high", __func__,
433			    apic->IoApicId);
434		if (ioapics[apic->IoApicId].io_apic != NULL)
435			panic("%s: Double APIC ID %d", __func__,
436			    apic->IoApicId);
437		ioapics[apic->IoApicId].io_apic = ioapic_create(
438			(uintptr_t)apic->Address, apic->IoApicId,
439			    apic->Interrupt);
440		ioapics[apic->IoApicId].io_vector = apic->Interrupt;
441		break;
442	default:
443		break;
444	}
445}
446
447/*
448 * Determine properties of an interrupt source.  Note that for ACPI,
449 * these are only used for ISA interrupts, so we assume ISA bus values
450 * (Active Hi, Edge Triggered) for conforming values.
451 */
452static u_char
453interrupt_polarity(UINT16 Polarity)
454{
455
456	switch (Polarity) {
457	case POLARITY_CONFORMS:
458	case POLARITY_ACTIVE_HIGH:
459		return (1);
460	case POLARITY_ACTIVE_LOW:
461		return (0);
462	default:
463		panic("Bogus Interrupt Polarity");
464	}
465}
466
467static u_char
468interrupt_trigger(UINT16 TriggerMode)
469{
470
471	switch (TriggerMode) {
472	case TRIGGER_CONFORMS:
473	case TRIGGER_EDGE:
474		return (1);
475	case TRIGGER_LEVEL:
476		return (0);
477	default:
478		panic("Bogus Interrupt Trigger Mode");
479	}
480}
481
482/*
483 * Find the local APIC ID associated with a given ACPI Processor ID.
484 */
485static int
486madt_find_cpu(u_int acpi_id, u_int *apic_id)
487{
488
489	if (!lapics[acpi_id].la_present)
490		return (ENOENT);
491	*apic_id = lapics[acpi_id].la_apic_id;
492	if (lapics[acpi_id].la_enabled)
493		return (0);
494	else
495		return (ENXIO);
496}
497
498/*
499 * Find the IO APIC and pin on that APIC associated with a given global
500 * interrupt.
501 */
502static int
503madt_find_interrupt(int intr, void **apic, u_int *pin)
504{
505	int i, best;
506
507	best = -1;
508	for (i = 0; i < NIOAPICS; i++) {
509		if (ioapics[i].io_apic == NULL ||
510		    ioapics[i].io_vector > intr)
511			continue;
512		if (best == -1 ||
513		    ioapics[best].io_vector < ioapics[i].io_vector)
514			best = i;
515	}
516	if (best == -1)
517		return (ENOENT);
518	*apic = ioapics[best].io_apic;
519	*pin = intr - ioapics[best].io_vector;
520	if (*pin > 32)
521		printf("WARNING: Found intpin of %u for vector %d\n", *pin,
522		    intr);
523	return (0);
524}
525
526/*
527 * Parse an interrupt source override for an ISA interrupt.
528 */
529static void
530madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
531{
532	void *new_ioapic, *old_ioapic;
533	u_int new_pin, old_pin;
534	int force_lo;
535
536	if (bootverbose)
537		printf("MADT: intr override: source %u, irq %u\n",
538		    intr->Source, intr->Interrupt);
539	KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero"));
540	if (madt_find_interrupt(intr->Interrupt, &new_ioapic,
541	    &new_pin) != 0) {
542		printf("MADT: Could not find APIC for vector %d (IRQ %d)\n",
543		    intr->Interrupt, intr->Source);
544		return;
545	}
546
547	/*
548	 * If the SCI is remapped to a non-ISA global interrupt,
549	 * force it to level trigger and active-lo polarity.
550	 * If the SCI is identity mapped but has edge trigger and
551	 * active-hi polarity, also force it to use level/lo.
552	 */
553	force_lo = 0;
554	if (intr->Source == AcpiGbl_FADT->SciInt)
555		if (intr->Interrupt > 15 || (intr->Interrupt == intr->Source &&
556		    intr->TriggerMode == TRIGGER_EDGE &&
557		    intr->Polarity == POLARITY_ACTIVE_HIGH))
558			force_lo = 1;
559
560	if (intr->Source != intr->Interrupt) {
561		/*
562		 * If the SCI is remapped to a non-ISA global interrupt,
563		 * then override the vector we use to setup and allocate
564		 * the interrupt.
565		 */
566		if (intr->Interrupt > 15 &&
567		    intr->Source == AcpiGbl_FADT->SciInt)
568			acpi_OverrideInterruptLevel(intr->Interrupt);
569		else
570			ioapic_remap_vector(new_ioapic, new_pin, intr->Source);
571		if (madt_find_interrupt(intr->Source, &old_ioapic,
572		    &old_pin) != 0)
573			printf("MADT: Could not find APIC for source IRQ %d\n",
574			    intr->Source);
575		else if (ioapic_get_vector(old_ioapic, old_pin) ==
576		    intr->Source)
577			ioapic_disable_pin(old_ioapic, old_pin);
578	}
579	if (force_lo) {
580		printf(
581	"MADT: Forcing active-lo polarity and level trigger for IRQ %d\n",
582		    intr->Source);
583		ioapic_set_polarity(new_ioapic, new_pin, 0);
584		ioapic_set_triggermode(new_ioapic, new_pin, 0);
585	} else {
586		ioapic_set_polarity(new_ioapic, new_pin,
587		    interrupt_polarity(intr->Polarity));
588		ioapic_set_triggermode(new_ioapic, new_pin,
589		    interrupt_trigger(intr->TriggerMode));
590	}
591}
592
593/*
594 * Parse an entry for an NMI routed to an IO APIC.
595 */
596static void
597madt_parse_nmi(MADT_NMI_SOURCE *nmi)
598{
599	void *ioapic;
600	u_int pin;
601
602	if (madt_find_interrupt(nmi->Interrupt, &ioapic, &pin) != 0) {
603		printf("MADT: Could not find APIC for vector %d\n",
604		    nmi->Interrupt);
605		return;
606	}
607
608	ioapic_set_nmi(ioapic, pin);
609	if (nmi->TriggerMode != TRIGGER_CONFORMS)
610		ioapic_set_triggermode(ioapic, pin,
611		    interrupt_trigger(nmi->TriggerMode));
612	if (nmi->Polarity != TRIGGER_CONFORMS)
613		ioapic_set_polarity(ioapic, pin,
614		    interrupt_polarity(nmi->Polarity));
615}
616
617/*
618 * Parse an entry for an NMI routed to a local APIC LVT pin.
619 */
620static void
621madt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi)
622{
623	u_int apic_id, pin;
624
625	if (nmi->ProcessorId == 0xff)
626		apic_id = APIC_ID_ALL;
627	else if (madt_find_cpu(nmi->ProcessorId, &apic_id) != 0) {
628		if (bootverbose)
629			printf("MADT: Ignoring local NMI routed to ACPI CPU %u\n",
630			    nmi->ProcessorId);
631		return;
632	}
633	if (nmi->Lint == 0)
634		pin = LVT_LINT0;
635	else
636		pin = LVT_LINT1;
637	lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
638	if (nmi->TriggerMode != TRIGGER_CONFORMS)
639		lapic_set_lvt_triggermode(apic_id, pin,
640		    interrupt_trigger(nmi->TriggerMode));
641	if (nmi->Polarity != POLARITY_CONFORMS)
642		lapic_set_lvt_polarity(apic_id, pin,
643		    interrupt_polarity(nmi->Polarity));
644}
645
646/*
647 * Parse interrupt entries.
648 */
649static void
650madt_parse_ints(APIC_HEADER *entry, void *arg __unused)
651{
652
653	switch (entry->Type) {
654	case APIC_XRUPT_OVERRIDE:
655		madt_parse_interrupt_override(
656			(MADT_INTERRUPT_OVERRIDE *)entry);
657		break;
658	case APIC_NMI:
659		madt_parse_nmi((MADT_NMI_SOURCE *)entry);
660		break;
661	case APIC_LOCAL_NMI:
662		madt_parse_local_nmi((MADT_LOCAL_APIC_NMI *)entry);
663		break;
664	}
665}
666
667/*
668 * Setup per-CPU ACPI IDs.
669 */
670static void
671madt_set_ids(void *dummy)
672{
673	struct pcpu *pc;
674	u_int i, j;
675
676	if (madt == NULL)
677		return;
678	for (i = 0; i <= mp_maxid; i++) {
679		if (CPU_ABSENT(i))
680			continue;
681		pc = pcpu_find(i);
682		KASSERT(pc != NULL, ("no pcpu data for CPU %d", i));
683		for (j = 0; j < NLAPICS + 1; j++) {
684			if (!lapics[j].la_present || !lapics[j].la_enabled)
685				continue;
686			if (lapics[j].la_apic_id == pc->pc_apic_id) {
687				pc->pc_acpi_id = j;
688				if (bootverbose)
689					printf("APIC: CPU %u has ACPI ID %u\n",
690					    i, j);
691				break;
692			}
693		}
694		if (j == NLAPICS + 1)
695			panic("Unable to find ACPI ID for CPU %d", i);
696	}
697}
698SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL)
699