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(int type, u32 acpi_id)
 112{
 113        unsigned long madt_end, entry;
 114        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;      /* CPU hardware ID */
 115        struct acpi_table_madt *madt;
 116
 117        madt = get_madt_table();
 118        if (!madt)
 119                return phys_id;
 120
 121        entry = (unsigned long)madt;
 122        madt_end = entry + madt->header.length;
 123
 124        /* Parse all entries looking for a match. */
 125
 126        entry += sizeof(struct acpi_table_madt);
 127        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 128                struct acpi_subtable_header *header =
 129                        (struct acpi_subtable_header *)entry;
 130                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
 131                        if (!map_lapic_id(header, acpi_id, &phys_id))
 132                                break;
 133                } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
 134                        if (!map_x2apic_id(header, type, acpi_id, &phys_id))
 135                                break;
 136                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
 137                        if (!map_lsapic_id(header, type, acpi_id, &phys_id))
 138                                break;
 139                } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
 140                        if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
 141                                break;
 142                }
 143                entry += header->length;
 144        }
 145        return phys_id;
 146}
 147
 148static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
 149{
 150        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 151        union acpi_object *obj;
 152        struct acpi_subtable_header *header;
 153        phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
 154
 155        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 156                goto exit;
 157
 158        if (!buffer.length || !buffer.pointer)
 159                goto exit;
 160
 161        obj = buffer.pointer;
 162        if (obj->type != ACPI_TYPE_BUFFER ||
 163            obj->buffer.length < sizeof(struct acpi_subtable_header)) {
 164                goto exit;
 165        }
 166
 167        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 168        if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
 169                map_lapic_id(header, acpi_id, &phys_id);
 170        else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
 171                map_lsapic_id(header, type, acpi_id, &phys_id);
 172        else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
 173                map_x2apic_id(header, type, acpi_id, &phys_id);
 174        else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
 175                map_gicc_mpidr(header, type, acpi_id, &phys_id);
 176
 177exit:
 178        kfree(buffer.pointer);
 179        return phys_id;
 180}
 181
 182phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
 183{
 184        phys_cpuid_t phys_id;
 185
 186        phys_id = map_mat_entry(handle, type, acpi_id);
 187        if (invalid_phys_cpuid(phys_id))
 188                phys_id = map_madt_entry(type, acpi_id);
 189
 190        return phys_id;
 191}
 192
 193int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
 194{
 195#ifdef CONFIG_SMP
 196        int i;
 197#endif
 198
 199        if (invalid_phys_cpuid(phys_id)) {
 200                /*
 201                 * On UP processor, there is no _MAT or MADT table.
 202                 * So above phys_id is always set to PHYS_CPUID_INVALID.
 203                 *
 204                 * BIOS may define multiple CPU handles even for UP processor.
 205                 * For example,
 206                 *
 207                 * Scope (_PR)
 208                 * {
 209                 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
 210                 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
 211                 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
 212                 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
 213                 * }
 214                 *
 215                 * Ignores phys_id and always returns 0 for the processor
 216                 * handle with acpi id 0 if nr_cpu_ids is 1.
 217                 * This should be the case if SMP tables are not found.
 218                 * Return -EINVAL for other CPU's handle.
 219                 */
 220                if (nr_cpu_ids <= 1 && acpi_id == 0)
 221                        return acpi_id;
 222                else
 223                        return -EINVAL;
 224        }
 225
 226#ifdef CONFIG_SMP
 227        for_each_possible_cpu(i) {
 228                if (cpu_physical_id(i) == phys_id)
 229                        return i;
 230        }
 231#else
 232        /* In UP kernel, only processor 0 is valid */
 233        if (phys_id == 0)
 234                return phys_id;
 235#endif
 236        return -ENODEV;
 237}
 238
 239int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 240{
 241        phys_cpuid_t phys_id;
 242
 243        phys_id = acpi_get_phys_id(handle, type, acpi_id);
 244
 245        return acpi_map_cpuid(phys_id, acpi_id);
 246}
 247EXPORT_SYMBOL_GPL(acpi_get_cpuid);
 248
 249#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
 250static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
 251                         u64 *phys_addr, int *ioapic_id)
 252{
 253        struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
 254
 255        if (ioapic->global_irq_base != gsi_base)
 256                return 0;
 257
 258        *phys_addr = ioapic->address;
 259        *ioapic_id = ioapic->id;
 260        return 1;
 261}
 262
 263static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
 264{
 265        struct acpi_subtable_header *hdr;
 266        unsigned long madt_end, entry;
 267        struct acpi_table_madt *madt;
 268        int apic_id = -1;
 269
 270        madt = get_madt_table();
 271        if (!madt)
 272                return apic_id;
 273
 274        entry = (unsigned long)madt;
 275        madt_end = entry + madt->header.length;
 276
 277        /* Parse all entries looking for a match. */
 278        entry += sizeof(struct acpi_table_madt);
 279        while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
 280                hdr = (struct acpi_subtable_header *)entry;
 281                if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
 282                    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
 283                        break;
 284                else
 285                        entry += hdr->length;
 286        }
 287
 288        return apic_id;
 289}
 290
 291static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
 292                                  u64 *phys_addr)
 293{
 294        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 295        struct acpi_subtable_header *header;
 296        union acpi_object *obj;
 297        int apic_id = -1;
 298
 299        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
 300                goto exit;
 301
 302        if (!buffer.length || !buffer.pointer)
 303                goto exit;
 304
 305        obj = buffer.pointer;
 306        if (obj->type != ACPI_TYPE_BUFFER ||
 307            obj->buffer.length < sizeof(struct acpi_subtable_header))
 308                goto exit;
 309
 310        header = (struct acpi_subtable_header *)obj->buffer.pointer;
 311        if (header->type == ACPI_MADT_TYPE_IO_APIC)
 312                get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
 313
 314exit:
 315        kfree(buffer.pointer);
 316        return apic_id;
 317}
 318
 319/**
 320 * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
 321 * @handle:     ACPI object for IOAPIC device
 322 * @gsi_base:   GSI base to match with
 323 * @phys_addr:  Pointer to store physical address of matching IOAPIC record
 324 *
 325 * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
 326 * for an ACPI IOAPIC record matching @gsi_base.
 327 * Return IOAPIC id and store physical address in @phys_addr if found a match,
 328 * otherwise return <0.
 329 */
 330int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
 331{
 332        int apic_id;
 333
 334        apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
 335        if (apic_id == -1)
 336                apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
 337
 338        return apic_id;
 339}
 340#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
 341