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 (!handler) 217 return -EINVAL; 218 219 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 220 acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); 221 else 222 acpi_get_table_with_size(id, 0, &table_header, &tbl_size); 223 224 if (!table_header) { 225 printk(KERN_WARNING PREFIX "%4.4s not present\n", id); 226 return -ENODEV; 227 } 228 229 table_end = (unsigned long)table_header + table_header->length; 230 231 /* Parse all entries looking for a match. */ 232 233 entry = (struct acpi_subtable_header *) 234 ((unsigned long)table_header + table_size); 235 236 while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < 237 table_end) { 238 if (entry->type == entry_id 239 && (!max_entries || count++ < max_entries)) 240 if (handler(entry, table_end)) { 241 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 242 return -EINVAL; 243 } 244 245 entry = (struct acpi_subtable_header *) 246 ((unsigned long)entry + entry->length); 247 } 248 if (max_entries && count > max_entries) { 249 printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " 250 "%i found\n", id, entry_id, count - max_entries, count); 251 } 252 253 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 254 return count; 255 } 256 257 int __init 258 acpi_table_parse_madt(enum acpi_madt_type id, 259 acpi_table_entry_handler handler, unsigned int max_entries) 260 { 261 return acpi_table_parse_entries(ACPI_SIG_MADT, 262 sizeof(struct acpi_table_madt), id, 263 handler, max_entries); 264 } 265 266 /** 267 * acpi_table_parse - find table with @id, run @handler on it 268 * 269 * @id: table id to find 270 * @handler: handler to run 271 * 272 * Scan the ACPI System Descriptor Table (STD) for a table matching @id, 273 * run @handler on it. Return 0 if table found, return on if not. 274 */ 275 int __init acpi_table_parse(char *id, acpi_table_handler handler) 276 { 277 struct acpi_table_header *table = NULL; 278 acpi_size tbl_size; 279 280 if (!handler) 281 return -EINVAL; 282 283 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 284 acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); 285 else 286 acpi_get_table_with_size(id, 0, &table, &tbl_size); 287 288 if (table) { 289 handler(table); 290 early_acpi_os_unmap_memory(table, tbl_size); 291 return 0; 292 } else 293 return 1; 294 } 295 296 /* 297 * The BIOS is supposed to supply a single APIC/MADT, 298 * but some report two. Provide a knob to use either. 299 * (don't you wish instance 0 and 1 were not the same?) 300 */ 301 static void __init check_multiple_madt(void) 302 { 303 struct acpi_table_header *table = NULL; 304 acpi_size tbl_size; 305 306 acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); 307 if (table) { 308 printk(KERN_WARNING PREFIX 309 "BIOS bug: multiple APIC/MADT found," 310 " using %d\n", acpi_apic_instance); 311 printk(KERN_WARNING PREFIX 312 "If \"acpi_apic_instance=%d\" works better, " 313 "notify linux-acpi@vger.kernel.org\n", 314 acpi_apic_instance ? 0 : 2); 315 early_acpi_os_unmap_memory(table, tbl_size); 316 317 } else 318 acpi_apic_instance = 0; 319 320 return; 321 } 322 323 /* 324 * acpi_table_init() 325 * 326 * find RSDP, find and checksum SDT/XSDT. 327 * checksum all tables, print SDT/XSDT 328 * 329 * result: sdt_entry[] is initialized 330 */ 331 332 int __init acpi_table_init(void) 333 { 334 acpi_status status; 335 336 status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); 337 if (ACPI_FAILURE(status)) 338 return 1; 339 340 check_multiple_madt(); 341 return 0; 342 } 343 344 static int __init acpi_parse_apic_instance(char *str) 345 { 346 if (!str) 347 return -EINVAL; 348 349 acpi_apic_instance = simple_strtoul(str, NULL, 0); 350 351 printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n", 352 acpi_apic_instance); 353 354 return 0; 355 } 356 357 early_param("acpi_apic_instance", acpi_parse_apic_instance); 358