From 91ceee782fa733eb67a5ce0201d9dc1f63432dac Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 11 Feb 2020 18:08:28 +0900 Subject: [PATCH] arch: arm: aarch64: Refactor interrupt interface The current AArch64 interrupt system relies on the multi-level interrupt mechanism and the `irq_nextlevel` public interface to invoke the Generic Interrupt Controller (GIC) driver functions. Since the GIC driver has been refactored to provide a direct interface, in order to resolve various implementation issues described in the GIC driver refactoring commit, the architecture interrupt control functions are updated to directly invoke the GIC driver functions. This commit also adds support for the ARMv8 cores (e.g. Cortex-A53) that allow interfacing to a custom external interrupt controller (i.e. non-GIC) by mapping the architecture interrupt control functions to the SoC layer interrupt control functions when `ARM_CUSTOM_INTERRUPT_CONTROLLER` configuration is enabled. Signed-off-by: Stephanos Ioannidis --- arch/arm/core/aarch64/CMakeLists.txt | 1 + arch/arm/core/aarch64/irq_init.c | 34 ++++++++++++++++++++++++++ arch/arm/core/aarch64/irq_manage.c | 35 ++++++++++++++------------- arch/arm/core/aarch64/isr_wrapper.S | 20 +++++++++++++++- arch/arm/core/aarch64/prep_c.c | 1 + include/arch/arm/aarch64/irq.h | 36 ++++++++++++++++++++++++++++ include/arch/arm/aarch64/timer.h | 2 +- 7 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 arch/arm/core/aarch64/irq_init.c diff --git a/arch/arm/core/aarch64/CMakeLists.txt b/arch/arm/core/aarch64/CMakeLists.txt index 8b49457d3a5..f29703e8123 100644 --- a/arch/arm/core/aarch64/CMakeLists.txt +++ b/arch/arm/core/aarch64/CMakeLists.txt @@ -9,6 +9,7 @@ endif () zephyr_library_sources( cpu_idle.S fatal.c + irq_init.c irq_manage.c prep_c.c reset.S diff --git a/arch/arm/core/aarch64/irq_init.c b/arch/arm/core/aarch64/irq_init.c new file mode 100644 index 00000000000..2f2b8306a08 --- /dev/null +++ b/arch/arm/core/aarch64/irq_init.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Stephanos Ioannidis + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM64 Cortex-A interrupt initialisation + */ + +#include +#include + +/** + * @brief Initialise interrupts + * + * This function invokes the ARM Generic Interrupt Controller (GIC) driver to + * initialise the interrupt system on the SoCs that use the GIC as the primary + * interrupt controller. + * + * When a custom interrupt controller is used, however, the SoC layer function + * is invoked for SoC-specific interrupt system initialisation. + */ +void z_arm64_interrupt_init(void) +{ +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + /* Initialise the Generic Interrupt Controller (GIC) driver */ + arm_gic_init(); +#else + /* Invoke SoC-specific interrupt controller initialisation */ + z_soc_irq_init(); +#endif +} diff --git a/arch/arm/core/aarch64/irq_manage.c b/arch/arm/core/aarch64/irq_manage.c index edd27c1a065..ce5aaae7f5b 100644 --- a/arch/arm/core/aarch64/irq_manage.c +++ b/arch/arm/core/aarch64/irq_manage.c @@ -11,46 +11,47 @@ #include #include -#include #include #include -#include #include #include #include +#include void z_arm64_fatal_error(unsigned int reason, const z_arch_esf_t *esf); +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) +/* + * The default interrupt controller for AArch64 is the ARM Generic Interrupt + * Controller (GIC) and therefore the architecture interrupt control functions + * are mapped to the GIC driver interface. + * + * When a custom interrupt controller is used (i.e. + * CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER is enabled), the architecture + * interrupt control functions are mapped to the SoC layer in + * `include/arch/arm/aarch64/irq.h`. + */ + void arch_irq_enable(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - irq_enable_next_level(dev, (irq >> 8) - 1); + arm_gic_irq_enable(irq); } void arch_irq_disable(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - irq_disable_next_level(dev, (irq >> 8) - 1); + arm_gic_irq_disable(irq); } int arch_irq_is_enabled(unsigned int irq) { - struct device *dev = _sw_isr_table[0].arg; - - return irq_is_enabled_next_level(dev); + return arm_gic_irq_is_enabled(irq); } void z_arm64_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags) { - struct device *dev = _sw_isr_table[0].arg; - - if (irq == 0) - return; - - irq_set_priority_next_level(dev, (irq >> 8) - 1, prio, flags); + arm_gic_irq_set_priority(irq, prio, flags); } +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ void z_irq_spurious(void *unused) { diff --git a/arch/arm/core/aarch64/isr_wrapper.S b/arch/arm/core/aarch64/isr_wrapper.S index b0dc7f561da..e36e1000b6e 100644 --- a/arch/arm/core/aarch64/isr_wrapper.S +++ b/arch/arm/core/aarch64/isr_wrapper.S @@ -64,11 +64,29 @@ SECTION_FUNC(TEXT, _isr_wrapper) bl sys_trace_isr_enter #endif - /* Cortex-A has one IRQ line so the main handler will be at offset 0 */ + /* Get active IRQ number from the interrupt controller */ +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_get_active +#else + bl z_soc_irq_get_active +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + stp x0, x1, [sp, #-16]! + lsl x0, x0, #4 /* table is 16-byte wide */ + + /* Call interrupt service routine */ ldr x1, =_sw_isr_table + add x1, x1, x0 ldp x0, x3, [x1] /* arg in x0, ISR in x3 */ blr x3 + /* Signal end-of-interrupt */ + ldp x0, x1, [sp], #16 +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + bl arm_gic_eoi +#else + bl z_soc_irq_eoi +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + #ifdef CONFIG_TRACING bl sys_trace_isr_exit #endif diff --git a/arch/arm/core/aarch64/prep_c.c b/arch/arm/core/aarch64/prep_c.c index 01c3a1492ea..e1f149eb3d3 100644 --- a/arch/arm/core/aarch64/prep_c.c +++ b/arch/arm/core/aarch64/prep_c.c @@ -28,6 +28,7 @@ extern FUNC_NORETURN void z_cstart(void); void z_arm64_prep_c(void) { z_bss_zero(); + z_arm64_interrupt_init(); z_cstart(); CODE_UNREACHABLE; diff --git a/include/arch/arm/aarch64/irq.h b/include/arch/arm/aarch64/irq.h index 47002d9754d..3fa4534d9e4 100644 --- a/include/arch/arm/aarch64/irq.h +++ b/include/arch/arm/aarch64/irq.h @@ -27,7 +27,14 @@ extern "C" { GTEXT(arch_irq_enable) GTEXT(arch_irq_disable) GTEXT(arch_irq_is_enabled) +#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) +GTEXT(z_soc_irq_get_active) +GTEXT(z_soc_irq_eoi) +#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ #else + +#if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) + extern void arch_irq_enable(unsigned int irq); extern void arch_irq_disable(unsigned int irq); extern int arch_irq_is_enabled(unsigned int irq); @@ -36,6 +43,35 @@ extern int arch_irq_is_enabled(unsigned int irq); extern void z_arm64_irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags); +#else + +/* + * When a custom interrupt controller is specified, map the architecture + * interrupt control functions to the SoC layer interrupt control functions. + */ + +void z_soc_irq_init(void); +void z_soc_irq_enable(unsigned int irq); +void z_soc_irq_disable(unsigned int irq); +int z_soc_irq_is_enabled(unsigned int irq); + +void z_soc_irq_priority_set( + unsigned int irq, unsigned int prio, unsigned int flags); + +unsigned int z_soc_irq_get_active(void); +void z_soc_irq_eoi(unsigned int irq); + +#define arch_irq_enable(irq) z_soc_irq_enable(irq) +#define arch_irq_disable(irq) z_soc_irq_disable(irq) +#define arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) + +#define z_arm64_irq_priority_set(irq, prio, flags) \ + z_soc_irq_priority_set(irq, prio, flags) + +#endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ + +extern void z_arm64_interrupt_init(void); + /* All arguments must be computable by the compiler at build time. * * Z_ISR_DECLARE will populate the .intList section with the interrupt's diff --git a/include/arch/arm/aarch64/timer.h b/include/arch/arm/aarch64/timer.h index 6964eb58100..384b7e29e0c 100644 --- a/include/arch/arm/aarch64/timer.h +++ b/include/arch/arm/aarch64/timer.h @@ -16,7 +16,7 @@ extern "C" { #endif -#define ARM_ARCH_TIMER_IRQ ((ARM_TIMER_VIRTUAL_IRQ + 1) << 8) +#define ARM_ARCH_TIMER_IRQ ARM_TIMER_VIRTUAL_IRQ #define CNTV_CTL_ENABLE ((1) << 0)