madt.c revision 100274
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 100274 2002-07-17 23:49:55Z peter $
27 */
28
29#include "acpi.h"
30
31#include <machine/cpu.h>
32
33struct sapic *sapic_create(int, int, u_int64_t);
34
35#pragma pack(1)
36
37#define	APIC_INTERRUPT_SOURCE_OVERRIDE	2
38#define	APIC_NMI			3
39#define	APIC_LOCAL_APIC_NMI		4
40#define	APIC_LOCAL_APIC_OVERRIDE	5
41#define	APIC_IO_SAPIC			6
42#define	APIC_LOCAL_SAPIC		7
43#define	APIC_PLATFORM_INTERRUPT		8
44
45typedef struct	/* Interrupt Source Override */
46{
47	APIC_HEADER	Header;
48	UINT8		Bus;
49	UINT8		Source;
50	UINT32		GlobalSystemInterrupt;
51	UINT16		Flags;
52} INTERRUPT_SOURCE_OVERRIDE;
53
54typedef struct	/* IO SAPIC */
55{
56	APIC_HEADER	Header;
57	UINT8		IoSapicId;		/* I/O SAPIC ID */
58	UINT8		Reserved;		/* reserved - must be zero */
59	UINT32		Vector;			/* interrupt base */
60	UINT64		IoSapicAddress;		/* SAPIC's physical address */
61} IO_SAPIC;
62
63typedef struct  /* LOCAL SAPIC */
64{
65	APIC_HEADER	Header;
66	UINT8		ProcessorId;		/* ACPI processor id */
67	UINT8		LocalSapicId;		/* Processor local SAPIC id */
68	UINT8		LocalSapicEid;		/* Processor local SAPIC eid */
69	UINT8		Reserved[3];
70	UINT32		ProcessorEnabled: 1;
71	UINT32		FlagsReserved: 31;
72} LOCAL_SAPIC;
73
74typedef struct  /* PLATFORM INTERRUPT SOURCE */
75{
76	APIC_HEADER	Header;
77	UINT16		Polarity   : 2;		/* Polarity of input signal */
78	UINT16		TriggerMode: 2;		/* Trigger mode of input signal */
79	UINT16		Reserved1  : 12;
80	UINT8		InterruptType;		/* 1-PMI, 2-INIT, 3-Error */
81	UINT8		ProcessorId;		/* Processor ID of destination */
82	UINT8		ProcessorEid;		/* Processor EID of destination */
83	UINT8		IoSapicVector;		/* Value for redirection table */
84	UINT32		GlobalSystemInterrupt;	/* Global System Interrupt */
85	UINT32		Reserved2;
86} PLATFORM_INTERRUPT_SOURCE;
87
88#pragma pack()
89
90static void
91parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *override)
92{
93	if (bootverbose)
94		printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", override->Bus,
95		    override->Source, override->GlobalSystemInterrupt);
96}
97
98static void
99parse_io_sapic(IO_SAPIC *sapic)
100{
101	if (bootverbose)
102		printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n",
103		    sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
104	sapic_create(sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
105}
106
107static void
108parse_local_sapic(LOCAL_SAPIC *sapic)
109{
110	if (bootverbose) {
111		printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x",
112		    sapic->ProcessorId, sapic->LocalSapicId,
113		    sapic->LocalSapicEid);
114		if (!sapic->ProcessorEnabled)
115			printf(" (disabled)");
116		printf("\n");
117	}
118#ifdef SMP
119	if (sapic->ProcessorEnabled)
120		cpu_mp_add(sapic->ProcessorId, sapic->LocalSapicId,
121		    sapic->LocalSapicEid);
122#endif
123}
124
125static void
126parse_platform_interrupt(PLATFORM_INTERRUPT_SOURCE *source)
127{
128	if (bootverbose)
129		printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, "
130		    "Eid=0x%x, Vector=0x%x, Irq=%d\n", source->Polarity,
131		    source->TriggerMode, source->ProcessorId,
132		    source->ProcessorEid, source->IoSapicVector,
133		    source->GlobalSystemInterrupt);
134}
135
136static int
137parse_madt(APIC_TABLE *madt, int countcpus)
138{
139	char *end, *p;
140	int cpus;
141
142	end = (char *)madt + madt->Header.Length;
143
144	/*
145	 * MADT header is followed by a number of variable length
146	 * structures.
147	 */
148
149	if (countcpus) {
150		cpus = 0;
151
152		for (p = (char *)(madt + 1); p < end; ) {
153			APIC_HEADER *head = (APIC_HEADER *)p;
154
155			if (head->Type == APIC_LOCAL_SAPIC) {
156				LOCAL_SAPIC *sapic = (LOCAL_SAPIC *) head;
157				if (sapic->ProcessorEnabled)
158					cpus++;
159			}
160			p = p + head->Length;
161		}
162
163		return (cpus);
164	}
165
166	for (p = (char *)(madt + 1); p < end; ) {
167		APIC_HEADER *head = (APIC_HEADER *)p;
168
169		if (bootverbose)
170			printf("\t");
171
172		switch (head->Type) {
173		case APIC_PROC:
174			if (bootverbose)
175				printf("Local APIC entry\n");
176			break;
177
178		case APIC_IO:
179			if (bootverbose)
180				printf("I/O APIC entry\n");
181			break;
182
183		case APIC_INTERRUPT_SOURCE_OVERRIDE:
184			if (bootverbose)
185				printf("Interrupt source override entry\n");
186			parse_interrupt_override
187				((INTERRUPT_SOURCE_OVERRIDE *) head);
188			break;
189
190		case APIC_NMI:
191			if (bootverbose)
192				printf("NMI entry\n");
193			break;
194
195		case APIC_LOCAL_APIC_NMI:
196			if (bootverbose)
197				printf("Local APIC NMI entry\n");
198			break;
199
200
201		case APIC_LOCAL_APIC_OVERRIDE:
202			if (bootverbose)
203				printf("Local APIC override entry\n");
204			break;
205
206		case APIC_IO_SAPIC:
207			if (bootverbose)
208				printf("I/O SAPIC entry\n");
209			parse_io_sapic((IO_SAPIC *) head);
210			break;
211
212		case APIC_LOCAL_SAPIC:
213			if (bootverbose)
214				printf("Local SAPIC entry\n");
215			parse_local_sapic((LOCAL_SAPIC *) head);
216			break;
217
218		case APIC_PLATFORM_INTERRUPT:
219			if (bootverbose)
220				printf("Platform interrupt entry\n");
221			parse_platform_interrupt
222				((PLATFORM_INTERRUPT_SOURCE *) head);
223			break;
224
225		default:
226			if (bootverbose)
227				printf("Unknown type %d entry\n", head->Type);
228			break;
229		}
230
231		p = p + head->Length;
232	}
233
234	return (0);
235}
236
237static int
238parse_table(int countcpus)
239{
240	ACPI_POINTER		rsdp_ptr;
241	RSDP_DESCRIPTOR		*rsdp;
242	XSDT_DESCRIPTOR		*xsdt;
243	ACPI_TABLE_HEADER	*table;
244	int			i, count;
245
246	if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
247		return 0;
248
249	rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_ptr.Pointer.Physical);
250	xsdt = (XSDT_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp->XsdtPhysicalAddress);
251
252	count = (UINT64 *)((char *)xsdt + xsdt->Header.Length)
253	    - xsdt->TableOffsetEntry;
254	for (i = 0; i < count; i++) {
255		table = (ACPI_TABLE_HEADER *)
256			IA64_PHYS_TO_RR7(xsdt->TableOffsetEntry[i]);
257
258		if (bootverbose && !countcpus)
259			printf("Table '%c%c%c%c' at %p\n", table->Signature[0],
260			    table->Signature[1], table->Signature[2],
261			    table->Signature[3], table);
262
263		if (!strncmp(table->Signature, APIC_SIG, 4))
264			return (parse_madt((APIC_TABLE *) table, countcpus));
265	}
266	return (0);
267}
268
269void
270ia64_probe_sapics(void)
271{
272	parse_table(0);
273}
274
275/*
276 * Count the number of local SAPIC entries in the APIC table. Every enabled
277 * entry corresponds to a processor.
278 */
279int
280ia64_count_cpus(void)
281{
282	return (parse_table(1));
283}
284