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