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 96912 2002-05-19 04:42:19Z marcel $
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_PHYSICAL_ADDRESS rsdp_phys;
241 RSDP_DESCRIPTOR *rsdp;
242 XSDT_DESCRIPTOR *xsdt;
243 ACPI_TABLE_HEADER *table;
244 int i, count;
245
246 if (AcpiOsGetRootPointer(0, &rsdp_phys) != AE_OK)
247 return 0;
248
249 rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_phys);
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}
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 96912 2002-05-19 04:42:19Z marcel $
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_PHYSICAL_ADDRESS rsdp_phys;
241 RSDP_DESCRIPTOR *rsdp;
242 XSDT_DESCRIPTOR *xsdt;
243 ACPI_TABLE_HEADER *table;
244 int i, count;
245
246 if (AcpiOsGetRootPointer(0, &rsdp_phys) != AE_OK)
247 return 0;
248
249 rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_phys);
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}