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