1 /* 2 * acpi_tables.c - ACPI Boot-Time Table Parsing 3 * 4 * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 5 * 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 * 24 */ 25 26 #include <linux/init.h> 27 #include <linux/kernel.h> 28 #include <linux/smp.h> 29 #include <linux/string.h> 30 #include <linux/types.h> 31 #include <linux/irq.h> 32 #include <linux/errno.h> 33 #include <linux/acpi.h> 34 #include <linux/bootmem.h> 35 36 #define PREFIX "ACPI: " 37 38 #define ACPI_MAX_TABLES 128 39 40 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; 41 static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; 42 43 static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; 44 45 static int acpi_apic_instance __initdata; 46 47 void acpi_table_print_madt_entry(struct acpi_subtable_header *header) 48 { 49 if (!header) 50 return; 51 52 switch (header->type) { 53 54 case ACPI_MADT_TYPE_LOCAL_APIC: 55 { 56 struct acpi_madt_local_apic *p = 57 (struct acpi_madt_local_apic *)header; 58 printk(KERN_INFO PREFIX 59 "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", 60 p->processor_id, p->id, 61 (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); 62 } 63 break; 64 65 case ACPI_MADT_TYPE_LOCAL_X2APIC: 66 { 67 struct acpi_madt_local_x2apic *p = 68 (struct acpi_madt_local_x2apic *)header; 69 printk(KERN_INFO PREFIX 70 "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n", 71 p->local_apic_id, p->uid, 72 (p->lapic_flags & ACPI_MADT_ENABLED) ? 73 "enabled" : "disabled"); 74 } 75 break; 76 77 case ACPI_MADT_TYPE_IO_APIC: 78 { 79 struct acpi_madt_io_apic *p = 80 (struct acpi_madt_io_apic *)header; 81 printk(KERN_INFO PREFIX 82 "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", 83 p->id, p->address, p->global_irq_base); 84 } 85 break; 86 87 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 88 { 89 struct acpi_madt_interrupt_override *p = 90 (struct acpi_madt_interrupt_override *)header; 91 printk(KERN_INFO PREFIX 92 "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", 93 p->bus, p->source_irq, p->global_irq, 94 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 95 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); 96 if (p->inti_flags & 97 ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) 98 printk(KERN_INFO PREFIX 99 "INT_SRC_OVR unexpected reserved flags: 0x%x\n", 100 p->inti_flags & 101 ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); 102 103 } 104 break; 105 106 case ACPI_MADT_TYPE_NMI_SOURCE: 107 { 108 struct acpi_madt_nmi_source *p = 109 (struct acpi_madt_nmi_source *)header; 110 printk(KERN_INFO PREFIX 111 "NMI_SRC (%s %s global_irq %d)\n", 112 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 113 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 114 p->global_irq); 115 } 116 break; 117 118 case ACPI_MADT_TYPE_LOCAL_APIC_NMI: 119 { 120 struct acpi_madt_local_apic_nmi *p = 121 (struct acpi_madt_local_apic_nmi *)header; 122 printk(KERN_INFO PREFIX 123 "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", 124 p->processor_id, 125 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], 126 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 127 p->lint); 128 } 129 break; 130 131 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: 132 { 133 u16 polarity, trigger; 134 struct acpi_madt_local_x2apic_nmi *p = 135 (struct acpi_madt_local_x2apic_nmi *)header; 136 137 polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK; 138 trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2; 139 140 printk(KERN_INFO PREFIX 141 "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n", 142 p->uid, 143 mps_inti_flags_polarity[polarity], 144 mps_inti_flags_trigger[trigger], 145 p->lint); 146 } 147 break; 148 149 case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: 150 { 151 struct acpi_madt_local_apic_override *p = 152 (struct acpi_madt_local_apic_override *)header; 153 printk(KERN_INFO PREFIX 154 "LAPIC_ADDR_OVR (address[%p])\n", 155 (void *)(unsigned long)p->address); 156 } 157 break; 158 159 case ACPI_MADT_TYPE_IO_SAPIC: 160 { 161 struct acpi_madt_io_sapic *p = 162 (struct acpi_madt_io_sapic *)header; 163 printk(KERN_INFO PREFIX 164 "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", 165 p->id, (void *)(unsigned long)p->address, 166 p->global_irq_base); 167 } 168 break; 169 170 case ACPI_MADT_TYPE_LOCAL_SAPIC: 171 { 172 struct acpi_madt_local_sapic *p = 173 (struct acpi_madt_local_sapic *)header; 174 printk(KERN_INFO PREFIX 175 "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", 176 p->processor_id, p->id, p->eid, 177 (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); 178 } 179 break; 180 181 case ACPI_MADT_TYPE_INTERRUPT_SOURCE: 182 { 183 struct acpi_madt_interrupt_source *p = 184 (struct acpi_madt_interrupt_source *)header; 185 printk(KERN_INFO PREFIX 186 "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", 187 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 188 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 189 p->type, p->id, p->eid, p->io_sapic_vector, 190 p->global_irq); 191 } 192 break; 193 194 default: 195 printk(KERN_WARNING PREFIX 196 "Found unsupported MADT entry (type = 0x%x)\n", 197 header->type); 198 break; 199 } 200 } 201 202 203 int __init 204 acpi_table_parse_entries(char *id, 205 unsigned long table_size, 206 int entry_id, 207 acpi_table_entry_handler handler, 208 unsigned int max_entries) 209 { 210 struct acpi_table_header *table_header = NULL; 211 struct acpi_subtable_header *entry; 212 unsigned int count = 0; 213 unsigned long table_end; 214 acpi_size tbl_size; 215 216 if (acpi_disabled && !acpi_ht) 217 return -ENODEV; 218 219 if (!handler) 220 return -EINVAL; 221 222 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 223 acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); 224 else 225 acpi_get_table_with_size(id, 0, &table_header, &tbl_size); 226 227 if (!table_header) { 228 printk(KERN_WARNING PREFIX "%4.4s not present\n", id); 229 return -ENODEV; 230 } 231 232 table_end = (unsigned long)table_header + table_header->length; 233 234 /* Parse all entries looking for a match. */ 235 236 entry = (struct acpi_subtable_header *) 237 ((unsigned long)table_header + table_size); 238 239 while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < 240 table_end) { 241 if (entry->type == entry_id 242 && (!max_entries || count++ < max_entries)) 243 if (handler(entry, table_end)) { 244 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 245 return -EINVAL; 246 } 247 248 entry = (struct acpi_subtable_header *) 249 ((unsigned long)entry + entry->length); 250 } 251 if (max_entries && count > max_entries) { 252 printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " 253 "%i found\n", id, entry_id, count - max_entries, count); 254 } 255 256 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 257 return count; 258 } 259 260 int __init 261 acpi_table_parse_madt(enum acpi_madt_type id, 262 acpi_table_entry_handler handler, unsigned int max_entries) 263 { 264 return acpi_table_parse_entries(ACPI_SIG_MADT, 265 sizeof(struct acpi_table_madt), id, 266 handler, max_entries); 267 } 268 269 /** 270 * acpi_table_parse - find table with @id, run @handler on it 271 * 272 * @id: table id to find 273 * @handler: handler to run 274 * 275 * Scan the ACPI System Descriptor Table (STD) for a table matching @id, 276 * run @handler on it. Return 0 if table found, return on if not. 277 */ 278 int __init acpi_table_parse(char *id, acpi_table_handler handler) 279 { 280 struct acpi_table_header *table = NULL; 281 acpi_size tbl_size; 282 283 if (acpi_disabled && !acpi_ht) 284 return -ENODEV; 285 286 if (!handler) 287 return -EINVAL; 288 289 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 290 acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); 291 else 292 acpi_get_table_with_size(id, 0, &table, &tbl_size); 293 294 if (table) { 295 handler(table); 296 early_acpi_os_unmap_memory(table, tbl_size); 297 return 0; 298 } else 299 return 1; 300 } 301 302 /* 303 * The BIOS is supposed to supply a single APIC/MADT, 304 * but some report two. Provide a knob to use either. 305 * (don't you wish instance 0 and 1 were not the same?) 306 */ 307 static void __init check_multiple_madt(void) 308 { 309 struct acpi_table_header *table = NULL; 310 acpi_size tbl_size; 311 312 acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); 313 if (table) { 314 printk(KERN_WARNING PREFIX 315 "BIOS bug: multiple APIC/MADT found," 316 " using %d\n", acpi_apic_instance); 317 printk(KERN_WARNING PREFIX 318 "If \"acpi_apic_instance=%d\" works better, " 319 "notify linux-acpi@vger.kernel.org\n", 320 acpi_apic_instance ? 0 : 2); 321 early_acpi_os_unmap_memory(table, tbl_size); 322 323 } else 324 acpi_apic_instance = 0; 325 326 return; 327 } 328 329 /* 330 * acpi_table_init() 331 * 332 * find RSDP, find and checksum SDT/XSDT. 333 * checksum all tables, print SDT/XSDT 334 * 335 * result: sdt_entry[] is initialized 336 */ 337 338 int __init acpi_table_init(void) 339 { 340 acpi_status status; 341 342 status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); 343 if (ACPI_FAILURE(status)) 344 return 1; 345 346 check_multiple_madt(); 347 return 0; 348 } 349 350 static int __init acpi_parse_apic_instance(char *str) 351 { 352 if (!str) 353 return -EINVAL; 354 355 acpi_apic_instance = simple_strtoul(str, NULL, 0); 356 357 printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n", 358 acpi_apic_instance); 359 360 return 0; 361 } 362 363 early_param("acpi_apic_instance", acpi_parse_apic_instance); 364