From b2cedba09dd7034c144c03eadc09ee1e4d791590 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 24 Mar 2015 14:02:36 +0000 Subject: ARM64: allow late use of early_ioremap Commit 0e63ea48b4d8 (arm64/efi: add missing call to early_ioremap_reset()) added a missing call to early_ioremap_reset(). This triggers a BUG if code tries using early_ioremap() after the early_ioremap_reset(). This is a problem for some ACPI code which needs short-lived temporary mappings after paging_init() but before acpi_early_init() in start_kernel(). This patch adds definitions for the __late_set_fixmap() and __late_clear_fixmap() which avoids the BUG by allowing later use of early_ioremap(). CC: Leif Lindholm CC: Ard Biesheuvel Tested-by: Suravee Suthikulpanit Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Robert Richter Tested-by: Timur Tabi Acked-by: Robert Richter Reviewed-by: Grant Likely Signed-off-by: Mark Salter Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/fixmap.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index defa0ff98250..f196e408a35c 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -62,6 +62,9 @@ void __init early_fixmap_init(void); #define __early_set_fixmap __set_fixmap +#define __late_set_fixmap __set_fixmap +#define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR) + extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); #include -- cgit v1.2.3 From 37655163ce1a3ef2635a9bba0ad614f25e01484e Mon Sep 17 00:00:00 2001 From: Al Stone Date: Tue, 24 Mar 2015 14:02:37 +0000 Subject: ARM64 / ACPI: Get RSDP and ACPI boot-time tables As we want to get ACPI tables to parse and then use the information for system initialization, we should get the RSDP (Root System Description Pointer) first, it then locates Extended Root Description Table (XSDT) which contains all the 64-bit physical address that pointer to other boot-time tables. Introduce acpi.c and its related head file in this patch to provide fundamental needs of extern variables and functions for ACPI core, and then get boot-time tables as needed. - asm/acenv.h for arch specific ACPICA environments and implementation, It is needed unconditionally by ACPI core; - asm/acpi.h for arch specific variables and functions needed by ACPI driver core; - acpi.c for ARM64 related ACPI implementation for ACPI driver core; acpi_boot_table_init() is introduced to get RSDP and boot-time tables, it will be called in setup_arch() before paging_init(), so we should use eary_memremap() mechanism here to get the RSDP and all the table pointers. FADT Major.Minor version was introduced in ACPI 5.1, it is the same as ACPI version. In ACPI 5.1, some major gaps are fixed for ARM, such as updates in MADT table for GIC and SMP init, without those updates, we can not get the MPIDR for SMP init, and GICv2/3 related init information, so we can't boot arm64 ACPI properly with table versions predating 5.1. If firmware provides ACPI tables with ACPI version less than 5.1, OS has no way to retrieve the configuration data that is necessary to init SMP boot protocol and the GIC properly, so disable ACPI if we get an FADT table with version less that 5.1 when acpi_boot_table_init() called. CC: Catalin Marinas CC: Will Deacon CC: Lorenzo Pieralisi Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Olof Johansson Acked-by: Grant Likely Signed-off-by: Al Stone Signed-off-by: Graeme Gregory Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acenv.h | 18 ++++++++ arch/arm64/include/asm/acpi.h | 45 ++++++++++++++++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/acpi.c | 101 +++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/setup.c | 5 ++ 5 files changed, 170 insertions(+) create mode 100644 arch/arm64/include/asm/acenv.h create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/kernel/acpi.c (limited to 'arch') diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h new file mode 100644 index 000000000000..b49166fde7ea --- /dev/null +++ b/arch/arm64/include/asm/acenv.h @@ -0,0 +1,18 @@ +/* + * ARM64 specific ACPICA environments and implementation + * + * Copyright (C) 2014, Linaro Ltd. + * Author: Hanjun Guo + * Author: Graeme Gregory + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ASM_ACENV_H +#define _ASM_ACENV_H + +/* It is required unconditionally by ACPI core, update it when needed. */ + +#endif /* _ASM_ACENV_H */ diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h new file mode 100644 index 000000000000..8b837ab59988 --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013-2014, Linaro Ltd. + * Author: Al Stone + * Author: Graeme Gregory + * Author: Hanjun Guo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + */ + +#ifndef _ASM_ACPI_H +#define _ASM_ACPI_H + +/* Basic configuration for ACPI */ +#ifdef CONFIG_ACPI +#define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ +extern int acpi_disabled; +extern int acpi_noirq; +extern int acpi_pci_disabled; + +static inline void disable_acpi(void) +{ + acpi_disabled = 1; + acpi_pci_disabled = 1; + acpi_noirq = 1; +} + +/* + * 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. + * Since MADT must provide at least one GICC structure for GIC + * initialization, CPU will be always available in MADT on ARM64. + */ +static inline bool acpi_has_cpu_in_madt(void) +{ + return true; +} + +static inline void arch_fix_phys_package_id(int num, u32 slot) { } + +#endif /* CONFIG_ACPI */ + +#endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5ee07eee80c2..fdc7877f2a3c 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -35,6 +35,7 @@ arm64-obj-$(CONFIG_KGDB) += kgdb.o arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o +arm64-obj-$(CONFIG_ACPI) += acpi.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c new file mode 100644 index 000000000000..7abac24d5584 --- /dev/null +++ b/arch/arm64/kernel/acpi.c @@ -0,0 +1,101 @@ +/* + * ARM64 Specific Low-Level ACPI Boot Support + * + * Copyright (C) 2013-2014, Linaro Ltd. + * Author: Al Stone + * Author: Graeme Gregory + * Author: Hanjun Guo + * Author: Tomasz Nowicki + * Author: Naresh Bhat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "ACPI: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +int acpi_noirq; /* skip ACPI IRQ initialization */ +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled); + +int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ +EXPORT_SYMBOL(acpi_pci_disabled); + +/* + * __acpi_map_table() will be called before page_init(), so early_ioremap() + * or early_memremap() should be called here to for ACPI table mapping. + */ +char *__init __acpi_map_table(unsigned long phys, unsigned long size) +{ + if (!size) + return NULL; + + return early_memremap(phys, size); +} + +void __init __acpi_unmap_table(char *map, unsigned long size) +{ + if (!map || !size) + return; + + early_memunmap(map, size); +} + +static int __init acpi_parse_fadt(struct acpi_table_header *table) +{ + struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; + + /* + * Revision in table header is the FADT Major revision, and there + * is a minor revision of FADT which was introduced by ACPI 5.1, + * we only deal with ACPI 5.1 or newer revision to get GIC and SMP + * boot protocol configuration data, or we will disable ACPI. + */ + if (table->revision > 5 || + (table->revision == 5 && fadt->minor_revision >= 1)) + return 0; + + pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", + table->revision, fadt->minor_revision); + disable_acpi(); + + return -EINVAL; +} + +/* + * acpi_boot_table_init() called from setup_arch(), always. + * 1. find RSDP and get its address, and then find XSDT + * 2. extract all tables and checksums them all + * 3. check ACPI FADT revision + * + * We can parse ACPI boot-time tables such as MADT after + * this function is called. + */ +void __init acpi_boot_table_init(void) +{ + /* If acpi_disabled, bail out */ + if (acpi_disabled) + return; + + /* Initialize the ACPI boot-time table parser. */ + if (acpi_table_init()) { + disable_acpi(); + return; + } + + if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) { + /* disable ACPI if no FADT is found */ + disable_acpi(); + pr_err("Can't find FADT\n"); + } +} diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index e8420f635bd4..4f1a014ace39 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -46,6 +47,7 @@ #include #include +#include #include #include #include @@ -380,6 +382,9 @@ void __init setup_arch(char **cmdline_p) efi_init(); arm64_memblock_init(); + /* Parse the ACPI tables for possible boot-time configuration */ + acpi_boot_table_init(); + paging_init(); request_standard_resources(); -- cgit v1.2.3 From 652261a7a86c884147930fa1e5ddd82a8a5748da Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 24 Mar 2015 14:02:38 +0000 Subject: ACPI: fix acpi_os_ioremap for arm64 The acpi_os_ioremap() function may be used to map normal RAM or IO regions. The current implementation simply uses ioremap_cache(). This will work for some architectures, but arm64 ioremap_cache() cannot be used to map IO regions which don't support caching. So for arm64, use ioremap() for non-RAM regions. CC: Rafael J Wysocki CC: Catalin Marinas Tested-by: Robert Richter Tested-by: Timur Tabi Acked-by: Robert Richter Acked-by: Rafael J. Wysocki Reviewed-by: Grant Likely Signed-off-by: Mark Salter Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 13 +++++++++++++ include/acpi/acpi_io.h | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 8b837ab59988..40e092483e96 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,8 +12,21 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H +#include + /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI +/* ACPI table mapping after acpi_gbl_permanent_mmap is set */ +static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, + acpi_size size) +{ + if (!page_is_ram(phys >> PAGE_SHIFT)) + return ioremap(phys, size); + + return ioremap_cache(phys, size); +} +#define acpi_os_ioremap acpi_os_ioremap + #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ extern int acpi_disabled; extern int acpi_noirq; diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index 444671e9c65d..dd86c5fc102d 100644 --- a/include/acpi/acpi_io.h +++ b/include/acpi/acpi_io.h @@ -3,11 +3,15 @@ #include +#include + +#ifndef acpi_os_ioremap static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) { return ioremap_cache(phys, size); } +#endif void __iomem *__init_refok acpi_os_map_iomem(acpi_physical_address phys, acpi_size size); -- cgit v1.2.3 From 6e0a0ea12962a2175a9f47621f9fe7a4c866cb12 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 24 Mar 2015 14:02:39 +0000 Subject: ACPI / sleep: Introduce CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT ACPI 5.1 does not currently support S states for ARM64 hardware but ACPI code will call acpi_target_system_state() and acpi_sleep_init() for device power management, so introduce CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT and select it for x86 and ia64 only to make sleep functions available, and also introduce stub function to allow other drivers to function until S states are defined for ARM64. It will be no functional change for x86 and IA64. Suggested-by: Rafael J. Wysocki Acked-by: Lorenzo Pieralisi Acked-by: Rafael J. Wysocki Signed-off-by: Graeme Gregory Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/ia64/Kconfig | 1 + arch/x86/Kconfig | 1 + drivers/acpi/Kconfig | 4 ++++ drivers/acpi/Makefile | 2 +- drivers/acpi/internal.h | 4 ++++ 5 files changed, 11 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 074e52bf815c..cc3414fda362 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -10,6 +10,7 @@ config IA64 select ARCH_MIGHT_HAVE_PC_SERIO select PCI if (!IA64_HP_SIM) select ACPI if (!IA64_HP_SIM) + select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b7d31ca55187..c3ea9f9a29d1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -22,6 +22,7 @@ config X86_64 ### Arch settings config X86 def_bool y + select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select ARCH_HAS_FAST_MULTIPLIER diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index e6c3ddd92665..a726381fea72 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -48,9 +48,13 @@ config ACPI_LEGACY_TABLES_LOOKUP config ARCH_MIGHT_HAVE_ACPI_PDC bool +config ACPI_SYSTEM_POWER_STATES_SUPPORT + bool + config ACPI_SLEEP bool depends on SUSPEND || HIBERNATION + depends on ACPI_SYSTEM_POWER_STATES_SUPPORT default y config ACPI_PROCFS_POWER diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 623b117ad1a2..db153c6a75d7 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -23,7 +23,7 @@ acpi-y += nvs.o # Power management related files acpi-y += wakeup.o -acpi-y += sleep.o +acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 56b321aa2b1c..ba4a61e964be 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -161,7 +161,11 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); /*-------------------------------------------------------------------------- Suspend/Resume -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT extern int acpi_sleep_init(void); +#else +static inline int acpi_sleep_init(void) { return -ENXIO; } +#endif #ifdef CONFIG_ACPI_SLEEP int acpi_sleep_proc_init(void); -- cgit v1.2.3 From a9cb97fe71d84df103994861f00112fe2cba91be Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:40 +0000 Subject: ARM64 / ACPI: Introduce PCI stub functions for ACPI CONFIG_ACPI depends CONFIG_PCI on x86 and ia64, in ARM64 server world we will have PCIe in most cases, but some of them may not, make CONFIG_ACPI depend CONFIG_PCI on ARM64 will satisfy both. With that case, we need some arch dependent PCI functions to access the config space before the PCI root bridge is created, and pci_acpi_scan_root() to create the PCI root bus. So introduce some stub function here to make ACPI core compile and revisit them later when implemented on ARM64. CC: Liviu Dudau CC: Catalin Marinas CC: Will Deacon Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/pci.h | 6 ++++++ arch/arm64/kernel/pci.c | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'arch') diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h index 872ba939fcb2..b008a72f8bc0 100644 --- a/arch/arm64/include/asm/pci.h +++ b/arch/arm64/include/asm/pci.h @@ -27,6 +27,12 @@ extern int isa_dma_bridge_buggy; #ifdef CONFIG_PCI +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + /* no legacy IRQ on arm64 */ + return -ENODEV; +} + static inline int pci_proc_domain(struct pci_bus *bus) { return 1; diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 6f93c24ca801..4095379dc069 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -46,3 +47,27 @@ int pcibios_add_device(struct pci_dev *dev) return 0; } + +/* + * raw_pci_read/write - Platform-specific PCI config space access. + */ +int raw_pci_read(unsigned int domain, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *val) +{ + return -ENXIO; +} + +int raw_pci_write(unsigned int domain, unsigned int bus, + unsigned int devfn, int reg, int len, u32 val) +{ + return -ENXIO; +} + +#ifdef CONFIG_ACPI +/* Root bridge scanning */ +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) +{ + /* TODO: Should be revisited when implementing PCI on ACPI */ + return NULL; +} +#endif -- cgit v1.2.3 From b10d79f76085b577673395daf92d6208ae09196f Mon Sep 17 00:00:00 2001 From: Al Stone Date: Tue, 24 Mar 2015 14:02:41 +0000 Subject: ARM64 / ACPI: Introduce early_param "acpi=" to enable/disable ACPI This implements the following policy to decide whether ACPI should be used to boot the system: - acpi=off: ACPI will not be used to boot the system, even if there is no alternative available (e.g., device tree is empty) - acpi=force: only ACPI will be used to boot the system; if that fails, there will be no fallback to alternative methods (such as device tree) - otherwise, ACPI will be used as a fallback if the device tree turns out to lack a platform description; the heuristic to decide this is whether /chosen is the only node present at depth 1 CC: Catalin Marinas CC: Will Deacon CC: Rafael J. Wysocki Acked-by: Olof Johansson Acked-by: Grant Likely Tested-by: Timur Tabi Signed-off-by: Al Stone Signed-off-by: Graeme Gregory Signed-off-by: Hanjun Guo Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- Documentation/kernel-parameters.txt | 3 ++- arch/arm64/include/asm/acpi.h | 7 +++++ arch/arm64/kernel/acpi.c | 52 +++++++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..d6c35a7f6ed4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -165,7 +165,7 @@ multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30 bytes respectively. Such letter suffixes can also be entirely omitted. - acpi= [HW,ACPI,X86] + acpi= [HW,ACPI,X86,ARM64] Advanced Configuration and Power Interface Format: { force | off | strict | noirq | rsdt } force -- enable ACPI if default was off @@ -175,6 +175,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. strictly ACPI specification compliant. rsdt -- prefer RSDT over (default) XSDT copy_dsdt -- copy DSDT to memory + For ARM64, ONLY "acpi=off" or "acpi=force" are available See also Documentation/power/runtime_pm.txt, pci=noacpi diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 40e092483e96..c5a9b9741635 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -39,6 +39,13 @@ static inline void disable_acpi(void) acpi_noirq = 1; } +static inline void enable_acpi(void) +{ + acpi_disabled = 0; + acpi_pci_disabled = 0; + acpi_noirq = 0; +} + /* * 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 diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 7abac24d5584..2269e3032c07 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -22,15 +22,49 @@ #include #include #include +#include #include -int acpi_noirq; /* skip ACPI IRQ initialization */ -int acpi_disabled; +int acpi_noirq = 1; /* skip ACPI IRQ initialization */ +int acpi_disabled = 1; EXPORT_SYMBOL(acpi_disabled); -int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ +int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled); +static bool param_acpi_off __initdata; +static bool param_acpi_force __initdata; + +static int __init parse_acpi(char *arg) +{ + if (!arg) + return -EINVAL; + + /* "acpi=off" disables both ACPI table parsing and interpreter */ + if (strcmp(arg, "off") == 0) + param_acpi_off = true; + else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */ + param_acpi_force = true; + else + return -EINVAL; /* Core will print when we return error */ + + return 0; +} +early_param("acpi", parse_acpi); + +static int __init dt_scan_depth1_nodes(unsigned long node, + const char *uname, int depth, + void *data) +{ + /* + * Return 1 as soon as we encounter a node at depth 1 that is + * not the /chosen node. + */ + if (depth == 1 && (strcmp(uname, "chosen") != 0)) + return 1; + return 0; +} + /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -83,10 +117,18 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) */ void __init acpi_boot_table_init(void) { - /* If acpi_disabled, bail out */ - if (acpi_disabled) + /* + * Enable ACPI instead of device tree unless + * - ACPI has been disabled explicitly (acpi=off), or + * - the device tree is not empty (it has more than just a /chosen node) + * and ACPI has not been force enabled (acpi=force) + */ + if (param_acpi_off || + (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) return; + enable_acpi(); + /* Initialize the ACPI boot-time table parser. */ if (acpi_table_init()) { disable_acpi(); -- cgit v1.2.3 From 3505f30fb6a980283116390e9a962d60cf8e2a57 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 24 Mar 2015 14:02:42 +0000 Subject: ARM64 / ACPI: If we chose to boot from acpi then disable FDT If the early boot methods of acpi are happy that we have valid ACPI tables and acpi=force has been passed, then do not unflat devicetree effectively disabling further hardware probing from DT. CC: Catalin Marinas CC: Will Deacon Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Olof Johansson Acked-by: Grant Likely Signed-off-by: Graeme Gregory Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 4f1a014ace39..e8c7000af5ba 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -390,7 +390,8 @@ void __init setup_arch(char **cmdline_p) early_ioremap_reset(); - unflatten_device_tree(); + if (acpi_disabled) + unflatten_device_tree(); psci_init(); -- cgit v1.2.3 From 7c59a3df15df29c8402a05b92385e83e55355778 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 24 Mar 2015 14:02:43 +0000 Subject: ARM64 / ACPI: Get PSCI flags in FADT for PSCI init There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set, the former signals to the OS that the firmware is PSCI compliant. The latter selects the appropriate conduit for PSCI calls by toggling between Hypervisor Calls (HVC) and Secure Monitor Calls (SMC). FADT table contains such information in ACPI 5.1, FADT table was parsed in ACPI table init and copy to struct acpi_gbl_FADT, so use the flags in struct acpi_gbl_FADT for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI function IDs, which means that only PSCI 0.2+ is supported in ACPI. CC: Lorenzo Pieralisi CC: Catalin Marinas CC: Will Deacon Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Olof Johansson Acked-by: Grant Likely Signed-off-by: Graeme Gregory Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 15 +++++++++ arch/arm64/include/asm/psci.h | 3 +- arch/arm64/kernel/psci.c | 78 ++++++++++++++++++++++++++++++------------- arch/arm64/kernel/setup.c | 8 +++-- 4 files changed, 76 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index c5a9b9741635..9ea650c991c9 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -32,6 +32,18 @@ extern int acpi_disabled; extern int acpi_noirq; extern int acpi_pci_disabled; +/* 1 to indicate PSCI 0.2+ is implemented */ +static inline bool acpi_psci_present(void) +{ + return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT; +} + +/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */ +static inline bool acpi_psci_use_hvc(void) +{ + return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC; +} + static inline void disable_acpi(void) { acpi_disabled = 1; @@ -60,6 +72,9 @@ static inline bool acpi_has_cpu_in_madt(void) static inline void arch_fix_phys_package_id(int num, u32 slot) { } +#else +static inline bool acpi_psci_present(void) { return false; } +static inline bool acpi_psci_use_hvc(void) { return false; } #endif /* CONFIG_ACPI */ #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index e5312ea0ec1a..2454bc59c916 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h @@ -14,6 +14,7 @@ #ifndef __ASM_PSCI_H #define __ASM_PSCI_H -int psci_init(void); +int psci_dt_init(void); +int psci_acpi_init(void); #endif /* __ASM_PSCI_H */ diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 9b8a70ae64a1..d3c52ce5faf3 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "psci: " fmt +#include #include #include #include @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -273,6 +275,33 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); } +static void __init psci_0_2_set_functions(void) +{ + pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; + psci_ops.cpu_suspend = psci_cpu_suspend; + + psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; + psci_ops.cpu_off = psci_cpu_off; + + psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; + psci_ops.cpu_on = psci_cpu_on; + + psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; + psci_ops.migrate = psci_migrate; + + psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO; + psci_ops.affinity_info = psci_affinity_info; + + psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = + PSCI_0_2_FN_MIGRATE_INFO_TYPE; + psci_ops.migrate_info_type = psci_migrate_info_type; + + arm_pm_restart = psci_sys_reset; + + pm_power_off = psci_sys_poweroff; +} + /* * PSCI Function IDs for v0.2+ are well defined so use * standard values. @@ -306,29 +335,7 @@ static int __init psci_0_2_init(struct device_node *np) } } - pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; - psci_ops.cpu_suspend = psci_cpu_suspend; - - psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; - psci_ops.cpu_off = psci_cpu_off; - - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; - psci_ops.cpu_on = psci_cpu_on; - - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; - psci_ops.migrate = psci_migrate; - - psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO; - psci_ops.affinity_info = psci_affinity_info; - - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = - PSCI_0_2_FN_MIGRATE_INFO_TYPE; - psci_ops.migrate_info_type = psci_migrate_info_type; - - arm_pm_restart = psci_sys_reset; - - pm_power_off = psci_sys_poweroff; + psci_0_2_set_functions(); out_put_node: of_node_put(np); @@ -381,7 +388,7 @@ static const struct of_device_id psci_of_match[] __initconst = { {}, }; -int __init psci_init(void) +int __init psci_dt_init(void) { struct device_node *np; const struct of_device_id *matched_np; @@ -396,6 +403,29 @@ int __init psci_init(void) return init_fn(np); } +/* + * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's + * explicitly clarified in SBBR + */ +int __init psci_acpi_init(void) +{ + if (!acpi_psci_present()) { + pr_info("is not implemented in ACPI.\n"); + return -EOPNOTSUPP; + } + + pr_info("probing for conduit method from ACPI.\n"); + + if (acpi_psci_use_hvc()) + invoke_psci_fn = __invoke_psci_fn_hvc; + else + invoke_psci_fn = __invoke_psci_fn_smc; + + psci_0_2_set_functions(); + + return 0; +} + #ifdef CONFIG_SMP static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index e8c7000af5ba..97fa7f31981d 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -390,10 +390,12 @@ void __init setup_arch(char **cmdline_p) early_ioremap_reset(); - if (acpi_disabled) + if (acpi_disabled) { unflatten_device_tree(); - - psci_init(); + psci_dt_init(); + } else { + psci_acpi_init(); + } cpu_read_bootcpu_ops(); #ifdef CONFIG_SMP -- cgit v1.2.3 From fccb9a81fd08b61bed91ddef88341694f8ecbfd1 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 22:02:45 +0800 Subject: ARM64 / ACPI: Parse MADT for SMP initialization MADT contains the information for MPIDR which is essential for SMP initialization, parse the GIC cpu interface structures to get the MPIDR value and map it to cpu_logical_map(), and add enabled cpu with valid MPIDR into cpu_possible_map. ACPI 5.1 only has two explicit methods to boot up SMP, PSCI and Parking protocol, but the Parking protocol is only specified for ARMv7 now, so make PSCI as the only way for the SMP boot protocol before some updates for the ACPI spec or the Parking protocol spec. Parking protocol patches for SMP boot will be sent to upstream when the new version of Parking protocol is ready. CC: Lorenzo Pieralisi CC: Catalin Marinas CC: Will Deacon CC: Mark Rutland Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Olof Johansson Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Tomasz Nowicki Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 2 + arch/arm64/include/asm/cpu_ops.h | 1 + arch/arm64/include/asm/smp.h | 5 +- arch/arm64/kernel/acpi.c | 149 ++++++++++++++++++++++++++++++++++++++- arch/arm64/kernel/cpu_ops.c | 2 +- arch/arm64/kernel/setup.c | 7 +- arch/arm64/kernel/smp.c | 2 +- 7 files changed, 160 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 9ea650c991c9..9719921aedb1 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -71,10 +71,12 @@ static inline bool acpi_has_cpu_in_madt(void) } static inline void arch_fix_phys_package_id(int num, u32 slot) { } +void __init acpi_init_cpus(void); #else static inline bool acpi_psci_present(void) { return false; } static inline bool acpi_psci_use_hvc(void) { return false; } +static inline void acpi_init_cpus(void) { } #endif /* CONFIG_ACPI */ #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index da301ee7395c..5a31d6716914 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h @@ -66,5 +66,6 @@ struct cpu_operations { extern const struct cpu_operations *cpu_ops[NR_CPUS]; int __init cpu_read_ops(struct device_node *dn, int cpu); void __init cpu_read_bootcpu_ops(void); +const struct cpu_operations *cpu_get_ops(const char *name); #endif /* ifndef __ASM_CPU_OPS_H */ diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 780f82c827b6..bf22650b1a78 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -39,9 +39,10 @@ extern void show_ipi_list(struct seq_file *p, int prec); extern void handle_IPI(int ipinr, struct pt_regs *regs); /* - * Setup the set of possible CPUs (via set_cpu_possible) + * Discover the set of possible CPUs and determine their + * SMP operations. */ -extern void smp_init_cpus(void); +extern void of_smp_init_cpus(void); /* * Provide a function to raise an IPI cross call on CPUs in callmap. diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 2269e3032c07..c9203c0a1179 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -25,6 +25,10 @@ #include #include +#include +#include +#include + int acpi_noirq = 1; /* skip ACPI IRQ initialization */ int acpi_disabled = 1; EXPORT_SYMBOL(acpi_disabled); @@ -32,6 +36,12 @@ EXPORT_SYMBOL(acpi_disabled); int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled); +/* Processors with enabled flag and sane MPIDR */ +static int enabled_cpus; + +/* Boot CPU is valid or not in MADT */ +static bool bootcpu_valid __initdata; + static bool param_acpi_off __initdata; static bool param_acpi_force __initdata; @@ -85,6 +95,129 @@ void __init __acpi_unmap_table(char *map, unsigned long size) early_memunmap(map, size); } +/** + * acpi_map_gic_cpu_interface - generates a logical cpu number + * and map to MPIDR represented by GICC structure + * @mpidr: CPU's hardware id to register, MPIDR represented in MADT + * @enabled: this cpu is enabled or not + * + * Returns the logical cpu number which maps to MPIDR + */ +static int __init acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{ + int i; + + if (mpidr == INVALID_HWID) { + pr_info("Skip MADT cpu entry with invalid MPIDR\n"); + return -EINVAL; + } + + total_cpus++; + if (!enabled) + return -EINVAL; + + if (enabled_cpus >= NR_CPUS) { + pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n", + NR_CPUS, total_cpus, mpidr); + return -EINVAL; + } + + /* Check if GICC structure of boot CPU is available in the MADT */ + if (cpu_logical_map(0) == mpidr) { + if (bootcpu_valid) { + pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", + mpidr); + return -EINVAL; + } + + bootcpu_valid = true; + } + + /* + * Duplicate MPIDRs are a recipe for disaster. Scan + * all initialized entries and check for + * duplicates. If any is found just ignore the CPU. + */ + for (i = 1; i < enabled_cpus; i++) { + if (cpu_logical_map(i) == mpidr) { + pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", + mpidr); + return -EINVAL; + } + } + + if (!acpi_psci_present()) + return -EOPNOTSUPP; + + cpu_ops[enabled_cpus] = cpu_get_ops("psci"); + /* CPU 0 was already initialized */ + if (enabled_cpus) { + if (!cpu_ops[enabled_cpus]) + return -EINVAL; + + if (cpu_ops[enabled_cpus]->cpu_init(NULL, enabled_cpus)) + return -EOPNOTSUPP; + + /* map the logical cpu id to cpu MPIDR */ + cpu_logical_map(enabled_cpus) = mpidr; + } + + enabled_cpus++; + return enabled_cpus; +} + +static int __init +acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK, + processor->flags & ACPI_MADT_ENABLED); + + return 0; +} + +/* Parse GIC cpu interface entries in MADT for SMP init */ +void __init acpi_init_cpus(void) +{ + int count, i; + + /* + * do a partial walk of MADT to determine how many CPUs + * we have including disabled CPUs, and get information + * we need for SMP init + */ + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + acpi_parse_gic_cpu_interface, 0); + + if (!count) { + pr_err("No GIC CPU interface entries present\n"); + return; + } else if (count < 0) { + pr_err("Error parsing GIC CPU interface entry\n"); + return; + } + + if (!bootcpu_valid) { + pr_err("MADT missing boot CPU MPIDR, not enabling secondaries\n"); + return; + } + + for (i = 0; i < enabled_cpus; i++) + set_cpu_possible(i, true); + + /* Make boot-up look pretty */ + pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); +} + static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; @@ -96,8 +229,20 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) * boot protocol configuration data, or we will disable ACPI. */ if (table->revision > 5 || - (table->revision == 5 && fadt->minor_revision >= 1)) - return 0; + (table->revision == 5 && fadt->minor_revision >= 1)) { + /* + * ACPI 5.1 only has two explicit methods to boot up SMP, + * PSCI and Parking protocol, but the Parking protocol is + * only specified for ARMv7 now, so make PSCI as the only + * way for the SMP boot protocol before some updates for + * the Parking protocol spec. + */ + if (acpi_psci_present()) + return 0; + + pr_warn("No PSCI support, will not bring up secondary CPUs\n"); + return -EOPNOTSUPP; + } pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", table->revision, fadt->minor_revision); diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c index cce952440c64..fb8ff9ba467a 100644 --- a/arch/arm64/kernel/cpu_ops.c +++ b/arch/arm64/kernel/cpu_ops.c @@ -35,7 +35,7 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = { NULL, }; -static const struct cpu_operations * __init cpu_get_ops(const char *name) +const struct cpu_operations * __init cpu_get_ops(const char *name) { const struct cpu_operations **ops = supported_cpu_ops; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 97fa7f31981d..b2783111fd52 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -393,13 +393,16 @@ void __init setup_arch(char **cmdline_p) if (acpi_disabled) { unflatten_device_tree(); psci_dt_init(); + cpu_read_bootcpu_ops(); +#ifdef CONFIG_SMP + of_smp_init_cpus(); +#endif } else { psci_acpi_init(); + acpi_init_cpus(); } - cpu_read_bootcpu_ops(); #ifdef CONFIG_SMP - smp_init_cpus(); smp_build_mpidr_hash(); #endif diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 328b8ce4b007..52998b7a89b5 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -322,7 +322,7 @@ void __init smp_prepare_boot_cpu(void) * cpu logical map array containing MPIDR values related to logical * cpus. Assumes that cpu_logical_map(0) has already been initialized. */ -void __init smp_init_cpus(void) +void __init of_smp_init_cpus(void) { struct device_node *dn = NULL; unsigned int i, cpu = 1; -- cgit v1.2.3 From 828aef376d7a129547bc4ebb949965040177e3da Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 24 Mar 2015 14:02:46 +0000 Subject: ACPI / processor: Introduce phys_cpuid_t for CPU hardware ID CPU hardware ID (phys_id) is defined as u32 in structure acpi_processor, but phys_id is used as int in acpi processor driver, so it will lead to some inconsistence for the drivers. Furthermore, to cater for ACPI arch ports that implement 64 bits CPU ids a generic CPU physical id type is required. So introduce typedef u32 phys_cpuid_t in a common file, and introduce a macro PHYS_CPUID_INVALID as (phys_cpuid_t)(-1) if it's not defined by other archs, this will solve the inconsistence in acpi processor driver, and will prepare for the ACPI on ARM64 for the 64 bit CPU hardware ID in the following patch. CC: Rafael J Wysocki Suggested-by: Lorenzo Pieralisi Reviewed-by: Grant Likely Acked-by: Sudeep Holla Acked-by: Lorenzo Pieralisi Acked-by: Rafael J. Wysocki Signed-off-by: Catalin Marinas [hj: reworked cpu physid map return codes] Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/ia64/kernel/acpi.c | 2 +- arch/x86/kernel/acpi/boot.c | 2 +- drivers/acpi/acpi_processor.c | 7 ++++--- drivers/acpi/processor_core.c | 30 +++++++++++++++--------------- include/acpi/processor.h | 6 +++--- include/linux/acpi.h | 7 ++++++- 6 files changed, 30 insertions(+), 24 deletions(-) (limited to 'arch') diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 2c4498919d3c..067ef4439fa4 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -887,7 +887,7 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) } /* wrapper to silence section mismatch warning */ -int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu) +int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu) { return _acpi_map_lsapic(handle, physid, pcpu); } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 3d525c6124f6..e4f8582eb756 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -757,7 +757,7 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) } /* wrapper to silence section mismatch warning */ -int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu) +int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu) { return _acpi_map_lsapic(handle, physid, pcpu); } diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 1020b1b53a17..58f335ca2e75 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) acpi_status status; int ret; - if (pr->phys_id == -1) + if (pr->phys_id == PHYS_CPUID_INVALID) return -ENODEV; status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); @@ -215,7 +215,8 @@ static int acpi_processor_get_info(struct acpi_device *device) union acpi_object object = { 0 }; struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; struct acpi_processor *pr = acpi_driver_data(device); - int phys_id, cpu_index, device_declaration = 0; + phys_cpuid_t phys_id; + int cpu_index, device_declaration = 0; acpi_status status = AE_OK; static int cpu0_initialized; unsigned long long value; @@ -263,7 +264,7 @@ static int acpi_processor_get_info(struct acpi_device *device) } phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id); - if (phys_id < 0) + if (phys_id == PHYS_CPUID_INVALID) acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n"); pr->phys_id = phys_id; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 7962651cdbd4..51cc29909e08 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -32,7 +32,7 @@ static struct acpi_table_madt *get_madt_table(void) } static int map_lapic_id(struct acpi_subtable_header *entry, - u32 acpi_id, int *apic_id) + u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_apic *lapic = container_of(entry, struct acpi_madt_local_apic, header); @@ -48,7 +48,7 @@ static int map_lapic_id(struct acpi_subtable_header *entry, } static int map_x2apic_id(struct acpi_subtable_header *entry, - int device_declaration, u32 acpi_id, int *apic_id) + int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_x2apic *apic = container_of(entry, struct acpi_madt_local_x2apic, header); @@ -65,7 +65,7 @@ static int map_x2apic_id(struct acpi_subtable_header *entry, } static int map_lsapic_id(struct acpi_subtable_header *entry, - int device_declaration, u32 acpi_id, int *apic_id) + int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_sapic *lsapic = container_of(entry, struct acpi_madt_local_sapic, header); @@ -83,10 +83,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } -static int map_madt_entry(int type, u32 acpi_id) +static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; - int phys_id = -1; /* CPU hardware ID */ + phys_cpuid_t phys_id = PHYS_CPUID_INVALID; /* CPU hardware ID */ struct acpi_table_madt *madt; madt = get_madt_table(); @@ -117,12 +117,12 @@ static int map_madt_entry(int type, u32 acpi_id) return phys_id; } -static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) +static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; struct acpi_subtable_header *header; - int phys_id = -1; + phys_cpuid_t phys_id = PHYS_CPUID_INVALID; if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) goto exit; @@ -149,27 +149,27 @@ exit: return phys_id; } -int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) +phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) { - int phys_id; + phys_cpuid_t phys_id; phys_id = map_mat_entry(handle, type, acpi_id); - if (phys_id == -1) + if (phys_id == PHYS_CPUID_INVALID) phys_id = map_madt_entry(type, acpi_id); return phys_id; } -int acpi_map_cpuid(int phys_id, u32 acpi_id) +int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id) { #ifdef CONFIG_SMP int i; #endif - if (phys_id == -1) { + if (phys_id == PHYS_CPUID_INVALID) { /* * On UP processor, there is no _MAT or MADT table. - * So above phys_id is always set to -1. + * So above phys_id is always set to PHYS_CPUID_INVALID. * * BIOS may define multiple CPU handles even for UP processor. * For example, @@ -190,7 +190,7 @@ int acpi_map_cpuid(int phys_id, u32 acpi_id) if (nr_cpu_ids <= 1 && acpi_id == 0) return acpi_id; else - return phys_id; + return -1; } #ifdef CONFIG_SMP @@ -208,7 +208,7 @@ int acpi_map_cpuid(int phys_id, u32 acpi_id) int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) { - int phys_id; + phys_cpuid_t phys_id; phys_id = acpi_get_phys_id(handle, type, acpi_id); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index b95dc32a6e6b..4188a4d3b597 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -196,7 +196,7 @@ struct acpi_processor_flags { struct acpi_processor { acpi_handle handle; u32 acpi_id; - u32 phys_id; /* CPU hardware ID such as APIC ID for x86 */ + phys_cpuid_t phys_id; /* CPU hardware ID such as APIC ID for x86 */ u32 id; /* CPU logical ID allocated by OS */ u32 pblk; int performance_platform_limit; @@ -310,8 +310,8 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) #endif /* CONFIG_CPU_FREQ */ /* in processor_core.c */ -int acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); -int acpi_map_cpuid(int phys_id, u32 acpi_id); +phys_cpuid_t acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); +int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id); int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); /* in processor_pdc.c */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 24c7aa8b1d20..6ec33c595aea 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -146,9 +146,14 @@ void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); void acpi_numa_arch_fixup(void); +#ifndef PHYS_CPUID_INVALID +typedef u32 phys_cpuid_t; +#define PHYS_CPUID_INVALID (phys_cpuid_t)(-1) +#endif + #ifdef CONFIG_ACPI_HOTPLUG_CPU /* Arch dependent functions for cpu hotplug support */ -int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu); +int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu); int acpi_unmap_cpu(int cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -- cgit v1.2.3 From 020295b4cb5b7d510ea1f4531a502c3f8a2380c5 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:47 +0000 Subject: ACPI / processor: Make it possible to get CPU hardware ID via GICC Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained from the GICC Structure introduced by ACPI 5.1, since MPIDR for ARM64 is 64-bit, so typedef u64 for phys_cpuid_t. The ARM architecture defines the MPIDR register as the CPU hardware identifier. This patch adds the code infrastructure to retrieve the MPIDR values from the ARM ACPI GICC structure in order to look-up the kernel CPU hardware ids required by the ACPI core code to identify CPUs. CC: Rafael J. Wysocki CC: Catalin Marinas CC: Will Deacon Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Lorenzo Pieralisi Acked-by: Rafael J. Wysocki Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 12 ++++++++++++ drivers/acpi/processor_core.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 9719921aedb1..eea0bc3b09d5 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -13,6 +13,8 @@ #define _ASM_ACPI_H #include +#include +#include /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI @@ -27,6 +29,9 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, } #define acpi_os_ioremap acpi_os_ioremap +typedef u64 phys_cpuid_t; +#define PHYS_CPUID_INVALID INVALID_HWID + #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ extern int acpi_disabled; extern int acpi_noirq; @@ -58,6 +63,13 @@ static inline void enable_acpi(void) acpi_noirq = 0; } +/* + * 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 diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 51cc29909e08..b1ec78b8a645 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -83,6 +83,31 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } +/* + * Retrieve the ARM CPU physical identifier (MPIDR) + */ +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; + + /* device_declaration means Device object in DSDT, 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; @@ -111,6 +136,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; } @@ -143,6 +171,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); -- cgit v1.2.3 From fbe61ec71ac975279cd47b6c299d5e33f63aac4e Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:48 +0000 Subject: ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi Introduce ACPI_IRQ_MODEL_GIC which is needed for ARM64 as GIC is used, and then register device's gsi with the core IRQ subsystem. acpi_register_gsi() is similar to DT based irq_of_parse_and_map(), since gsi is unique in the system, so use hwirq number directly for the mapping. We are going to implement stacked domains when GICv2m, GICv3, ITS support are added. CC: Marc Zyngier Originally-by: Amit Daniel Kachhap Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Rafael J. Wysocki Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+) (limited to 'arch') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index c9203c0a1179..dec6f8aed3dc 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -75,6 +75,12 @@ static int __init dt_scan_depth1_nodes(unsigned long node, return 0; } +/* + * Since we're on ARM, the default interrupt routing model + * clearly has to be GIC. + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC; + /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -218,6 +224,73 @@ void __init acpi_init_cpus(void) pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); } +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ + *irq = irq_find_mapping(NULL, gsi); + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +/* + * success: return IRQ number (>0) + * failure: return =< 0 + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{ + unsigned int irq; + unsigned int irq_type; + + /* + * ACPI have no bindings to indicate SPI or PPI, so we + * use different mappings from DT in ACPI. + * + * For FDT + * PPI interrupt: in the range [0, 15]; + * SPI interrupt: in the range [0, 987]; + * + * For ACPI, GSI should be unique so using + * the hwirq directly for the mapping: + * PPI interrupt: in the range [16, 31]; + * SPI interrupt: in the range [32, 1019]; + */ + + if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + irq_type = IRQ_TYPE_EDGE_FALLING; + else if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + irq_type = IRQ_TYPE_EDGE_RISING; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + irq_type = IRQ_TYPE_LEVEL_LOW; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + irq_type = IRQ_TYPE_LEVEL_HIGH; + else + irq_type = IRQ_TYPE_NONE; + + /* + * Since only one GIC is supported in ACPI 5.0, we can + * create mapping refer to the default domain + */ + irq = irq_create_mapping(NULL, gsi); + if (!irq) + return irq; + + /* Set irq type if specified and different than the current one */ + if (irq_type != IRQ_TYPE_NONE && + irq_type != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_type); + return irq; +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); + static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 8b67bd0f6bb5..c412fdb28d34 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -448,6 +448,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_IOSAPIC: message = "IOSAPIC"; break; + case ACPI_IRQ_MODEL_GIC: + message = "GIC"; + break; case ACPI_IRQ_MODEL_PLATFORM: message = "platform specific model"; break; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 6ec33c595aea..de4e86f89c83 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -73,6 +73,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, ACPI_IRQ_MODEL_PLATFORM, + ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_COUNT }; -- cgit v1.2.3 From d60fc3892c4de4a25658786f941690462c5a5bab Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Tue, 24 Mar 2015 14:02:49 +0000 Subject: irqchip: Add GICv2 specific ACPI boot support ACPI kernel uses MADT table for proper GIC initialization. It needs to parse GIC related subtables, collect CPU interface and distributor addresses and call driver initialization function (which is hardware abstraction agnostic). In a similar way, FDT initialize GICv1/2. NOTE: This commit allow to initialize GICv1/2 basic functionality. While now simple GICv2 init call is used, any further GIC features require generic infrastructure for proper ACPI irqchip initialization. That mechanism and stacked irqdomains to support GICv2 MSI/virtualization extension, GICv3/4 and its ITS are considered as next steps. CC: Jason Cooper CC: Marc Zyngier CC: Thomas Gleixner Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Marc Zyngier Acked-by: Jason Cooper Reviewed-by: Grant Likely Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 2 + arch/arm64/include/asm/irq.h | 13 +++++ arch/arm64/kernel/acpi.c | 25 +++++++++ drivers/irqchip/irq-gic.c | 102 +++++++++++++++++++++++++++++++++++ drivers/irqchip/irqchip.c | 3 ++ include/linux/acpi_irq.h | 10 ++++ include/linux/irqchip/arm-gic-acpi.h | 31 +++++++++++ 7 files changed, 186 insertions(+) create mode 100644 include/linux/acpi_irq.h create mode 100644 include/linux/irqchip/arm-gic-acpi.h (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index eea0bc3b09d5..59c05d8ea4a0 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -13,6 +13,8 @@ #define _ASM_ACPI_H #include +#include + #include #include diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 94c53674a31d..bbb251b14746 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -1,6 +1,8 @@ #ifndef __ASM_IRQ_H #define __ASM_IRQ_H +#include + #include struct pt_regs; @@ -8,4 +10,15 @@ struct pt_regs; extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); +static inline void acpi_irq_init(void) +{ + /* + * Hardcode ACPI IRQ chip initialization to GICv2 for now. + * Proper irqchip infrastructure will be implemented along with + * incoming GICv2m|GICv3|ITS bits. + */ + acpi_gic_init(); +} +#define acpi_irq_init acpi_irq_init + #endif diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index dec6f8aed3dc..6468f8898530 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -359,3 +359,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT\n"); } } + +void __init acpi_gic_init(void) +{ + struct acpi_table_header *table; + acpi_status status; + acpi_size tbl_size; + int err; + + if (acpi_disabled) + return; + + status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size); + if (ACPI_FAILURE(status)) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get MADT table, %s\n", msg); + return; + } + + err = gic_v2_acpi_init(table); + if (err) + pr_err("Failed to initialize GIC IRQ controller"); + + early_acpi_os_unmap_memory((char *)table, tbl_size); +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 471e1cdc1933..d15a36a93c52 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -1090,3 +1092,103 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); #endif + +#ifdef CONFIG_ACPI +static phys_addr_t dist_phy_base, cpu_phy_base __initdata; + +static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + phys_addr_t gic_cpu_base; + static int cpu_base_assigned; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + /* + * There is no support for non-banked GICv1/2 register in ACPI spec. + * All CPU interface addresses have to be the same. + */ + gic_cpu_base = processor->base_address; + if (cpu_base_assigned && gic_cpu_base != cpu_phy_base) + return -EINVAL; + + cpu_phy_base = gic_cpu_base; + cpu_base_assigned = 1; + return 0; +} + +static int __init +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_distributor *dist; + + dist = (struct acpi_madt_generic_distributor *)header; + + if (BAD_MADT_ENTRY(dist, end)) + return -EINVAL; + + dist_phy_base = dist->base_address; + return 0; +} + +int __init +gic_v2_acpi_init(struct acpi_table_header *table) +{ + void __iomem *cpu_base, *dist_base; + int count; + + /* Collect CPU base addresses */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_cpu, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + if (count <= 0) { + pr_err("No valid GICC entries exist\n"); + return -EINVAL; + } + + /* + * Find distributor base address. We expect one distributor entry since + * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade. + */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_distributor, table, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0); + if (count <= 0) { + pr_err("No valid GICD entries exist\n"); + return -EINVAL; + } else if (count > 1) { + pr_err("More than one GICD entry detected\n"); + return -EINVAL; + } + + cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); + if (!cpu_base) { + pr_err("Unable to map GICC registers\n"); + return -ENOMEM; + } + + dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE); + if (!dist_base) { + pr_err("Unable to map GICD registers\n"); + iounmap(cpu_base); + return -ENOMEM; + } + + /* + * Initialize zero GIC instance (no multi-GIC support). Also, set GIC + * as default IRQ domain to allow for GSI registration and GSI to IRQ + * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). + */ + gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); + irq_set_default_host(gic_data[0].domain); + return 0; +} +#endif diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 0fe2f718d81c..afd1af3dfe5a 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -8,6 +8,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[]; void __init irqchip_init(void) { of_irq_init(__irqchip_of_table); + + acpi_irq_init(); } diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h new file mode 100644 index 000000000000..f10c87265855 --- /dev/null +++ b/include/linux/acpi_irq.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_ACPI_IRQ_H +#define _LINUX_ACPI_IRQ_H + +#include + +#ifndef acpi_irq_init +static inline void acpi_irq_init(void) { } +#endif + +#endif /* _LINUX_ACPI_IRQ_H */ diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 000000000000..de3419ed3937 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, Linaro Ltd. + * Author: Tomasz Nowicki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ARM_GIC_ACPI_H_ +#define ARM_GIC_ACPI_H_ + +#ifdef CONFIG_ACPI + +/* + * Hard code here, we can not get memory size from MADT (but FDT does), + * Actually no need to do that, because this size can be inferred + * from GIC spec. + */ +#define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K) +#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) + +struct acpi_table_header; + +int gic_v2_acpi_init(struct acpi_table_header *table); +void acpi_gic_init(void); +#else +static inline void acpi_gic_init(void) { } +#endif + +#endif /* ARM_GIC_ACPI_H_ */ -- cgit v1.2.3 From b09ca1ecf6d499d5a33f978c905d2fbcc79b55d9 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:50 +0000 Subject: clocksource / arch_timer: Parse GTDT to initialize arch timer Using the information presented by GTDT (Generic Timer Description Table) to initialize the arch timer (not memory-mapped). CC: Daniel Lezcano CC: Thomas Gleixner Originally-by: Amit Daniel Kachhap Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Daniel Lezcano Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/time.c | 7 ++ drivers/clocksource/arm_arch_timer.c | 132 ++++++++++++++++++++++++++++------- include/linux/clocksource.h | 6 ++ 3 files changed, 118 insertions(+), 27 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 1a7125c3099b..42f9195cf2f8 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -72,6 +73,12 @@ void __init time_init(void) tick_setup_hrtimer_broadcast(); + /* + * Since ACPI or FDT will only one be available in the system, + * we can use acpi_generic_timer_init() here safely + */ + acpi_generic_timer_init(); + arch_timer_rate = arch_timer_get_rate(); if (!arch_timer_rate) panic("Unable to initialise architected timer.\n"); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a3025e7ae35f..ea62fc79e1e8 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -371,8 +372,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) if (arch_timer_rate) return; - /* Try to determine the frequency from the device tree or CNTFRQ */ - if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { + /* + * Try to determine the frequency from the device tree or CNTFRQ, + * if ACPI is enabled, get the frequency from CNTFRQ ONLY. + */ + if (!acpi_disabled || + of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { if (cntbase) arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); else @@ -691,28 +696,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np) +static void __init arch_timer_init(void) { - int i; - - if (arch_timers_present & ARCH_CP15_TIMER) { - pr_warn("arch_timer: multiple nodes in dt, skipping\n"); - return; - } - - arch_timers_present |= ARCH_CP15_TIMER; - for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) - arch_timer_ppi[i] = irq_of_parse_and_map(np, i); - arch_timer_detect_rate(NULL, np); - - /* - * If we cannot rely on firmware initializing the timer registers then - * we should use the physical timers instead. - */ - if (IS_ENABLED(CONFIG_ARM) && - of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) - arch_timer_use_virtual = false; - /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -731,13 +716,39 @@ static void __init arch_timer_init(struct device_node *np) } } - arch_timer_c3stop = !of_property_read_bool(np, "always-on"); - arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); + +static void __init arch_timer_of_init(struct device_node *np) +{ + int i; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; + } + + arch_timers_present |= ARCH_CP15_TIMER; + for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) + arch_timer_ppi[i] = irq_of_parse_and_map(np, i); + + arch_timer_detect_rate(NULL, np); + + arch_timer_c3stop = !of_property_read_bool(np, "always-on"); + + /* + * If we cannot rely on firmware initializing the timer registers then + * we should use the physical timers instead. + */ + if (IS_ENABLED(CONFIG_ARM) && + of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) + arch_timer_use_virtual = false; + + arch_timer_init(); +} +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); static void __init arch_timer_mem_init(struct device_node *np) { @@ -804,3 +815,70 @@ static void __init arch_timer_mem_init(struct device_node *np) } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); + +#ifdef CONFIG_ACPI +static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags) +{ + int trigger, polarity; + + if (!interrupt) + return 0; + + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE + : ACPI_LEVEL_SENSITIVE; + + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW + : ACPI_ACTIVE_HIGH; + + return acpi_register_gsi(NULL, interrupt, trigger, polarity); +} + +/* Initialize per-processor generic timer */ +static int __init arch_timer_acpi_init(struct acpi_table_header *table) +{ + struct acpi_table_gtdt *gtdt; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: already initialized, skipping\n"); + return -EINVAL; + } + + gtdt = container_of(table, struct acpi_table_gtdt, header); + + arch_timers_present |= ARCH_CP15_TIMER; + + arch_timer_ppi[PHYS_SECURE_PPI] = + map_generic_timer_interrupt(gtdt->secure_el1_interrupt, + gtdt->secure_el1_flags); + + arch_timer_ppi[PHYS_NONSECURE_PPI] = + map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, + gtdt->non_secure_el1_flags); + + arch_timer_ppi[VIRT_PPI] = + map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, + gtdt->virtual_timer_flags); + + arch_timer_ppi[HYP_PPI] = + map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, + gtdt->non_secure_el2_flags); + + /* Get the frequency from CNTFRQ */ + arch_timer_detect_rate(NULL, NULL); + + /* Always-on capability */ + arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); + + arch_timer_init(); + return 0; +} + +/* Initialize all the generic timers presented in GTDT */ +void __init acpi_generic_timer_init(void) +{ + if (acpi_disabled) + return; + + acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init); +} +#endif diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 9c78d15d33e4..2b2e1f80c519 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -244,4 +244,10 @@ extern void clocksource_of_init(void); static inline void clocksource_of_init(void) {} #endif +#ifdef CONFIG_ACPI +void acpi_generic_timer_init(void); +#else +static inline void acpi_generic_timer_init(void) { } +#endif + #endif /* _LINUX_CLOCKSOURCE_H */ -- cgit v1.2.3 From 6933de0ca0b7656db94f67731c8c53c7dcacae3a Mon Sep 17 00:00:00 2001 From: Al Stone Date: Tue, 24 Mar 2015 14:02:51 +0000 Subject: ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64 ACPI reduced hardware mode is disabled by default, but ARM64 can only run properly in ACPI hardware reduced mode, so select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64. If the firmware is not using hardware reduced ACPI mode, we will disable ACPI to avoid nightmare such as accessing some registers which are not available on ARM64. CC: Catalin Marinas CC: Will Deacon Reviewed-by: Grant Likely Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Signed-off-by: Al Stone Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 1 + arch/arm64/kernel/acpi.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1b8e97331ffb..d00ab9a71d59 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1,5 +1,6 @@ config ARM64 def_bool y + select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ARCH_BINFMT_ELF_RANDOMIZE_PIE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_GCOV_PROFILE_ALL diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 6468f8898530..5819ef7aa2c3 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -303,6 +303,11 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) */ if (table->revision > 5 || (table->revision == 5 && fadt->minor_revision >= 1)) { + if (!acpi_gbl_reduced_hardware) { + pr_err("Not hardware reduced ACPI mode, will not be supported\n"); + goto disable_acpi; + } + /* * ACPI 5.1 only has two explicit methods to boot up SMP, * PSCI and Parking protocol, but the Parking protocol is @@ -319,8 +324,9 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", table->revision, fadt->minor_revision); - disable_acpi(); +disable_acpi: + disable_acpi(); return -EINVAL; } -- cgit v1.2.3 From b6a0217371317298c900f0e0f84afb04312d5af0 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 24 Mar 2015 14:02:53 +0000 Subject: ARM64 / ACPI: Enable ARM64 in Kconfig Add Kconfigs to build ACPI on ARM64, and make ACPI available on ARM64. acpi_idle driver is x86/IA64 dependent now, so make CONFIG_ACPI_PROCESSOR depend on X86 || IA64, and implement it on ARM64 in the future. CC: Rafael J. Wysocki CC: Catalin Marinas CC: Will Deacon Reviewed-by: Grant Likely Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Rafael J. Wysocki Signed-off-by: Graeme Gregory Signed-off-by: Al Stone Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 2 ++ drivers/acpi/Kconfig | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d00ab9a71d59..e5aa081b4845 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -713,6 +713,8 @@ source "drivers/Kconfig" source "drivers/firmware/Kconfig" +source "drivers/acpi/Kconfig" + source "fs/Kconfig" source "arch/arm64/kvm/Kconfig" diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a726381fea72..a8f531e2b97c 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -5,7 +5,7 @@ menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on !IA64_HP_SIM - depends on IA64 || X86 + depends on IA64 || X86 || (ARM64 && EXPERT) depends on PCI select PNP default y @@ -167,6 +167,7 @@ config ACPI_PROCESSOR tristate "Processor" select THERMAL select CPU_IDLE + depends on X86 || IA64 default y help This driver installs ACPI as the idle handler for Linux and uses -- cgit v1.2.3 From 33757ded074918eb49243968a82e7c9ec2d71720 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:56 +0000 Subject: ARM64 / ACPI: Don't unflatten device tree if acpi=force is passed Since the policy is that once we pass acpi=force in the early param, we will not unflatten device tree even if ACPI is disabled in ACPI table init fails, so fix the code by comparinging both acpi_disabled and param_acpi_force before the device tree is unflattened. CC: Ard Biesheuvel Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 3 +++ arch/arm64/kernel/acpi.c | 2 +- arch/arm64/kernel/setup.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 59c05d8ea4a0..e1a89656f17e 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -38,6 +38,7 @@ typedef u64 phys_cpuid_t; extern int acpi_disabled; extern int acpi_noirq; extern int acpi_pci_disabled; +extern bool param_acpi_force; /* 1 to indicate PSCI 0.2+ is implemented */ static inline bool acpi_psci_present(void) @@ -91,6 +92,8 @@ void __init acpi_init_cpus(void); static inline bool acpi_psci_present(void) { return false; } static inline bool acpi_psci_use_hvc(void) { return false; } static inline void acpi_init_cpus(void) { } + +#define param_acpi_force false #endif /* CONFIG_ACPI */ #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 5819ef7aa2c3..fe9d8f0df4a3 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -43,7 +43,7 @@ static int enabled_cpus; static bool bootcpu_valid __initdata; static bool param_acpi_off __initdata; -static bool param_acpi_force __initdata; +bool param_acpi_force __initdata; static int __init parse_acpi(char *arg) { diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index b2783111fd52..d60b1adc7500 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -390,7 +390,7 @@ void __init setup_arch(char **cmdline_p) early_ioremap_reset(); - if (acpi_disabled) { + if (acpi_disabled && !param_acpi_force) { unflatten_device_tree(); psci_dt_init(); cpu_read_bootcpu_ops(); -- cgit v1.2.3 From d8f4f161e31f3ee9768467344e6cc31a0b9d9249 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 24 Mar 2015 17:58:51 +0000 Subject: ACPI: move arm64 GSI IRQ model to generic GSI IRQ layer The code deployed to implement GSI linux IRQ numbers mapping on arm64 turns out to be generic enough so that it can be moved to ACPI core code along with its respective config option ACPI_GENERIC_GSI selectable on architectures that can reuse the same code. Current ACPI IRQ mapping code is not integrated in the kernel IRQ domain infrastructure, in particular there is no way to look-up the IRQ domain associated with a particular interrupt controller, so this first version of GSI generic code carries out the GSI<->IRQ mapping relying on the IRQ default domain which is supposed to be always set on a specific architecture in case the domain structure passed to irq_create/find_mapping() functions is missing. This patch moves the arm64 acpi functions that implement the gsi mappings: acpi_gsi_to_irq() acpi_register_gsi() acpi_unregister_gsi() to ACPI core code. Since the generic GSI<->domain mapping is based on IRQ domains, it can be extended as soon as a way to map an interrupt controller to an IRQ domain is implemented for ACPI in the IRQ domain layer. x86 and ia64 code for GSI mappings cannot rely on the generic GSI layer at present for legacy reasons, so they do not select the ACPI_GENERIC_GSI config options and keep relying on their arch specific GSI mapping layer. Cc: Jiang Liu Cc: Catalin Marinas Cc: Rafael J. Wysocki Acked-by: Hanjun Guo Acked-by: Will Deacon Acked-by: Marc Zyngier Signed-off-by: Lorenzo Pieralisi Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 1 + arch/arm64/kernel/acpi.c | 73 -------------------------------- drivers/acpi/Kconfig | 3 ++ drivers/acpi/Makefile | 1 + drivers/acpi/gsi.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 2 + 6 files changed, 112 insertions(+), 73 deletions(-) create mode 100644 drivers/acpi/gsi.c (limited to 'arch') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e5aa081b4845..0659db374731 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1,5 +1,6 @@ config ARM64 def_bool y + select ACPI_GENERIC_GSI if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ARCH_BINFMT_ELF_RANDOMIZE_PIE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index fe9d8f0df4a3..a70f7141c0f6 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -75,12 +75,6 @@ static int __init dt_scan_depth1_nodes(unsigned long node, return 0; } -/* - * Since we're on ARM, the default interrupt routing model - * clearly has to be GIC. - */ -enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC; - /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -224,73 +218,6 @@ void __init acpi_init_cpus(void) pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); } -int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) -{ - *irq = irq_find_mapping(NULL, gsi); - - return 0; -} -EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); - -/* - * success: return IRQ number (>0) - * failure: return =< 0 - */ -int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) -{ - unsigned int irq; - unsigned int irq_type; - - /* - * ACPI have no bindings to indicate SPI or PPI, so we - * use different mappings from DT in ACPI. - * - * For FDT - * PPI interrupt: in the range [0, 15]; - * SPI interrupt: in the range [0, 987]; - * - * For ACPI, GSI should be unique so using - * the hwirq directly for the mapping: - * PPI interrupt: in the range [16, 31]; - * SPI interrupt: in the range [32, 1019]; - */ - - if (trigger == ACPI_EDGE_SENSITIVE && - polarity == ACPI_ACTIVE_LOW) - irq_type = IRQ_TYPE_EDGE_FALLING; - else if (trigger == ACPI_EDGE_SENSITIVE && - polarity == ACPI_ACTIVE_HIGH) - irq_type = IRQ_TYPE_EDGE_RISING; - else if (trigger == ACPI_LEVEL_SENSITIVE && - polarity == ACPI_ACTIVE_LOW) - irq_type = IRQ_TYPE_LEVEL_LOW; - else if (trigger == ACPI_LEVEL_SENSITIVE && - polarity == ACPI_ACTIVE_HIGH) - irq_type = IRQ_TYPE_LEVEL_HIGH; - else - irq_type = IRQ_TYPE_NONE; - - /* - * Since only one GIC is supported in ACPI 5.0, we can - * create mapping refer to the default domain - */ - irq = irq_create_mapping(NULL, gsi); - if (!irq) - return irq; - - /* Set irq type if specified and different than the current one */ - if (irq_type != IRQ_TYPE_NONE && - irq_type != irq_get_trigger_type(irq)) - irq_set_irq_type(irq, irq_type); - return irq; -} -EXPORT_SYMBOL_GPL(acpi_register_gsi); - -void acpi_unregister_gsi(u32 gsi) -{ -} -EXPORT_SYMBOL_GPL(acpi_unregister_gsi); - static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a8f531e2b97c..ab2cbb51c6aa 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -48,6 +48,9 @@ config ACPI_LEGACY_TABLES_LOOKUP config ARCH_MIGHT_HAVE_ACPI_PDC bool +config ACPI_GENERIC_GSI + bool + config ACPI_SYSTEM_POWER_STATES_SUPPORT bool diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index db153c6a75d7..8a063e276530 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -56,6 +56,7 @@ ifdef CONFIG_ACPI_VIDEO acpi-y += video_detect.o endif acpi-y += acpi_lpat.o +acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o # These are (potentially) separate modules diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c new file mode 100644 index 000000000000..38208f2d0e69 --- /dev/null +++ b/drivers/acpi/gsi.c @@ -0,0 +1,105 @@ +/* + * ACPI GSI IRQ layer + * + * Copyright (C) 2015 ARM Ltd. + * Author: Lorenzo Pieralisi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +enum acpi_irq_model_id acpi_irq_model; + +static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) +{ + switch (polarity) { + case ACPI_ACTIVE_LOW: + return trigger == ACPI_EDGE_SENSITIVE ? + IRQ_TYPE_EDGE_FALLING : + IRQ_TYPE_LEVEL_LOW; + case ACPI_ACTIVE_HIGH: + return trigger == ACPI_EDGE_SENSITIVE ? + IRQ_TYPE_EDGE_RISING : + IRQ_TYPE_LEVEL_HIGH; + case ACPI_ACTIVE_BOTH: + if (trigger == ACPI_EDGE_SENSITIVE) + return IRQ_TYPE_EDGE_BOTH; + default: + return IRQ_TYPE_NONE; + } +} + +/** + * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI + * @gsi: GSI IRQ number to map + * @irq: pointer where linux IRQ number is stored + * + * irq location updated with irq value [>0 on success, 0 on failure] + * + * Returns: linux IRQ number on success (>0) + * -EINVAL on failure + */ +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ + /* + * Only default domain is supported at present, always find + * the mapping corresponding to default domain by passing NULL + * as irq_domain parameter + */ + *irq = irq_find_mapping(NULL, gsi); + /* + * *irq == 0 means no mapping, that should + * be reported as a failure + */ + return (*irq > 0) ? *irq : -EINVAL; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +/** + * acpi_register_gsi() - Map a GSI to a linux IRQ number + * @dev: device for which IRQ has to be mapped + * @gsi: GSI IRQ number + * @trigger: trigger type of the GSI number to be mapped + * @polarity: polarity of the GSI to be mapped + * + * Returns: a valid linux IRQ number on success + * -EINVAL on failure + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) +{ + unsigned int irq; + unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity); + + /* + * There is no way at present to look-up the IRQ domain on ACPI, + * hence always create mapping referring to the default domain + * by passing NULL as irq_domain parameter + */ + irq = irq_create_mapping(NULL, gsi); + if (!irq) + return -EINVAL; + + /* Set irq type if specified and different than the current one */ + if (irq_type != IRQ_TYPE_NONE && + irq_type != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_type); + return irq; +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +/** + * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping + * @gsi: GSI IRQ number + */ +void acpi_unregister_gsi(u32 gsi) +{ + int irq = irq_find_mapping(NULL, gsi); + + irq_dispose_mapping(irq); +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index d15a36a93c52..f1efb53faebc 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1189,6 +1189,8 @@ gic_v2_acpi_init(struct acpi_table_header *table) */ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); irq_set_default_host(gic_data[0].domain); + + acpi_irq_model = ACPI_IRQ_MODEL_GIC; return 0; } #endif -- cgit v1.2.3 From 48eb3c8a8b4fffb48f64019e1f68a7de4db4cc43 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 24 Mar 2015 17:58:52 +0000 Subject: ARM64: kernel: psci: factor out probe function PSCI v0.2+ versions provide a specific PSCI call (PSCI_VERSION) to detect the PSCI version at run-time. Current PSCI v0.2 init code carries out the version probing in the PSCI 0.2 DT init function, but the version probing does not depend on DT so it can be factored out in order to make it available to other boot mechanisms (ie ACPI) to reuse. The psci_probe() probing function can be easily extended to add detection and initialization of PSCI functions defined in PSCI versions >0.2. Cc: Sudeep Holla Cc: Mark Rutland Reviewed-by: Hanjun Guo Signed-off-by: Lorenzo Pieralisi Signed-off-by: Will Deacon --- arch/arm64/kernel/psci.c | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index d3c52ce5faf3..2caac4498154 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -303,25 +303,19 @@ static void __init psci_0_2_set_functions(void) } /* - * PSCI Function IDs for v0.2+ are well defined so use - * standard values. + * Probe function for PSCI firmware versions >= 0.2 */ -static int __init psci_0_2_init(struct device_node *np) +static int __init psci_probe(void) { - int err, ver; - - err = get_set_conduit_method(np); - - if (err) - goto out_put_node; - - ver = psci_get_version(); + int ver = psci_get_version(); if (ver == PSCI_RET_NOT_SUPPORTED) { - /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ + /* + * PSCI versions >=0.2 mandates implementation of + * PSCI_VERSION. + */ pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); - err = -EOPNOTSUPP; - goto out_put_node; + return -EOPNOTSUPP; } else { pr_info("PSCIv%d.%d detected in firmware.\n", PSCI_VERSION_MAJOR(ver), @@ -329,14 +323,38 @@ static int __init psci_0_2_init(struct device_node *np) if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { - err = -EINVAL; pr_err("Conflicting PSCI version detected.\n"); - goto out_put_node; + return -EINVAL; } } psci_0_2_set_functions(); + return 0; +} + +/* + * PSCI init function for PSCI versions >=0.2 + * + * Probe based on PSCI PSCI_VERSION function + */ +static int __init psci_0_2_init(struct device_node *np) +{ + int err; + + err = get_set_conduit_method(np); + + if (err) + goto out_put_node; + /* + * Starting with v0.2, the PSCI specification introduced a call + * (PSCI_VERSION) that allows probing the firmware version, so + * that PSCI function IDs and version specific initialization + * can be carried out according to the specific version reported + * by firmware + */ + err = psci_probe(); + out_put_node: of_node_put(np); return err; -- cgit v1.2.3 From d9895571877e965a9f3e18a2a30611322099ae30 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 24 Mar 2015 17:58:53 +0000 Subject: ARM64: kernel: psci: let ACPI probe PSCI version PSCI v0.2+ allows the kernel to probe the PSCI firmware version. This patch replaces the default initialization of PSCI v0.2+ functions with code that allows probing PSCI firmware version and initializes PSCI functions accordingly. Cc: Sudeep Holla Cc: Mark Rutland Reviewed-by: Hanjun Guo Signed-off-by: Lorenzo Pieralisi Signed-off-by: Will Deacon --- arch/arm64/kernel/psci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 2caac4498154..ea18cb53921e 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -439,9 +439,7 @@ int __init psci_acpi_init(void) else invoke_psci_fn = __invoke_psci_fn_smc; - psci_0_2_set_functions(); - - return 0; + return psci_probe(); } #ifdef CONFIG_SMP -- cgit v1.2.3 From 54971e43b9d6cb37366d2da64cc5a2d8f8102bc4 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 25 Mar 2015 15:13:56 +0000 Subject: ARM64: kernel: acpi: refactor ACPI tables init and checks Current ACPI init code on ARM64 relies on acpi_table_parse() API to check if the FADT is present and to carry out sanity checks on that. The handler passed to the acpi_table_parse() function and used to carry out the parsing on the requested table returns a value that is ignored by the acpi_table_parse() function, so it is not possible to propagate errors back to the acpi_table_parse() caller through the handler. This forces ARM64 ACPI init code to have disable_acpi() calls scattered all over the place that makes code unwieldy and not easy to follow. This patch refactors the ARM64 ACPI init code, by creating a self-contained function (ie acpi_fadt_sanity_check()) that carries out the required checks on FADT and returns an adequate return value to the caller. This allows creating a common error path that disables ACPI and makes code more readable and easy to parse and change were further checks FADT to be added in the future. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Hanjun Guo Cc: Will Deacon Cc: Hanjun Guo Cc: Catalin Marinas Cc: Rafael J. Wysocki Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 95 ++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index a70f7141c0f6..172b7c9f6881 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -218,43 +218,60 @@ void __init acpi_init_cpus(void) pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); } -static int __init acpi_parse_fadt(struct acpi_table_header *table) +/* + * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity + * checks on it + * + * Return 0 on success, <0 on failure + */ +static int __init acpi_fadt_sanity_check(void) { - struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; + struct acpi_table_header *table; + struct acpi_table_fadt *fadt; + acpi_status status; + acpi_size tbl_size; + int ret = 0; + + /* + * FADT is required on arm64; retrieve it to check its presence + * and carry out revision and ACPI HW reduced compliancy tests + */ + status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size); + if (ACPI_FAILURE(status)) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get FADT table, %s\n", msg); + return -ENODEV; + } + + fadt = (struct acpi_table_fadt *)table; /* * Revision in table header is the FADT Major revision, and there * is a minor revision of FADT which was introduced by ACPI 5.1, * we only deal with ACPI 5.1 or newer revision to get GIC and SMP - * boot protocol configuration data, or we will disable ACPI. + * boot protocol configuration data. */ - if (table->revision > 5 || - (table->revision == 5 && fadt->minor_revision >= 1)) { - if (!acpi_gbl_reduced_hardware) { - pr_err("Not hardware reduced ACPI mode, will not be supported\n"); - goto disable_acpi; - } - - /* - * ACPI 5.1 only has two explicit methods to boot up SMP, - * PSCI and Parking protocol, but the Parking protocol is - * only specified for ARMv7 now, so make PSCI as the only - * way for the SMP boot protocol before some updates for - * the Parking protocol spec. - */ - if (acpi_psci_present()) - return 0; - - pr_warn("No PSCI support, will not bring up secondary CPUs\n"); - return -EOPNOTSUPP; + if (table->revision < 5 || + (table->revision == 5 && fadt->minor_revision < 1)) { + pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n", + table->revision, fadt->minor_revision); + ret = -EINVAL; + goto out; } - pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", - table->revision, fadt->minor_revision); + if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { + pr_err("FADT not ACPI hardware reduced compliant\n"); + ret = -EINVAL; + } -disable_acpi: - disable_acpi(); - return -EINVAL; +out: + /* + * acpi_get_table_with_size() creates FADT table mapping that + * should be released after parsing and before resuming boot + */ + early_acpi_os_unmap_memory(table, tbl_size); + return ret; } /* @@ -262,9 +279,13 @@ disable_acpi: * 1. find RSDP and get its address, and then find XSDT * 2. extract all tables and checksums them all * 3. check ACPI FADT revision + * 4. check ACPI FADT HW reduced flag * * We can parse ACPI boot-time tables such as MADT after * this function is called. + * + * ACPI is enabled on return if ACPI tables initialized and sanity checks + * passed, disabled otherwise */ void __init acpi_boot_table_init(void) { @@ -278,18 +299,20 @@ void __init acpi_boot_table_init(void) (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) return; + /* + * ACPI is disabled at this point. Enable it in order to parse + * the ACPI tables and carry out sanity checks + */ enable_acpi(); - /* Initialize the ACPI boot-time table parser. */ - if (acpi_table_init()) { - disable_acpi(); - return; - } - - if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) { - /* disable ACPI if no FADT is found */ + /* + * If ACPI tables are initialized and FADT sanity checks passed, + * leave ACPI enabled and carry on booting; otherwise disable ACPI + * on initialization error. + */ + if (acpi_table_init() || acpi_fadt_sanity_check()) { + pr_err("Failed to init ACPI tables\n"); disable_acpi(); - pr_err("Can't find FADT\n"); } } -- cgit v1.2.3 From fb094eb19900937322848beaf1a622c6afb6250b Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 25 Mar 2015 15:22:13 +0000 Subject: ARM64: kernel: acpi: honour acpi=force command line parameter If acpi=force is passed on the command line, it forces ACPI to be the only available boot method, hence it must be left enabled even if the initialization and sanity checks on ACPI tables fails. This patch refactors ACPI initialization to prevent disabling ACPI if acpi=force is passed on the command line. Signed-off-by: Lorenzo Pieralisi Acked-by: Ard Biesheuvel Acked-by: Hanjun Guo Cc: Ard Biesheuvel Cc: Hanjun Guo Cc: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 3 --- arch/arm64/kernel/acpi.c | 16 ++++++++++++---- arch/arm64/kernel/setup.c | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e1a89656f17e..59c05d8ea4a0 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -38,7 +38,6 @@ typedef u64 phys_cpuid_t; extern int acpi_disabled; extern int acpi_noirq; extern int acpi_pci_disabled; -extern bool param_acpi_force; /* 1 to indicate PSCI 0.2+ is implemented */ static inline bool acpi_psci_present(void) @@ -92,8 +91,6 @@ void __init acpi_init_cpus(void); static inline bool acpi_psci_present(void) { return false; } static inline bool acpi_psci_use_hvc(void) { return false; } static inline void acpi_init_cpus(void) { } - -#define param_acpi_force false #endif /* CONFIG_ACPI */ #endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 172b7c9f6881..cd60329da8c4 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -43,7 +43,7 @@ static int enabled_cpus; static bool bootcpu_valid __initdata; static bool param_acpi_off __initdata; -bool param_acpi_force __initdata; +static bool param_acpi_force __initdata; static int __init parse_acpi(char *arg) { @@ -284,8 +284,13 @@ out: * We can parse ACPI boot-time tables such as MADT after * this function is called. * - * ACPI is enabled on return if ACPI tables initialized and sanity checks - * passed, disabled otherwise + * On return ACPI is enabled if either: + * + * - ACPI tables are initialized and sanity checks passed + * - acpi=force was passed in the command line and ACPI was not disabled + * explicitly through acpi=off command line parameter + * + * ACPI is disabled on function return otherwise */ void __init acpi_boot_table_init(void) { @@ -309,10 +314,13 @@ void __init acpi_boot_table_init(void) * If ACPI tables are initialized and FADT sanity checks passed, * leave ACPI enabled and carry on booting; otherwise disable ACPI * on initialization error. + * If acpi=force was passed on the command line it forces ACPI + * to be enabled even if its initialization failed. */ if (acpi_table_init() || acpi_fadt_sanity_check()) { pr_err("Failed to init ACPI tables\n"); - disable_acpi(); + if (!param_acpi_force) + disable_acpi(); } } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index d60b1adc7500..b2783111fd52 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -390,7 +390,7 @@ void __init setup_arch(char **cmdline_p) early_ioremap_reset(); - if (acpi_disabled && !param_acpi_force) { + if (acpi_disabled) { unflatten_device_tree(); psci_dt_init(); cpu_read_bootcpu_ops(); -- cgit v1.2.3 From 8ef320319592693f4a6286d80df210fd47b3e356 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 26 Mar 2015 15:09:20 +0000 Subject: ARM64 / ACPI: fix usage of acpi_map_gic_cpu_interface acpi_parse_gic_cpu_interface calls acpi_map_gic_cpu_interface by both passing a 32-bit value in the u8 enabled parameter and then subsequently ignoring its return value. Sort it out. Reported-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index cd60329da8c4..07649e413244 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -103,9 +103,12 @@ void __init __acpi_unmap_table(char *map, unsigned long size) * * Returns the logical cpu number which maps to MPIDR */ -static int __init acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +static int __init +acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) { int i; + u64 mpidr = processor->arm_mpidr & MPIDR_HWID_BITMASK; + bool enabled = !!(processor->flags & ACPI_MADT_ENABLED); if (mpidr == INVALID_HWID) { pr_info("Skip MADT cpu entry with invalid MPIDR\n"); @@ -178,11 +181,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, return -EINVAL; acpi_table_print_madt_entry(header); - - acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK, - processor->flags & ACPI_MADT_ENABLED); - - return 0; + return acpi_map_gic_cpu_interface(processor); } /* Parse GIC cpu interface entries in MADT for SMP init */ -- cgit v1.2.3 From ec81ad4eca9736bb73d4458fb7d8a5ccaf3e908e Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 27 Mar 2015 12:14:35 +0000 Subject: ARM64 / ACPI: Ignore the return error value of acpi_map_gic_cpu_interface() MADT scanning will stop when it gets an error from the handler, acpi_map_gic_cpu_interface(), on arm64. However, we need to find all of the enabled CPUs so that SMP initialization can work properly. So, if an error occurs in this case, ignore it for now so that we can find all of the enabled CPUs. Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 07649e413244..c263cbaa6484 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -181,7 +181,8 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, return -EINVAL; acpi_table_print_madt_entry(header); - return acpi_map_gic_cpu_interface(processor); + acpi_map_gic_cpu_interface(processor); + return 0; } /* Parse GIC cpu interface entries in MADT for SMP init */ -- cgit v1.2.3 From 7676fa70feb2f3bcdd4b854a553a57d8ef8505aa Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 27 Mar 2015 12:14:36 +0000 Subject: ARM64 / ACPI: make acpi_map_gic_cpu_interface() as void function Since the only caller of acpi_parse_gic_cpu_interface() doesn't need the return value, make it have a void return type to avoid introducing subtle bugs, and update the comments of the function accordingly. Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index c263cbaa6484..8b839558838e 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -98,12 +98,8 @@ void __init __acpi_unmap_table(char *map, unsigned long size) /** * acpi_map_gic_cpu_interface - generates a logical cpu number * and map to MPIDR represented by GICC structure - * @mpidr: CPU's hardware id to register, MPIDR represented in MADT - * @enabled: this cpu is enabled or not - * - * Returns the logical cpu number which maps to MPIDR */ -static int __init +static void __init acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) { int i; @@ -112,17 +108,17 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) if (mpidr == INVALID_HWID) { pr_info("Skip MADT cpu entry with invalid MPIDR\n"); - return -EINVAL; + return; } total_cpus++; if (!enabled) - return -EINVAL; + return; if (enabled_cpus >= NR_CPUS) { pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n", NR_CPUS, total_cpus, mpidr); - return -EINVAL; + return; } /* Check if GICC structure of boot CPU is available in the MADT */ @@ -130,7 +126,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) if (bootcpu_valid) { pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", mpidr); - return -EINVAL; + return; } bootcpu_valid = true; @@ -145,28 +141,27 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) if (cpu_logical_map(i) == mpidr) { pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", mpidr); - return -EINVAL; + return; } } if (!acpi_psci_present()) - return -EOPNOTSUPP; + return; cpu_ops[enabled_cpus] = cpu_get_ops("psci"); /* CPU 0 was already initialized */ if (enabled_cpus) { if (!cpu_ops[enabled_cpus]) - return -EINVAL; + return; if (cpu_ops[enabled_cpus]->cpu_init(NULL, enabled_cpus)) - return -EOPNOTSUPP; + return; /* map the logical cpu id to cpu MPIDR */ cpu_logical_map(enabled_cpus) = mpidr; } enabled_cpus++; - return enabled_cpus; } static int __init -- cgit v1.2.3