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_tbl_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) 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 goto err; 245 246 /* 247 * If entry->length is 0, break from this loop to avoid 248 * infinite loop. 249 */ 250 if (entry->length == 0) { 251 pr_err(PREFIX "[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); 252 goto err; 253 } 254 255 entry = (struct acpi_subtable_header *) 256 ((unsigned long)entry + entry->length); 257 } 258 if (max_entries && count > max_entries) { 259 printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " 260 "%i found\n", id, entry_id, count - max_entries, count); 261 } 262 263 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 264 return count; 265 err: 266 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 267 return -EINVAL; 268 } 269 270 int __init 271 acpi_table_parse_madt(enum acpi_madt_type id, 272 acpi_tbl_entry_handler handler, unsigned int max_entries) 273 { 274 return acpi_table_parse_entries(ACPI_SIG_MADT, 275 sizeof(struct acpi_table_madt), id, 276 handler, max_entries); 277 } 278 279 /** 280 * acpi_table_parse - find table with @id, run @handler on it 281 * @id: table id to find 282 * @handler: handler to run 283 * 284 * Scan the ACPI System Descriptor Table (STD) for a table matching @id, 285 * run @handler on it. 286 * 287 * Return 0 if table found, -errno if not. 288 */ 289 int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) 290 { 291 struct acpi_table_header *table = NULL; 292 acpi_size tbl_size; 293 294 if (acpi_disabled) 295 return -ENODEV; 296 297 if (!id || !handler) 298 return -EINVAL; 299 300 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 301 acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); 302 else 303 acpi_get_table_with_size(id, 0, &table, &tbl_size); 304 305 if (table) { 306 handler(table); 307 early_acpi_os_unmap_memory(table, tbl_size); 308 return 0; 309 } else 310 return -ENODEV; 311 } 312 313 /* 314 * The BIOS is supposed to supply a single APIC/MADT, 315 * but some report two. Provide a knob to use either. 316 * (don't you wish instance 0 and 1 were not the same?) 317 */ 318 static void __init check_multiple_madt(void) 319 { 320 struct acpi_table_header *table = NULL; 321 acpi_size tbl_size; 322 323 acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); 324 if (table) { 325 printk(KERN_WARNING PREFIX 326 "BIOS bug: multiple APIC/MADT found," 327 " using %d\n", acpi_apic_instance); 328 printk(KERN_WARNING PREFIX 329 "If \"acpi_apic_instance=%d\" works better, " 330 "notify linux-acpi@vger.kernel.org\n", 331 acpi_apic_instance ? 0 : 2); 332 early_acpi_os_unmap_memory(table, tbl_size); 333 334 } else 335 acpi_apic_instance = 0; 336 337 return; 338 } 339 340 /* 341 * acpi_table_init() 342 * 343 * find RSDP, find and checksum SDT/XSDT. 344 * checksum all tables, print SDT/XSDT 345 * 346 * result: sdt_entry[] is initialized 347 */ 348 349 int __init acpi_table_init(void) 350 { 351 acpi_status status; 352 353 status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); 354 if (ACPI_FAILURE(status)) 355 return -EINVAL; 356 357 check_multiple_madt(); 358 return 0; 359 } 360 361 static int __init acpi_parse_apic_instance(char *str) 362 { 363 if (!str) 364 return -EINVAL; 365 366 acpi_apic_instance = simple_strtoul(str, NULL, 0); 367 368 printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n", 369 acpi_apic_instance); 370 371 return 0; 372 } 373 374 early_param("acpi_apic_instance", acpi_parse_apic_instance); 375