Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained from the GICC Structure introduced by ACPI 5.1.
MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use MPIDR not the GIC CPU interface ID to identify CPUs.
CC: Rafael J. Wysocki rjw@rjwysocki.net CC: Catalin Marinas catalin.marinas@arm.com CC: Will Deacon will.deacon@arm.com Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Tested-by: Yijing Wang wangyijing@huawei.com Tested-by: Mark Langsdorf mlangsdo@redhat.com Tested-by: Jon Masters jcm@redhat.com Tested-by: Timur Tabi timur@codeaurora.org Tested-by: Robert Richter rrichter@cavium.com Acked-by: Robert Richter rrichter@cavium.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/acpi.h | 13 +++++++++++++ drivers/acpi/processor_core.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 88932a9..5244d11 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -13,6 +13,8 @@ #define _ASM_ACPI_H
#include <linux/mm.h> +#include <asm/smp_plat.h> +#include <asm/cputype.h>
/* ACPI table mapping after acpi_gbl_permanent_mmap is set */ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, @@ -25,6 +27,10 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, } #define acpi_os_ioremap acpi_os_ioremap
+typedef u64 phys_cpuid_t; + +#define CPU_PHYS_ID_INVALID INVALID_HWID + /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ @@ -59,6 +65,13 @@ static inline void enable_acpi(void) }
/* + * The ACPI processor driver for ACPI core code needs this macro + * to find out this cpu was already mapped (mapping from CPU hardware + * ID to CPU logical ID) or not. + */ +#define cpu_physical_id(cpu) cpu_logical_map(cpu) + +/* * It's used from ACPI core in kdump to boot UP system with SMP kernel, * with this check the ACPI core will not override the CPU index * obtained from GICC with 0 and not print some error message as well. diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f3b10a9..ccdfd96 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -64,6 +64,31 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; }
+/* + * On ARM platform, MPIDR value is the hardware ID as apic ID + * on Intel platforms + */ +static int map_gicc_mpidr(struct acpi_subtable_header *entry, + int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr) +{ + struct acpi_madt_generic_interrupt *gicc = + container_of(entry, struct acpi_madt_generic_interrupt, header); + + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return -ENODEV; + + /* In the GIC interrupt model, logical processors are + * required to have a Processor Device object in the DSDT, + * so we should check device_declaration here + */ + if (device_declaration && (gicc->uid == acpi_id)) { + *mpidr = gicc->arm_mpidr; + return 0; + } + + return -EINVAL; +} + static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; @@ -99,6 +124,9 @@ static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { if (!map_lsapic_id(header, type, acpi_id, &phys_id)) break; + } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { + if (!map_gicc_mpidr(header, type, acpi_id, &phys_id)) + break; } entry += header->length; } @@ -131,6 +159,8 @@ static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_lsapic_id(header, type, acpi_id, &phys_id); else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) map_x2apic_id(header, type, acpi_id, &phys_id); + else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) + map_gicc_mpidr(header, type, acpi_id, &phys_id);
exit: kfree(buffer.pointer);