LCOV - code coverage report
Current view: top level - drivers/acpi - processor_core.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 37 152 24.3 %
Date: 2022-04-01 13:59:58 Functions: 4 10 40.0 %
Branches: 12 124 9.7 %

           Branch data     Line data    Source code
       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                 :          0 : static struct acpi_table_madt *get_madt_table(void)
      21                 :            : {
      22                 :          0 :         static struct acpi_table_madt *madt;
      23                 :          0 :         static int read_madt;
      24                 :            : 
      25         [ #  # ]:          0 :         if (!read_madt) {
      26         [ #  # ]:          0 :                 if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
      27                 :            :                                         (struct acpi_table_header **)&madt)))
      28                 :          0 :                         madt = NULL;
      29                 :          0 :                 read_madt++;
      30                 :            :         }
      31                 :            : 
      32                 :          0 :         return madt;
      33                 :            : }
      34                 :            : 
      35                 :        156 : static int map_lapic_id(struct acpi_subtable_header *entry,
      36                 :            :                  u32 acpi_id, phys_cpuid_t *apic_id)
      37                 :            : {
      38                 :        156 :         struct acpi_madt_local_apic *lapic =
      39                 :        156 :                 container_of(entry, struct acpi_madt_local_apic, header);
      40                 :            : 
      41                 :        156 :         if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
      42                 :            :                 return -ENODEV;
      43                 :            : 
      44   [ +  -  -  - ]:        156 :         if (lapic->processor_id != acpi_id)
      45                 :            :                 return -EINVAL;
      46                 :            : 
      47                 :        156 :         *apic_id = lapic->id;
      48                 :        156 :         return 0;
      49                 :            : }
      50                 :            : 
      51                 :          0 : static int map_x2apic_id(struct acpi_subtable_header *entry,
      52                 :            :                 int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
      53                 :            : {
      54                 :          0 :         struct acpi_madt_local_x2apic *apic =
      55                 :          0 :                 container_of(entry, struct acpi_madt_local_x2apic, header);
      56                 :            : 
      57                 :          0 :         if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
      58                 :            :                 return -ENODEV;
      59                 :            : 
      60   [ #  #  #  #  :          0 :         if (device_declaration && (apic->uid == acpi_id)) {
             #  #  #  # ]
      61                 :          0 :                 *apic_id = apic->local_apic_id;
      62                 :          0 :                 return 0;
      63                 :            :         }
      64                 :            : 
      65                 :            :         return -EINVAL;
      66                 :            : }
      67                 :            : 
      68                 :          0 : static int map_lsapic_id(struct acpi_subtable_header *entry,
      69                 :            :                 int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
      70                 :            : {
      71                 :          0 :         struct acpi_madt_local_sapic *lsapic =
      72                 :          0 :                 container_of(entry, struct acpi_madt_local_sapic, header);
      73                 :            : 
      74                 :          0 :         if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
      75                 :            :                 return -ENODEV;
      76                 :            : 
      77   [ #  #  #  # ]:          0 :         if (device_declaration) {
      78   [ #  #  #  #  :          0 :                 if ((entry->length < 16) || (lsapic->uid != acpi_id))
             #  #  #  # ]
      79                 :            :                         return -EINVAL;
      80   [ #  #  #  # ]:          0 :         } else if (lsapic->processor_id != acpi_id)
      81                 :            :                 return -EINVAL;
      82                 :            : 
      83                 :          0 :         *apic_id = (lsapic->id << 8) | lsapic->eid;
      84                 :          0 :         return 0;
      85                 :            : }
      86                 :            : 
      87                 :            : /*
      88                 :            :  * Retrieve the ARM CPU physical identifier (MPIDR)
      89                 :            :  */
      90                 :          0 : static int map_gicc_mpidr(struct acpi_subtable_header *entry,
      91                 :            :                 int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr)
      92                 :            : {
      93                 :          0 :         struct acpi_madt_generic_interrupt *gicc =
      94                 :          0 :             container_of(entry, struct acpi_madt_generic_interrupt, header);
      95                 :            : 
      96                 :          0 :         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   [ #  #  #  #  :          0 :         if (device_declaration && (gicc->uid == acpi_id)) {
             #  #  #  # ]
     105                 :          0 :                 *mpidr = gicc->arm_mpidr;
     106                 :          0 :                 return 0;
     107                 :            :         }
     108                 :            : 
     109                 :            :         return -EINVAL;
     110                 :            : }
     111                 :            : 
     112                 :          0 : static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
     113                 :            :                                    int type, u32 acpi_id)
     114                 :            : {
     115                 :          0 :         unsigned long madt_end, entry;
     116                 :          0 :         phys_cpuid_t phys_id = PHYS_CPUID_INVALID;      /* CPU hardware ID */
     117                 :            : 
     118         [ #  # ]:          0 :         if (!madt)
     119                 :            :                 return phys_id;
     120                 :            : 
     121                 :          0 :         entry = (unsigned long)madt;
     122                 :          0 :         madt_end = entry + madt->header.length;
     123                 :            : 
     124                 :            :         /* Parse all entries looking for a match. */
     125                 :            : 
     126                 :          0 :         entry += sizeof(struct acpi_table_madt);
     127         [ #  # ]:          0 :         while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
     128                 :          0 :                 struct acpi_subtable_header *header =
     129                 :            :                         (struct acpi_subtable_header *)entry;
     130         [ #  # ]:          0 :                 if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
     131         [ #  # ]:          0 :                         if (!map_lapic_id(header, acpi_id, &phys_id))
     132                 :            :                                 break;
     133         [ #  # ]:          0 :                 } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
     134         [ #  # ]:          0 :                         if (!map_x2apic_id(header, type, acpi_id, &phys_id))
     135                 :            :                                 break;
     136         [ #  # ]:          0 :                 } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
     137         [ #  # ]:          0 :                         if (!map_lsapic_id(header, type, acpi_id, &phys_id))
     138                 :            :                                 break;
     139         [ #  # ]:          0 :                 } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
     140         [ #  # ]:          0 :                         if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
     141                 :            :                                 break;
     142                 :            :                 }
     143                 :          0 :                 entry += header->length;
     144                 :            :         }
     145                 :            :         return phys_id;
     146                 :            : }
     147                 :            : 
     148                 :          0 : phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
     149                 :            : {
     150                 :          0 :         struct acpi_table_madt *madt = NULL;
     151                 :          0 :         phys_cpuid_t rv;
     152                 :            : 
     153                 :          0 :         acpi_get_table(ACPI_SIG_MADT, 0,
     154                 :            :                        (struct acpi_table_header **)&madt);
     155         [ #  # ]:          0 :         if (!madt)
     156                 :            :                 return PHYS_CPUID_INVALID;
     157                 :            : 
     158                 :          0 :         rv = map_madt_entry(madt, 1, acpi_id);
     159                 :            : 
     160                 :          0 :         acpi_put_table((struct acpi_table_header *)madt);
     161                 :            : 
     162                 :          0 :         return rv;
     163                 :            : }
     164                 :            : 
     165                 :        156 : static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
     166                 :            : {
     167                 :        156 :         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
     168                 :        156 :         union acpi_object *obj;
     169                 :        156 :         struct acpi_subtable_header *header;
     170                 :        156 :         phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
     171                 :            : 
     172         [ -  + ]:        156 :         if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
     173                 :          0 :                 goto exit;
     174                 :            : 
     175   [ +  -  -  + ]:        156 :         if (!buffer.length || !buffer.pointer)
     176                 :          0 :                 goto exit;
     177                 :            : 
     178                 :        156 :         obj = buffer.pointer;
     179         [ +  - ]:        156 :         if (obj->type != ACPI_TYPE_BUFFER ||
     180         [ -  + ]:        156 :             obj->buffer.length < sizeof(struct acpi_subtable_header)) {
     181                 :          0 :                 goto exit;
     182                 :            :         }
     183                 :            : 
     184                 :        156 :         header = (struct acpi_subtable_header *)obj->buffer.pointer;
     185         [ +  - ]:        156 :         if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
     186         [ +  - ]:        156 :                 map_lapic_id(header, acpi_id, &phys_id);
     187         [ #  # ]:          0 :         else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
     188         [ #  # ]:          0 :                 map_lsapic_id(header, type, acpi_id, &phys_id);
     189         [ #  # ]:          0 :         else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
     190         [ #  # ]:          0 :                 map_x2apic_id(header, type, acpi_id, &phys_id);
     191         [ #  # ]:          0 :         else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
     192         [ #  # ]:          0 :                 map_gicc_mpidr(header, type, acpi_id, &phys_id);
     193                 :            : 
     194                 :          0 : exit:
     195                 :        156 :         kfree(buffer.pointer);
     196                 :        156 :         return phys_id;
     197                 :            : }
     198                 :            : 
     199                 :        156 : phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
     200                 :            : {
     201                 :        156 :         phys_cpuid_t phys_id;
     202                 :            : 
     203                 :        156 :         phys_id = map_mat_entry(handle, type, acpi_id);
     204         [ -  + ]:        156 :         if (invalid_phys_cpuid(phys_id))
     205                 :          0 :                 phys_id = map_madt_entry(get_madt_table(), type, acpi_id);
     206                 :            : 
     207                 :        156 :         return phys_id;
     208                 :            : }
     209                 :            : EXPORT_SYMBOL_GPL(acpi_get_phys_id);
     210                 :            : 
     211                 :        156 : int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
     212                 :            : {
     213                 :            : #ifdef CONFIG_SMP
     214                 :        156 :         int i;
     215                 :            : #endif
     216                 :            : 
     217         [ -  + ]:        156 :         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   [ #  #  #  # ]:          0 :                 if (nr_cpu_ids <= 1 && acpi_id == 0)
     239                 :            :                         return acpi_id;
     240                 :            :                 else
     241                 :          0 :                         return -EINVAL;
     242                 :            :         }
     243                 :            : 
     244                 :            : #ifdef CONFIG_SMP
     245         [ +  - ]:        156 :         for_each_possible_cpu(i) {
     246         [ +  - ]:        156 :                 if (cpu_physical_id(i) == phys_id)
     247                 :        156 :                         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                 :         78 : int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
     258                 :            : {
     259                 :         78 :         phys_cpuid_t phys_id;
     260                 :            : 
     261                 :         78 :         phys_id = acpi_get_phys_id(handle, type, acpi_id);
     262                 :            : 
     263                 :         78 :         return acpi_map_cpuid(phys_id, acpi_id);
     264                 :            : }
     265                 :            : EXPORT_SYMBOL_GPL(acpi_get_cpuid);
     266                 :            : 
     267                 :            : #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
     268                 :          0 : static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
     269                 :            :                          u64 *phys_addr, int *ioapic_id)
     270                 :            : {
     271                 :          0 :         struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
     272                 :            : 
     273         [ #  # ]:          0 :         if (ioapic->global_irq_base != gsi_base)
     274                 :            :                 return 0;
     275                 :            : 
     276                 :          0 :         *phys_addr = ioapic->address;
     277                 :          0 :         *ioapic_id = ioapic->id;
     278                 :          0 :         return 1;
     279                 :            : }
     280                 :            : 
     281                 :          0 : static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
     282                 :            : {
     283                 :          0 :         struct acpi_subtable_header *hdr;
     284                 :          0 :         unsigned long madt_end, entry;
     285                 :          0 :         struct acpi_table_madt *madt;
     286                 :          0 :         int apic_id = -1;
     287                 :            : 
     288                 :          0 :         madt = get_madt_table();
     289         [ #  # ]:          0 :         if (!madt)
     290                 :            :                 return apic_id;
     291                 :            : 
     292                 :          0 :         entry = (unsigned long)madt;
     293                 :          0 :         madt_end = entry + madt->header.length;
     294                 :            : 
     295                 :            :         /* Parse all entries looking for a match. */
     296                 :          0 :         entry += sizeof(struct acpi_table_madt);
     297         [ #  # ]:          0 :         while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
     298                 :          0 :                 hdr = (struct acpi_subtable_header *)entry;
     299         [ #  # ]:          0 :                 if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
     300                 :            :                     get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
     301                 :            :                         break;
     302                 :            :                 else
     303                 :          0 :                         entry += hdr->length;
     304                 :            :         }
     305                 :            : 
     306                 :            :         return apic_id;
     307                 :            : }
     308                 :            : 
     309                 :          0 : static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
     310                 :            :                                   u64 *phys_addr)
     311                 :            : {
     312                 :          0 :         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
     313                 :          0 :         struct acpi_subtable_header *header;
     314                 :          0 :         union acpi_object *obj;
     315                 :          0 :         int apic_id = -1;
     316                 :            : 
     317         [ #  # ]:          0 :         if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
     318                 :          0 :                 goto exit;
     319                 :            : 
     320   [ #  #  #  # ]:          0 :         if (!buffer.length || !buffer.pointer)
     321                 :          0 :                 goto exit;
     322                 :            : 
     323                 :          0 :         obj = buffer.pointer;
     324         [ #  # ]:          0 :         if (obj->type != ACPI_TYPE_BUFFER ||
     325         [ #  # ]:          0 :             obj->buffer.length < sizeof(struct acpi_subtable_header))
     326                 :          0 :                 goto exit;
     327                 :            : 
     328                 :          0 :         header = (struct acpi_subtable_header *)obj->buffer.pointer;
     329         [ #  # ]:          0 :         if (header->type == ACPI_MADT_TYPE_IO_APIC)
     330         [ #  # ]:          0 :                 get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
     331                 :            : 
     332                 :          0 : exit:
     333                 :          0 :         kfree(buffer.pointer);
     334                 :          0 :         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                 :          0 : int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
     349                 :            : {
     350                 :          0 :         int apic_id;
     351                 :            : 
     352                 :          0 :         apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
     353         [ #  # ]:          0 :         if (apic_id == -1)
     354                 :          0 :                 apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
     355                 :            : 
     356                 :          0 :         return apic_id;
     357                 :            : }
     358                 :            : #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */

Generated by: LCOV version 1.14