madt.c revision 118990
1/*-
2 * Copyright (c) 2001 Doug Rabson
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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/ia64/acpica/madt.c 118990 2003-08-16 16:57:57Z marcel $
27 */
28
29#include "acpi.h"
30
31#include <machine/md_var.h>
32
33extern u_int64_t ia64_lapic_address;
34
35struct sapic *sapic_create(int, int, u_int64_t);
36
37#pragma pack(1)
38
39#define	APIC_INTERRUPT_SOURCE_OVERRIDE	2
40#define	APIC_NMI			3
41#define	APIC_LOCAL_APIC_NMI		4
42#define	APIC_LOCAL_APIC_OVERRIDE	5
43#define	APIC_IO_SAPIC			6
44#define	APIC_LOCAL_SAPIC		7
45#define	APIC_PLATFORM_INTERRUPT		8
46
47typedef struct	/* Interrupt Source Override */
48{
49	APIC_HEADER	Header;
50	UINT8		Bus;
51	UINT8		Source;
52	UINT32		GlobalSystemInterrupt;
53	UINT16		Flags;
54} INTERRUPT_SOURCE_OVERRIDE;
55
56typedef struct	/* IO SAPIC */
57{
58	APIC_HEADER	Header;
59	UINT8		IoSapicId;		/* I/O SAPIC ID */
60	UINT8		Reserved;		/* reserved - must be zero */
61	UINT32		Vector;			/* interrupt base */
62	UINT64		IoSapicAddress;		/* SAPIC's physical address */
63} IO_SAPIC;
64
65typedef struct  /* LOCAL SAPIC */
66{
67	APIC_HEADER	Header;
68	UINT8		ProcessorId;		/* ACPI processor id */
69	UINT8		LocalSapicId;		/* Processor local SAPIC id */
70	UINT8		LocalSapicEid;		/* Processor local SAPIC eid */
71	UINT8		Reserved[3];
72	UINT32		ProcessorEnabled: 1;
73	UINT32		FlagsReserved: 31;
74} LOCAL_SAPIC;
75
76typedef struct	/* LOCAL APIC OVERRIDE */
77{
78	APIC_HEADER	Header;
79	UINT16		Reserved;
80	UINT64		LocalApicAddress;
81} LAPIC_OVERRIDE;
82
83typedef struct  /* PLATFORM INTERRUPT SOURCE */
84{
85	APIC_HEADER	Header;
86	UINT16		Polarity   : 2;		/* Polarity of input signal */
87	UINT16		TriggerMode: 2;		/* Trigger mode of input signal */
88	UINT16		Reserved1  : 12;
89	UINT8		InterruptType;		/* 1-PMI, 2-INIT, 3-Error */
90	UINT8		ProcessorId;		/* Processor ID of destination */
91	UINT8		ProcessorEid;		/* Processor EID of destination */
92	UINT8		IoSapicVector;		/* Value for redirection table */
93	UINT32		GlobalSystemInterrupt;	/* Global System Interrupt */
94	UINT32		Reserved2;
95} PLATFORM_INTERRUPT_SOURCE;
96
97#pragma pack()
98
99static void
100parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *override)
101{
102	if (bootverbose)
103		printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", override->Bus,
104		    override->Source, override->GlobalSystemInterrupt);
105}
106
107static void
108parse_io_sapic(IO_SAPIC *sapic)
109{
110	if (bootverbose)
111		printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n",
112		    sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
113	sapic_create(sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
114}
115
116static void
117parse_local_sapic(LOCAL_SAPIC *sapic)
118{
119	if (bootverbose) {
120		printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x",
121		    sapic->ProcessorId, sapic->LocalSapicId,
122		    sapic->LocalSapicEid);
123		if (!sapic->ProcessorEnabled)
124			printf(" (disabled)");
125		printf("\n");
126	}
127#ifdef SMP
128	if (sapic->ProcessorEnabled)
129		cpu_mp_add(sapic->ProcessorId, sapic->LocalSapicId,
130		    sapic->LocalSapicEid);
131#endif
132}
133
134static void
135parse_lapic_override(LAPIC_OVERRIDE *lapic)
136{
137	if (bootverbose)
138		printf("\t\tLocal APIC address=0x%lx\n",
139		    lapic->LocalApicAddress);
140	ia64_lapic_address = lapic->LocalApicAddress;
141}
142
143static void
144parse_platform_interrupt(PLATFORM_INTERRUPT_SOURCE *source)
145{
146	if (bootverbose)
147		printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, "
148		    "Eid=0x%x, Vector=0x%x, Irq=%d\n", source->Polarity,
149		    source->TriggerMode, source->ProcessorId,
150		    source->ProcessorEid, source->IoSapicVector,
151		    source->GlobalSystemInterrupt);
152}
153
154static int
155parse_madt(APIC_TABLE *madt, int countcpus)
156{
157	char *end, *p;
158	int cpus;
159
160	end = (char *)madt + madt->Header.Length;
161
162	/*
163	 * MADT header is followed by a number of variable length
164	 * structures.
165	 */
166
167	if (countcpus) {
168		cpus = 0;
169
170		for (p = (char *)(madt + 1); p < end; ) {
171			APIC_HEADER *head = (APIC_HEADER *)p;
172
173			if (head->Type == APIC_LOCAL_SAPIC) {
174				LOCAL_SAPIC *sapic = (LOCAL_SAPIC *) head;
175				if (sapic->ProcessorEnabled)
176					cpus++;
177			}
178			p = p + head->Length;
179		}
180
181		return (cpus);
182	}
183
184	/* Save the address of the processor interrupt block. */
185	if (bootverbose)
186		printf("\tLocal APIC address=0x%x\n",
187		    madt->LocalApicAddress);
188	ia64_lapic_address = madt->LocalApicAddress;
189
190	for (p = (char *)(madt + 1); p < end; ) {
191		APIC_HEADER *head = (APIC_HEADER *)p;
192
193		if (bootverbose)
194			printf("\t");
195
196		switch (head->Type) {
197		case APIC_PROC:
198			if (bootverbose)
199				printf("Local APIC entry\n");
200			break;
201
202		case APIC_IO:
203			if (bootverbose)
204				printf("I/O APIC entry\n");
205			break;
206
207		case APIC_INTERRUPT_SOURCE_OVERRIDE:
208			if (bootverbose)
209				printf("Interrupt source override entry\n");
210			parse_interrupt_override
211				((INTERRUPT_SOURCE_OVERRIDE *) head);
212			break;
213
214		case APIC_NMI:
215			if (bootverbose)
216				printf("NMI entry\n");
217			break;
218
219		case APIC_LOCAL_APIC_NMI:
220			if (bootverbose)
221				printf("Local APIC NMI entry\n");
222			break;
223
224
225		case APIC_LOCAL_APIC_OVERRIDE:
226			if (bootverbose)
227				printf("Local APIC override entry\n");
228			parse_lapic_override((LAPIC_OVERRIDE*)head);
229			break;
230
231		case APIC_IO_SAPIC:
232			if (bootverbose)
233				printf("I/O SAPIC entry\n");
234			parse_io_sapic((IO_SAPIC *) head);
235			break;
236
237		case APIC_LOCAL_SAPIC:
238			if (bootverbose)
239				printf("Local SAPIC entry\n");
240			parse_local_sapic((LOCAL_SAPIC *) head);
241			break;
242
243		case APIC_PLATFORM_INTERRUPT:
244			if (bootverbose)
245				printf("Platform interrupt entry\n");
246			parse_platform_interrupt
247				((PLATFORM_INTERRUPT_SOURCE *) head);
248			break;
249
250		default:
251			if (bootverbose)
252				printf("Unknown type %d entry\n", head->Type);
253			break;
254		}
255
256		p = p + head->Length;
257	}
258
259	return (0);
260}
261
262static int
263parse_table(int countcpus)
264{
265	ACPI_POINTER		rsdp_ptr;
266	RSDP_DESCRIPTOR		*rsdp;
267	XSDT_DESCRIPTOR		*xsdt;
268	ACPI_TABLE_HEADER	*table;
269	int			i, count;
270
271	if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
272		return 0;
273
274	rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_ptr.Pointer.Physical);
275	xsdt = (XSDT_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp->XsdtPhysicalAddress);
276
277	count = (UINT64 *)((char *)xsdt + xsdt->Header.Length)
278	    - xsdt->TableOffsetEntry;
279	for (i = 0; i < count; i++) {
280		table = (ACPI_TABLE_HEADER *)
281			IA64_PHYS_TO_RR7(xsdt->TableOffsetEntry[i]);
282
283		if (bootverbose && !countcpus)
284			printf("Table '%c%c%c%c' at %p\n", table->Signature[0],
285			    table->Signature[1], table->Signature[2],
286			    table->Signature[3], table);
287
288		if (!strncmp(table->Signature, APIC_SIG, 4))
289			return (parse_madt((APIC_TABLE *) table, countcpus));
290	}
291	return (0);
292}
293
294void
295ia64_probe_sapics(void)
296{
297	parse_table(0);
298}
299
300/*
301 * Count the number of local SAPIC entries in the APIC table. Every enabled
302 * entry corresponds to a processor.
303 */
304int
305ia64_count_cpus(void)
306{
307	return (parse_table(1));
308}
309