ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms: 1) MADT table updates. 2) FADT updates for PSCI 3) GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2: - Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz - make ACPI depend on EXPERT - Address lots of comments from Catalin, Sudeep, Geoff - Add Juno device ACPI driver patches for review
Updates since v1: - Set ACPI default off on ARM64 suggested by Olof; - Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support. - Update the document as suggested; - Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
[1]: http://www.uefi.org/sites/default/files/resources/ACPI_5_1release.pdf
Al Stone (3): ARM64 / ACPI: Get RSDP and ACPI boot-time tables ARM64 / ACPI: Introduce early_param for "acpi" ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64
Ashwin Chaugule (1): ACPI / table: Add new function to get table entries
Graeme Gregory (4): ARM64 / ACPI: Introduce lowlevel suspend function ARM64 / ACPI: If we chose to boot from acpi then disable FDT ARM64 / ACPI: Enable ARM64 in Kconfig Documentation: ACPI for ARM64
Hanjun Guo (8): ARM64: Move the init of cpu_logical_map(0) before unflatten_device_tree() ARM64 / ACPI: Make PCI optional for ACPI on ARM64 ARM64 / ACPI: Parse FADT table to get PSCI flags for PSCI init ACPI / table: Print GIC information when MADT is parsed ARM64 / ACPI: Parse MADT for SMP initialization ACPI / processor: Make it possible to get CPU hardware ID via GICC ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi ARM64 / ACPI: Parse GTDT to initialize arch timer
Tomasz Nowicki (1): ARM64 / ACPI: Add GICv2 specific ACPI boot support
Documentation/arm64/arm-acpi.txt | 218 +++++++++++++++++++++ Documentation/kernel-parameters.txt | 3 +- arch/arm64/Kconfig | 3 + arch/arm64/include/asm/acenv.h | 18 ++ arch/arm64/include/asm/acpi.h | 108 ++++++++++ arch/arm64/include/asm/cpu_ops.h | 1 + arch/arm64/include/asm/pci.h | 11 ++ arch/arm64/include/asm/psci.h | 3 +- arch/arm64/include/asm/smp.h | 5 +- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/acpi.c | 359 ++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_ops.c | 4 +- arch/arm64/kernel/irq.c | 5 + arch/arm64/kernel/psci.c | 78 +++++--- arch/arm64/kernel/setup.c | 23 ++- arch/arm64/kernel/smp.c | 2 +- arch/arm64/kernel/time.c | 7 + drivers/acpi/Kconfig | 6 +- drivers/acpi/Makefile | 2 +- drivers/acpi/bus.c | 3 + drivers/acpi/internal.h | 5 + drivers/acpi/processor_core.c | 37 ++++ drivers/acpi/tables.c | 113 +++++++++-- drivers/clocksource/arm_arch_timer.c | 117 +++++++++-- drivers/irqchip/irq-gic.c | 114 +++++++++++ include/linux/acpi.h | 5 + include/linux/clocksource.h | 6 + include/linux/irqchip/arm-gic-acpi.h | 33 ++++ include/linux/pci.h | 37 +++- 29 files changed, 1237 insertions(+), 90 deletions(-) create mode 100644 Documentation/arm64/arm-acpi.txt create mode 100644 arch/arm64/include/asm/acenv.h create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/include/asm/pci.h create mode 100644 arch/arm64/kernel/acpi.c create mode 100644 include/linux/irqchip/arm-gic-acpi.h
It always make sense to initialize CPU0's logical map entry from the hardware values, so move the initialization of cpu_logical_map(0) before unflatten_device_tree() which is needed by ACPI code later.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index f6f0ccf..c96172a 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -390,11 +390,11 @@ void __init setup_arch(char **cmdline_p)
efi_idmap_init();
+ cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; unflatten_device_tree();
psci_init();
- cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; cpu_read_bootcpu_ops(); #ifdef CONFIG_SMP smp_init_cpus();
From: Al Stone al.stone@linaro.org
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; - 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.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/acenv.h | 18 +++++++++++ arch/arm64/include/asm/acpi.h | 45 ++++++++++++++++++++++++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/acpi.c | 69 ++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/setup.c | 4 +++ 5 files changed, 137 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
diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h new file mode 100644 index 0000000..3899ee6 --- /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 hanjun.guo@linaro.org + * Author: Graeme Gregory graeme.gregory@linaro.org + * + * 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 + +#define ACPI_FLUSH_CPU_CACHE() WARN_ONCE(1, "Not currently supported on ARM64") + +#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 0000000..8b837ab --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013-2014, Linaro Ltd. + * Author: Al Stone al.stone@linaro.org + * Author: Graeme Gregory graeme.gregory@linaro.org + * Author: Hanjun Guo hanjun.guo@linaro.org + * + * 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 df7ef87..29ea7d6 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -29,6 +29,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.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 0000000..9252f72 --- /dev/null +++ b/arch/arm64/kernel/acpi.c @@ -0,0 +1,69 @@ +/* + * ARM64 Specific Low-Level ACPI Boot Support + * + * Copyright (C) 2013-2014, Linaro Ltd. + * Author: Al Stone al.stone@linaro.org + * Author: Graeme Gregory graeme.gregory@linaro.org + * Author: Hanjun Guo hanjun.guo@linaro.org + * Author: Tomasz Nowicki tomasz.nowicki@linaro.org + * Author: Naresh Bhat naresh.bhat@linaro.org + * + * 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 <linux/init.h> +#include <linux/acpi.h> +#include <linux/cpumask.h> +#include <linux/memblock.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/bootmem.h> +#include <linux/smp.h> + +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 (!phys || !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); +} + +/* + * 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 + * + * 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(); +} diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index c96172a..fb7cc0e 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,6 +43,7 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/efi.h> +#include <linux/acpi.h>
#include <asm/fixmap.h> #include <asm/cpu.h> @@ -385,6 +386,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();
On Mon, Sep 01, 2014 at 03:57:40PM +0100, Hanjun Guo wrote:
diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h new file mode 100644 index 0000000..3899ee6 --- /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 hanjun.guo@linaro.org
- Author: Graeme Gregory graeme.gregory@linaro.org
- 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
+#define ACPI_FLUSH_CPU_CACHE() WARN_ONCE(1, "Not currently supported on ARM64")
Does this mean that it will be supported at some point? Looking at the places where this function is called, I don't really see how this would ever work on ARM. Which means that we add such macro just to be able to compile code that would never be used on arm64. I would rather see the relevant ACPI files only compiled on x86/IA-64 rather than arm64.
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c new file mode 100644 index 0000000..9252f72 --- /dev/null +++ b/arch/arm64/kernel/acpi.c
[...]
+/*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- 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;
So at this point, there wouldn't be anything yet to set acpi_disabled to 1, unless !CONFIG_ACPI.
- /* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
disable_acpi();
Do you need anything more to add to this function later? Otherwise, just call it in setup_arch() directly (maybe dependent on IS_ENABLED(CONFIG_ACPI) or just create an equivalent dummy acpi_table_init() when not configured).
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index c96172a..fb7cc0e 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,6 +43,7 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/efi.h> +#include <linux/acpi.h> #include <asm/fixmap.h> #include <asm/cpu.h> @@ -385,6 +386,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();
Is there any dummy acpi_boot_table_init() when !CONFIG_ACPI? I couldn't see one in this patch, so I don't see how this would compile when ACPI is disabled.
On Tue, Sep 09, 2014 at 05:26:49PM +0100, Catalin Marinas wrote:
On Mon, Sep 01, 2014 at 03:57:40PM +0100, Hanjun Guo wrote:
diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h new file mode 100644 index 0000000..3899ee6 --- /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 hanjun.guo@linaro.org
- Author: Graeme Gregory graeme.gregory@linaro.org
- 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
+#define ACPI_FLUSH_CPU_CACHE() WARN_ONCE(1, "Not currently supported on ARM64")
Does this mean that it will be supported at some point?
From what I recall it's impossible to support as we have no equivalent
of WBINVD -- the possibility migration of dirty cache lines renders it impossible to guarantee that the caches remain empty (or that data even left the local caches in the first place).
Looking at the places where this function is called, I don't really see how this would ever work on ARM. Which means that we add such macro just to be able to compile code that would never be used on arm64. I would rather see the relevant ACPI files only compiled on x86/IA-64 rather than arm64.
Agreed.
It looks like include/acpi/platform/acenv.h defines an empty ACPI_FLUSH_CPU_CACHE() stub, so something else should probably be done to turn the use of ACPI_FLUSH_CPU_CACHE() into a build-time bug on arm64.
Mark.
On 2014/9/10 0:26, Catalin Marinas wrote:
On Mon, Sep 01, 2014 at 03:57:40PM +0100, Hanjun Guo wrote:
diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h new file mode 100644 index 0000000..3899ee6 --- /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 hanjun.guo@linaro.org
- Author: Graeme Gregory graeme.gregory@linaro.org
- 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
+#define ACPI_FLUSH_CPU_CACHE() WARN_ONCE(1, "Not currently supported on ARM64")
Does this mean that it will be supported at some point? Looking at the places where this function is called, I don't really see how this would ever work on ARM. Which means that we add such macro just to be able to compile code that would never be used on arm64. I would rather see the relevant ACPI files only compiled on x86/IA-64 rather than arm64.
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c new file mode 100644 index 0000000..9252f72 --- /dev/null +++ b/arch/arm64/kernel/acpi.c
[...]
+/*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- 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;
So at this point, there wouldn't be anything yet to set acpi_disabled to 1, unless !CONFIG_ACPI.
- /* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
disable_acpi();
Do you need anything more to add to this function later? Otherwise, just call it in setup_arch() directly (maybe dependent on IS_ENABLED(CONFIG_ACPI) or just create an equivalent dummy acpi_table_init() when not configured).
We add FADT parse function to this function later.
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index c96172a..fb7cc0e 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,6 +43,7 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/efi.h> +#include <linux/acpi.h> #include <asm/fixmap.h> #include <asm/cpu.h> @@ -385,6 +386,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();
Is there any dummy acpi_boot_table_init() when !CONFIG_ACPI? I couldn't see one in this patch, so I don't see how this would compile when ACPI is disabled.
There is a stub function in linux/acpi.h when ACPI is disabled.
Thanks Hanjun
On Tue, 9 Sep 2014 17:26:49 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Mon, Sep 01, 2014 at 03:57:40PM +0100, Hanjun Guo wrote:
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index c96172a..fb7cc0e 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,6 +43,7 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/efi.h> +#include <linux/acpi.h> #include <asm/fixmap.h> #include <asm/cpu.h> @@ -385,6 +386,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();
Is there any dummy acpi_boot_table_init() when !CONFIG_ACPI? I couldn't see one in this patch, so I don't see how this would compile when ACPI is disabled.
It's in include/linux/acpi.h in the !CONFIG_ACPI section.
g.
From: Graeme Gregory graeme.gregory@linaro.org
acpi_wakeup_address is used on x86 as the address bios jumps into when machine wakes up from suspend. As arm64 does not have such a bios this mechanism will be provided by other means. But the define is still required inside the acpi core.
Introduce a null stub for acpi_suspend_lowlevel as this is also required by core. This will be filled in when standards are defined for arm64 ACPI global power states.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/acpi.h | 12 ++++++++++++ arch/arm64/kernel/acpi.c | 7 +++++++ 2 files changed, 19 insertions(+)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 8b837ab..02bbb0b 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -40,6 +40,18 @@ static inline bool acpi_has_cpu_in_madt(void)
static inline void arch_fix_phys_package_id(int num, u32 slot) { }
+/* Low-level suspend routine. + * + * ACPI S-states for ARM64 have to be defined + * and approved before doing anything else, maybe + * we need update the ACPI spec, here we + * just introduce function and macro needed by + * ACPI core as IA64 did, and revisit them when + * the spec is ready. + */ +extern int (*acpi_suspend_lowlevel)(void); +#define acpi_wakeup_address 0 + #endif /* CONFIG_ACPI */
#endif /*_ASM_ACPI_H*/ diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 9252f72..b6940a0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -67,3 +67,10 @@ void __init acpi_boot_table_init(void) if (acpi_table_init()) disable_acpi(); } + +/* + * acpi_suspend_lowlevel() - save kernel state and suspend. + * + * TBD when ARM/ARM64 starts to support suspend... + */ +int (*acpi_suspend_lowlevel)(void) = NULL;
On Mon, Sep 01, 2014 at 03:57:41PM +0100, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
acpi_wakeup_address is used on x86 as the address bios jumps into when machine wakes up from suspend. As arm64 does not have such a bios this mechanism will be provided by other means. But the define is still required inside the acpi core.
Introduce a null stub for acpi_suspend_lowlevel as this is also required by core. This will be filled in when standards are defined for arm64 ACPI global power states.
Do we actually plan to use these on arm64? I'm worried most of these don't make sense on arm64 (the aim is to use PSCI). Is it possible to refactor the core code so that we don't have to define dummy macros or variables just to be able to build the kernel?
On Tue, Sep 09, 2014 at 05:35:29PM +0100, Catalin Marinas wrote:
On Mon, Sep 01, 2014 at 03:57:41PM +0100, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
acpi_wakeup_address is used on x86 as the address bios jumps into when machine wakes up from suspend. As arm64 does not have such a bios this mechanism will be provided by other means. But the define is still required inside the acpi core.
Introduce a null stub for acpi_suspend_lowlevel as this is also required by core. This will be filled in when standards are defined for arm64 ACPI global power states.
Do we actually plan to use these on arm64? I'm worried most of these don't make sense on arm64 (the aim is to use PSCI). Is it possible to refactor the core code so that we don't have to define dummy macros or variables just to be able to build the kernel?
Currently ia64 does the same as this for stubbing out the functions.
We did investigate removing the code but that ultimately ended with more functions and variables stubbed then this.
Graeme
From: Al Stone al.stone@linaro.org
Introduce one early parameters "off" for "acpi" to disable ACPI on ARM64.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- Documentation/kernel-parameters.txt | 3 ++- arch/arm64/kernel/acpi.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5ae8608..9dfb1d8 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,ARM] 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" is available.
See also Documentation/power/runtime_pm.txt, pci=noacpi
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index b6940a0..9547275 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -74,3 +74,18 @@ void __init acpi_boot_table_init(void) * TBD when ARM/ARM64 starts to support suspend... */ int (*acpi_suspend_lowlevel)(void) = NULL; + +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) + disable_acpi(); + else + return -EINVAL; /* Core will print when we return error */ + + return 0; +} +early_param("acpi", parse_acpi);
On Mon, Sep 01, 2014 at 03:57:42PM +0100, Hanjun Guo wrote:
--- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -74,3 +74,18 @@ void __init acpi_boot_table_init(void)
- TBD when ARM/ARM64 starts to support suspend...
*/ int (*acpi_suspend_lowlevel)(void) = NULL;
+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)
disable_acpi();
- else
return -EINVAL; /* Core will print when we return error */
- return 0;
+} +early_param("acpi", parse_acpi);
I forgot about early param, so there is a way to set acpi_disabled to 1 before populating the tables.
On Mon, Sep 1, 2014 at 8:57 AM, Hanjun Guo hanjun.guo@linaro.org wrote:
From: Al Stone al.stone@linaro.org
Introduce one early parameters "off" for "acpi" to disable ACPI on ARM64.
It might be worth mentioning the purpose of this in the changelog (and maybe the documentation). I don't think this parameter is supported on ia64, and on x86 it seems like it's mostly used as a "fix" by Ubuntu users who consider the problem resolved when they find this parameter. That just means we don't get a chance to fix the real underlying problem, so I'm not sure it's a real benefit to have the parameter.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
Documentation/kernel-parameters.txt | 3 ++- arch/arm64/kernel/acpi.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5ae8608..9dfb1d8 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,ARM] 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" is available. See also Documentation/power/runtime_pm.txt, pci=noacpi
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index b6940a0..9547275 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -74,3 +74,18 @@ void __init acpi_boot_table_init(void)
- TBD when ARM/ARM64 starts to support suspend...
*/ int (*acpi_suspend_lowlevel)(void) = NULL;
+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)
disable_acpi();
else
return -EINVAL; /* Core will print when we return error */
return 0;
+}
+early_param("acpi", parse_acpi);
1.7.9.5
From: Graeme Gregory graeme.gregory@linaro.org
If the early boot methods of acpi are happy that we have valid ACPI tables and acpi=off has not been passed. Then do not unflat devicetree effectively disabling further hardware probing from DT.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/kernel/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index fb7cc0e..ba181ba 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -395,7 +395,8 @@ void __init setup_arch(char **cmdline_p) efi_idmap_init();
cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; - unflatten_device_tree(); + if (acpi_disabled) + unflatten_device_tree();
psci_init();
As PCI for ARM64 is not ready, so introduce some stub functions to make PCI optional for ACPI, and make ACPI core run without CONFIG_PCI on ARM64.
Since ACPI on X86 and IA64 depends on PCI and this patch only makes PCI optional for ARM64, it will not break anything on X86 and IA64.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/pci.h | 11 +++++++++++ drivers/acpi/Makefile | 2 +- drivers/acpi/internal.h | 5 +++++ include/linux/pci.h | 37 +++++++++++++++++++++++++++---------- 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 arch/arm64/include/asm/pci.h
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h new file mode 100644 index 0000000..250cd24 --- /dev/null +++ b/arch/arm64/include/asm/pci.h @@ -0,0 +1,11 @@ +#ifndef __ASM_PCI_H +#define __ASM_PCI_H +#ifdef __KERNEL__ + +/* + * PCI address space differs from physical memory address space + */ +#define PCI_DMA_BUS_IS_PHYS (0) + +#endif /* __KERNEL__ */ +#endif /* __ASM_PCI_H */ diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 505d4d7..8e9bbe6 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -39,7 +39,7 @@ acpi-y += processor_core.o acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o -acpi-y += pci_root.o pci_link.o pci_irq.o +acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o acpi-y += acpi_lpss.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4c5cf77..e1e6487 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -26,8 +26,13 @@ acpi_status acpi_os_initialize1(void); int init_acpi_device_notify(void); int acpi_scan_init(void); +#ifdef CONFIG_PCI void acpi_pci_root_init(void); void acpi_pci_link_init(void); +#else +static inline void acpi_pci_root_init(void) {} +static inline void acpi_pci_link_init(void) {} +#endif void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); diff --git a/include/linux/pci.h b/include/linux/pci.h index 61978a4..50fa750 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -558,15 +558,6 @@ struct pci_ops { int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); };
-/* - * ACPI needs to be able to access PCI config space before we've done a - * PCI bus scan and created pci_bus structures. - */ -int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, - int reg, int len, u32 *val); -int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, - int reg, int len, u32 val); - struct pci_bus_region { dma_addr_t start; dma_addr_t end; @@ -1293,6 +1284,16 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, unsigned int command_bits, u32 flags); void pci_register_set_vga_state(arch_set_vga_state_t func);
+/* + * ACPI needs to be able to access PCI config space before we've done a + * PCI bus scan and created pci_bus structures. + */ +int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, + int reg, int len, u32 *val); +int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, + int reg, int len, u32 val); +void pcibios_penalize_isa_irq(int irq, int active); + #else /* CONFIG_PCI is not enabled */
/* @@ -1394,6 +1395,23 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) { return NULL; }
+static inline struct pci_bus *pci_find_bus(int domain, int busnr) +{ return NULL; } + +static inline int pci_bus_write_config_byte(struct pci_bus *bus, + unsigned int devfn, int where, u8 val) +{ return -ENOSYS; } + +static inline int raw_pci_read(unsigned int domain, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *val) +{ return -ENOSYS; } + +static inline int raw_pci_write(unsigned int domain, unsigned int bus, + unsigned int devfn, int reg, int len, u32 val) +{ return -ENOSYS; } + +static inline void pcibios_penalize_isa_irq(int irq, int active) { } + static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
@@ -1607,7 +1625,6 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); int pcibios_add_device(struct pci_dev *dev); void pcibios_release_device(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq, int active);
#ifdef CONFIG_HIBERNATE_CALLBACKS extern struct dev_pm_ops pcibios_pm_ops;
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, parse FADT to get the flags 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.
At the same time, only ACPI 5.1 or higher verison supports PSCI, and FADT Major.Minor version was introduced in ACPI 5.1, so we will check the version and only parse FADT table with version >= 5.1.
If firmware provides ACPI tables with ACPI version less than 5.1, OS will be messed up with those information and have no way to init smp and GIC, so disable ACPI if we get an FADT table with version less that 5.1.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org --- arch/arm64/include/asm/acpi.h | 17 +++++++++ arch/arm64/include/asm/psci.h | 3 +- arch/arm64/kernel/acpi.c | 31 +++++++++++++++- arch/arm64/kernel/psci.c | 78 ++++++++++++++++++++++++++++------------- arch/arm64/kernel/setup.c | 8 +++-- 5 files changed, 108 insertions(+), 29 deletions(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 02bbb0b..620057c 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -19,6 +19,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; @@ -52,6 +64,11 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { } extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
+#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 e5312ea..2454bc5 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/acpi.c b/arch/arm64/kernel/acpi.c index 9547275..470570c 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -13,6 +13,8 @@ * published by the Free Software Foundation. */
+#define pr_fmt(fmt) "ACPI: " fmt + #include <linux/init.h> #include <linux/acpi.h> #include <linux/cpumask.h> @@ -49,10 +51,32 @@ void __init __acpi_unmap_table(char *map, unsigned long size) 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 higher revision + * to get arm boot flags, 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 revisoin * * We can parse ACPI boot-time tables such as MADT after * this function is called. @@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void) return;
/* Initialize the ACPI boot-time table parser. */ - if (acpi_table_init()) + if (acpi_table_init()) { disable_acpi(); + return; + } + + if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) + pr_err("Can't find FADT or error happened during parsing FADT\n"); }
/* diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 5539547..15ba470 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -15,6 +15,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/acpi.h> #include <linux/init.h> #include <linux/of.h> #include <linux/smp.h> @@ -23,6 +24,7 @@ #include <linux/delay.h> #include <uapi/linux/psci.h>
+#include <asm/acpi.h> #include <asm/compiler.h> #include <asm/cpu_ops.h> #include <asm/errno.h> @@ -231,6 +233,33 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); }
+static void 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. @@ -264,29 +293,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); @@ -339,7 +346,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; @@ -354,6 +361,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 ba181ba..ac9ec55 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -395,10 +395,12 @@ void __init setup_arch(char **cmdline_p) efi_idmap_init();
cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; - 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
When MADT is parsed, print GIC information to make the boot log look pretty.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org --- drivers/acpi/tables.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 6d5a6cd..a97d2aa 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -183,6 +183,49 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) } break;
+ case ACPI_MADT_TYPE_GENERIC_INTERRUPT: + { + struct acpi_madt_generic_interrupt *p = + (struct acpi_madt_generic_interrupt *)header; + pr_info("GICC (acpi_id[0x%04x] address[%p] MPDIR[0x%llx] %s)\n", + p->uid, (void *)(unsigned long)p->base_address, + p->arm_mpidr, + (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); + + } + break; + + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + { + struct acpi_madt_generic_distributor *p = + (struct acpi_madt_generic_distributor *)header; + pr_info("GIC Distributor (gic_id[0x%04x] address[%p] gsi_base[%d])\n", + p->gic_id, + (void *)(unsigned long)p->base_address, + p->global_irq_base); + } + break; + + case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: + { + struct acpi_madt_generic_msi_frame *p = + (struct acpi_madt_generic_msi_frame *)header; + pr_info("GIC MSI Frame (msi_fame_id[%d] address[%p])\n", + p->msi_frame_id, + (void *)(unsigned long)p->base_address); + } + break; + + case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: + { + struct acpi_madt_generic_redistributor *p = + (struct acpi_madt_generic_redistributor *)header; + pr_info("GIC Redistributor (address[%p] region_size[0x%x])\n", + (void *)(unsigned long)p->base_address, + p->length); + } + break; + default: pr_warn("Found unsupported MADT entry (type = 0x%x)\n", header->type);
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.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org --- arch/arm64/include/asm/acpi.h | 4 ++ arch/arm64/include/asm/cpu_ops.h | 1 + arch/arm64/include/asm/smp.h | 5 +- arch/arm64/kernel/acpi.c | 144 ++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_ops.c | 4 +- arch/arm64/kernel/setup.c | 8 ++- arch/arm64/kernel/smp.c | 2 +- 7 files changed, 161 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 620057c..e013dbb 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -51,6 +51,7 @@ static inline bool acpi_has_cpu_in_madt(void) }
static inline void arch_fix_phys_package_id(int num, u32 slot) { } +void __init acpi_smp_init_cpus(void);
/* Low-level suspend routine. * @@ -64,10 +65,13 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { } extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
+#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535 + #else
static inline bool acpi_psci_present(void) { return false; } static inline bool acpi_psci_use_hvc(void) { return false; } +static inline void acpi_smp_init_cpus(void) { }
#endif /* CONFIG_ACPI */
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index d7b4b38..d149580 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h @@ -61,6 +61,7 @@ struct cpu_operations { };
extern const struct cpu_operations *cpu_ops[NR_CPUS]; +const struct cpu_operations *cpu_get_ops(const char *name); extern int __init cpu_read_ops(struct device_node *dn, int cpu); extern void __init cpu_read_bootcpu_ops(void);
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index a498f2c..c877adc 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 470570c..fbaaf01 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -24,6 +24,10 @@ #include <linux/bootmem.h> #include <linux/smp.h>
+#include <asm/smp_plat.h> +#include <asm/cputype.h> +#include <asm/cpu_ops.h> + int acpi_noirq; /* skip ACPI IRQ initialization */ int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); @@ -31,6 +35,8 @@ EXPORT_SYMBOL(acpi_disabled); int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled);
+static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */ + /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -51,6 +57,144 @@ 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 acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{ + int cpu; + + if (mpidr == INVALID_HWID) { + pr_info("Skip invalid cpu hardware ID\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; + } + + /* No need to check duplicate MPIDRs for the first CPU */ + if (enabled_cpus) { + /* + * Duplicate MPIDRs are a recipe for disaster. Scan + * all initialized entries and check for + * duplicates. If any is found just ignore the CPU. + */ + for_each_possible_cpu(cpu) { + if (cpu_logical_map(cpu) == mpidr) { + pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n", + mpidr); + return -EINVAL; + } + } + } else { + /* Fist GICC entry must be BSP as ACPI spec said */ + if (cpu_logical_map(0) != mpidr) { + pr_err("First GICC entry is not BSP for MPIDR 0x%llx\n", + mpidr); + return -EINVAL; + } + } + + /* allocate a logical cpu id for the new comer */ + if (cpu_logical_map(0) == mpidr) { + /* + * boot_cpu_init() already hold bit 0 in cpu_present_mask + * for BSP, no need to allocate again. + */ + cpu = 0; + } else { + cpu = cpumask_next_zero(-1, cpu_possible_mask); + } + + /* + * 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. + */ + if (!acpi_psci_present()) { + pr_warn("CPU %d has no PSCI support, will not boot\n", cpu); + return -EOPNOTSUPP; + } + + /* Get cpu_ops include the boot CPU */ + cpu_ops[cpu] = cpu_get_ops("psci"); + if (!cpu_ops[cpu]) + return -EINVAL; + + /* CPU 0 was already initialized */ + if (cpu) { + if (cpu_ops[cpu]->cpu_init(NULL, cpu)) + return -EOPNOTSUPP; + + /* map the logical cpu id to cpu MPIDR */ + cpu_logical_map(cpu) = mpidr; + + set_cpu_possible(cpu, true); + } + + enabled_cpus++; + return cpu; +} + +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, + processor->flags & ACPI_MADT_ENABLED); + + return 0; +} + +/* Parse GIC cpu interface entries in MADT for SMP init */ +void __init acpi_smp_init_cpus(void) +{ + int count; + + /* + * 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, + ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES); + + 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; + } + + /* 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; diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c index cce9524..1a04deb 100644 --- a/arch/arm64/kernel/cpu_ops.c +++ b/arch/arm64/kernel/cpu_ops.c @@ -27,7 +27,7 @@ extern const struct cpu_operations cpu_psci_ops;
const struct cpu_operations *cpu_ops[NR_CPUS];
-static const struct cpu_operations *supported_cpu_ops[] __initconst = { +static const struct cpu_operations *supported_cpu_ops[] = { #ifdef CONFIG_SMP &smp_spin_table_ops, #endif @@ -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 *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 ac9ec55..a45ceb3 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -60,6 +60,7 @@ #include <asm/memblock.h> #include <asm/psci.h> #include <asm/efi.h> +#include <asm/acpi.h>
unsigned int processor_id; EXPORT_SYMBOL(processor_id); @@ -398,13 +399,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_smp_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 4743397..4e390ac 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -321,7 +321,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;
On Mon, Sep 01, 2014 at 03:57:47PM +0100, Hanjun Guo wrote:
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.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org
arch/arm64/include/asm/acpi.h | 4 ++ arch/arm64/include/asm/cpu_ops.h | 1 + arch/arm64/include/asm/smp.h | 5 +- arch/arm64/kernel/acpi.c | 144 ++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_ops.c | 4 +- arch/arm64/kernel/setup.c | 8 ++- arch/arm64/kernel/smp.c | 2 +- 7 files changed, 161 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 620057c..e013dbb 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -51,6 +51,7 @@ static inline bool acpi_has_cpu_in_madt(void) } static inline void arch_fix_phys_package_id(int num, u32 slot) { } +void __init acpi_smp_init_cpus(void); /* Low-level suspend routine.
@@ -64,10 +65,13 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { } extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0 +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else static inline bool acpi_psci_present(void) { return false; } static inline bool acpi_psci_use_hvc(void) { return false; } +static inline void acpi_smp_init_cpus(void) { } #endif /* CONFIG_ACPI */ diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index d7b4b38..d149580 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h @@ -61,6 +61,7 @@ struct cpu_operations { }; extern const struct cpu_operations *cpu_ops[NR_CPUS]; +const struct cpu_operations *cpu_get_ops(const char *name); extern int __init cpu_read_ops(struct device_node *dn, int cpu); extern void __init cpu_read_bootcpu_ops(void); diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index a498f2c..c877adc 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 470570c..fbaaf01 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -24,6 +24,10 @@ #include <linux/bootmem.h> #include <linux/smp.h> +#include <asm/smp_plat.h> +#include <asm/cputype.h> +#include <asm/cpu_ops.h>
int acpi_noirq; /* skip ACPI IRQ initialization */ int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); @@ -31,6 +35,8 @@ EXPORT_SYMBOL(acpi_disabled); int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled); +static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
Will this be ever different from (num_possible_cpus() - 1) ?
/*
- __acpi_map_table() will be called before page_init(), so early_ioremap()
- or early_memremap() should be called here to for ACPI table mapping.
@@ -51,6 +57,144 @@ 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 acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{
- int cpu;
- if (mpidr == INVALID_HWID) {
pr_info("Skip invalid cpu hardware ID\n");
return -EINVAL;
- }
- total_cpus++;
What's this used for ?
- 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;
- }
- /* No need to check duplicate MPIDRs for the first CPU */
- if (enabled_cpus) {
/*
* Duplicate MPIDRs are a recipe for disaster. Scan
* all initialized entries and check for
* duplicates. If any is found just ignore the CPU.
*/
for_each_possible_cpu(cpu) {
if (cpu_logical_map(cpu) == mpidr) {
pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
mpidr);
return -EINVAL;
}
}
- } else {
/* Fist GICC entry must be BSP as ACPI spec said */
s/Fist/First/
if (cpu_logical_map(0) != mpidr) {
pr_err("First GICC entry is not BSP for MPIDR 0x%llx\n",
mpidr);
return -EINVAL;
}
Interesting, this means that if I want to change the boot CPU I have to recompile the ACPI tables. Is that really true ?
- }
- /* allocate a logical cpu id for the new comer */
- if (cpu_logical_map(0) == mpidr) {
/*
* boot_cpu_init() already hold bit 0 in cpu_present_mask
* for BSP, no need to allocate again.
*/
cpu = 0;
- } else {
cpu = cpumask_next_zero(-1, cpu_possible_mask);
- }
You may use a ternary operator, more compact and clearer.
BTW you seem to be contradicting yourself. On one hand you keep a counter for enabled_cpus, and then use cpu_possible_mask to allocate a logical cpu id. Make a decision, either you use a counter or you use cpu_possible_mask and its bitweight.
- /*
* 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.
*/
- if (!acpi_psci_present()) {
pr_warn("CPU %d has no PSCI support, will not boot\n", cpu);
return -EOPNOTSUPP;
- }
This check really does not belong here. You do not even start parsing the gic cpu interfaces if psci is missing or I am missing something myself. Anyway, this check must not be in this function.
- /* Get cpu_ops include the boot CPU */
- cpu_ops[cpu] = cpu_get_ops("psci");
- if (!cpu_ops[cpu])
return -EINVAL;
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
set_cpu_possible(cpu, true);
- }
- enabled_cpus++;
See above to me enabled_cpus and (num_possible_cpus() - 1) are identical.
- return cpu;
+}
+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,
processor->flags & ACPI_MADT_ENABLED);
Ehm. You must check the return value here right (and return an error if that's an error, otherwise the count value below can be botched ?!).
Or you do not consider a parsing error as an error and want to keep parsing remaining GIC CPU IF entries ?
- return 0;
+}
+/* Parse GIC cpu interface entries in MADT for SMP init */ +void __init acpi_smp_init_cpus(void) +{
- int count;
- /*
* 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,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- 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;
- }
What would you consider an error ? A single GIC CPU IF entry error ?
Thanks, Lorenzo
- /* 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; diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c index cce9524..1a04deb 100644 --- a/arch/arm64/kernel/cpu_ops.c +++ b/arch/arm64/kernel/cpu_ops.c @@ -27,7 +27,7 @@ extern const struct cpu_operations cpu_psci_ops; const struct cpu_operations *cpu_ops[NR_CPUS]; -static const struct cpu_operations *supported_cpu_ops[] __initconst = { +static const struct cpu_operations *supported_cpu_ops[] = { #ifdef CONFIG_SMP &smp_spin_table_ops, #endif @@ -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 *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 ac9ec55..a45ceb3 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -60,6 +60,7 @@ #include <asm/memblock.h> #include <asm/psci.h> #include <asm/efi.h> +#include <asm/acpi.h> unsigned int processor_id; EXPORT_SYMBOL(processor_id); @@ -398,13 +399,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_smp_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 4743397..4e390ac 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -321,7 +321,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; -- 1.7.9.5
Hi Lorenzo,
On 2014年09月04日 01:21, Lorenzo Pieralisi wrote:
On Mon, Sep 01, 2014 at 03:57:47PM +0100, Hanjun Guo wrote:
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.
[...]
int acpi_noirq; /* skip ACPI IRQ initialization */ int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); @@ -31,6 +35,8 @@ EXPORT_SYMBOL(acpi_disabled); int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled); +static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
Will this be ever different from (num_possible_cpus() - 1) ?
Yes, num_possible_cpus() will much more than enabled cpus in MADT, when ACPI based CPU hot plug is introduced, you can refer to the code in x86.
/*
- __acpi_map_table() will be called before page_init(), so early_ioremap()
- or early_memremap() should be called here to for ACPI table mapping.
@@ -51,6 +57,144 @@ 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 acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{
- int cpu;
- if (mpidr == INVALID_HWID) {
pr_info("Skip invalid cpu hardware ID\n");
return -EINVAL;
- }
- total_cpus++;
What's this used for ?
It is for all the CPU entries in MADT table, it is used to let people know how many CPUs in MADT (enabled and disabled).
- 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;
- }
- /* No need to check duplicate MPIDRs for the first CPU */
- if (enabled_cpus) {
/*
* Duplicate MPIDRs are a recipe for disaster. Scan
* all initialized entries and check for
* duplicates. If any is found just ignore the CPU.
*/
for_each_possible_cpu(cpu) {
if (cpu_logical_map(cpu) == mpidr) {
pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
mpidr);
return -EINVAL;
}
}
- } else {
/* Fist GICC entry must be BSP as ACPI spec said */
s/Fist/First/
if (cpu_logical_map(0) != mpidr) {
pr_err("First GICC entry is not BSP for MPIDR 0x%llx\n",
mpidr);
return -EINVAL;
}
Interesting, this means that if I want to change the boot CPU I have to recompile the ACPI tables. Is that really true ?
No, you needn't. there is a logic problem here, we just need to print some message here and continue, OS will still ok with that.
- }
- /* allocate a logical cpu id for the new comer */
- if (cpu_logical_map(0) == mpidr) {
/*
* boot_cpu_init() already hold bit 0 in cpu_present_mask
* for BSP, no need to allocate again.
*/
cpu = 0;
- } else {
cpu = cpumask_next_zero(-1, cpu_possible_mask);
- }
You may use a ternary operator, more compact and clearer.
BTW you seem to be contradicting yourself. On one hand you keep a counter for enabled_cpus, and then use cpu_possible_mask to allocate a logical cpu id. Make a decision, either you use a counter or you use cpu_possible_mask and its bitweight.
ok.
- /*
* 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.
*/
- if (!acpi_psci_present()) {
pr_warn("CPU %d has no PSCI support, will not boot\n", cpu);
return -EOPNOTSUPP;
- }
This check really does not belong here. You do not even start parsing the gic cpu interfaces if psci is missing or I am missing something myself. Anyway, this check must not be in this function.
I agree with you, i will update the patch.
- /* Get cpu_ops include the boot CPU */
- cpu_ops[cpu] = cpu_get_ops("psci");
- if (!cpu_ops[cpu])
return -EINVAL;
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
set_cpu_possible(cpu, true);
- }
- enabled_cpus++;
See above to me enabled_cpus and (num_possible_cpus() - 1) are identical.
I think I need to remove all the CPU hotplug related code and make this function as simple as possible and introduce them when needed.
- return cpu;
+}
+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,
processor->flags & ACPI_MADT_ENABLED);
Ehm. You must check the return value here right (and return an error if that's an error, otherwise the count value below can be botched ?!).
Or you do not consider a parsing error as an error and want to keep parsing remaining GIC CPU IF entries ?
yes, this is my intension. we can skip the error ones and boot other CPUs which have no errors.
- return 0;
+}
+/* Parse GIC cpu interface entries in MADT for SMP init */ +void __init acpi_smp_init_cpus(void) +{
- int count;
- /*
* 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,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- 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;
- }
What would you consider an error ? A single GIC CPU IF entry error ?
could you please explain it in detail? I can't catch up with you, my apologizes.
Thanks Hanjun
On Thu, Sep 04, 2014 at 04:29:15PM +0100, Hanjun Guo wrote:
Hi Lorenzo,
On 2014?09?04? 01:21, Lorenzo Pieralisi wrote:
On Mon, Sep 01, 2014 at 03:57:47PM +0100, Hanjun Guo wrote:
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.
[...]
int acpi_noirq; /* skip ACPI IRQ initialization */ int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); @@ -31,6 +35,8 @@ EXPORT_SYMBOL(acpi_disabled); int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ EXPORT_SYMBOL(acpi_pci_disabled); +static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
Will this be ever different from (num_possible_cpus() - 1) ?
Yes, num_possible_cpus() will much more than enabled cpus in MADT, when ACPI based CPU hot plug is introduced, you can refer to the code in x86.
Ok, but in the context of this patch to me they represent the same value. I understand you need a counter, which you should probably use to enumerate the logical cpus instead of resorting to the first empty slot in cpu_possible_mask.
Anyway, it is a minor point, please be consistent that's all I am asking.
/*
- __acpi_map_table() will be called before page_init(), so early_ioremap()
- or early_memremap() should be called here to for ACPI table mapping.
@@ -51,6 +57,144 @@ 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 acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{
- int cpu;
- if (mpidr == INVALID_HWID) {
pr_info("Skip invalid cpu hardware ID\n");
return -EINVAL;
- }
- total_cpus++;
What's this used for ?
It is for all the CPU entries in MADT table, it is used to let people know how many CPUs in MADT (enabled and disabled).
I think its usage is very limited at the moment, again it is not a major point, I was just asking, I certainly do not think it is essential at this stage (apart from debugging the parsing code).
- 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;
- }
- /* No need to check duplicate MPIDRs for the first CPU */
- if (enabled_cpus) {
/*
* Duplicate MPIDRs are a recipe for disaster. Scan
* all initialized entries and check for
* duplicates. If any is found just ignore the CPU.
*/
for_each_possible_cpu(cpu) {
if (cpu_logical_map(cpu) == mpidr) {
pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
mpidr);
return -EINVAL;
}
}
- } else {
/* Fist GICC entry must be BSP as ACPI spec said */
s/Fist/First/
if (cpu_logical_map(0) != mpidr) {
pr_err("First GICC entry is not BSP for MPIDR 0x%llx\n",
mpidr);
return -EINVAL;
}
Interesting, this means that if I want to change the boot CPU I have to recompile the ACPI tables. Is that really true ?
No, you needn't. there is a logic problem here, we just need to print some message here and continue, OS will still ok with that.
I need to look at the specs here. I do not like fixed dependencies on the boot CPU, which risk being translated in dependencies on first/last CPU going-to/getting-out-of idle and that is a major concern, among others.
- }
- /* allocate a logical cpu id for the new comer */
- if (cpu_logical_map(0) == mpidr) {
/*
* boot_cpu_init() already hold bit 0 in cpu_present_mask
* for BSP, no need to allocate again.
*/
cpu = 0;
- } else {
cpu = cpumask_next_zero(-1, cpu_possible_mask);
- }
You may use a ternary operator, more compact and clearer.
BTW you seem to be contradicting yourself. On one hand you keep a counter for enabled_cpus, and then use cpu_possible_mask to allocate a logical cpu id. Make a decision, either you use a counter or you use cpu_possible_mask and its bitweight.
ok.
- /*
* 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.
*/
- if (!acpi_psci_present()) {
pr_warn("CPU %d has no PSCI support, will not boot\n", cpu);
return -EOPNOTSUPP;
- }
This check really does not belong here. You do not even start parsing the gic cpu interfaces if psci is missing or I am missing something myself. Anyway, this check must not be in this function.
I agree with you, i will update the patch.
- /* Get cpu_ops include the boot CPU */
- cpu_ops[cpu] = cpu_get_ops("psci");
- if (!cpu_ops[cpu])
return -EINVAL;
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
set_cpu_possible(cpu, true);
- }
- enabled_cpus++;
See above to me enabled_cpus and (num_possible_cpus() - 1) are identical.
I think I need to remove all the CPU hotplug related code and make this function as simple as possible and introduce them when needed.
Yes that makes sense, even though a bit of foresight is always appreciated; I certainly do not want you to completely rewrite this code to support CPU hotplug to be 100% clear. "Disabled" CPUs is a concept that is not managed at the moment with DT (on ARM and ARM64), and we need to introduce it properly. Again, I was asking questions, to understand why you would need those variables.
Have a look at this discussion:
https://lkml.org/lkml/2013/6/6/470
- return cpu;
+}
+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,
processor->flags & ACPI_MADT_ENABLED);
Ehm. You must check the return value here right (and return an error if that's an error, otherwise the count value below can be botched ?!).
Or you do not consider a parsing error as an error and want to keep parsing remaining GIC CPU IF entries ?
yes, this is my intension. we can skip the error ones and boot other CPUs which have no errors.
- return 0;
+}
+/* Parse GIC cpu interface entries in MADT for SMP init */ +void __init acpi_smp_init_cpus(void) +{
- int count;
- /*
* 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,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- 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;
- }
What would you consider an error ? A single GIC CPU IF entry error ?
could you please explain it in detail? I can't catch up with you, my apologizes.
You explained to me above. A bogus entry does not stop you from parsing other CPUs, this is a design choice and that's what we do in ARM64 DT today, so I would say that's fine.
Lorenzo
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Jon.
Hi Jon,
On 2014年09月09日 12:23, Jon Masters wrote:
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Yes, I agree with you. When I tested this patch set on our ARM64 platform, I found this problem too. some firmware will just present the real MPIDR value to OS which some reserved bit set to 1, and it will lead to some logic problem in this patch. (actually firmware didn't obey with ACPI spec)
I had updated the patch with:
+ acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK, + processor->flags & ACPI_MADT_ENABLED);
and then the problem was gone :)
Thanks Hanjun
On 09/09/2014 12:57 AM, Hanjun Guo wrote:
Hi Jon,
On 2014年09月09日 12:23, Jon Masters wrote:
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Yes, I agree with you. When I tested this patch set on our ARM64 platform, I found this problem too. some firmware will just present the real MPIDR value to OS which some reserved bit set to 1, and it will lead to some logic problem in this patch. (actually firmware didn't obey with ACPI spec)
I had updated the patch with:
- acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
processor->flags & ACPI_MADT_ENABLED);
and then the problem was gone :)
Did I miss an updated patch posting then? It is possible...I was keeping out of this thread for "obvious" reasons (I'm somewhat biased in favor of ACPI on 64-bit ARM server platforms and thus not objective in all cases...so I am confining my feedback to technical specifics). But it's necessary that there be a little more discussion here. I've got a couple of requests into various vendors to get more vocal too.
Jon.
On 2014年09月09日 13:44, Jon Masters wrote:
On 09/09/2014 12:57 AM, Hanjun Guo wrote:
Hi Jon,
On 2014年09月09日 12:23, Jon Masters wrote:
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Yes, I agree with you. When I tested this patch set on our ARM64 platform, I found this problem too. some firmware will just present the real MPIDR value to OS which some reserved bit set to 1, and it will lead to some logic problem in this patch. (actually firmware didn't obey with ACPI spec)
I had updated the patch with:
- acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
processor->flags & ACPI_MADT_ENABLED);
and then the problem was gone :)
Did I miss an updated patch posting then? It is possible...
No, you didn't miss it, I'm still working on the new version, sorry I didn't clarify that in my previous email.
Thanks Hanjun
On 09/09/2014 12:00 PM, Hanjun Guo wrote:
On 2014年09月09日 13:44, Jon Masters wrote:
On 09/09/2014 12:57 AM, Hanjun Guo wrote:
Hi Jon,
On 2014年09月09日 12:23, Jon Masters wrote:
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Yes, I agree with you. When I tested this patch set on our ARM64 platform, I found this problem too. some firmware will just present the real MPIDR value to OS which some reserved bit set to 1, and it will lead to some logic problem in this patch. (actually firmware didn't obey with ACPI spec)
I had updated the patch with:
- acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
processor->flags & ACPI_MADT_ENABLED);
and then the problem was gone :)
Did I miss an updated patch posting then? It is possible...
No, you didn't miss it, I'm still working on the new version, sorry I didn't clarify that in my previous email.
Thanks. If you could copy me on the next posting that would rock. In a few hours we should have another platform posted as an example. In addition, a couple of lower priority patches (building upon the core ACPI pieces) should be posted as well.
Jon.
On 2014年09月10日 00:04, Jon Masters wrote:
On 09/09/2014 12:00 PM, Hanjun Guo wrote:
On 2014年09月09日 13:44, Jon Masters wrote:
On 09/09/2014 12:57 AM, Hanjun Guo wrote:
Hi Jon,
On 2014年09月09日 12:23, Jon Masters wrote:
On 09/01/2014 10:57 AM, Hanjun Guo wrote:
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.
- /* CPU 0 was already initialized */
- if (cpu) {
if (cpu_ops[cpu]->cpu_init(NULL, cpu))
return -EOPNOTSUPP;
/* map the logical cpu id to cpu MPIDR */
cpu_logical_map(cpu) = mpidr;
I'm not sure it's worth noting in a comment or just in the dialogue that none of these MPIDR values is literally the value in the MPIDR. Linux doesn't store that anyway (even in the cpu_logical_map), since it is pre-filtered against MPIDR_HWID_BITMASK to remove the non-affinity level bits. And since the ACPI5.1 specification requires that non-affinity bits be zero everything works. But it relies upon this assumption so it might be worth explicitly masking out the bits when making the call into:
acpi_map_gic_cpu_interface(processor->arm_mpidr, processor->flags & ACPI_MADT_ENABLED);
During the parsing of the processor object's MPIDR value.
Yes, I agree with you. When I tested this patch set on our ARM64 platform, I found this problem too. some firmware will just present the real MPIDR value to OS which some reserved bit set to 1, and it will lead to some logic problem in this patch. (actually firmware didn't obey with ACPI spec)
I had updated the patch with:
- acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
processor->flags & ACPI_MADT_ENABLED);
and then the problem was gone :)
Did I miss an updated patch posting then? It is possible...
No, you didn't miss it, I'm still working on the new version, sorry I didn't clarify that in my previous email.
Thanks. If you could copy me on the next posting that would rock.
Sure I will.
In a few hours we should have another platform posted as an example. In addition, a couple of lower priority patches (building upon the core ACPI pieces) should be posted as well.
That will be great! :)
Thanks Hanjun
On Tue, Sep 09, 2014 at 05:04:15PM +0100, Jon Masters wrote:
On 09/09/2014 12:00 PM, Hanjun Guo wrote:
No, you didn't miss it, I'm still working on the new version, sorry I didn't clarify that in my previous email.
Thanks. If you could copy me on the next posting that would rock. In a few hours we should have another platform posted as an example. In addition, a couple of lower priority patches (building upon the core ACPI pieces) should be posted as well.
Can I breath out yet or did I miss the platform posting?
Will
On 09/11/2014 10:15 AM, Will Deacon wrote:
On Tue, Sep 09, 2014 at 05:04:15PM +0100, Jon Masters wrote:
On 09/09/2014 12:00 PM, Hanjun Guo wrote:
No, you didn't miss it, I'm still working on the new version, sorry I didn't clarify that in my previous email.
Thanks. If you could copy me on the next posting that would rock. In a few hours we should have another platform posted as an example. In addition, a couple of lower priority patches (building upon the core ACPI pieces) should be posted as well.
Can I breath out yet or did I miss the platform posting?
There's a posting for AMD Seattle coming soon as an example. Also, there should be some hardware at Connect on which patches can run.
Jon.
On Mon, 1 Sep 2014 22:57:47 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
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.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org
+/**
- 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 acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled) +{
- int cpu;
- if (mpidr == INVALID_HWID) {
pr_info("Skip invalid cpu hardware ID\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;
- }
- /* No need to check duplicate MPIDRs for the first CPU */
- if (enabled_cpus) {
/*
* Duplicate MPIDRs are a recipe for disaster. Scan
* all initialized entries and check for
* duplicates. If any is found just ignore the CPU.
*/
for_each_possible_cpu(cpu) {
if (cpu_logical_map(cpu) == mpidr) {
pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
mpidr);
return -EINVAL;
}
}
- } else {
/* Fist GICC entry must be BSP as ACPI spec said */
if (cpu_logical_map(0) != mpidr) {
pr_err("First GICC entry is not BSP for MPIDR 0x%llx\n",
mpidr);
return -EINVAL;
}
- }
- /* allocate a logical cpu id for the new comer */
- if (cpu_logical_map(0) == mpidr) {
/*
* boot_cpu_init() already hold bit 0 in cpu_present_mask
* for BSP, no need to allocate again.
*/
cpu = 0;
- } else {
cpu = cpumask_next_zero(-1, cpu_possible_mask);
- }
Nit: so the above two if/else blocks are essentially testing for the same condition: Is this the first cpu? or a secondary cpu? I would merge the two into a single if/else block.
g.
Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained from the GICC Structure introduced by ACPI 5.1.
MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use MPIDR not the GIC CPU interface ID to identify CPUs.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/acpi.h | 32 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/acpi.c | 1 - drivers/acpi/processor_core.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e013dbb..a867467 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,6 +12,8 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H
+#include <asm/smp_plat.h> + /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ @@ -38,6 +40,36 @@ static inline void disable_acpi(void) acpi_noirq = 1; }
+/* MPIDR value provided in GICC structure is 64 bits, but + * the acpi processor driver use the 32 bits cpu hardware + * ID (apic_id on intel platform) everywhere, it is pretty + * hard to modify the acpi processor driver to accept the + * 64 bits MPIDR value, at the same time, only 32 bits of + * the MPIDR is used in the 64 bits MPIDR, just pack the + * Affx fields into a single 32 bit identifier to accommodate + * the acpi processor drivers. + */ +static inline u32 pack_mpidr_into_32_bits(u64 mpidr) +{ + /* + * Bits [0:7] Aff0; + * Bits [8:15] Aff1; + * Bits [16:23] Aff2; + * Bits [32:39] Aff3; + */ + return (u32) ((mpidr & 0xff00000000) >> 8) | mpidr; +} + +/* + * 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. + * + * cpu_logical_map(cpu) is the mapping of MPIDR and the logical cpu, + * and MPIDR is the cpu hardware ID we needed to pack. + */ +#define cpu_physical_id(cpu) pack_mpidr_into_32_bits(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/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index fbaaf01..35dff11 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -24,7 +24,6 @@ #include <linux/bootmem.h> #include <linux/smp.h>
-#include <asm/smp_plat.h> #include <asm/cputype.h> #include <asm/cpu_ops.h>
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e32321c..4007313 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -64,6 +64,38 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; }
+/* + * On ARM platform, MPIDR value is the hardware ID as apic ID + * on Intel platforms + */ +static int map_gicc_mpidr(struct acpi_subtable_header *entry, + int device_declaration, u32 acpi_id, int *mpidr) +{ + struct acpi_madt_generic_interrupt *gicc = + container_of(entry, struct acpi_madt_generic_interrupt, header); + + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return -ENODEV; + + /* In the GIC interrupt model, logical processors are + * required to have a Processor Device object in the DSDT, + * so we should check device_declaration here + */ + if (device_declaration && (gicc->uid == acpi_id)) { + /* + * Only bits [0:7] Aff0, bits [8:15] Aff1, bits [16:23] Aff2 + * and bits [32:39] Aff3 are meaningful, so pack the Affx + * fields into a single 32 bit identifier to accommodate the + * acpi processor drivers. + */ + *mpidr = ((gicc->arm_mpidr & 0xff00000000) >> 8) + | gicc->arm_mpidr; + return 0; + } + + return -EINVAL; +} + static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; @@ -99,6 +131,9 @@ static int 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, &apic_id)) break; + } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { + if (!map_gicc_mpidr(header, type, acpi_id, &apic_id)) + break; } entry += header->length; } @@ -131,6 +166,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_lsapic_id(header, type, acpi_id, &apic_id); } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) { map_x2apic_id(header, type, acpi_id, &apic_id); + } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { + map_gicc_mpidr(header, type, acpi_id, &apic_id); }
exit:
Hi Hanjun,
On Mon, Sep 01, 2014 at 03:57:48PM +0100, Hanjun Guo wrote:
Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained from the GICC Structure introduced by ACPI 5.1.
MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use MPIDR not the GIC CPU interface ID to identify CPUs.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 32 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/acpi.c | 1 - drivers/acpi/processor_core.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e013dbb..a867467 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,6 +12,8 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H +#include <asm/smp_plat.h>
/* Basic configuration for ACPI */ #ifdef CONFIG_ACPI #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ @@ -38,6 +40,36 @@ static inline void disable_acpi(void) acpi_noirq = 1; } +/* MPIDR value provided in GICC structure is 64 bits, but
- the acpi processor driver use the 32 bits cpu hardware
- ID (apic_id on intel platform) everywhere, it is pretty
- hard to modify the acpi processor driver to accept the
- 64 bits MPIDR value, at the same time, only 32 bits of
- the MPIDR is used in the 64 bits MPIDR, just pack the
- Affx fields into a single 32 bit identifier to accommodate
- the acpi processor drivers.
- */
I have comments on the code in this patch, but they are not the most important point. What I am really worried about, it is that as ARM, I do not want to know what an apic_id is. This code is *supposed* to be generic and yet it is chock-full of x86 specific stuff and you are trying to make ARM HW concepts fit with x86 ones, and I am not happy with that.
To be clearer, why does not this look-up of:
logical-cpu-index -> physical-cpu-index
is not carried out using the acpi_id ? Every architecture will have to add arch specific code to carry out the reverse look-up:
acpi_id -> apic_id (x86) acpi_id -> mpidr_el1 (arm64)
and the code would end up being split in a nice way. On top of that, I wonder why ACPI structures like eg struct acpi_processor contain x86 specific data (ie apic_id). I know it is a HW identifier as the MPIDR_EL1 is on arm64, but I do not want to deal with that in generic ACPI code because that's not generic at ALL.
What if another architecture wants to use ACPI ? Are we going to map its HW CPU identifier to an apic_id only because that's what x86 requires ?
I am sorry I do not like that. I understand it is easier to map ARM code to existing ACPI structures but I feel we will run into issues very soon because of that.
Is it that complex to remove the apic_id dependency in *generic* ACPI code and replace it with functions that hook into arch specific code to carry out the logical to physical cpu mappings ?
I understand this is harder to do, but it will make your life easier in the long run. I am thinking of other pieces of code like the supposedly generic ACPI CPUidle driver, where we *still* depend on the apic to detect idle states, this is not going to fly, I am sorry, we need to have code that has a chance to be generic from the beginning not as an afterthought.
Lorenzo
+static inline u32 pack_mpidr_into_32_bits(u64 mpidr) +{
- /*
* Bits [0:7] Aff0;
* Bits [8:15] Aff1;
* Bits [16:23] Aff2;
* Bits [32:39] Aff3;
*/
- return (u32) ((mpidr & 0xff00000000) >> 8) | mpidr;
+}
+/*
- 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.
- cpu_logical_map(cpu) is the mapping of MPIDR and the logical cpu,
- and MPIDR is the cpu hardware ID we needed to pack.
- */
+#define cpu_physical_id(cpu) pack_mpidr_into_32_bits(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/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index fbaaf01..35dff11 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -24,7 +24,6 @@ #include <linux/bootmem.h> #include <linux/smp.h> -#include <asm/smp_plat.h> #include <asm/cputype.h> #include <asm/cpu_ops.h> diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e32321c..4007313 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -64,6 +64,38 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } +/*
- On ARM platform, MPIDR value is the hardware ID as apic ID
- on Intel platforms
- */
+static int map_gicc_mpidr(struct acpi_subtable_header *entry,
int device_declaration, u32 acpi_id, int *mpidr)
+{
- struct acpi_madt_generic_interrupt *gicc =
container_of(entry, struct acpi_madt_generic_interrupt, header);
- if (!(gicc->flags & ACPI_MADT_ENABLED))
return -ENODEV;
- /* In the GIC interrupt model, logical processors are
* required to have a Processor Device object in the DSDT,
* so we should check device_declaration here
*/
- if (device_declaration && (gicc->uid == acpi_id)) {
/*
* Only bits [0:7] Aff0, bits [8:15] Aff1, bits [16:23] Aff2
* and bits [32:39] Aff3 are meaningful, so pack the Affx
* fields into a single 32 bit identifier to accommodate the
* acpi processor drivers.
*/
*mpidr = ((gicc->arm_mpidr & 0xff00000000) >> 8)
| gicc->arm_mpidr;
return 0;
- }
- return -EINVAL;
+}
static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; @@ -99,6 +131,9 @@ static int 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, &apic_id)) break;
} else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
if (!map_gicc_mpidr(header, type, acpi_id, &apic_id))
} entry += header->length; }break;
@@ -131,6 +166,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_lsapic_id(header, type, acpi_id, &apic_id); } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) { map_x2apic_id(header, type, acpi_id, &apic_id);
- } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
}map_gicc_mpidr(header, type, acpi_id, &apic_id);
exit: -- 1.7.9.5
On 2014年09月04日 00:27, Lorenzo Pieralisi wrote:
Hi Hanjun,
Hi Lorenzo,
Sorry for the late reply, some comments below.
On Mon, Sep 01, 2014 at 03:57:48PM +0100, Hanjun Guo wrote:
Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained from the GICC Structure introduced by ACPI 5.1.
MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use MPIDR not the GIC CPU interface ID to identify CPUs.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 32 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/acpi.c | 1 - drivers/acpi/processor_core.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e013dbb..a867467 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,6 +12,8 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H +#include <asm/smp_plat.h>
/* Basic configuration for ACPI */ #ifdef CONFIG_ACPI #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ @@ -38,6 +40,36 @@ static inline void disable_acpi(void) acpi_noirq = 1; } +/* MPIDR value provided in GICC structure is 64 bits, but
- the acpi processor driver use the 32 bits cpu hardware
- ID (apic_id on intel platform) everywhere, it is pretty
- hard to modify the acpi processor driver to accept the
- 64 bits MPIDR value, at the same time, only 32 bits of
- the MPIDR is used in the 64 bits MPIDR, just pack the
- Affx fields into a single 32 bit identifier to accommodate
- the acpi processor drivers.
- */
I have comments on the code in this patch, but they are not the most important point. What I am really worried about, it is that as ARM, I do not want to know what an apic_id is. This code is *supposed* to be generic and yet it is chock-full of x86 specific stuff and you are trying to make ARM HW concepts fit with x86 ones, and I am not happy with that.
apic_id actually represents unique cpu hardware id in MADT to identify a CPU for x86 and ia64, it was introduced before ACPI supports ARM platform, when ARM was introduced to ACPI, it needs some updates as you said.
To be clearer, why does not this look-up of:
logical-cpu-index -> physical-cpu-index
is not carried out using the acpi_id ? Every architecture will have to add arch specific code to carry out the reverse look-up:
acpi_id -> apic_id (x86) acpi_id -> mpidr_el1 (arm64)
and the code would end up being split in a nice way. On top of that, I wonder why ACPI structures like eg struct acpi_processor contain x86 specific data (ie apic_id). I know it is a HW identifier as the MPIDR_EL1 is on arm64, but I do not want to deal with that in generic ACPI code because that's not generic at ALL.
As I said above, apic_id is cpu hardware id in MADT, its name is x86 specific now, but meaning behind the name is not x86 specific, we can rename it as physid or cpu_hw_id, and then will be generic.
Rafael, is it ok to you to rename apic_id to physid or cpu_hw_id in ACPI core for the reason above?
What if another architecture wants to use ACPI ? Are we going to map its HW CPU identifier to an apic_id only because that's what x86 requires ?
I am sorry I do not like that. I understand it is easier to map ARM code to existing ACPI structures but I feel we will run into issues very soon because of that.
Is it that complex to remove the apic_id dependency in *generic* ACPI code and replace it with functions that hook into arch specific code to carry out the logical to physical cpu mappings ?
Yes, I think there is no easy way to fix that, the main reason is that MPIDR for ARM64 is 64bit, and apic_id for x86 and ia64 is no more than 32bit.
thanks Hanjun
I understand this is harder to do, but it will make your life easier in the long run. I am thinking of other pieces of code like the supposedly generic ACPI CPUidle driver, where we *still* depend on the apic to detect idle states, this is not going to fly, I am sorry, we need to have code that has a chance to be generic from the beginning not as an afterthought.
Lorenzo
+static inline u32 pack_mpidr_into_32_bits(u64 mpidr) +{
- /*
* Bits [0:7] Aff0;
* Bits [8:15] Aff1;
* Bits [16:23] Aff2;
* Bits [32:39] Aff3;
*/
- return (u32) ((mpidr & 0xff00000000) >> 8) | mpidr;
+}
+/*
- 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.
- cpu_logical_map(cpu) is the mapping of MPIDR and the logical cpu,
- and MPIDR is the cpu hardware ID we needed to pack.
- */
+#define cpu_physical_id(cpu) pack_mpidr_into_32_bits(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/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index fbaaf01..35dff11 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -24,7 +24,6 @@ #include <linux/bootmem.h> #include <linux/smp.h> -#include <asm/smp_plat.h> #include <asm/cputype.h> #include <asm/cpu_ops.h> diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e32321c..4007313 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -64,6 +64,38 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } +/*
- On ARM platform, MPIDR value is the hardware ID as apic ID
- on Intel platforms
- */
+static int map_gicc_mpidr(struct acpi_subtable_header *entry,
int device_declaration, u32 acpi_id, int *mpidr)
+{
- struct acpi_madt_generic_interrupt *gicc =
container_of(entry, struct acpi_madt_generic_interrupt, header);
- if (!(gicc->flags & ACPI_MADT_ENABLED))
return -ENODEV;
- /* In the GIC interrupt model, logical processors are
* required to have a Processor Device object in the DSDT,
* so we should check device_declaration here
*/
- if (device_declaration && (gicc->uid == acpi_id)) {
/*
* Only bits [0:7] Aff0, bits [8:15] Aff1, bits [16:23] Aff2
* and bits [32:39] Aff3 are meaningful, so pack the Affx
* fields into a single 32 bit identifier to accommodate the
* acpi processor drivers.
*/
*mpidr = ((gicc->arm_mpidr & 0xff00000000) >> 8)
| gicc->arm_mpidr;
return 0;
- }
- return -EINVAL;
+}
static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; @@ -99,6 +131,9 @@ static int 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, &apic_id)) break;
} else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
if (!map_gicc_mpidr(header, type, acpi_id, &apic_id))
} entry += header->length; }break;
@@ -131,6 +166,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_lsapic_id(header, type, acpi_id, &apic_id); } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) { map_x2apic_id(header, type, acpi_id, &apic_id);
- } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
}map_gicc_mpidr(header, type, acpi_id, &apic_id);
exit: -- 1.7.9.5
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.
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 35dff11..354b912 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -37,6 +37,12 @@ EXPORT_SYMBOL(acpi_pci_disabled); static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
/* + * 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. */ @@ -194,6 +200,73 @@ void __init acpi_smp_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 8581f5b..d132c1b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -458,6 +458,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 807cbc4..ed1c2d1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -71,6 +71,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 };
On Mon, 1 Sep 2014 22:57:49 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
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.
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 35dff11..354b912 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -37,6 +37,12 @@ EXPORT_SYMBOL(acpi_pci_disabled); static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */ /*
- 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.
*/ @@ -194,6 +200,73 @@ void __init acpi_smp_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);
Why is this exported? x86 exports it, but ia64 does not. There aren't very many callers, and none of them can be built as a module AFAICS.
+/*
- 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];
*/
Hmmm, so doing it this way means that DT systems will have a different irq_domain setup compared with ACPI systems. I'm not convinced we want to do that, but I need to look at the code that sets up the new domains before I comment further...
g.
On Thu, Sep 11, 2014 at 12:08 PM, Grant Likely grant.likely@linaro.org wrote:
On Mon, 1 Sep 2014 22:57:49 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
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.
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 35dff11..354b912 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -37,6 +37,12 @@ EXPORT_SYMBOL(acpi_pci_disabled); static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
/*
- 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.
*/ @@ -194,6 +200,73 @@ void __init acpi_smp_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);
Why is this exported? x86 exports it, but ia64 does not. There aren't very many callers, and none of them can be built as a module AFAICS.
+/*
- 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];
*/
Hmmm, so doing it this way means that DT systems will have a different irq_domain setup compared with ACPI systems. I'm not convinced we want to do that, but I need to look at the code that sets up the new domains before I comment further...
Okay, nevermind. I looked at the setup code. This isn't an issue of the irq domain being set up differently, but rather the binding translation operates differently between DT and ACPI. ACPI used a single integer encapsulating PPI and SPI which just happens to line up with the hwirq numbers, whereas DT uses a [type,number] tuple that needs translating into the hwirq. This code is fine.
g.
On 2014年09月11日 19:08, Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:49 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
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.
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 35dff11..354b912 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -37,6 +37,12 @@ EXPORT_SYMBOL(acpi_pci_disabled); static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */ /*
- 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.
*/ @@ -194,6 +200,73 @@ void __init acpi_smp_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);
Why is this exported? x86 exports it, but ia64 does not. There aren't very many callers, and none of them can be built as a module AFAICS.
It will be called by Generic Hardware Error Source driver which can be built as module, and it provides a way to report platform hardware errors (such as that from chipset) which can also used by ARM platform, so I think we can keep it as exported.
Thanks Hanjun
From: Ashwin Chaugule ashwin.chaugule@linaro.org
The acpi_table_parse() function has a callback that passes a pointer to a table_header. Add a new function which takes this pointer and parses its entries. This eliminates the need to re-traverse all the tables for each call. e.g. as in acpi_table_parse_madt() which is normally called after acpi_table_parse().
Signed-off-by: Ashwin Chaugule ashwin.chaugule@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/tables.c | 70 +++++++++++++++++++++++++++++++++++-------------- include/linux/acpi.h | 4 +++ 2 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index a97d2aa..4ab7566 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -235,17 +235,14 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
int __init -acpi_table_parse_entries(char *id, - unsigned long table_size, - int entry_id, - acpi_tbl_entry_handler handler, - unsigned int max_entries) +acpi_parse_entries(unsigned long table_size, + acpi_tbl_entry_handler handler, + struct acpi_table_header *table_header, + int entry_id, unsigned int max_entries) { - struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *entry; - unsigned int count = 0; + int count = 0; unsigned long table_end; - acpi_size tbl_size;
if (acpi_disabled) return -ENODEV; @@ -253,13 +250,11 @@ acpi_table_parse_entries(char *id, if (!handler) return -EINVAL;
- if (strncmp(id, ACPI_SIG_MADT, 4) == 0) - acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); - else - acpi_get_table_with_size(id, 0, &table_header, &tbl_size); + if (!table_size) + return -EINVAL;
if (!table_header) { - pr_warn("%4.4s not present\n", id); + pr_warn("Table header not present\n"); return -ENODEV; }
@@ -274,31 +269,66 @@ acpi_table_parse_entries(char *id, table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) - if (handler(entry, table_end)) + if (handler(entry, table_end)) { + count = -EINVAL; goto err; + }
/* * If entry->length is 0, break from this loop to avoid * infinite loop. */ if (entry->length == 0) { - pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); + pr_err("[0x%02x] Invalid zero length\n", entry_id); + count = -EINVAL; goto err; }
entry = (struct acpi_subtable_header *) ((unsigned long)entry + entry->length); } + if (max_entries && count > max_entries) { - pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n", - id, entry_id, count - max_entries, count); + pr_warn("[0x%02x] ignored %i entries of %i found\n", + entry_id, count - max_entries, count); }
- early_acpi_os_unmap_memory((char *)table_header, tbl_size); - return count; err: + return count; +} + +int __init +acpi_table_parse_entries(char *id, + unsigned long table_size, + int entry_id, + acpi_tbl_entry_handler handler, + unsigned int max_entries) +{ + struct acpi_table_header *table_header = NULL; + acpi_size tbl_size; + int count; + + if (acpi_disabled) + return -ENODEV; + + if (!handler) + return -EINVAL; + + if (strncmp(id, ACPI_SIG_MADT, 4) == 0) + acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); + else + acpi_get_table_with_size(id, 0, &table_header, &tbl_size); + + if (!table_header) { + pr_warn("%4.4s not present\n", id); + return -ENODEV; + } + + count = acpi_parse_entries(table_size, handler, table_header, + entry_id, max_entries); + early_acpi_os_unmap_memory((char *)table_header, tbl_size); - return -EINVAL; + return count; }
int __init diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ed1c2d1..a9d79c2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -124,6 +124,10 @@ int acpi_numa_init (void);
int acpi_table_init (void); int acpi_table_parse(char *id, acpi_tbl_table_handler handler); +int __init acpi_parse_entries(unsigned long table_size, + acpi_tbl_entry_handler handler, + struct acpi_table_header *table_header, + int entry_id, unsigned int max_entries); int __init acpi_table_parse_entries(char *id, unsigned long table_size, int entry_id, acpi_tbl_entry_handler handler,
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535 - #else
static inline bool acpi_psci_present(void) { return false; } diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{ + struct acpi_table_header *table; + acpi_status status; + acpi_size tbl_size; + int err; + + 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); +} + /* * acpi_suspend_lowlevel() - save kernel state and suspend. * diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init(); + + if (!handle_arch_irq) + acpi_gic_init(); + if (!handle_arch_irq) panic("No interrupt controller found."); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX; + +static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + u64 gic_cpu_base; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + gic_cpu_base = processor->base_address; + if (!gic_cpu_base) + return -EFAULT; + + /* + * There is no support for non-banked GICv1/2 register in ACPI spec. + * All CPU interface addresses have to be the same. + */ + if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base) + return -EFAULT; + + cpu_phy_base = gic_cpu_base; + 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; + if (!dist_phy_base) + return -EFAULT; + + 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(sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_cpu, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, + ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES); + if (count < 0) { + pr_err("Error during GICC entries parsing\n"); + return -EFAULT; + } else if (!count) { + /* No GICC entries provided, use address from MADT header */ + struct acpi_table_madt *madt = (struct acpi_table_madt *)table; + + if (!madt->address) + return -EFAULT; + + cpu_phy_base = (u64)madt->address; + } + + /* + * 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(sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_distributor, table, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, + ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES); + if (count <= 0) { + pr_err("Error during GICD entries parsing\n"); + return -EFAULT; + } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014, Linaro Ltd. + * Author: Tomasz Nowicki tomasz.nowicki@linaro.org + * + * 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_ + +#include <linux/acpi.h> + +#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535 +#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1 + +/* + * 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_GIC_DIST_MEM_SIZE (SZ_64K) +#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) + +void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif + +#endif /* ARM_GIC_ACPI_H_ */
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0 -#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else static inline bool acpi_psci_present(void) { return false; } diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h> #include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); } +void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
/*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h> unsigned long irq_err_count; @@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
if (!handle_arch_irq) panic("No interrupt controller found."); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h> #include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
+#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1
+/*
- 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_GIC_DIST_MEM_SIZE (SZ_64K)
I don't know which version of the spec you're looking at, but my version of the GICv2 spec has a 4kB distributor. Also, it would be good to make obvious which GIC version this define is about.
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif
+#endif /* ARM_GIC_ACPI_H_ */
In the end, why do we need a separate file for this? I cannot see anything that prevents it from being merged with arm-gic.h.
Thanks,
M.
On 1 September 2014 19:35, Marc Zyngier marc.zyngier@arm.com wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
Just a heads up for this, I run up to this problem too while testing and by forcing some values for vgic and arch_timers I could boot a QEMU guest without problems.
I'll try and see if it will be easy to handle this more properly instead of hardcoded values.
Regards.
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
if (!handle_arch_irq) panic("No interrupt controller found."); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
+#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1
+/*
- 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_GIC_DIST_MEM_SIZE (SZ_64K)
I don't know which version of the spec you're looking at, but my version of the GICv2 spec has a 4kB distributor. Also, it would be good to make obvious which GIC version this define is about.
OK
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif
+#endif /* ARM_GIC_ACPI_H_ */
In the end, why do we need a separate file for this? I cannot see anything that prevents it from being merged with arm-gic.h.
Thanks,
M.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Regards, Tomasz
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
+#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1
+/*
- 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_GIC_DIST_MEM_SIZE (SZ_64K)
I don't know which version of the spec you're looking at, but my version of the GICv2 spec has a 4kB distributor. Also, it would be good to make obvious which GIC version this define is about.
OK
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif
+#endif /* ARM_GIC_ACPI_H_ */
In the end, why do we need a separate file for this? I cannot see anything that prevents it from being merged with arm-gic.h.
Thanks,
M.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
Thanks,
M.
On 2014年09月02日 21:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
Thanks Hanjun
On 02/09/14 16:45, Hanjun Guo wrote:
On 2014年09月02日 21:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
Then it is worth mentioning that this is an arbitrary limit, unrelated to what the architecture describes.
Thanks,
M.
On 02/09/14 16:45, Hanjun Guo wrote:
On 2014年09月02日 21:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
This is the exact reason I kept mentioning *not to link it with GIC architecture* in my previous reviews. It's just *max possible entries in MADT*.
Regards, Sudeep
On 02/09/14 16:45, Hanjun Guo wrote:
On 2014年09月02日 21:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
Also, with GICv3++, there is no such thing as a memory-mapped CPU interface anymore. What you get is a bunch of redistributors (one per CPU). I assume what you have here actually describe the redistributors, and its name should reflect that.
Thanks,
M.
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
Also, with GICv3++, there is no such thing as a memory-mapped CPU interface anymore. What you get is a bunch of redistributors (one per CPU). I assume what you have here actually describe the redistributors, and its name should reflect that.
As Sudeep said, it is not to link to GIC architecture, so I think we can keep it stick with ACPI spec, in ACPI spec, it called "GICC structure" (section 5.2.12.14 in ACPI 5.1), so we can name it as ACPI_MAX_GICC_STRUCTURE_ENTRIES no matter GICv2 or GICv3/4 (with GICv2, it may have more than 8 entries with some disabled ones, will no more than 8 enabled entries).
What do you think?
Thanks Hanjun
On 2014年09月03日 19:17, Hanjun Guo wrote:
> + > +#ifdef CONFIG_ACPI > +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535 With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
This value is for max processors entries in MADT, and we will use it to scan MADT for SMP/GIC Init, I just make it big enough for GICv3/4. since ACPI core will stop scan MADT if the real numbers of processors entries are reached no matter how big ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES is, I think we can just define a number big enough then it will work (x86 and ia64 did the same thing).
Also, with GICv3++, there is no such thing as a memory-mapped CPU interface anymore. What you get is a bunch of redistributors (one per CPU). I assume what you have here actually describe the redistributors, and its name should reflect that.
As Sudeep said, it is not to link to GIC architecture, so I think we can keep it stick with ACPI spec, in ACPI spec, it called "GICC structure" (section 5.2.12.14 in ACPI 5.1), so we can name it as ACPI_MAX_GICC_STRUCTURE_ENTRIES no matter GICv2 or GICv3/4 (with GICv2, it may have more than 8 entries with some disabled ones, will no more than 8 enabled entries).
What do you think?
After more consideration on this, we think that we can remove those macros which introduce confusions, and just pass 0 to ACPI core for the max entries of GICC structure or GICR structure, ACPI core will continue scan all the entries in MADT with 0 passed. With that, we can avoid such name confusions for all GIC related structures in MADT no matter GICv2 or GICv3/4.
Thanks Hanjun
On 02.09.2014 15:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
+#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1
+/*
- 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_GIC_DIST_MEM_SIZE (SZ_64K)
I don't know which version of the spec you're looking at, but my version of the GICv2 spec has a 4kB distributor. Also, it would be good to make obvious which GIC version this define is about.
OK
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif
+#endif /* ARM_GIC_ACPI_H_ */
In the end, why do we need a separate file for this? I cannot see anything that prevents it from being merged with arm-gic.h.
Thanks,
M.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
We had that discussion but I see we still don't have consensus here. It would be good to know our direction before we prepare next patch version. Arnd any comments on this from you side?
Tomasz
On Wednesday 03 September 2014 11:26:14 Tomasz Nowicki wrote:
On 02.09.2014 15:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
We had that discussion but I see we still don't have consensus here. It would be good to know our direction before we prepare next patch version. Arnd any comments on this from you side?
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
Arnd
On 03.09.2014 16:57, Arnd Bergmann wrote:
On Wednesday 03 September 2014 11:26:14 Tomasz Nowicki wrote:
On 02.09.2014 15:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
We had that discussion but I see we still don't have consensus here. It would be good to know our direction before we prepare next patch version. Arnd any comments on this from you side?
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
Yes, it is just one table with bunch of different subtables types. Since GIC identification register is at different offset across GICv1/2 and GICv3, the probe logic seems to be slightly different. IMO, we should look into our MADT and try GICv3 fist and then GICv2, that means presence of redistributor entries suggests GICv3/4. Its absence means we need to look for GICC subtables and then call GICv2 init.
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
We already had tried making MADT parser common for all GICs in the separate file (outside GIC driver), it did not end up well. In the light of above comment, the logic will be complex and some GIC local strutures need to be exported: 1. Check redistributor entries. 2. If none exist, as fallback, check GICC entries, there are redistributor base address assigned to CPU. Unfortunately it has no register set size so ioremap only two pages (RD + SGI) check if we support VLPI and extend ioremap if true. We cannot operate on GIC register outside GIC driver so that requires another exported GICv3 function. 3. Jump to redistributor part if we are OK so far, if not, then we start playing with GICC enries and look for cpu base addresses.
Honestly, apart from distributor parsing logic, there is no common code.
As you can see, current gic_v2_acpi_init() logic is quite easy to follow. And gic_v3_acpi_init() inside of GICv3 driver is easy too. I might not see other solutions but I am open to other suggestions, so please correct me in that case.
Regards, Tomasz
On 03/09/14 15:57, Arnd Bergmann wrote:
On Wednesday 03 September 2014 11:26:14 Tomasz Nowicki wrote:
On 02.09.2014 15:02, Marc Zyngier wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
We had that discussion but I see we still don't have consensus here. It would be good to know our direction before we prepare next patch version. Arnd any comments on this from you side?
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
I'm not suggesting that we should support more than the ACPI spec says. And that's certainly the whole point of a spec, isn't it? ACPI says what we support, and we're not going any further. I'm just saying that we shouldn't make the maintenance burden heavier, and the code nothing short of disgusting. Using our current infrastructure doesn't mean we're going to support GIcv2.37.
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
This is not the way I read the spec. Table 5-46 (Interrupt Controller Structure) tells you if you have a CPU interface (GICv1/v2) or a redistributor (GICv3/v4). That's enough to know whether or not you should carry on probing a particular controller.
The various GIC versions don't really have a unified memory map anyway (well, none that you can rely on), and you really have to rely on ACPI to tell you what you have.
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
I don't think so you can make that common code very easily. The information required by both drivers is organized differently. If it was, I'd have done that for the DT binding.
Thanks,
M.
On Friday 05 September 2014 10:47:30 Marc Zyngier wrote:
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
I'm not suggesting that we should support more than the ACPI spec says. And that's certainly the whole point of a spec, isn't it? ACPI says what we support, and we're not going any further. I'm just saying that we shouldn't make the maintenance burden heavier, and the code nothing short of disgusting. Using our current infrastructure doesn't mean we're going to support GIcv2.37.
Ok
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
This is not the way I read the spec. Table 5-46 (Interrupt Controller Structure) tells you if you have a CPU interface (GICv1/v2) or a redistributor (GICv3/v4). That's enough to know whether or not you should carry on probing a particular controller.
Ah, good. I missed that.
The various GIC versions don't really have a unified memory map anyway (well, none that you can rely on), and you really have to rely on ACPI to tell you what you have.
So we are back to needing to support two different irqchip drivers (v1/v2/v2m and v3/v4), instead of five or more, right?
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
I don't think so you can make that common code very easily. The information required by both drivers is organized differently. If it was, I'd have done that for the DT binding.
I see, and that's also what Tomasz just explained. So can we just have one an irqchip_init() function doing this:?
if (dt) of_irq_init(__irqchip_of_table); else if (acpi) { read cpu-interface and redistributor address from acpi tables if (cpu-interface) gic_v2_acpi_init(table); else if(redistributor) gic_v3_acpi_init(table) }
Arnd
On 05.09.2014 12:13, Arnd Bergmann wrote:
On Friday 05 September 2014 10:47:30 Marc Zyngier wrote:
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
I'm not suggesting that we should support more than the ACPI spec says. And that's certainly the whole point of a spec, isn't it? ACPI says what we support, and we're not going any further. I'm just saying that we shouldn't make the maintenance burden heavier, and the code nothing short of disgusting. Using our current infrastructure doesn't mean we're going to support GIcv2.37.
Ok
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
This is not the way I read the spec. Table 5-46 (Interrupt Controller Structure) tells you if you have a CPU interface (GICv1/v2) or a redistributor (GICv3/v4). That's enough to know whether or not you should carry on probing a particular controller.
Ah, good. I missed that.
The various GIC versions don't really have a unified memory map anyway (well, none that you can rely on), and you really have to rely on ACPI to tell you what you have.
So we are back to needing to support two different irqchip drivers (v1/v2/v2m and v3/v4), instead of five or more, right?
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
I don't think so you can make that common code very easily. The information required by both drivers is organized differently. If it was, I'd have done that for the DT binding.
I see, and that's also what Tomasz just explained. So can we just have one an irqchip_init() function doing this:?
if (dt) of_irq_init(__irqchip_of_table); else if (acpi) { read cpu-interface and redistributor address from acpi tables if (cpu-interface) gic_v2_acpi_init(table); else if(redistributor) gic_v3_acpi_init(table) }
It is pretty much the same as: if (dt) of_irq_init(__irqchip_of_table); else if (acpi) { err = gic_v3_acpi_init(table) { read redistributor address from acpi tables [...] } if (err) { err = gic_v2_acpi_init(table) { read cpu-interface address from acpi tables [...] } } } What basically is my current implementation (well, without GICv3 support but that will be next step).
Tomasz
On 05/09/14 11:13, Arnd Bergmann wrote:
On Friday 05 September 2014 10:47:30 Marc Zyngier wrote:
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
I'm not suggesting that we should support more than the ACPI spec says. And that's certainly the whole point of a spec, isn't it? ACPI says what we support, and we're not going any further. I'm just saying that we shouldn't make the maintenance burden heavier, and the code nothing short of disgusting. Using our current infrastructure doesn't mean we're going to support GIcv2.37.
Ok
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
This is not the way I read the spec. Table 5-46 (Interrupt Controller Structure) tells you if you have a CPU interface (GICv1/v2) or a redistributor (GICv3/v4). That's enough to know whether or not you should carry on probing a particular controller.
Ah, good. I missed that.
The various GIC versions don't really have a unified memory map anyway (well, none that you can rely on), and you really have to rely on ACPI to tell you what you have.
So we are back to needing to support two different irqchip drivers (v1/v2/v2m and v3/v4), instead of five or more, right?
As long as we make sure that the variants are directly probed from the "canonical" driver (v2m from v2, ITS and v4 from v3), then we're OK.
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
I don't think so you can make that common code very easily. The information required by both drivers is organized differently. If it was, I'd have done that for the DT binding.
I see, and that's also what Tomasz just explained. So can we just have one an irqchip_init() function doing this:?
if (dt) of_irq_init(__irqchip_of_table); else if (acpi) { read cpu-interface and redistributor address from acpi tables if (cpu-interface) gic_v2_acpi_init(table); else if(redistributor) gic_v3_acpi_init(table) }
That'd be better, but that only considers the basic architecture. GICv2m and GICv3's ITS bring additional complexity (and their own table parsing). At that stage, I'm not sure how much commonality we're left with.
Thanks,
M.
On 05.09.2014 12:39, Marc Zyngier wrote:
On 05/09/14 11:13, Arnd Bergmann wrote:
On Friday 05 September 2014 10:47:30 Marc Zyngier wrote:
I still prefer being explicit here for the same reason I mentioned earlier: I want it to be very clear that we don't support arbitrary irqchips other than the ones in the APCI specification. The infrastructure exists on DT because we have to support a large number of incompatible irqchips.
I'm not suggesting that we should support more than the ACPI spec says. And that's certainly the whole point of a spec, isn't it? ACPI says what we support, and we're not going any further. I'm just saying that we shouldn't make the maintenance burden heavier, and the code nothing short of disgusting. Using our current infrastructure doesn't mean we're going to support GIcv2.37.
Ok
In particular, the ACPI tables describing the irqchip have no way to identify the GIC at all, if I read the spec correctly, you have to parse the tables, ioremap the registers and then read the ID to know if you have GICv1/v2/v2m/v3/v4. There doesn't seem to be any "device" for the GIC that a hypothetical probe function would be based on.
This is not the way I read the spec. Table 5-46 (Interrupt Controller Structure) tells you if you have a CPU interface (GICv1/v2) or a redistributor (GICv3/v4). That's enough to know whether or not you should carry on probing a particular controller.
Ah, good. I missed that.
The various GIC versions don't really have a unified memory map anyway (well, none that you can rely on), and you really have to rely on ACPI to tell you what you have.
So we are back to needing to support two different irqchip drivers (v1/v2/v2m and v3/v4), instead of five or more, right?
As long as we make sure that the variants are directly probed from the "canonical" driver (v2m from v2, ITS and v4 from v3), then we're OK.
Yes, that is our intention.
It does seem wrong to parse the tables in the irq-gic.c file though: that part can well be common across the various gic versions and then call into either irq-gic.c or irq-gic-v3.c for the version specific parts. Whether we put that common code into drivers/irqchip/irqchip.c, drivers/irqchip/gic-common.c, drivers/irqchip/irq-acpi-gic.c or drivers/acpi/irq-gic.c I don't care at all.
I don't think so you can make that common code very easily. The information required by both drivers is organized differently. If it was, I'd have done that for the DT binding.
I see, and that's also what Tomasz just explained. So can we just have one an irqchip_init() function doing this:?
if (dt) of_irq_init(__irqchip_of_table); else if (acpi) { read cpu-interface and redistributor address from acpi tables if (cpu-interface) gic_v2_acpi_init(table); else if(redistributor) gic_v3_acpi_init(table) }
That'd be better, but that only considers the basic architecture. GICv2m and GICv3's ITS bring additional complexity (and their own table parsing). At that stage, I'm not sure how much commonality we're left with.
Right, my local ACPI GICv3 support assumes to probe ITS from gic_v3_acpi_init() body.
Tomasz
On Tue, 02 Sep 2014 14:02:31 +0100, Marc Zyngier marc.zyngier@arm.com wrote:
On 02/09/14 12:48, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
No. irqchip.c is not OF dependent, it is just that DT is the only thing we support so far. I don't think duplicating the kernel infrastructure "because we're different" is the right way.
There is no reason for your probing structure to be artificially different (you're parsing the same information, at the same time). Just put in place a similar probing mechanism, and this will look a lot better.
if (!handle_arch_irq) panic("No interrupt controller found.");
} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e6..85cbf43 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/irq.h> @@ -1029,3 +1031,115 @@ 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 u64 dist_phy_base, cpu_phy_base = ULONG_MAX;
Please use phys_addr_t for physical addresses. The use of ULONG_MAX looks dodgy. Please have a proper symbol to flag the fact that it hasn't been assigned yet.
Sure, will do.
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- u64 gic_cpu_base;
phys_addr_t
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- gic_cpu_base = processor->base_address;
- if (!gic_cpu_base)
return -EFAULT;
Is zero an invalid address?
Yeah, good point.
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- if (cpu_phy_base != ULONG_MAX && gic_cpu_base != cpu_phy_base)
return -EFAULT;
- cpu_phy_base = gic_cpu_base;
- 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;
- if (!dist_phy_base)
return -EFAULT;
Same question about zero.
- 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
- } else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
- }
- /*
* 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(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES);
- if (count <= 0) {
pr_err("Error during GICD entries parsing\n");
return -EFAULT;
- } 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_GIC_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/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 0000000..ce2ae1a8 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,33 @@ +/*
- Copyright (C) 2014, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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_
+#include <linux/acpi.h>
Do we need linux/acpi.h here? You could have a separate forward declaration of struct acpi_table_header, specially in the light of my last remark below.
Indeed, we can do forward declaration instead of #include <linux/acpi.h>. Thanks!
+#ifdef CONFIG_ACPI +#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
With GICv2? I doubt it.
I will create macro for each GIC driver: #define ACPI_MAX_GICV2_CPU_INTERFACE_ENTRIES 8 #define ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES 65535
Where do you get this value (ACPI_MAX_GICV3_CPU_INTERFACE_ENTRIES) from?
+#define ACPI_MAX_GIC_DISTRIBUTOR_ENTRIES 1
+/*
- 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_GIC_DIST_MEM_SIZE (SZ_64K)
I don't know which version of the spec you're looking at, but my version of the GICv2 spec has a 4kB distributor. Also, it would be good to make obvious which GIC version this define is about.
OK
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+void acpi_gic_init(void); +int gic_v2_acpi_init(struct acpi_table_header *table); +#else +static inline void acpi_gic_init(void) { } +#endif
+#endif /* ARM_GIC_ACPI_H_ */
In the end, why do we need a separate file for this? I cannot see anything that prevents it from being merged with arm-gic.h.
Thanks,
M.
Having only GICv2, it would work. Considering we would do the same for GICv3 (arm-gic-v3.h) there will be register name conflicts for both headers inclusion:
[...] #include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-v3.h> [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] So instead of changing register names prefix, I choose new header will be less painfully.
Yes, and this is exactly why I pushed back on that last time. I'll continue saying that interrupt controllers should be self-probing, with ACPI as they are with DT.
We are in a completely different situation with ACPI compared to DT. In ACPI there is currently exactly one interrupt controller that is allowed (GICv2). In the near future there will be a second one (GICv3). There is zero need to have a infrastructure to abstract a pluggable interface for registering interrupt controllers.
With DT we've got a tonne of controllers that we need to support. The pluggable infrastructure was created because we needed it for maintenance.
All we're really talking about here is a table of registered irq controllers vs. a few lines of if/else if/else initialization code. The moment it gets unwieldy, we will refactor it. Until then, the if/else block is better code.
As for putting the ACPI hook into irqchip_init(), I don't doing so buys us anything. Common code is good when it is common, but in this case there is no other platform is going to use this ACPI irq initialization. Not x86, not ia64. It is ARM64 specific code and moving it out from arm64 doesn't make sense.
I'm not going to grump and complain if Hanjun decides to move it into irqchip_init() anyway, but, I don't think this is an issue that should block the patch series.
g.
Even with the restrictions of ACPI and SBSA, we end-up with at least 2 main families of interrupt controllers (GICv2 and GICv3), both with a number of "interesting" variations (GICv2m and GICv4, to only mention those I'm directly involved with).
I can safely predict that the above will become a tangled mess within 18 months, and the idea of littering the arch code with a bunch of hardcoded "if (blah())" doesn't fill me with joy and confidence.
In summary: we have the infrastructure already, just use it.
Thanks,
M.
Jazz is not dead. It just smells funny...
On Tue, Sep 02, 2014 at 12:48:37PM +0100, Tomasz Nowicki wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
It's also worth mentioning if there are any plans to fix this ;).
On Tue, 02 Sep 2014 13:48:37 +0200, Tomasz Nowicki tomasz.nowicki@linaro.org wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
It doesn't have to be that way, but given that ARM64 is the only platform in the foreseeable future that will use ACPI irq setup, it doesn't make sense to put it in there.
g.
Hi Grant,
On 11/09/14 12:48, Grant Likely wrote:
On Tue, 02 Sep 2014 13:48:37 +0200, Tomasz Nowicki tomasz.nowicki@linaro.org wrote:
On 01.09.2014 19:35, Marc Zyngier wrote:
On 01/09/14 15:57, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
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 only.
I cannot help but notice that there is no support for KVM here. It'd be good to add a note to that effect, so that people do not expect virtualization support to be working when booting with ACPI.
yes, it is worth mentioning!
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/include/asm/acpi.h | 2 - arch/arm64/kernel/acpi.c | 23 +++++++ arch/arm64/kernel/irq.c | 5 ++ drivers/irqchip/irq-gic.c | 114 ++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 33 ++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 include/linux/irqchip/arm-gic-acpi.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index a867467..5d2ab63 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -97,8 +97,6 @@ void __init acpi_smp_init_cpus(void); extern int (*acpi_suspend_lowlevel)(void); #define acpi_wakeup_address 0
-#define ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES 65535
#else
static inline bool acpi_psci_present(void) { return false; }
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 354b912..b3b82b0 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -23,6 +23,7 @@ #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/smp.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h> #include <asm/cpu_ops.h> @@ -313,6 +314,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT or error happened during parsing FADT\n"); }
+void __init acpi_gic_init(void) +{
- struct acpi_table_header *table;
- acpi_status status;
- acpi_size tbl_size;
- int err;
- 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");
What will happen when you get to implement GICv3 support? Another entry like this? Why isn't this entirely contained in the GIC driver? Do I sound like a stuck record?
There will be another call to GICv3 init: [...] err = gic_v3_acpi_init(table); if (err) err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); [...] This is the main reason I put common code here.
- early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
- /*
- acpi_suspend_lowlevel() - save kernel state and suspend.
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 0f08dfd..c074d60 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -28,6 +28,7 @@ #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> +#include <linux/irqchip/arm-gic-acpi.h>
unsigned long irq_err_count;
@@ -78,6 +79,10 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) void __init init_IRQ(void) { irqchip_init();
- if (!handle_arch_irq)
acpi_gic_init();
Why isn't this called from irqchip_init? It would seem like the logical spot to probe an interrupt controller.
irqchip.c is OF dependent, I want to decouple these from the very beginning.
It doesn't have to be that way, but given that ARM64 is the only platform in the foreseeable future that will use ACPI irq setup, it doesn't make sense to put it in there.
I have a different perspective. There is no reason to pollute the arch code with something that is essentially platform specific.
irqchip_init is the logical place to probe for an irqchip, and I fail to see the point of sticking this code somewhere else. Why would ACPI be so special that it requires additional hooks in the arch code?
Thanks,
M.
On Monday 01 September 2014 22:57:51 Hanjun Guo wrote:
/* Collect CPU base addresses */
count = acpi_parse_entries(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
} else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
}
After I read through ACPI-5.1 section 5.2.12.14, I wonder if this is the best way to treat a missing ACPI_MADT_TYPE_GENERIC_INTERRUPT table.
Do we expect to see those in practice? It seems like using the x86 local APIC address as a fallback for the GIC address is not something we should do unless we absolutely have to support a system that doesn't have the GIC table.
Arnd
On 03.09.2014 20:42, Arnd Bergmann wrote:
On Monday 01 September 2014 22:57:51 Hanjun Guo wrote:
/* Collect CPU base addresses */
count = acpi_parse_entries(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
} else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
}
After I read through ACPI-5.1 section 5.2.12.14, I wonder if this is the best way to treat a missing ACPI_MADT_TYPE_GENERIC_INTERRUPT table.
Do we expect to see those in practice? It seems like using the x86 local APIC address as a fallback for the GIC address is not something we should do unless we absolutely have to support a system that doesn't have the GIC table.
No, we do not expect and hopefully there will be no such :)
But, we are trying to be as much as possible inline with 5.1 spec, 5.2.12.14 says: [...] If provided here (CPU physical base address), the "Local Interrupt Controller Address" field in the MADT must be ignored by the OSPM. [...]
Regards, Tomasz
On Thursday 04 September 2014 12:10:28 Tomasz Nowicki wrote:
On 03.09.2014 20:42, Arnd Bergmann wrote:
On Monday 01 September 2014 22:57:51 Hanjun Guo wrote:
/* Collect CPU base addresses */
count = acpi_parse_entries(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
} else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
}
After I read through ACPI-5.1 section 5.2.12.14, I wonder if this is the best way to treat a missing ACPI_MADT_TYPE_GENERIC_INTERRUPT table.
Do we expect to see those in practice? It seems like using the x86 local APIC address as a fallback for the GIC address is not something we should do unless we absolutely have to support a system that doesn't have the GIC table.
No, we do not expect and hopefully there will be no such
But, we are trying to be as much as possible inline with 5.1 spec, 5.2.12.14 says: [...] If provided here (CPU physical base address), the "Local Interrupt Controller Address" field in the MADT must be ignored by the OSPM. [...]
Yes, that's what I saw. So ignoring it all the time is fine, right? Presumably the madt->address field is only referenced here because some pre-5.1 implementations used to do that.
Arnd
On 04.09.2014 12:14, Arnd Bergmann wrote:
On Thursday 04 September 2014 12:10:28 Tomasz Nowicki wrote:
On 03.09.2014 20:42, Arnd Bergmann wrote:
On Monday 01 September 2014 22:57:51 Hanjun Guo wrote:
/* Collect CPU base addresses */
count = acpi_parse_entries(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
} else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
}
After I read through ACPI-5.1 section 5.2.12.14, I wonder if this is the best way to treat a missing ACPI_MADT_TYPE_GENERIC_INTERRUPT table.
Do we expect to see those in practice? It seems like using the x86 local APIC address as a fallback for the GIC address is not something we should do unless we absolutely have to support a system that doesn't have the GIC table.
No, we do not expect and hopefully there will be no such
But, we are trying to be as much as possible inline with 5.1 spec, 5.2.12.14 says: [...] If provided here (CPU physical base address), the "Local Interrupt Controller Address" field in the MADT must be ignored by the OSPM. [...]
Yes, that's what I saw. So ignoring it all the time is fine, right? Presumably the madt->address field is only referenced here because some pre-5.1 implementations used to do that.
So this is very vague statement. On the one hand it would make sense to take madt->address if we have no GICC entries. On the other hand we do not support non-banked GIC cpu registers. So all of then need to have the same cpu_base_address. What if one has null address? Should the rest take madt->address? I think you are right, I will remove madt->address fallback and simplify the code.
Thanks, Tomasz
On 09/03/2014 02:42 PM, Arnd Bergmann wrote:
On Monday 01 September 2014 22:57:51 Hanjun Guo wrote:
/* Collect CPU base addresses */
count = acpi_parse_entries(sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
if (count < 0) {
pr_err("Error during GICC entries parsing\n");
return -EFAULT;
} else if (!count) {
/* No GICC entries provided, use address from MADT header */
struct acpi_table_madt *madt = (struct acpi_table_madt *)table;
if (!madt->address)
return -EFAULT;
cpu_phy_base = (u64)madt->address;
}
After I read through ACPI-5.1 section 5.2.12.14, I wonder if this is the best way to treat a missing ACPI_MADT_TYPE_GENERIC_INTERRUPT table.
Do we expect to see those in practice? It seems like using the x86 local APIC address as a fallback for the GIC address is not something we should do unless we absolutely have to support a system that doesn't have the GIC table.
All GICv2 based ACPI systems should define GICCs for the CPU interfaces.
Jon.
Using the information presented by GTDT to initialize the arch timer (not memory-mapped).
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/kernel/time.c | 7 ++ drivers/clocksource/arm_arch_timer.c | 117 ++++++++++++++++++++++++++++------ include/linux/clocksource.h | 6 ++ 3 files changed, 111 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 1a7125c..42f9195 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -35,6 +35,7 @@ #include <linux/delay.h> #include <linux/clocksource.h> #include <linux/clk-provider.h> +#include <linux/acpi.h>
#include <clocksource/arm_arch_timer.h>
@@ -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 5163ec1..397783f 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/sched_clock.h> +#include <linux/acpi.h>
#include <asm/arch_timer.h> #include <asm/virt.h> @@ -338,8 +339,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 @@ -635,20 +640,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 HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -667,13 +660,31 @@ 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"); + + 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) { @@ -740,3 +751,71 @@ 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 653f0e2..5839f98 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -346,4 +346,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 */
From: Al Stone al.stone@linaro.org
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.
Reviewed-by: Grant Likely grant.likely@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index fd4e81a..065438c 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_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_SG_CHAIN select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
From: Graeme Gregory graeme.gregory@linaro.org
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.
Reviewed-by: Grant Likely grant.likely@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/Kconfig | 2 ++ drivers/acpi/Kconfig | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 065438c..8dabaeb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -422,6 +422,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 d0f3265..f935d2e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -5,8 +5,7 @@ menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on !IA64_HP_SIM - depends on IA64 || X86 - depends on PCI + depends on ((IA64 || X86) && PCI) || (ARM64 && EXPERT) select PNP default y help @@ -163,6 +162,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 @@ -263,7 +263,7 @@ config ACPI_DEBUG
config ACPI_PCI_SLOT bool "PCI slot detection driver" - depends on SYSFS + depends on SYSFS && PCI default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI
On Mon, Sep 01, 2014 at 03:57:54PM +0100, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
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.
So are S states. Maybe I am being pedantic, but why can't you do the same thing for drivers/acpi/sleep.c ? Is it really that complicated to add a config option and avoid compiling it (that file supports a part of the ACPI specs that is completely undefined for ARM64), and with that removing the need for useless hooks on ARM64 ?
Why do we have to compile that code at all on ARM64 ?
Thanks, Lorenzo
Reviewed-by: Grant Likely grant.likely@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
arch/arm64/Kconfig | 2 ++ drivers/acpi/Kconfig | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 065438c..8dabaeb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -422,6 +422,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 d0f3265..f935d2e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -5,8 +5,7 @@ menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on !IA64_HP_SIM
- depends on IA64 || X86
- depends on PCI
- depends on ((IA64 || X86) && PCI) || (ARM64 && EXPERT) select PNP default y help
@@ -163,6 +162,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
@@ -263,7 +263,7 @@ config ACPI_DEBUG config ACPI_PCI_SLOT bool "PCI slot detection driver"
- depends on SYSFS
- depends on SYSFS && PCI default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI
-- 1.7.9.5
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- Documentation/arm64/arm-acpi.txt | 218 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 Documentation/arm64/arm-acpi.txt
diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt new file mode 100644 index 0000000..704a9e0 --- /dev/null +++ b/Documentation/arm64/arm-acpi.txt @@ -0,0 +1,218 @@ +ACPI on ARMv8 Servers +--------------------- + +ACPI can be used for ARMv8 general purpose servers designed to follow +the SBSA specification (currently available to people with an ARM login at +http://silver.arm.com). + +The kernel will implement minimum ACPI version is 5.1 + errata as released by +the UEFI Forum, which is available at http://www.uefi.org/acpi/specs. + +If the machine does not meet the requirements of the SBSA, or cannot be +described in the required ACPI specifications then it is likely that Device Tree +(DT) is more suitable for the hardware. + +Relationship with Device Tree +----------------------------- + +ACPI support in drivers and subsystems for ARMv8 should never be mutually +exclusive with DT support at compile time. + +At boot time the kernel will only use one description method depending on +parameters passed from the bootloader (including kernel bootargs). + +Regardless of whether DT or ACPI is used, the kernel must always be capable +of booting with either scheme (in kernels with both schemes enabled at compile +time). + +When booting using ACPI tables the /chosen node in DT will still be parsed +to extract the kernel command line and initrd path. No other section of +the DT will be used. + +Booting using ACPI tables +------------------------- + +Currently, the only defined method to pass ACPI tables to the kernel on ARMv8 +is via the UEFI system configuration table. + +The UEFI implementation MUST set the ACPI_20_TABLE_GUID to point to the +RSDP table (the table with the ACPI signature "RSD PTR "). + +The pointer to the RSDP table will be retrieved from EFI by the ACPI core. + +Processing of ACPI tables may be disabled by passing acpi=off on the kernel +command line. + +DO use an XSDT; RSDTs are deprecated and should not be used on arm64. They +only allow for 32-bit addresses. + +DO NOT use the 32-bit address fields in the FADT; they are deprecated. The +64-bit alternatives MUST be used. + +The minimum set of tables MUST include RSDP, XSDT, FACS, FADT, DSDT, MADT +and GTDT. If PCI is used the MCFG table MUST also be present. + +ACPI Detection +-------------- + +Drivers should determine their probe() type by checking for ACPI_HANDLE, +or .of_node, or other information in the device structure. This is +detailed further in the "Driver Recommendations" section. + +In non-driver code If the presence of ACPI needs to be detected at runtime, +then check the value of acpi_disabled. If CONFIG_ACPI is not set, +acpi_disabled will always be 1. + +Device Enumeration +------------------ + +Device descriptions in ACPI should use standard recognized ACPI interfaces. +These are far simpler than the information provided via Device Tree. Drivers +should take into account this simplicity and work with sensible defaults. + +On no account should a Device Tree attempt to be replicated in ASL using such +constructs as Name(KEY0, "Value1") type constructs. Additional driver specific +data should be represented with the appropriate _DSD (ACPI Section 6.2.5) +structure. _DSM (ACPI Section 9.14.1) should only be used if _DSD cannot +represent the data required. + +This data should be rare and not OS specific. For x86 ACPI has taken to +identifying itself as Windows because it was found that only one path was +routinely tested. For ARMv8 it would be preferable to have only one well +tested path. + +_DSD covers more than the generic server case and care should be taken not to +replicate highly specific embedded behaviour from DT into generic servers. + +Common _DSD bindings should be submitted to ASWG to be included in the +document :- + +http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-... + +If these bindings are mirrored from DT care should be taken to ensure they are +reviewed as DT bindings before submission to limit divergance in bindings. + +Programmable Power Control Resources +------------------------------------ + +Programmable power control resources include such resources as voltage/current +providers (regulators) and clock sources. + +For power control of these resources they should be represented with Power +Resource Objects (ACPI Section 7.1). The ACPI core will then handle correctly +enabling/disabling of resources as they are needed. + +The ACPI 5.1 specification does not contain any standard binding for these +objects to enable programmable levels or rates so this should be avoided if +possible and the resources set to appropriate levels by the firmware. If this is +not possible then any manipulation should be abstracted in ASL. + +Each device in ACPI has D-states and these can be controlled through +the optional methods _PS0..._PS3 where _PS0 is full on and _PS3 is full off. + +If either _PS0 or _PS3 is implemented, then the other method must also be +implemented. + +If a device requires usage or setup of a power resource when on, the ASL +should organize that it is allocated/enabled using the _PS0 method. + +Resources allocated/enabled in the _PS0 method should be disabled/de-allocated +in the _PS3 method. + +Such code in _PS? methods will of course be very platform specific but +should allow the driver to operate the device without special non-standard +values being read from ASL. Further, abstracting the use of these resources +allows hardware revisions without requiring updates to the kernel. + +Clocks +------ + +Like clocks that are part of the power resources there is no standard way +to represent a clock tree in ACPI 5.1 in a similar manner to how it is +described in DT. + +Devices affected by this include things like UARTs, SoC driven LCD displays, +etc. + +The firmware (for example, UEFI) should initialize these clocks to fixed working +values before the kernel is executed. + +Driver Recommendations +---------------------- + +DO NOT remove any FDT handling when adding ACPI support for a driver. Different +systems may use the same device. + +DO try and keep complex sections of ACPI and DT functionality separate. This +may mean a patch to break out some complex DT to another function before +the patch to add ACPI. This may happen in other functions but is most likely +in probe function. This gives a clearer flow of data for reviewing driver +source. + +probe() :- + +static int device_probe_dt(struct platform_device *pdev) +{ + /* DT specific functionality */ + ... +} + +static int device_probe_acpi(struct platform_device *pdev) +{ + /* ACPI specific functionality */ + ... +} + +static int device_probe(stuct platform_device *pdev) +{ + ... + struct device_node node = pdev->dev.of_node; + ... + + if (node) + ret = device_probe_dt(pdev); + else if (ACPI_HANDLE(&pdev->dev)) + ret = device_probe_acpi(pdev); + else + /* other initialization */ + ... + /* Continue with any generic probe operations */ + ... +} + +DO keep the MODULE_DEVICE_TABLE entries together in the driver to make it clear +the different names the driver is probed for, both from DT and from ACPI. + +module device tables :- + +static struct of_device_id virtio_mmio_match[] = { + { .compatible = "virtio,mmio", }, + { } +}; +MODULE_DEVICE_TABLE(of, virtio_mmio_match); + +static const struct acpi_device_id virtio_mmio_acpi_match[] = { + { "LNRO0005", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match); + +ASWG +---- + +The following areas are not yet well defined for ARM in the current ACPI +specification and are expected to be worked through in the UEFI ACPI +Specification Working Group (ASWG) http://www.uefi.org/workinggroups. +Participation in this group is open to all UEFI members. + + - ACPI based CPU topology + - ACPI based Power management + - CPU idle control based on PSCI + - CPU performance control (CPPC) + - ACPI based SMMU + - ITS support for GIC in MADT + +No code shall be accepted into the kernel unless it complies with the released +standards from UEFI ASWG. If there are features missing from ACPI to make it +function on a platform, ECRs should be submitted to ASWG and go through the +approval process.
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2:
- Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz
- make ACPI depend on EXPERT
- Address lots of comments from Catalin, Sudeep, Geoff
- Add Juno device ACPI driver patches for review
Updates since v1:
- Set ACPI default off on ARM64 suggested by Olof;
- Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support.
- Update the document as suggested;
- Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
g.
Al Stone (3): ARM64 / ACPI: Get RSDP and ACPI boot-time tables ARM64 / ACPI: Introduce early_param for "acpi" ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64
Ashwin Chaugule (1): ACPI / table: Add new function to get table entries
Graeme Gregory (4): ARM64 / ACPI: Introduce lowlevel suspend function ARM64 / ACPI: If we chose to boot from acpi then disable FDT ARM64 / ACPI: Enable ARM64 in Kconfig Documentation: ACPI for ARM64
Hanjun Guo (8): ARM64: Move the init of cpu_logical_map(0) before unflatten_device_tree() ARM64 / ACPI: Make PCI optional for ACPI on ARM64 ARM64 / ACPI: Parse FADT table to get PSCI flags for PSCI init ACPI / table: Print GIC information when MADT is parsed ARM64 / ACPI: Parse MADT for SMP initialization ACPI / processor: Make it possible to get CPU hardware ID via GICC ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi ARM64 / ACPI: Parse GTDT to initialize arch timer
Tomasz Nowicki (1): ARM64 / ACPI: Add GICv2 specific ACPI boot support
Documentation/arm64/arm-acpi.txt | 218 +++++++++++++++++++++ Documentation/kernel-parameters.txt | 3 +- arch/arm64/Kconfig | 3 + arch/arm64/include/asm/acenv.h | 18 ++ arch/arm64/include/asm/acpi.h | 108 ++++++++++ arch/arm64/include/asm/cpu_ops.h | 1 + arch/arm64/include/asm/pci.h | 11 ++ arch/arm64/include/asm/psci.h | 3 +- arch/arm64/include/asm/smp.h | 5 +- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/acpi.c | 359 ++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_ops.c | 4 +- arch/arm64/kernel/irq.c | 5 + arch/arm64/kernel/psci.c | 78 +++++--- arch/arm64/kernel/setup.c | 23 ++- arch/arm64/kernel/smp.c | 2 +- arch/arm64/kernel/time.c | 7 + drivers/acpi/Kconfig | 6 +- drivers/acpi/Makefile | 2 +- drivers/acpi/bus.c | 3 + drivers/acpi/internal.h | 5 + drivers/acpi/processor_core.c | 37 ++++ drivers/acpi/tables.c | 113 +++++++++-- drivers/clocksource/arm_arch_timer.c | 117 +++++++++-- drivers/irqchip/irq-gic.c | 114 +++++++++++ include/linux/acpi.h | 5 + include/linux/clocksource.h | 6 + include/linux/irqchip/arm-gic-acpi.h | 33 ++++ include/linux/pci.h | 37 +++- 29 files changed, 1237 insertions(+), 90 deletions(-) create mode 100644 Documentation/arm64/arm-acpi.txt create mode 100644 arch/arm64/include/asm/acenv.h create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/include/asm/pci.h create mode 100644 arch/arm64/kernel/acpi.c create mode 100644 include/linux/irqchip/arm-gic-acpi.h
-- 1.7.9.5
Hi Grant,
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
[...]
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
Apart from build testing, what does this wider exposure achieve? Is there a platform available that would be able to boot Linux (to a meaingful state) with this patch series alone?
I'm mindful of merging arch code that I'm unable to test, so I'd really rather it was merged along with the code (and a devicetree) for a platform that can use it.
Will
On Thu, 11 Sep 2014 14:49:22 +0100, Will Deacon will.deacon@arm.com wrote:
Hi Grant,
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
[...]
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
Apart from build testing, what does this wider exposure achieve?
It tests that ACPI support does not break existing platform support and it builds in configurations that we simply haven't tested yet. The LEG wiki has instructions for running the code on Fvp and Juno. It gets us confidence that the patches aren't dangerous and that they work outside of the ACPI developers environment.
Hanjun, what is the state of firmware binaries? I know we're building them for releases and snapshots, but I don't know if they contain the required ACPI bits.
Is there a platform available that would be able to boot Linux (to a meaingful state) with this patch series alone?
(Hanjun/Graeme, correct me if I'm wrong here) There are two driver patches that makes Juno and the FVP model usable. One for Ethernet and one for the UART, but the UART one is going to be dropped in favour of ARM's SBSA UART patch. It also works on AMD Seatlle with driver patches, but those ones haven't been published yet.
g.
I'm mindful of merging arch code that I'm unable to test, so I'd really rather it was merged along with the code (and a devicetree) for a platform that can use it.
Will
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
On 15 September 2014 12:21, Grant Likely grant.likely@linaro.org wrote:
On Thu, 11 Sep 2014 14:49:22 +0100, Will Deacon will.deacon@arm.com wrote:
Hi Grant,
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org
wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
[...]
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should
be
a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
Apart from build testing, what does this wider exposure achieve?
It tests that ACPI support does not break existing platform support and it builds in configurations that we simply haven't tested yet. The LEG wiki has instructions for running the code on Fvp and Juno. It gets us confidence that the patches aren't dangerous and that they work outside of the ACPI developers environment.
Hanjun, what is the state of firmware binaries? I know we're building them for releases and snapshots, but I don't know if they contain the required ACPI bits.
yes, firmware binaries will contain ACPI tables. I will talk to Graeme to update the wiki about how to build UEFI binaries for FVP and Juno board, then post it to open.
Is there a platform available that would be able to boot Linux (to a meaingful
state)
with this patch series alone?
(Hanjun/Graeme, correct me if I'm wrong here) There are two driver patches that makes Juno and the FVP model usable. One for Ethernet and one for the UART, but the UART one is going to be dropped in favour of ARM's SBSA UART patch. It also works on AMD Seatlle with driver patches, but those ones haven't been published yet.
Yes, you are right.
Thanks Hanjun
On Thursday, September 11, 2014 02:29:34 PM Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2:
- Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz
- make ACPI depend on EXPERT
- Address lots of comments from Catalin, Sudeep, Geoff
- Add Juno device ACPI driver patches for review
Updates since v1:
- Set ACPI default off on ARM64 suggested by Olof;
- Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support.
- Update the document as suggested;
- Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
Having looked at the patches recently, I don't see any major problems in them from the ACPI core perspective, so to me they are good to go.
Question is who's going to handle them?
On Thu, Sep 11, 2014 at 3:23 PM, Rafael J. Wysocki rjw@rjwysocki.net wrote:
On Thursday, September 11, 2014 02:29:34 PM Grant Likely wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2:
- Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz
- make ACPI depend on EXPERT
- Address lots of comments from Catalin, Sudeep, Geoff
- Add Juno device ACPI driver patches for review
Updates since v1:
- Set ACPI default off on ARM64 suggested by Olof;
- Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support.
- Update the document as suggested;
- Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
Having looked at the patches recently, I don't see any major problems in them from the ACPI core perspective, so to me they are good to go.
Question is who's going to handle them?
They should absolutely go via Catalin & Will's tree.
g.
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables? If we can't guarantee this, we rather fix it now. Some suggestions:
a) Make sure code which doesn't have a clear behaviour on ARM is not compiled in and doesn't even try to interpret such tables on ARM (you could just go for the latter but I'm not sure how feasible it is) b) Ensure that the current patches don't support anything other than ACPI 5.1 (6 or later would not be supported; can we get information about which errata update do vendor tables cover?) c) Consider the current ACPI code broken for ARM (rather than feature incomplete) and strongly recommend vendors not to use it
Point (a) looks the sanest to me. Point (b) kind of defeats one of the ACPI goals while point (c) would question why we even bother discussing merging now.
On 11/09/14 16:37, Catalin Marinas wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables? If we can't guarantee this, we rather fix it now. Some suggestions:
a) Make sure code which doesn't have a clear behaviour on ARM is not compiled in and doesn't even try to interpret such tables on ARM (you could just go for the latter but I'm not sure how feasible it is)
This what we have suggested in past especially for this S-state support. Currently the core acpi code compiles in sleep support unconditionally. That doesn't mean we need to do the same on ARM64, we can easily make sure that's not enabled for ARM64 until we have clarification on how to support them on ARM in ACPI specification.
I just pointed out at one "out of spec" workaround done for x86 "unconditionally" in the code just to tell that it won't work on ARM. That shouldn't be misunderstood as demand for refactoring as we have no clue how S-state would look on ARM to take up any such task.
Regards, Sudeep
On Thu, Sep 11, 2014 at 04:57:24PM +0100, Sudeep Holla wrote:
On 11/09/14 16:37, Catalin Marinas wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables? If we can't guarantee this, we rather fix it now. Some suggestions:
a) Make sure code which doesn't have a clear behaviour on ARM is not compiled in and doesn't even try to interpret such tables on ARM (you could just go for the latter but I'm not sure how feasible it is)
This what we have suggested in past especially for this S-state support. Currently the core acpi code compiles in sleep support unconditionally. That doesn't mean we need to do the same on ARM64, we can easily make sure that's not enabled for ARM64 until we have clarification on how to support them on ARM in ACPI specification.
I just pointed out at one "out of spec" workaround done for x86 "unconditionally" in the code just to tell that it won't work on ARM. That shouldn't be misunderstood as demand for refactoring as we have no clue how S-state would look on ARM to take up any such task.
For the sleep.c case I worked on this and sent some updates to Hanjun so it should be compiled out in the next version of the patches.
Graeme
On 11/09/14 17:06, Graeme Gregory wrote:
On Thu, Sep 11, 2014 at 04:57:24PM +0100, Sudeep Holla wrote:
[...]
This what we have suggested in past especially for this S-state support. Currently the core acpi code compiles in sleep support unconditionally. That doesn't mean we need to do the same on ARM64, we can easily make sure that's not enabled for ARM64 until we have clarification on how to support them on ARM in ACPI specification.
I just pointed out at one "out of spec" workaround done for x86 "unconditionally" in the code just to tell that it won't work on ARM. That shouldn't be misunderstood as demand for refactoring as we have no clue how S-state would look on ARM to take up any such task.
For the sleep.c case I worked on this and sent some updates to Hanjun so it should be compiled out in the next version of the patches.
Thanks Graeme, that's much better than any hooks/stubs which might fail depending on ACPI table contents.
Regards, Sudeep
On Thu, 11 Sep 2014 16:37:39 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
We're good on this front. ACPI-future platforms aren't allowed to use new features when booting an older kernel. ACPI has a mechanism to check version numbers. Similarly, when ACPI-future defines those states, the kernel shouldn't expose them to an older platform.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables?
Yes - at least as much as we can guarantee anything in systems programming.
g.
On Mon, Sep 15, 2014 at 05:31:16AM +0100, Grant Likely wrote:
On Thu, 11 Sep 2014 16:37:39 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
We're good on this front. ACPI-future platforms aren't allowed to use new features when booting an older kernel.
Do you mean ACPI-future firmware should not provide new information to older kernels? The firmware must not care which kernel version (not even which OS) runs on top. That's the whole point of an OS-agnostic standardisation body).
ACPI has a mechanism to check version numbers.
I assume you are referring to the kernel checking of the ACPI version the tables are compatible with (acpi_parse_fadt() in patch 7/17 in the v3 series). With these patches, it currently assumes that it is compatible with anything 5.1 and later.
Similarly, when ACPI-future defines those states, the kernel shouldn't expose them to an older platform.
When the kernel implements ACPI-future, all is fine, it should still be backwards compatible with 5.1.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables?
Yes - at least as much as we can guarantee anything in systems programming.
No, we don't. Once you define some sleep states in ACPI-future and the firmware provides such tables to an older kernel, it is possible that the current (x86-centric) ACPI sleep code will fault. Just look at the acpi_suspend_enter() (and you also seemed OK to define ACPI_FLUSH_CPU_CACHE as BUG).
Even if v4 of these patches removed the sleep code, given uncertainties like above I'm thinking more and more that we should actually make the acpi_parse_fadt() version check succeed only on ACPI 5.1 and no later version (apart from ACPI sleep, is there anything else we would expect to blow up when additional information is provided via ACPI-future tables?).
On Mon, 15 Sep 2014 10:15:16 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Mon, Sep 15, 2014 at 05:31:16AM +0100, Grant Likely wrote:
On Thu, 11 Sep 2014 16:37:39 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
We're good on this front. ACPI-future platforms aren't allowed to use new features when booting an older kernel.
Do you mean ACPI-future firmware should not provide new information to older kernels?
I mean that ACPI has the mechanism so that the platform (via AML) doesn't try to do things that the OS doesn't understand. AML methods are to use the _REV object to determine whether or not it can use a feature. If, for example, the _REV is 5, then the AML must switch itself to code paths that don't use ACPI 6 features.
The firmware must not care which kernel version (not even which OS) runs on top. That's the whole point of an OS-agnostic standardisation body).
It shouldn't care about the OS, but it absolutely needs to care about which revision of ACPI spec that the OS implements, and the ACPI spec accounts for exactly that.
ACPI has a mechanism to check version numbers.
I assume you are referring to the kernel checking of the ACPI version the tables are compatible with (acpi_parse_fadt() in patch 7/17 in the v3 series). With these patches, it currently assumes that it is compatible with anything 5.1 and later.
No, that's the other side. That's how the OS determines which version of the spec the ACPI tables implement. That's how the OS decides if it needs to use the behaviour from an older revision of the spec.
For the kernel to accept anything 5.1 or later is the correct behavour here. ACPI compatibility is driven by the lowest common denominator. The kernel and the platform (AML) choose the most recent version of the spec that is supported by both.
Similarly, when ACPI-future defines those states, the kernel shouldn't expose them to an older platform.
When the kernel implements ACPI-future, all is fine, it should still be backwards compatible with 5.1.
What if in a year time we get ACPI 5.2 or 6 (or an errata update) covering the S and C states for ARM? I would expect hardware vendors to take advantage and provide such information in ACPI tables. Can we guarantee that a kernel with the current ACPI patches wouldn't blow up when it tries to interpret the new tables?
Yes - at least as much as we can guarantee anything in systems programming.
No, we don't. Once you define some sleep states in ACPI-future and the firmware provides such tables to an older kernel, it is possible that the current (x86-centric) ACPI sleep code will fault. Just look at the acpi_suspend_enter() (and you also seemed OK to define ACPI_FLUSH_CPU_CACHE as BUG).
Even if v4 of these patches removed the sleep code, given uncertainties like above I'm thinking more and more that we should actually make the acpi_parse_fadt() version check succeed only on ACPI 5.1 and no later version (apart from ACPI sleep, is there anything else we would expect to blow up when additional information is provided via ACPI-future tables?).
I was about to agree with you that we could do that temporarily, but after thinking about it more, this is actually an actively dangerous thing to do because it will encourage firmware vendors to lie about which version of the ACPI spec it conforms to. ie. A vendor may build a platform and use the ACPI6.0 spec, but they want it to boot on an older kernel, and so they make their tables lie and report 5.1. This would be a horrible situation. We would loose the ability to use reported ACPI spec comformance to determine which features to enable.
Selecting on v5.1 or later really is the right choice here. Vendors who do the wrong thing and produce broken firmware will get rightly dumped on by Red Hat and Canonical for shipping something that doesn't work. We have a lot less risk here than ACPI had historically in the x86 world because these systems are primarily built to run Linux instead of Windows. That means the systems will be tested and validated with released Linux distros, and they will fix the firmware if it is broken.
g.
On Mon, Sep 15, 2014 at 11:48:00PM +0100, Grant Likely wrote:
On Mon, 15 Sep 2014 10:15:16 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Mon, Sep 15, 2014 at 05:31:16AM +0100, Grant Likely wrote:
On Thu, 11 Sep 2014 16:37:39 +0100, Catalin Marinas catalin.marinas@arm.com wrote:
On Thu, Sep 11, 2014 at 02:29:34PM +0100, Grant Likely wrote:
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I have to disagree here. As I said, I'm perfectly fine with refactoring happening later but I'm not happy with compiling in code with undefined behaviour on ARM that may actually be executed at run-time.
I'm being told one of the main advantages of ACPI is forward compatibility: running older kernels on newer hardware (potentially with newer ACPI version tables). ACPI 5.1 includes partial support for ARM but the S and C states are not defined yet. We therefore assume that hardware vendors deploying servers using ACPI would not provide such yet to be defined information in ACPI 5.1 tables.
We're good on this front. ACPI-future platforms aren't allowed to use new features when booting an older kernel.
Do you mean ACPI-future firmware should not provide new information to older kernels?
I mean that ACPI has the mechanism so that the platform (via AML) doesn't try to do things that the OS doesn't understand. AML methods are to use the _REV object to determine whether or not it can use a feature. If, for example, the _REV is 5, then the AML must switch itself to code paths that don't use ACPI 6 features.
So you are talking about AML code paths and from what I understand they should be fine.
However, what I'm talking about is _kernel_ code paths and functions like acpi_suspend_enter(). Do you mean this function can only be called as a result of some AML execution (it doesn't look so to me)? If not, what guarantees do we have that ACPI-future tables exposed to an older kernel would not trigger this kernel code path (if compiled in)?
On Thu, Sep 11, 2014 at 6:29 AM, Grant Likely grant.likely@linaro.org wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2:
- Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz
- make ACPI depend on EXPERT
- Address lots of comments from Catalin, Sudeep, Geoff
- Add Juno device ACPI driver patches for review
Updates since v1:
- Set ACPI default off on ARM64 suggested by Olof;
- Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support.
- Update the document as suggested;
- Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
I'm going to take a pass on the next version of the series that will get posted; I've been a bit too busy to pay close attention to the series the last few weeks and I might as well wait until the next version at this rate.
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
That's not how -next works. We only add code to -next that is targeted to the upcoming release, we certainly don't add it to get "wider exposure". If the code is ready then it can go in, but that's not the case at this time.
For "wider exposure" -- who do you have in mind? Everybody that's currently got hardware relevant for this already needs out-of-tree patches, so getting it into -next doesn't add any exposure. Doesn't Linaro do kernel builds and publish trees for this reason already?
-Olof
On Thu, 11 Sep 2014 09:05:25 -0700, Olof Johansson olof@lixom.net wrote:
On Thu, Sep 11, 2014 at 6:29 AM, Grant Likely grant.likely@linaro.org wrote:
On Mon, 1 Sep 2014 22:57:38 +0800, Hanjun Guo hanjun.guo@linaro.org wrote:
ACPI 5.1 has been released and now be freely available for download [1]. It fixed some major gaps to run ACPI on ARM, this patch just follow the ACPI 5.1 spec and prepare the code to run ACPI on ARM64.
ACPI 5.1 has some major changes for the following tables and method which are essential for ARM platforms:
- MADT table updates.
- FADT updates for PSCI
- GTDT
This patch set is the ARM64 ACPI core patches covered MADT, FADT and GTDT, platform board specific drivers are not covered by this patch set, but we provide drivers for Juno to boot with ACPI only in the follwing patch set for review purpose.
We first introduce acpi.c and its related head file which are needed by ACPI core, and then get RSDP to extract all the ACPI boot-time tables. When all the boot-time tables (FADT, MADT, GTDT) are ready, then parse them to init the sytem when booted. Specifically, a) we use FADT to init PSCI and use PSCI to boot SMP; b) Use MADT for GIC init and SMP init; c) GTDT for arch timer init.
This patch set is based on 3.17-rc2 and was tested by Graeme on Juno and FVP base model boot with ACPI only OK, if you want to test them, you can pull from acpi-5.1-v3 branch in leg/acpi repo: git://git.linaro.org/leg/acpi/acpi.git
Updates since v2:
- Refactor the code to make SMP/PSCI init with less sperated init path by Tomasz
- make ACPI depend on EXPERT
- Address lots of comments from Catalin, Sudeep, Geoff
- Add Juno device ACPI driver patches for review
Updates since v1:
- Set ACPI default off on ARM64 suggested by Olof;
- Rebase the patch set on top of linux-next branch/linux-pm tree which includes the ACPICA for full ACPI 5.1 support.
- Update the document as suggested;
- Adress lots of comments from Mark, Sudeep, Randy, Naresh, Olof, Geoff and more...
I've read through this entire series now. In my mind, aside from a few comments that I know you're addressing, this is ready. The hooks into arm64 core code are not terribly invasive, it is nicely organized and manageable. Get the next version out ASAP, but I would also like to see the diffs from this version to the next so I don't need to review the entire series again.
I'm going to take a pass on the next version of the series that will get posted; I've been a bit too busy to pay close attention to the series the last few weeks and I might as well wait until the next version at this rate.
I've asked Hanjun to prepare diffs from one version of the series to the next so that I don't need to rereview the entire thing. He sent them to me privately. Do you want me to pass them along to you?
Regarding the requests to refactor ACPICA to work better for ARM. I completely agree that it should be done, but I do not think it should be a prerequisite to getting this core support merged. That kind of refactoring is far easier to justify when it has immediate improvement on the mainline codebase, and it gives us a working baseline to test against. Doing it the other way around just makes things harder.
I would really like to see the next version of this series go into linux-next. I think this is ready for some wider exposure. Have you got a branch being pulled into Fengguang's autobuilder yet?
That's not how -next works. We only add code to -next that is targeted to the upcoming release, we certainly don't add it to get "wider exposure". If the code is ready then it can go in, but that's not the case at this time.
Sorry, I had a bad moment there. Apologies. Getting it into Fengguang's builder is appropriate though.
For "wider exposure" -- who do you have in mind? Everybody that's currently got hardware relevant for this already needs out-of-tree patches, so getting it into -next doesn't add any exposure. Doesn't Linaro do kernel builds and publish trees for this reason already?
There is the wider exposure of ensuring the ACPI patches don't interfere with non-ACPI users, and also making sure it builds with configuration combinations that we've not tried.
g.