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