madt.c revision 119867
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 119867 2003-09-07 23:09:08Z 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
100print_entry(APIC_HEADER *entry)
101{
102
103	switch (entry->Type) {
104	case APIC_INTERRUPT_SOURCE_OVERRIDE: {
105		INTERRUPT_SOURCE_OVERRIDE *iso =
106		    (INTERRUPT_SOURCE_OVERRIDE *)entry;
107		printf("\tInterrupt source override entry\n");
108		printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", iso->Bus,
109		    iso->Source, iso->GlobalSystemInterrupt);
110		break;
111	}
112
113	case APIC_IO:
114		printf("\tI/O APIC entry\n");
115		break;
116
117	case APIC_IO_SAPIC: {
118		IO_SAPIC *sapic = (IO_SAPIC *)entry;
119		printf("\tI/O SAPIC entry\n");
120		printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n",
121		    sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
122		break;
123	}
124
125	case APIC_LOCAL_APIC_NMI:
126		printf("\tLocal APIC NMI entry\n");
127		break;
128
129	case APIC_LOCAL_APIC_OVERRIDE: {
130		LAPIC_OVERRIDE *lapic = (LAPIC_OVERRIDE *)entry;
131		printf("\tLocal APIC override entry\n");
132		printf("\t\tLocal APIC address=0x%lx\n",
133		    lapic->LocalApicAddress);
134		break;
135	}
136
137	case APIC_LOCAL_SAPIC: {
138		LOCAL_SAPIC *sapic = (LOCAL_SAPIC *)entry;
139		printf("\tLocal SAPIC entry\n");
140		printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x",
141		    sapic->ProcessorId, sapic->LocalSapicId,
142		    sapic->LocalSapicEid);
143		if (!sapic->ProcessorEnabled)
144			printf(" (disabled)");
145		printf("\n");
146		break;
147	}
148
149	case APIC_NMI:
150		printf("\tNMI entry\n");
151		break;
152
153	case APIC_PLATFORM_INTERRUPT: {
154		PLATFORM_INTERRUPT_SOURCE *pis =
155		    (PLATFORM_INTERRUPT_SOURCE *)entry;
156		printf("\tPlatform interrupt entry\n");
157		printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, "
158		    "Eid=0x%x, Vector=0x%x, Irq=%d\n",
159		    pis->Polarity, pis->TriggerMode, pis->ProcessorId,
160		    pis->ProcessorEid, pis->IoSapicVector,
161		    pis->GlobalSystemInterrupt);
162		break;
163	}
164
165	case APIC_PROC:
166		printf("\tLocal APIC entry\n");
167		break;
168
169	default:
170		printf("\tUnknown type %d entry\n", entry->Type);
171		break;
172	}
173}
174
175void
176ia64_probe_sapics(void)
177{
178	ACPI_POINTER rsdp_ptr;
179	APIC_HEADER *entry;
180	APIC_TABLE *table;
181	RSDP_DESCRIPTOR *rsdp;
182	XSDT_DESCRIPTOR *xsdt;
183	char *end, *p;
184	int t, tables;
185
186	if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
187		return;
188
189	rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_ptr.Pointer.Physical);
190	xsdt = (XSDT_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp->XsdtPhysicalAddress);
191
192	tables = (UINT64 *)((char *)xsdt + xsdt->Header.Length) -
193	    xsdt->TableOffsetEntry;
194
195	for (t = 0; t < tables; t++) {
196		table = (APIC_TABLE *)
197		    IA64_PHYS_TO_RR7(xsdt->TableOffsetEntry[t]);
198
199		if (bootverbose)
200			printf("Table '%c%c%c%c' at %p\n",
201			    table->Header.Signature[0],
202			    table->Header.Signature[1],
203			    table->Header.Signature[2],
204			    table->Header.Signature[3], table);
205
206		if (strncmp(table->Header.Signature, APIC_SIG, 4) != 0)
207			continue;
208
209		/* Save the address of the processor interrupt block. */
210		if (bootverbose)
211			printf("\tLocal APIC address=0x%x\n",
212			    table->LocalApicAddress);
213		ia64_lapic_address = table->LocalApicAddress;
214
215		end = (char *)table + table->Header.Length;
216		p = (char *)(table + 1);
217		while (p < end) {
218			entry = (APIC_HEADER *)p;
219
220			if (bootverbose)
221				print_entry(entry);
222
223			switch (entry->Type) {
224			case APIC_IO_SAPIC: {
225				IO_SAPIC *sapic = (IO_SAPIC *)entry;
226				sapic_create(sapic->IoSapicId, sapic->Vector,
227				    sapic->IoSapicAddress);
228				break;
229			}
230
231			case APIC_LOCAL_APIC_OVERRIDE: {
232				LAPIC_OVERRIDE *lapic = (LAPIC_OVERRIDE*)entry;
233				ia64_lapic_address = lapic->LocalApicAddress;
234				break;
235			}
236
237#ifdef SMP
238			case APIC_LOCAL_SAPIC: {
239				LOCAL_SAPIC *sapic = (LOCAL_SAPIC *)entry;
240				if (sapic->ProcessorEnabled)
241					cpu_mp_add(sapic->ProcessorId,
242					    sapic->LocalSapicId,
243					    sapic->LocalSapicEid);
244				break;
245			}
246#endif
247
248			default:
249				break;
250			}
251
252			p += entry->Length;
253		}
254	}
255}
256
257/*
258 * Count the number of local SAPIC entries in the APIC table. Every enabled
259 * entry corresponds to a processor.
260 */
261int
262ia64_count_cpus(void)
263{
264	ACPI_POINTER rsdp_ptr;
265	APIC_TABLE *table;
266	LOCAL_SAPIC *entry;
267	RSDP_DESCRIPTOR *rsdp;
268	XSDT_DESCRIPTOR *xsdt;
269	char *end, *p;
270	int cpus, t, tables;
271
272	if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
273		return (0);
274
275	rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_ptr.Pointer.Physical);
276	xsdt = (XSDT_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp->XsdtPhysicalAddress);
277
278	tables = (UINT64 *)((char *)xsdt + xsdt->Header.Length) -
279	    xsdt->TableOffsetEntry;
280
281	cpus = 0;
282
283	for (t = 0; t < tables; t++) {
284		table = (APIC_TABLE *)
285		    IA64_PHYS_TO_RR7(xsdt->TableOffsetEntry[t]);
286
287		if (strncmp(table->Header.Signature, APIC_SIG, 4) != 0)
288			continue;
289
290		end = (char *)table + table->Header.Length;
291		p = (char *)(table + 1);
292		while (p < end) {
293			entry = (LOCAL_SAPIC *)p;
294
295			if (entry->Header.Type == APIC_LOCAL_SAPIC &&
296			    entry->ProcessorEnabled)
297				cpus++;
298
299			p += entry->Header.Length;
300		}
301	}
302
303	return (cpus);
304}
305