1 /* 2 * Copyright (c) 2013-2014 Wind River Systems, Inc. 3 * Copyright (c) 2019 Nordic Semiconductor ASA. 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 /** 9 * @file 10 * @brief ARM AArch32 public interrupt handling 11 * 12 * ARM AArch32-specific kernel interrupt handling interface. Included by 13 * arm/arch.h. 14 */ 15 16 #ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ 17 #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ 18 19 #include <irq.h> 20 #include <sw_isr_table.h> 21 #include <stdbool.h> 22 23 #ifdef __cplusplus 24 extern "C" { 25 #endif 26 27 #ifdef _ASMLANGUAGE 28 GTEXT(z_arm_int_exit); 29 GTEXT(arch_irq_enable) 30 GTEXT(arch_irq_disable) 31 GTEXT(arch_irq_is_enabled) 32 #if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) 33 GTEXT(z_soc_irq_get_active) 34 GTEXT(z_soc_irq_eoi) 35 #endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ 36 #else 37 38 #if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) 39 40 extern void arch_irq_enable(unsigned int irq); 41 extern void arch_irq_disable(unsigned int irq); 42 extern int arch_irq_is_enabled(unsigned int irq); 43 44 /* internal routine documented in C file, needed by IRQ_CONNECT() macro */ 45 extern void z_arm_irq_priority_set(unsigned int irq, unsigned int prio, 46 uint32_t flags); 47 48 #else 49 50 /* 51 * When a custom interrupt controller is specified, map the architecture 52 * interrupt control functions to the SoC layer interrupt control functions. 53 */ 54 55 void z_soc_irq_init(void); 56 void z_soc_irq_enable(unsigned int irq); 57 void z_soc_irq_disable(unsigned int irq); 58 int z_soc_irq_is_enabled(unsigned int irq); 59 60 void z_soc_irq_priority_set( 61 unsigned int irq, unsigned int prio, unsigned int flags); 62 63 unsigned int z_soc_irq_get_active(void); 64 void z_soc_irq_eoi(unsigned int irq); 65 66 #define arch_irq_enable(irq) z_soc_irq_enable(irq) 67 #define arch_irq_disable(irq) z_soc_irq_disable(irq) 68 #define arch_irq_is_enabled(irq) z_soc_irq_is_enabled(irq) 69 70 #define z_arm_irq_priority_set(irq, prio, flags) \ 71 z_soc_irq_priority_set(irq, prio, flags) 72 73 #endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ 74 75 extern void z_arm_int_exit(void); 76 77 extern void z_arm_interrupt_init(void); 78 79 /* macros convert value of it's argument to a string */ 80 #define DO_TOSTR(s) #s 81 #define TOSTR(s) DO_TOSTR(s) 82 83 /* concatenate the values of the arguments into one */ 84 #define DO_CONCAT(x, y) x ## y 85 #define CONCAT(x, y) DO_CONCAT(x, y) 86 87 /* Flags for use with IRQ_CONNECT() */ 88 /** 89 * Set this interrupt up as a zero-latency IRQ. It has a fixed hardware 90 * priority level (discarding what was supplied in the interrupt's priority 91 * argument), and will run even if irq_lock() is active. Be careful! 92 */ 93 #define IRQ_ZERO_LATENCY BIT(0) 94 95 #ifdef CONFIG_CPU_CORTEX_M 96 #define _CHECK_PRIO(priority_p, flags_p) \ 97 BUILD_ASSERT((flags_p & IRQ_ZERO_LATENCY) || \ 98 priority_p <= IRQ_PRIO_LOWEST, \ 99 "Invalid interrupt priority. Values must not exceed IRQ_PRIO_LOWEST"); 100 #else 101 #define _CHECK_PRIO(priority_p, flags_p) 102 #endif 103 104 /* All arguments must be computable by the compiler at build time. 105 * 106 * Z_ISR_DECLARE will populate the .intList section with the interrupt's 107 * parameters, which will then be used by gen_irq_tables.py to create 108 * the vector table and the software ISR table. This is all done at 109 * build-time. 110 * 111 * We additionally set the priority in the interrupt controller at 112 * runtime. 113 */ 114 #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ 115 { \ 116 BUILD_ASSERT(IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) || !(flags_p & IRQ_ZERO_LATENCY), \ 117 "ZLI interrupt registered but feature is disabled"); \ 118 _CHECK_PRIO(priority_p, flags_p) \ 119 Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \ 120 z_arm_irq_priority_set(irq_p, priority_p, flags_p); \ 121 } 122 123 #define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ 124 { \ 125 BUILD_ASSERT(IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) || !(flags_p & IRQ_ZERO_LATENCY), \ 126 "ZLI interrupt registered but feature is disabled"); \ 127 _CHECK_PRIO(priority_p, flags_p) \ 128 Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ 129 z_arm_irq_priority_set(irq_p, priority_p, flags_p); \ 130 } 131 132 #ifdef CONFIG_PM 133 extern void _arch_isr_direct_pm(void); 134 #define ARCH_ISR_DIRECT_PM() _arch_isr_direct_pm() 135 #else 136 #define ARCH_ISR_DIRECT_PM() do { } while (false) 137 #endif 138 139 #define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header() 140 #define ARCH_ISR_DIRECT_FOOTER(swap) arch_isr_direct_footer(swap) 141 142 /* arch/arm/core/aarch32/exc_exit.S */ 143 extern void z_arm_int_exit(void); 144 145 #ifdef CONFIG_TRACING_ISR 146 extern void sys_trace_isr_enter(void); 147 extern void sys_trace_isr_exit(void); 148 #endif 149 150 static inline void arch_isr_direct_header(void) 151 { 152 #ifdef CONFIG_TRACING_ISR 153 sys_trace_isr_enter(); 154 #endif 155 } 156 157 static inline void arch_isr_direct_footer(int maybe_swap) 158 { 159 #ifdef CONFIG_TRACING_ISR 160 sys_trace_isr_exit(); 161 #endif 162 if (maybe_swap != 0) { 163 z_arm_int_exit(); 164 } 165 } 166 167 #define ARCH_ISR_DIRECT_DECLARE(name) \ 168 static inline int name##_body(void); \ 169 __attribute__ ((interrupt ("IRQ"))) void name(void) \ 170 { \ 171 int check_reschedule; \ 172 ISR_DIRECT_HEADER(); \ 173 check_reschedule = name##_body(); \ 174 ISR_DIRECT_FOOTER(check_reschedule); \ 175 } \ 176 static inline int name##_body(void) 177 178 #if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) 179 180 extern void z_arm_irq_direct_dynamic_dispatch_reschedule(void); 181 extern void z_arm_irq_direct_dynamic_dispatch_no_reschedule(void); 182 183 /** 184 * @brief Macro to register an ISR Dispatcher (with or without re-scheduling 185 * request) for dynamic direct interrupts. 186 * 187 * This macro registers the ISR dispatcher function for dynamic direct 188 * interrupts for a particular IRQ line, allowing the use of dynamic 189 * direct ISRs in the kernel for that interrupt source. 190 * The dispatcher function is invoked when the hardware 191 * interrupt occurs and then triggers the (software) Interrupt Service Routine 192 * (ISR) that is registered dynamically (i.e. at run-time) into the software 193 * ISR table stored in SRAM. The ISR must be connected with 194 * irq_connect_dynamic() and enabled via irq_enable() before the dynamic direct 195 * interrupt can be serviced. This ISR dispatcher must be configured by the 196 * user to trigger thread re-secheduling upon return, using the @param resch 197 * parameter. 198 * 199 * These ISRs are designed for performance-critical interrupt handling and do 200 * not go through all of the common interrupt handling code. 201 * 202 * With respect to their declaration, dynamic 'direct' interrupts are regular 203 * Zephyr interrupts; their signature must match void isr(void* parameter), as, 204 * unlike regular direct interrupts, they are not placed directly into the 205 * ROM hardware vector table but instead they are installed in the software 206 * ISR table. 207 * 208 * The major differences with regular Zephyr interrupts are the following: 209 * - Similar to direct interrupts, the call into the OS to exit power 210 * management idle state is optional. Normal interrupts always do this 211 * before the ISR is run, but with dynamic direct ones when and if it runs 212 * is controlled by the placement of 213 * a ISR_DIRECT_PM() macro, or omitted entirely. 214 * - Similar to direct interrupts, scheduling decisions are optional. Unlike 215 * direct interrupts, the decisions must be made at build time. 216 * They are controlled by @param resch to this macro. 217 * 218 * @param irq_p IRQ line number. 219 * @param priority_p Interrupt priority. 220 * @param flags_p Architecture-specific IRQ configuration flags. 221 * @param resch Set flag to 'reschedule' to request thread 222 * re-scheduling upon ISR function. Set flag 223 * 'no_reschedule' to skip thread re-scheduling 224 * 225 * Note: the function is an ARM Cortex-M only API. 226 * 227 * @return Interrupt vector assigned to this interrupt. 228 */ 229 #define ARM_IRQ_DIRECT_DYNAMIC_CONNECT(irq_p, priority_p, flags_p, resch) \ 230 IRQ_DIRECT_CONNECT(irq_p, priority_p, \ 231 CONCAT(z_arm_irq_direct_dynamic_dispatch_, resch), flags_p) 232 233 #endif /* CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ 234 235 /* Spurious interrupt handler. Throws an error if called */ 236 extern void z_irq_spurious(const void *unused); 237 238 #ifdef CONFIG_GEN_SW_ISR_TABLE 239 /* Architecture-specific common entry point for interrupts from the vector 240 * table. Most likely implemented in assembly. Looks up the correct handler 241 * and parameter from the _sw_isr_table and executes it. 242 */ 243 extern void _isr_wrapper(void); 244 #endif 245 246 #if defined(CONFIG_ARM_SECURE_FIRMWARE) 247 /* Architecture-specific definition for the target security 248 * state of an NVIC IRQ line. 249 */ 250 typedef enum { 251 IRQ_TARGET_STATE_SECURE = 0, 252 IRQ_TARGET_STATE_NON_SECURE 253 } irq_target_state_t; 254 255 #endif /* CONFIG_ARM_SECURE_FIRMWARE */ 256 257 #endif /* _ASMLANGUAGE */ 258 259 #ifdef __cplusplus 260 } 261 #endif 262 263 #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ */ 264