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 <root@stephanos.io>
This commit is contained in:
Stephanos Ioannidis 2020-02-11 18:08:28 +09:00 committed by Ioannis Glaropoulos
commit 91ceee782f
7 changed files with 110 additions and 19 deletions

View file

@ -9,6 +9,7 @@ endif ()
zephyr_library_sources(
cpu_idle.S
fatal.c
irq_init.c
irq_manage.c
prep_c.c
reset.S

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ARM64 Cortex-A interrupt initialisation
*/
#include <arch/cpu.h>
#include <drivers/interrupt_controller/gic.h>
/**
* @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
}

View file

@ -11,46 +11,47 @@
#include <kernel.h>
#include <arch/cpu.h>
#include <device.h>
#include <tracing/tracing.h>
#include <irq.h>
#include <irq_nextlevel.h>
#include <toolchain.h>
#include <linker/sections.h>
#include <sw_isr_table.h>
#include <drivers/interrupt_controller/gic.h>
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)
{

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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)