linux/drivers/acpi/processor_core.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005 Intel Corporation
   3 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
   4 *
   5 *      Alex Chiang <achiang@hp.com>
   6 *      - Unified x86/ia64 implementations
   7 *
   8 * I/O APIC hotplug support
   9 *      Yinghai Lu <yinghai@kernel.org>
  10 *      Jiang Liu <jiang.liu@intel.com>
  11 */
  12#include <linux/export.h>
  13#include <linux/acpi.h>
  14#include <acpi/processor.h>
  15
  16#define _COMPONENT              ACPI_PROCESSOR_COMPONENT
  17ACPI_MODULE_NAME("processor_core");
  18
  19static struct acpi_table_madt *get_madt_table(void)
  20{
  21        static struct acpi_table_madt *madt;
  22        static int read_madt;
  23
  24        if (!read_madt) {
  25                if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
  26                                        (struct acpi_table_header **)&madt)))
  27                        madt = NULL;
  28                read_madt++;
  29        }
  30
  31        return madt;
  32}
  33
  34static int map_lapic_id(struct acpi_subtable_header *entry,
  35                 u32 acpi_id, phys_cpuid_t *apic_id)
  36{
  37        struct acpi_madt_local_apic *lapic =
  38                container_of(entry, struct acpi_madt_local_apic, header);
  39
  40        if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
  41                return -ENODEV;
  42
  43        if (lapic->processor_id != acpi_id)
  44                return -EINVAL;
  45
  46        *apic_id = lapic->id;
  47        return 0;
  48}
  49
  50static int map_x2apic_id(struct acpi_subtable_header *entry,
  51                int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
  52{
  53        struct acpi_madt_local_x2apic *apic =
  54                container_of(entry, struct acpi_madt_local_x2apic, header);
  55
  56        if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
  57                return -ENODEV;
  58
  59        if (device_declaration && (apic->uid == acpi_id)) {
  60                *apic_id = apic->local_apic_id;
  61                return 0;
  62        }
  63
  64        return -EINVAL;
  65}
  66
  67static int map_lsapic_id(struct acpi_subtable_header *entry,
  68                int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
  69{
  70        struct acpi_madt_local_sapic *lsapic =
  71                container_of(entry, struct acpi_madt_local_sapic, header);
  72
  73        if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
  74                return -ENODEV;
  75
  76        if (device_declaration) {
  77                if ((entry->length < 16) || (lsapic->uid != acpi_id))
  78                        return -EINVAL;
  79        } else if (lsapic->processor_id != acpi_id)
  80                return -EINVAL;
  81
  82        *apic_id = (lsapic->id << 8) | lsapic->eid;
  83        return 0;
  84}
  85
  86/*
  87 * Retrieve the ARM CPU physical identifier (MPIDR)
  88 */
  89static int map_gicc_mpidr(struct acpi_subtable_header *entry,
  90                int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr)
  91{
  92        struct acpi_madt_generic_interrupt *gicc =
  93            container_of(entry, struct acpi_madt_generic_interrupt, header);
  94
  95        if (!(gicc->flags & ACPI_MADT_ENABLED))
  96                return -ENODEV;
  97
  98        /* device_declaration means Device object in DSDT, in the
  99         * GIC interrupt model, logical processors are required to
 100         * have a Processor Device object in the DSDT, so we should
 101         * check device_declaration here
 102         */
 103        if (device_declaration && (gicc->uid == acpi_id)) {
 104                *mpidr = gicc->arm_mpidr;
 105                return 0;
 106        }
 107
 108        return -EINVAL;
 109}
 110
 111static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
 112                                   int type, u32 acpi_id)
 113{
 114        unsigned long madt_end, entry;
 115        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;      /* CPU hardware ID */
 116
 117        if (!madt)
 118                return phys_id;
 119
 120        entry = (unsigned long)madt;
 121        madt_end = entry + madt->header.length;
 122
 123        /* Parse all entries looking for a match. */
 124
 125        entry += sizeof(struct acpi_table_madt);
 126        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 127                struct acpi_subtable_header *header =
 128                        (struct acpi_subtable_header *)entry;
 129                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
 130                        if (!map_lapic_id(header, acpi_id, &phys_id))
 131                                break;
 132                } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
 133                        if (!map_x2apic_id(header, type, acpi_id, &phys_id))
 134                                break;
 135                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
 136                        if (!map_lsapic_id(header, type, acpi_id, &phys_id))
 137                                break;
 138                } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
 139                        if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
 140                                break;
 141                }
 142                entry += header->length;
 143        }
 144        return phys_id;
 145}
 146
 147phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
 148{
 149        struct acpi_table_madt *madt = NULL;
 150        phys_cpuid_t rv;
 151
 152        acpi_get_table(ACPI_SIG_MADT, 0,
 153                       (struct acpi_table_header **)&madt);
 154        if (!madt)
 155                return PHYS_CPUID_INVALID;
 156
 157        rv = map_madt_entry(madt, 1, acpi_id);
 158
 159        acpi_put_table((struct acpi_table_header *)madt);
 160
 161        return rv;
 162}
 163
 164static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
 165{
 166        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 167        union acpi_object *obj;
 168        struct acpi_subtable_header *header;
 169        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
 170
 171        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 172                goto exit;
 173
 174        if (!buffer.length || !buffer.pointer)
 175                goto exit;
 176
 177        obj = buffer.pointer;
 178        if (obj->type != ACPI_TYPE_BUFFER ||
 179            obj->buffer.length < sizeof(struct acpi_subtable_header)) {
 180                goto exit;
 181        }
 182
 183        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 184        if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
 185                map_lapic_id(header, acpi_id, &phys_id);
 186        else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
 187                map_lsapic_id(header, type, acpi_id, &phys_id);
 188        else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
 189                map_x2apic_id(header, type, acpi_id, &phys_id);
 190        else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
 191                map_gicc_mpidr(header, type, acpi_id, &phys_id);
 192
 193exit:
 194        kfree(buffer.pointer);
 195        return phys_id;
 196}
 197
 198phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
 199{
 200        phys_cpuid_t phys_id;
 201
 202        phys_id = map_mat_entry(handle, type, acpi_id);
 203        if (invalid_phys_cpuid(phys_id))
 204                phys_id = map_madt_entry(get_madt_table(), type, acpi_id);
 205
 206        return phys_id;
 207}
 208EXPORT_SYMBOL_GPL(acpi_get_phys_id);
 209
 210int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
 211{
 212#ifdef CONFIG_SMP
 213        int i;
 214#endif
 215
 216        if (invalid_phys_cpuid(phys_id)) {
 217                /*
 218                 * On UP processor, there is no _MAT or MADT table.
 219                 * So above phys_id is always set to PHYS_CPUID_INVALID.
 220                 *
 221                 * BIOS may define multiple CPU handles even for UP processor.
 222                 * For example,
 223                 *
 224                 * Scope (_PR)
 225                 * {
 226                 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
 227                 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
 228                 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
 229                 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
 230                 * }
 231                 *
 232                 * Ignores phys_id and always returns 0 for the processor
 233                 * handle with acpi id 0 if nr_cpu_ids is 1.
 234                 * This should be the case if SMP tables are not found.
 235                 * Return -EINVAL for other CPU's handle.
 236                 */
 237                if (nr_cpu_ids <= 1 && acpi_id == 0)
 238                        return acpi_id;
 239                else
 240                        return -EINVAL;
 241        }
 242
 243#ifdef CONFIG_SMP
 244        for_each_possible_cpu(i) {
 245                if (cpu_physical_id(i) == phys_id)
 246                        return i;
 247        }
 248#else
 249        /* In UP kernel, only processor 0 is valid */
 250        if (phys_id == 0)
 251                return phys_id;
 252#endif
 253        return -ENODEV;
 254}
 255
 256int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 257{
 258        phys_cpuid_t phys_id;
 259
 260        phys_id = acpi_get_phys_id(handle, type, acpi_id);
 261
 262        return acpi_map_cpuid(phys_id, acpi_id);
 263}
 264EXPORT_SYMBOL_GPL(acpi_get_cpuid);
 265
 266#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
 267static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
 268                         u64 *phys_addr, int *ioapic_id)
 269{
 270        struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
 271
 272        if (ioapic->global_irq_base != gsi_base)
 273                return 0;
 274
 275        *phys_addr = ioapic->address;
 276        *ioapic_id = ioapic->id;
 277        return 1;
 278}
 279
 280static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
 281{
 282        struct acpi_subtable_header *hdr;
 283        unsigned long madt_end, entry;
 284        struct acpi_table_madt *madt;
 285        int apic_id = -1;
 286
 287        madt = get_madt_table();
 288        if (!madt)
 289                return apic_id;
 290
 291        entry = (unsigned long)madt;
 292        madt_end = entry + madt->header.length;
 293
 294        /* Parse all entries looking for a match. */
 295        entry += sizeof(struct acpi_table_madt);
 296        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 297                hdr = (struct acpi_subtable_header *)entry;
 298                if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
 299                    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
 300                        break;
 301                else
 302                        entry += hdr->length;
 303        }
 304
 305        return apic_id;
 306}
 307
 308static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
 309                                  u64 *phys_addr)
 310{
 311        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 312        struct acpi_subtable_header *header;
 313        union acpi_object *obj;
 314        int apic_id = -1;
 315
 316        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 317                goto exit;
 318
 319        if (!buffer.length || !buffer.pointer)
 320                goto exit;
 321
 322        obj = buffer.pointer;
 323        if (obj->type != ACPI_TYPE_BUFFER ||
 324            obj->buffer.length < sizeof(struct acpi_subtable_header))
 325                goto exit;
 326
 327        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 328        if (header->type == ACPI_MADT_TYPE_IO_APIC)
 329                get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
 330
 331exit:
 332        kfree(buffer.pointer);
 333        return apic_id;
 334}
 335
 336/**
 337 * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
 338 * @handle:     ACPI object for IOAPIC device
 339 * @gsi_base:   GSI base to match with
 340 * @phys_addr:  Pointer to store physical address of matching IOAPIC record
 341 *
 342 * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
 343 * for an ACPI IOAPIC record matching @gsi_base.
 344 * Return IOAPIC id and store physical address in @phys_addr if found a match,
 345 * otherwise return <0.
 346 */
 347int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
 348{
 349        int apic_id;
 350
 351        apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
 352        if (apic_id == -1)
 353                apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
 354
 355        return apic_id;
 356}
 357#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
 358