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 #define pr_fmt(fmt) "ACPI: " fmt 27 28 #include <linux/init.h> 29 #include <linux/kernel.h> 30 #include <linux/smp.h> 31 #include <linux/string.h> 32 #include <linux/types.h> 33 #include <linux/irq.h> 34 #include <linux/errno.h> 35 #include <linux/acpi.h> 36 #include <linux/bootmem.h> 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 pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", 59 p->processor_id, p->id, 60 (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); 61 } 62 break; 63 64 case ACPI_MADT_TYPE_LOCAL_X2APIC: 65 { 66 struct acpi_madt_local_x2apic *p = 67 (struct acpi_madt_local_x2apic *)header; 68 pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n", 69 p->local_apic_id, p->uid, 70 (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); 71 } 72 break; 73 74 case ACPI_MADT_TYPE_IO_APIC: 75 { 76 struct acpi_madt_io_apic *p = 77 (struct acpi_madt_io_apic *)header; 78 pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", 79 p->id, p->address, p->global_irq_base); 80 } 81 break; 82 83 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 84 { 85 struct acpi_madt_interrupt_override *p = 86 (struct acpi_madt_interrupt_override *)header; 87 pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", 88 p->bus, p->source_irq, p->global_irq, 89 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 90 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); 91 if (p->inti_flags & 92 ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) 93 pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n", 94 p->inti_flags & 95 ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); 96 } 97 break; 98 99 case ACPI_MADT_TYPE_NMI_SOURCE: 100 { 101 struct acpi_madt_nmi_source *p = 102 (struct acpi_madt_nmi_source *)header; 103 pr_info("NMI_SRC (%s %s global_irq %d)\n", 104 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 105 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 106 p->global_irq); 107 } 108 break; 109 110 case ACPI_MADT_TYPE_LOCAL_APIC_NMI: 111 { 112 struct acpi_madt_local_apic_nmi *p = 113 (struct acpi_madt_local_apic_nmi *)header; 114 pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", 115 p->processor_id, 116 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], 117 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 118 p->lint); 119 } 120 break; 121 122 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: 123 { 124 u16 polarity, trigger; 125 struct acpi_madt_local_x2apic_nmi *p = 126 (struct acpi_madt_local_x2apic_nmi *)header; 127 128 polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK; 129 trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2; 130 131 pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n", 132 p->uid, 133 mps_inti_flags_polarity[polarity], 134 mps_inti_flags_trigger[trigger], 135 p->lint); 136 } 137 break; 138 139 case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: 140 { 141 struct acpi_madt_local_apic_override *p = 142 (struct acpi_madt_local_apic_override *)header; 143 pr_info("LAPIC_ADDR_OVR (address[%p])\n", 144 (void *)(unsigned long)p->address); 145 } 146 break; 147 148 case ACPI_MADT_TYPE_IO_SAPIC: 149 { 150 struct acpi_madt_io_sapic *p = 151 (struct acpi_madt_io_sapic *)header; 152 pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", 153 p->id, (void *)(unsigned long)p->address, 154 p->global_irq_base); 155 } 156 break; 157 158 case ACPI_MADT_TYPE_LOCAL_SAPIC: 159 { 160 struct acpi_madt_local_sapic *p = 161 (struct acpi_madt_local_sapic *)header; 162 pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", 163 p->processor_id, p->id, p->eid, 164 (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); 165 } 166 break; 167 168 case ACPI_MADT_TYPE_INTERRUPT_SOURCE: 169 { 170 struct acpi_madt_interrupt_source *p = 171 (struct acpi_madt_interrupt_source *)header; 172 pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", 173 mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], 174 mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], 175 p->type, p->id, p->eid, p->io_sapic_vector, 176 p->global_irq); 177 } 178 break; 179 180 default: 181 pr_warn("Found unsupported MADT entry (type = 0x%x)\n", 182 header->type); 183 break; 184 } 185 } 186 187 188 int __init 189 acpi_table_parse_entries(char *id, 190 unsigned long table_size, 191 int entry_id, 192 acpi_tbl_entry_handler handler, 193 unsigned int max_entries) 194 { 195 struct acpi_table_header *table_header = NULL; 196 struct acpi_subtable_header *entry; 197 unsigned int count = 0; 198 unsigned long table_end; 199 acpi_size tbl_size; 200 201 if (acpi_disabled) 202 return -ENODEV; 203 204 if (!handler) 205 return -EINVAL; 206 207 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 208 acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); 209 else 210 acpi_get_table_with_size(id, 0, &table_header, &tbl_size); 211 212 if (!table_header) { 213 pr_warn("%4.4s not present\n", id); 214 return -ENODEV; 215 } 216 217 table_end = (unsigned long)table_header + table_header->length; 218 219 /* Parse all entries looking for a match. */ 220 221 entry = (struct acpi_subtable_header *) 222 ((unsigned long)table_header + table_size); 223 224 while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < 225 table_end) { 226 if (entry->type == entry_id 227 && (!max_entries || count++ < max_entries)) 228 if (handler(entry, table_end)) 229 goto err; 230 231 /* 232 * If entry->length is 0, break from this loop to avoid 233 * infinite loop. 234 */ 235 if (entry->length == 0) { 236 pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); 237 goto err; 238 } 239 240 entry = (struct acpi_subtable_header *) 241 ((unsigned long)entry + entry->length); 242 } 243 if (max_entries && count > max_entries) { 244 pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n", 245 id, entry_id, count - max_entries, count); 246 } 247 248 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 249 return count; 250 err: 251 early_acpi_os_unmap_memory((char *)table_header, tbl_size); 252 return -EINVAL; 253 } 254 255 int __init 256 acpi_table_parse_madt(enum acpi_madt_type id, 257 acpi_tbl_entry_handler handler, unsigned int max_entries) 258 { 259 return acpi_table_parse_entries(ACPI_SIG_MADT, 260 sizeof(struct acpi_table_madt), id, 261 handler, max_entries); 262 } 263 264 /** 265 * acpi_table_parse - find table with @id, run @handler on it 266 * @id: table id to find 267 * @handler: handler to run 268 * 269 * Scan the ACPI System Descriptor Table (STD) for a table matching @id, 270 * run @handler on it. 271 * 272 * Return 0 if table found, -errno if not. 273 */ 274 int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) 275 { 276 struct acpi_table_header *table = NULL; 277 acpi_size tbl_size; 278 279 if (acpi_disabled) 280 return -ENODEV; 281 282 if (!id || !handler) 283 return -EINVAL; 284 285 if (strncmp(id, ACPI_SIG_MADT, 4) == 0) 286 acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); 287 else 288 acpi_get_table_with_size(id, 0, &table, &tbl_size); 289 290 if (table) { 291 handler(table); 292 early_acpi_os_unmap_memory(table, tbl_size); 293 return 0; 294 } else 295 return -ENODEV; 296 } 297 298 /* 299 * The BIOS is supposed to supply a single APIC/MADT, 300 * but some report two. Provide a knob to use either. 301 * (don't you wish instance 0 and 1 were not the same?) 302 */ 303 static void __init check_multiple_madt(void) 304 { 305 struct acpi_table_header *table = NULL; 306 acpi_size tbl_size; 307 308 acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); 309 if (table) { 310 pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n", 311 acpi_apic_instance); 312 pr_warn("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 -EINVAL; 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 pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance); 352 353 return 0; 354 } 355 356 early_param("acpi_apic_instance", acpi_parse_apic_instance); 357