linux/drivers/acpi/tables.c
<<
>>
Prefs
   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
  40static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
  41static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
  42
  43static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
  44
  45static int acpi_apic_instance __initdata;
  46
  47/*
  48 * Disable table checksum verification for the early stage due to the size
  49 * limitation of the current x86 early mapping implementation.
  50 */
  51static bool acpi_verify_table_checksum __initdata = false;
  52
  53void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
  54{
  55        if (!header)
  56                return;
  57
  58        switch (header->type) {
  59
  60        case ACPI_MADT_TYPE_LOCAL_APIC:
  61                {
  62                        struct acpi_madt_local_apic *p =
  63                            (struct acpi_madt_local_apic *)header;
  64                        pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
  65                                p->processor_id, p->id,
  66                                (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
  67                }
  68                break;
  69
  70        case ACPI_MADT_TYPE_LOCAL_X2APIC:
  71                {
  72                        struct acpi_madt_local_x2apic *p =
  73                            (struct acpi_madt_local_x2apic *)header;
  74                        pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
  75                                p->local_apic_id, p->uid,
  76                                (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
  77                }
  78                break;
  79
  80        case ACPI_MADT_TYPE_IO_APIC:
  81                {
  82                        struct acpi_madt_io_apic *p =
  83                            (struct acpi_madt_io_apic *)header;
  84                        pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
  85                                p->id, p->address, p->global_irq_base);
  86                }
  87                break;
  88
  89        case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
  90                {
  91                        struct acpi_madt_interrupt_override *p =
  92                            (struct acpi_madt_interrupt_override *)header;
  93                        pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
  94                                p->bus, p->source_irq, p->global_irq,
  95                                mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
  96                                mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
  97                        if (p->inti_flags  &
  98                            ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
  99                                pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
 100                                        p->inti_flags  &
 101                                        ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
 102                }
 103                break;
 104
 105        case ACPI_MADT_TYPE_NMI_SOURCE:
 106                {
 107                        struct acpi_madt_nmi_source *p =
 108                            (struct acpi_madt_nmi_source *)header;
 109                        pr_info("NMI_SRC (%s %s global_irq %d)\n",
 110                                mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
 111                                mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
 112                                p->global_irq);
 113                }
 114                break;
 115
 116        case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
 117                {
 118                        struct acpi_madt_local_apic_nmi *p =
 119                            (struct acpi_madt_local_apic_nmi *)header;
 120                        pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
 121                                p->processor_id,
 122                                mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
 123                                mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
 124                                p->lint);
 125                }
 126                break;
 127
 128        case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
 129                {
 130                        u16 polarity, trigger;
 131                        struct acpi_madt_local_x2apic_nmi *p =
 132                            (struct acpi_madt_local_x2apic_nmi *)header;
 133
 134                        polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
 135                        trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
 136
 137                        pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
 138                                p->uid,
 139                                mps_inti_flags_polarity[polarity],
 140                                mps_inti_flags_trigger[trigger],
 141                                p->lint);
 142                }
 143                break;
 144
 145        case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
 146                {
 147                        struct acpi_madt_local_apic_override *p =
 148                            (struct acpi_madt_local_apic_override *)header;
 149                        pr_info("LAPIC_ADDR_OVR (address[%p])\n",
 150                                (void *)(unsigned long)p->address);
 151                }
 152                break;
 153
 154        case ACPI_MADT_TYPE_IO_SAPIC:
 155                {
 156                        struct acpi_madt_io_sapic *p =
 157                            (struct acpi_madt_io_sapic *)header;
 158                        pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
 159                                p->id, (void *)(unsigned long)p->address,
 160                                p->global_irq_base);
 161                }
 162                break;
 163
 164        case ACPI_MADT_TYPE_LOCAL_SAPIC:
 165                {
 166                        struct acpi_madt_local_sapic *p =
 167                            (struct acpi_madt_local_sapic *)header;
 168                        pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
 169                                p->processor_id, p->id, p->eid,
 170                                (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
 171                }
 172                break;
 173
 174        case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
 175                {
 176                        struct acpi_madt_interrupt_source *p =
 177                            (struct acpi_madt_interrupt_source *)header;
 178                        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",
 179                                mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
 180                                mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
 181                                p->type, p->id, p->eid, p->io_sapic_vector,
 182                                p->global_irq);
 183                }
 184                break;
 185
 186        default:
 187                pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
 188                        header->type);
 189                break;
 190        }
 191}
 192
 193
 194int __init
 195acpi_table_parse_entries(char *id,
 196                             unsigned long table_size,
 197                             int entry_id,
 198                             acpi_tbl_entry_handler handler,
 199                             unsigned int max_entries)
 200{
 201        struct acpi_table_header *table_header = NULL;
 202        struct acpi_subtable_header *entry;
 203        unsigned int count = 0;
 204        unsigned long table_end;
 205        acpi_size tbl_size;
 206
 207        if (acpi_disabled)
 208                return -ENODEV;
 209
 210        if (!handler)
 211                return -EINVAL;
 212
 213        if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
 214                acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
 215        else
 216                acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
 217
 218        if (!table_header) {
 219                pr_warn("%4.4s not present\n", id);
 220                return -ENODEV;
 221        }
 222
 223        table_end = (unsigned long)table_header + table_header->length;
 224
 225        /* Parse all entries looking for a match. */
 226
 227        entry = (struct acpi_subtable_header *)
 228            ((unsigned long)table_header + table_size);
 229
 230        while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
 231               table_end) {
 232                if (entry->type == entry_id
 233                    && (!max_entries || count++ < max_entries))
 234                        if (handler(entry, table_end))
 235                                goto err;
 236
 237                /*
 238                 * If entry->length is 0, break from this loop to avoid
 239                 * infinite loop.
 240                 */
 241                if (entry->length == 0) {
 242                        pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
 243                        goto err;
 244                }
 245
 246                entry = (struct acpi_subtable_header *)
 247                    ((unsigned long)entry + entry->length);
 248        }
 249        if (max_entries && count > max_entries) {
 250                pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
 251                        id, entry_id, count - max_entries, count);
 252        }
 253
 254        early_acpi_os_unmap_memory((char *)table_header, tbl_size);
 255        return count;
 256err:
 257        early_acpi_os_unmap_memory((char *)table_header, tbl_size);
 258        return -EINVAL;
 259}
 260
 261int __init
 262acpi_table_parse_madt(enum acpi_madt_type id,
 263                      acpi_tbl_entry_handler handler, unsigned int max_entries)
 264{
 265        return acpi_table_parse_entries(ACPI_SIG_MADT,
 266                                            sizeof(struct acpi_table_madt), id,
 267                                            handler, max_entries);
 268}
 269
 270/**
 271 * acpi_table_parse - find table with @id, run @handler on it
 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.
 277 *
 278 * Return 0 if table found, -errno if not.
 279 */
 280int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
 281{
 282        struct acpi_table_header *table = NULL;
 283        acpi_size tbl_size;
 284
 285        if (acpi_disabled)
 286                return -ENODEV;
 287
 288        if (!id || !handler)
 289                return -EINVAL;
 290
 291        if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
 292                acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size);
 293        else
 294                acpi_get_table_with_size(id, 0, &table, &tbl_size);
 295
 296        if (table) {
 297                handler(table);
 298                early_acpi_os_unmap_memory(table, tbl_size);
 299                return 0;
 300        } else
 301                return -ENODEV;
 302}
 303
 304/* 
 305 * The BIOS is supposed to supply a single APIC/MADT,
 306 * but some report two.  Provide a knob to use either.
 307 * (don't you wish instance 0 and 1 were not the same?)
 308 */
 309static void __init check_multiple_madt(void)
 310{
 311        struct acpi_table_header *table = NULL;
 312        acpi_size tbl_size;
 313
 314        acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
 315        if (table) {
 316                pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
 317                        acpi_apic_instance);
 318                pr_warn("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
 338int __init acpi_table_init(void)
 339{
 340        acpi_status status;
 341
 342        if (acpi_verify_table_checksum) {
 343                pr_info("Early table checksum verification enabled\n");
 344                acpi_gbl_verify_table_checksum = TRUE;
 345        } else {
 346                pr_info("Early table checksum verification disabled\n");
 347                acpi_gbl_verify_table_checksum = FALSE;
 348        }
 349
 350        status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
 351        if (ACPI_FAILURE(status))
 352                return -EINVAL;
 353
 354        check_multiple_madt();
 355        return 0;
 356}
 357
 358static int __init acpi_parse_apic_instance(char *str)
 359{
 360        if (!str)
 361                return -EINVAL;
 362
 363        if (kstrtoint(str, 0, &acpi_apic_instance))
 364                return -EINVAL;
 365
 366        pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
 367
 368        return 0;
 369}
 370
 371early_param("acpi_apic_instance", acpi_parse_apic_instance);
 372
 373static int __init acpi_force_table_verification_setup(char *s)
 374{
 375        acpi_verify_table_checksum = true;
 376
 377        return 0;
 378}
 379
 380early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
 381