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