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