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, bool ignore_disabled)
  36{
  37        struct acpi_madt_local_apic *lapic =
  38                container_of(entry, struct acpi_madt_local_apic, header);
  39
  40        if (ignore_disabled && !(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                bool ignore_disabled)
  53{
  54        struct acpi_madt_local_x2apic *apic =
  55                container_of(entry, struct acpi_madt_local_x2apic, header);
  56
  57        if (ignore_disabled && !(apic->lapic_flags & ACPI_MADT_ENABLED))
  58                return -ENODEV;
  59
  60        if (device_declaration && (apic->uid == acpi_id)) {
  61                *apic_id = apic->local_apic_id;
  62                return 0;
  63        }
  64
  65        return -EINVAL;
  66}
  67
  68static int map_lsapic_id(struct acpi_subtable_header *entry,
  69                int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id,
  70                bool ignore_disabled)
  71{
  72        struct acpi_madt_local_sapic *lsapic =
  73                container_of(entry, struct acpi_madt_local_sapic, header);
  74
  75        if (ignore_disabled && !(lsapic->lapic_flags & ACPI_MADT_ENABLED))
  76                return -ENODEV;
  77
  78        if (device_declaration) {
  79                if ((entry->length < 16) || (lsapic->uid != acpi_id))
  80                        return -EINVAL;
  81        } else if (lsapic->processor_id != acpi_id)
  82                return -EINVAL;
  83
  84        *apic_id = (lsapic->id << 8) | lsapic->eid;
  85        return 0;
  86}
  87
  88/*
  89 * Retrieve the ARM CPU physical identifier (MPIDR)
  90 */
  91static int map_gicc_mpidr(struct acpi_subtable_header *entry,
  92                int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr,
  93                bool ignore_disabled)
  94{
  95        struct acpi_madt_generic_interrupt *gicc =
  96            container_of(entry, struct acpi_madt_generic_interrupt, header);
  97
  98        if (ignore_disabled && !(gicc->flags & ACPI_MADT_ENABLED))
  99                return -ENODEV;
 100
 101        /* device_declaration means Device object in DSDT, in the
 102         * GIC interrupt model, logical processors are required to
 103         * have a Processor Device object in the DSDT, so we should
 104         * check device_declaration here
 105         */
 106        if (device_declaration && (gicc->uid == acpi_id)) {
 107                *mpidr = gicc->arm_mpidr;
 108                return 0;
 109        }
 110
 111        return -EINVAL;
 112}
 113
 114static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
 115                                   int type, u32 acpi_id, bool ignore_disabled)
 116{
 117        unsigned long madt_end, entry;
 118        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;      /* CPU hardware ID */
 119
 120        if (!madt)
 121                return phys_id;
 122
 123        entry = (unsigned long)madt;
 124        madt_end = entry + madt->header.length;
 125
 126        /* Parse all entries looking for a match. */
 127
 128        entry += sizeof(struct acpi_table_madt);
 129        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 130                struct acpi_subtable_header *header =
 131                        (struct acpi_subtable_header *)entry;
 132                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
 133                        if (!map_lapic_id(header, acpi_id, &phys_id,
 134                                          ignore_disabled))
 135                                break;
 136                } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
 137                        if (!map_x2apic_id(header, type, acpi_id, &phys_id,
 138                                           ignore_disabled))
 139                                break;
 140                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
 141                        if (!map_lsapic_id(header, type, acpi_id, &phys_id,
 142                                           ignore_disabled))
 143                                break;
 144                } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
 145                        if (!map_gicc_mpidr(header, type, acpi_id, &phys_id,
 146                                            ignore_disabled))
 147                                break;
 148                }
 149                entry += header->length;
 150        }
 151        return phys_id;
 152}
 153
 154phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
 155{
 156        struct acpi_table_madt *madt = NULL;
 157        acpi_size tbl_size;
 158        phys_cpuid_t rv;
 159
 160        acpi_get_table_with_size(ACPI_SIG_MADT, 0,
 161                                 (struct acpi_table_header **)&madt,
 162                                 &tbl_size);
 163        if (!madt)
 164                return PHYS_CPUID_INVALID;
 165
 166        rv = map_madt_entry(madt, 1, acpi_id, true);
 167
 168        early_acpi_os_unmap_memory(madt, tbl_size);
 169
 170        return rv;
 171}
 172
 173static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id,
 174                                  bool ignore_disabled)
 175{
 176        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 177        union acpi_object *obj;
 178        struct acpi_subtable_header *header;
 179        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
 180
 181        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 182                goto exit;
 183
 184        if (!buffer.length || !buffer.pointer)
 185                goto exit;
 186
 187        obj = buffer.pointer;
 188        if (obj->type != ACPI_TYPE_BUFFER ||
 189            obj->buffer.length < sizeof(struct acpi_subtable_header)) {
 190                goto exit;
 191        }
 192
 193        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 194        if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
 195                map_lapic_id(header, acpi_id, &phys_id, ignore_disabled);
 196        else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
 197                map_lsapic_id(header, type, acpi_id, &phys_id, ignore_disabled);
 198        else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
 199                map_x2apic_id(header, type, acpi_id, &phys_id, ignore_disabled);
 200        else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
 201                map_gicc_mpidr(header, type, acpi_id, &phys_id,
 202                               ignore_disabled);
 203
 204exit:
 205        kfree(buffer.pointer);
 206        return phys_id;
 207}
 208
 209static phys_cpuid_t __acpi_get_phys_id(acpi_handle handle, int type,
 210                                       u32 acpi_id, bool ignore_disabled)
 211{
 212        phys_cpuid_t phys_id;
 213
 214        phys_id = map_mat_entry(handle, type, acpi_id, ignore_disabled);
 215        if (invalid_phys_cpuid(phys_id))
 216                phys_id = map_madt_entry(get_madt_table(), type, acpi_id,
 217                                           ignore_disabled);
 218
 219        return phys_id;
 220}
 221
 222phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
 223{
 224        return __acpi_get_phys_id(handle, type, acpi_id, true);
 225}
 226
 227int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
 228{
 229#ifdef CONFIG_SMP
 230        int i;
 231#endif
 232
 233        if (invalid_phys_cpuid(phys_id)) {
 234                /*
 235                 * On UP processor, there is no _MAT or MADT table.
 236                 * So above phys_id is always set to PHYS_CPUID_INVALID.
 237                 *
 238                 * BIOS may define multiple CPU handles even for UP processor.
 239                 * For example,
 240                 *
 241                 * Scope (_PR)
 242                 * {
 243                 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
 244                 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
 245                 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
 246                 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
 247                 * }
 248                 *
 249                 * Ignores phys_id and always returns 0 for the processor
 250                 * handle with acpi id 0 if nr_cpu_ids is 1.
 251                 * This should be the case if SMP tables are not found.
 252                 * Return -EINVAL for other CPU's handle.
 253                 */
 254                if (nr_cpu_ids <= 1 && acpi_id == 0)
 255                        return acpi_id;
 256                else
 257                        return -EINVAL;
 258        }
 259
 260#ifdef CONFIG_SMP
 261        for_each_possible_cpu(i) {
 262                if (cpu_physical_id(i) == phys_id)
 263                        return i;
 264        }
 265#else
 266        /* In UP kernel, only processor 0 is valid */
 267        if (phys_id == 0)
 268                return phys_id;
 269#endif
 270        return -ENODEV;
 271}
 272
 273int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 274{
 275        phys_cpuid_t phys_id;
 276
 277        phys_id = acpi_get_phys_id(handle, type, acpi_id);
 278
 279        return acpi_map_cpuid(phys_id, acpi_id);
 280}
 281EXPORT_SYMBOL_GPL(acpi_get_cpuid);
 282
 283#ifdef CONFIG_ACPI_HOTPLUG_CPU
 284static bool __init
 285map_processor(acpi_handle handle, phys_cpuid_t *phys_id, int *cpuid)
 286{
 287        int type, id;
 288        u32 acpi_id;
 289        acpi_status status;
 290        acpi_object_type acpi_type;
 291        unsigned long long tmp;
 292        union acpi_object object = { 0 };
 293        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
 294
 295        status = acpi_get_type(handle, &acpi_type);
 296        if (ACPI_FAILURE(status))
 297                return false;
 298
 299        switch (acpi_type) {
 300        case ACPI_TYPE_PROCESSOR:
 301                status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
 302                if (ACPI_FAILURE(status))
 303                        return false;
 304                acpi_id = object.processor.proc_id;
 305
 306                /* validate the acpi_id */
 307                if(acpi_processor_validate_proc_id(acpi_id))
 308                        return false;
 309                break;
 310        case ACPI_TYPE_DEVICE:
 311                status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
 312                if (ACPI_FAILURE(status))
 313                        return false;
 314                acpi_id = tmp;
 315                break;
 316        default:
 317                return false;
 318        }
 319
 320        type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
 321
 322        *phys_id = __acpi_get_phys_id(handle, type, acpi_id, false);
 323        id = acpi_map_cpuid(*phys_id, acpi_id);
 324
 325        if (id < 0)
 326                return false;
 327        *cpuid = id;
 328        return true;
 329}
 330
 331static acpi_status __init
 332set_processor_node_mapping(acpi_handle handle, u32 lvl, void *context,
 333                           void **rv)
 334{
 335        phys_cpuid_t phys_id;
 336        int cpu_id;
 337
 338        if (!map_processor(handle, &phys_id, &cpu_id))
 339                return AE_ERROR;
 340
 341        acpi_map_cpu2node(handle, cpu_id, phys_id);
 342        return AE_OK;
 343}
 344
 345void __init acpi_set_processor_mapping(void)
 346{
 347        /* Set persistent cpu <-> node mapping for all processors. */
 348        acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
 349                            ACPI_UINT32_MAX, set_processor_node_mapping,
 350                            NULL, NULL, NULL);
 351}
 352#else
 353void __init acpi_set_processor_mapping(void) {}
 354#endif /* CONFIG_ACPI_HOTPLUG_CPU */
 355
 356#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
 357static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
 358                         u64 *phys_addr, int *ioapic_id)
 359{
 360        struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
 361
 362        if (ioapic->global_irq_base != gsi_base)
 363                return 0;
 364
 365        *phys_addr = ioapic->address;
 366        *ioapic_id = ioapic->id;
 367        return 1;
 368}
 369
 370static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
 371{
 372        struct acpi_subtable_header *hdr;
 373        unsigned long madt_end, entry;
 374        struct acpi_table_madt *madt;
 375        int apic_id = -1;
 376
 377        madt = get_madt_table();
 378        if (!madt)
 379                return apic_id;
 380
 381        entry = (unsigned long)madt;
 382        madt_end = entry + madt->header.length;
 383
 384        /* Parse all entries looking for a match. */
 385        entry += sizeof(struct acpi_table_madt);
 386        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 387                hdr = (struct acpi_subtable_header *)entry;
 388                if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
 389                    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
 390                        break;
 391                else
 392                        entry += hdr->length;
 393        }
 394
 395        return apic_id;
 396}
 397
 398static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
 399                                  u64 *phys_addr)
 400{
 401        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 402        struct acpi_subtable_header *header;
 403        union acpi_object *obj;
 404        int apic_id = -1;
 405
 406        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 407                goto exit;
 408
 409        if (!buffer.length || !buffer.pointer)
 410                goto exit;
 411
 412        obj = buffer.pointer;
 413        if (obj->type != ACPI_TYPE_BUFFER ||
 414            obj->buffer.length < sizeof(struct acpi_subtable_header))
 415                goto exit;
 416
 417        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 418        if (header->type == ACPI_MADT_TYPE_IO_APIC)
 419                get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
 420
 421exit:
 422        kfree(buffer.pointer);
 423        return apic_id;
 424}
 425
 426/**
 427 * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
 428 * @handle:     ACPI object for IOAPIC device
 429 * @gsi_base:   GSI base to match with
 430 * @phys_addr:  Pointer to store physical address of matching IOAPIC record
 431 *
 432 * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
 433 * for an ACPI IOAPIC record matching @gsi_base.
 434 * Return IOAPIC id and store physical address in @phys_addr if found a match,
 435 * otherwise return <0.
 436 */
 437int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
 438{
 439        int apic_id;
 440
 441        apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
 442        if (apic_id == -1)
 443                apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
 444
 445        return apic_id;
 446}
 447#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
 448