From 27523579226b7dbff68d12ca28abce63d52e77d2 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Thu, 9 Feb 2017 12:40:08 -0800 Subject: [PATCH] arm: enable direct interrupts feature Issue: ZEP-1038 Change-Id: I5417e516cc994e2bbe6bb987d9ed95e912941aa0 Signed-off-by: Andrew Boie --- arch/arm/core/irq_manage.c | 57 +++++++++++++++++++++++++++++++++ include/arch/arm/cortex_m/irq.h | 53 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/arch/arm/core/irq_manage.c b/arch/arm/core/irq_manage.c index d2cc2dbbfd4..b36b007800d 100644 --- a/arch/arm/core/irq_manage.c +++ b/arch/arm/core/irq_manage.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include extern void __reserved(void); @@ -131,3 +133,58 @@ void _irq_spurious(void *unused) __reserved(); } +/* FIXME: IRQ direct inline functions have to be placed here and not in + * arch/cpu.h as inline functions due to nasty circular dependency between + * arch/cpu.h and kernel_structs.h; the inline functions typically need to + * perform operations on _kernel. For now, leave as regular functions, a + * future iteration will resolve this. + * We have a similar issue with the k_event_logger functions. + * + * See https://jira.zephyrproject.org/browse/ZEP-1595 + */ + +#ifdef CONFIG_SYS_POWER_MANAGEMENT +void _arch_isr_direct_pm(void) +{ +#if defined(CONFIG_ARMV6_M) + int key; + + /* irq_lock() does what we wan for this CPU */ + key = irq_lock(); +#elif defined(CONFIG_ARMV7_M) + /* Lock all interrupts. irq_lock() will on this CPU only disable those + * lower than BASEPRI, which is not what we want. See comments in + * arch/arm/core/isr_wrapper.S + */ + __asm__ volatile("cpsid i" : : : "memory"); +#else +#error Unknown ARM architecture +#endif /* CONFIG_ARMV6_M */ + + if (_kernel.idle) { + int32_t idle_val = _kernel.idle; + + _kernel.idle = 0; + _sys_power_save_idle_exit(idle_val); + } + +#if defined(CONFIG_ARMV6_M) + irq_unlock(key); +#elif defined(CONFIG_ARMV7_M) + __asm__ volatile("cpsie i" : : : "memory"); +#else +#error Unknown ARM architecture +#endif /* CONFIG_ARMV6_M */ + +} +#endif + +#if defined(CONFIG_KERNEL_EVENT_LOGGER_SLEEP) || \ + defined(CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT) +void _arch_isr_direct_header(void) +{ + _sys_k_event_logger_interrupt(); + _sys_k_event_logger_exit_sleep(); +} +#endif + diff --git a/include/arch/arm/cortex_m/irq.h b/include/arch/arm/cortex_m/irq.h index 971aca71a2c..da8a6b4b7b4 100644 --- a/include/arch/arm/cortex_m/irq.h +++ b/include/arch/arm/cortex_m/irq.h @@ -85,6 +85,59 @@ extern void _irq_priority_set(unsigned int irq, unsigned int prio, irq_p; \ }) + +/** + * Configure a 'direct' static interrupt. + * + * See include/irq.h for details. + * All arguments must be computable at build time. + */ +#define _ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ +({ \ + _ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ + _irq_priority_set(irq_p, priority_p, flags_p); \ + irq_p; \ +}) + +/* FIXME prefer these inline, but see ZEP-1595 */ +#ifdef CONFIG_SYS_POWER_MANAGEMENT +extern void _arch_isr_direct_pm(void); +#define _ARCH_ISR_DIRECT_PM() _arch_isr_direct_pm() +#else +#define _ARCH_ISR_DIRECT_PM() do { } while (0) +#endif + +#if defined(CONFIG_KERNEL_EVENT_LOGGER_SLEEP) || \ + defined(CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT) +#define _ARCH_ISR_DIRECT_HEADER() _arch_isr_direct_header() +extern void _arch_isr_direct_header(void); +#else +#define _ARCH_ISR_DIRECT_HEADER() do { } while (0) +#endif + +#define _ARCH_ISR_DIRECT_FOOTER(swap) _arch_isr_direct_footer(swap) + +/* arch/arm/core/exc_exit.S */ +extern void _IntExit(void); + +static inline void _arch_isr_direct_footer(int maybe_swap) +{ + if (maybe_swap) { + _IntExit(); + } +} + +#define _ARCH_ISR_DIRECT_DECLARE(name) \ + static inline int name##_body(void); \ + __attribute__ ((interrupt ("IRQ"))) void name(void) \ + { \ + int check_reschedule; \ + ISR_DIRECT_HEADER(); \ + check_reschedule = name##_body(); \ + ISR_DIRECT_FOOTER(check_reschedule); \ + } \ + static inline int name##_body(void) + /* Spurious interrupt handler. Throws an error if called */ extern void _irq_spurious(void *unused);