root/drivers/acpi/processor_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_madt_table
  2. map_lapic_id
  3. map_x2apic_id
  4. map_lsapic_id
  5. map_gicc_mpidr
  6. map_madt_entry
  7. acpi_map_madt_entry
  8. map_mat_entry
  9. acpi_get_phys_id
  10. acpi_map_cpuid
  11. acpi_get_cpuid
  12. get_ioapic_id
  13. parse_madt_ioapic_entry
  14. parse_mat_ioapic_entry
  15. acpi_get_ioapic_id

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

/* [<][>][^][v][top][bottom][index][help] */