Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | /* * Copyright (c) 2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief ARCv2 public interrupt handling * * ARCv2 kernel interrupt handling interface. Included by arc/arch.h. */ #ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_IRQ_H_ #define ZEPHYR_INCLUDE_ARCH_ARC_V2_IRQ_H_ #include <arch/arc/v2/aux_regs.h> #include <toolchain/common.h> #include <irq.h> #include <sys/util.h> #include <sw_isr_table.h> #ifdef __cplusplus extern "C" { #endif #ifndef _ASMLANGUAGE extern void z_arc_firq_stack_set(void); 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); #ifdef CONFIG_TRACING_ISR extern void sys_trace_isr_enter(void); extern void sys_trace_isr_exit(void); #endif extern void z_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags); extern void _isr_wrapper(void); extern void z_irq_spurious(const void *unused); /* Z_ISR_DECLARE will populate the .intList section with the interrupt's * parameters, which will then be used by gen_irq_tables.py to create * the vector table and the software ISR table. This is all done at * build-time. * * We additionally set the priority in the interrupt controller at * runtime. */ #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ { \ Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \ z_irq_priority_set(irq_p, priority_p, flags_p); \ } /** * Configure a 'direct' static interrupt. * * When firq has no separate stack(CONFIG_ARC_FIRQ_STACK=N), it's not safe * to call C ISR handlers because sp will be switched to bank1's sp which * is undefined value. * So for this case, the priority cannot be set to 0 but next level 1 * * When firq has separate stack (CONFIG_ARC_FIRQ_STACK=y) but at the same * time stack checking is enabled (CONFIG_ARC_STACK_CHECKING=y) * the stack checking can raise stack check exception as sp is switched to * firq's stack (bank1's sp). So for this case, the priority cannot be set * to 0 but next level 1. * * Note that for the above cases, if application still wants to use firq by * setting priority to 0. Application can call z_irq_priority_set again. * Then it's left to application to handle the details of firq * * 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) \ { \ Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ BUILD_ASSERT(priority_p || !IS_ENABLED(CONFIG_ARC_FIRQ) || \ (IS_ENABLED(CONFIG_ARC_FIRQ_STACK) && \ !IS_ENABLED(CONFIG_ARC_STACK_CHECKING)), \ "irq priority cannot be set to 0 when CONFIG_ARC_FIRQ_STACK" \ "is not configured or CONFIG_ARC_FIRQ_STACK " \ "and CONFIG_ARC_STACK_CHECKING are configured together"); \ z_irq_priority_set(irq_p, priority_p, flags_p); \ } static inline void arch_isr_direct_header(void) { #ifdef CONFIG_TRACING_ISR sys_trace_isr_enter(); #endif } static inline void arch_isr_direct_footer(int maybe_swap) { /* clear SW generated interrupt */ if (z_arc_v2_aux_reg_read(_ARC_V2_ICAUSE) == z_arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_HINT)) { z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, 0); } #ifdef CONFIG_TRACING_ISR sys_trace_isr_exit(); #endif } #define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header() extern void arch_isr_direct_header(void); #define ARCH_ISR_DIRECT_FOOTER(swap) arch_isr_direct_footer(swap) #if defined(__CCAC__) #define _ARC_DIRECT_ISR_FUNC_ATTRIBUTE __interrupt__ #else #define _ARC_DIRECT_ISR_FUNC_ATTRIBUTE interrupt("ilink") #endif /* * Scheduling can not be done in direct isr. If required, please use kernel * aware interrupt handling */ #define ARCH_ISR_DIRECT_DECLARE(name) \ static inline int name##_body(void); \ __attribute__ ((_ARC_DIRECT_ISR_FUNC_ATTRIBUTE))void name(void) \ { \ ISR_DIRECT_HEADER(); \ name##_body(); \ ISR_DIRECT_FOOTER(0); \ } \ static inline int name##_body(void) /** * * @brief Disable all interrupts on the local CPU * * This routine disables interrupts. It can be called from either interrupt or * thread level. This routine returns an architecture-dependent * lock-out key representing the "interrupt disable state" prior to the call; * this key can be passed to irq_unlock() to re-enable interrupts. * * The lock-out key should only be used as the argument to the * irq_unlock() API. It should never be used to manually re-enable * interrupts or to inspect or manipulate the contents of the source register. * * This function can be called recursively: it will return a key to return the * state of interrupt locking to the previous level. * * WARNINGS * Invoking a kernel routine with interrupts locked may result in * interrupts being re-enabled for an unspecified period of time. If the * called routine blocks, interrupts will be re-enabled while another * thread executes, or while the system is idle. * * The "interrupt disable state" is an attribute of a thread. Thus, if a * thread disables interrupts and subsequently invokes a kernel * routine that causes the calling thread to block, the interrupt * disable state will be restored when the thread is later rescheduled * for execution. * * @return An architecture-dependent lock-out key representing the * "interrupt disable state" prior to the call. */ static ALWAYS_INLINE unsigned int arch_irq_lock(void) { unsigned int key; __asm__ volatile("clri %0" : "=r"(key):: "memory"); return key; } static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { __asm__ volatile("seti %0" : : "ir"(key) : "memory"); } static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { /* ARC irq lock uses instruction "clri r0", * r0 == {26’d0, 1’b1, STATUS32.IE, STATUS32.E[3:0] } * bit4 is used to record IE (Interrupt Enable) bit */ return (key & 0x10) == 0x10; } #endif /* _ASMLANGUAGE */ #ifdef __cplusplus } #endif #endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_IRQ_H_ */ |