1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2006-02-24 Bernard first version
9 * 2006-05-03 Bernard add IRQ_DEBUG
10 * 2016-08-09 ArdaFu add interrupt enter and leave hook.
11 * 2018-11-22 Jesven rt_interrupt_get_nest function add disable irq
12 * 2021-08-15 Supperthomas fix the comment
13 * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to irq.c
14 * 2022-07-04 Yunjie fix RT_DEBUG_LOG
15 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
16 * 2024-01-05 Shell Fixup of data racing in rt_interrupt_get_nest
17 * 2024-01-03 Shell Support for interrupt context
18 */
19
20 #include <rthw.h>
21 #include <rtthread.h>
22
23 #define DBG_TAG "kernel.irq"
24 #define DBG_LVL DBG_INFO
25 #include <rtdbg.h>
26
27 #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
28
29 static void (*rt_interrupt_enter_hook)(void);
30 static void (*rt_interrupt_leave_hook)(void);
31
32 /**
33 * @ingroup group_hook
34 *
35 * @brief This function set a hook function when the system enter a interrupt
36 *
37 * @note The hook function must be simple and never be blocked or suspend.
38 *
39 * @param hook the function point to be called
40 */
rt_interrupt_enter_sethook(void (* hook)(void))41 void rt_interrupt_enter_sethook(void (*hook)(void))
42 {
43 rt_interrupt_enter_hook = hook;
44 }
45
46 /**
47 * @ingroup group_hook
48 *
49 * @brief This function set a hook function when the system exit a interrupt.
50 *
51 * @note The hook function must be simple and never be blocked or suspend.
52 *
53 * @param hook the function point to be called
54 */
rt_interrupt_leave_sethook(void (* hook)(void))55 void rt_interrupt_leave_sethook(void (*hook)(void))
56 {
57 rt_interrupt_leave_hook = hook;
58 }
59 #endif /* RT_USING_HOOK */
60
61 /**
62 * @addtogroup group_kernel_core
63 */
64
65 /**@{*/
66
67 #ifdef RT_USING_SMP
68 #define rt_interrupt_nest rt_cpu_self()->irq_nest
69 #else
70 volatile rt_atomic_t rt_interrupt_nest = 0;
71 #endif /* RT_USING_SMP */
72
73 #ifdef ARCH_USING_IRQ_CTX_LIST
rt_interrupt_context_push(rt_interrupt_context_t this_ctx)74 void rt_interrupt_context_push(rt_interrupt_context_t this_ctx)
75 {
76 struct rt_cpu *this_cpu = rt_cpu_self();
77 rt_slist_insert(&this_cpu->irq_ctx_head, &this_ctx->node);
78 }
79
rt_interrupt_context_pop(void)80 void rt_interrupt_context_pop(void)
81 {
82 struct rt_cpu *this_cpu = rt_cpu_self();
83 rt_slist_pop(&this_cpu->irq_ctx_head);
84 }
85
rt_interrupt_context_get(void)86 void *rt_interrupt_context_get(void)
87 {
88 struct rt_cpu *this_cpu = rt_cpu_self();
89 return rt_slist_first_entry(&this_cpu->irq_ctx_head, struct rt_interrupt_context, node)->context;
90 }
91 #endif /* ARCH_USING_IRQ_CTX_LIST */
92
93 /**
94 * @brief This function will be invoked by BSP, when enter interrupt service routine
95 *
96 * @note Please don't invoke this routine in application
97 *
98 * @see rt_interrupt_leave
99 */
rt_interrupt_enter(void)100 rt_weak void rt_interrupt_enter(void)
101 {
102 rt_atomic_add(&(rt_interrupt_nest), 1);
103 RT_OBJECT_HOOK_CALL(rt_interrupt_enter_hook,());
104 LOG_D("irq has come..., irq current nest:%d",
105 (rt_int32_t)rt_atomic_load(&(rt_interrupt_nest)));
106 }
107 RTM_EXPORT(rt_interrupt_enter);
108
109
110 /**
111 * @brief This function will be invoked by BSP, when leave interrupt service routine
112 *
113 * @note Please don't invoke this routine in application
114 *
115 * @see rt_interrupt_enter
116 */
rt_interrupt_leave(void)117 rt_weak void rt_interrupt_leave(void)
118 {
119 LOG_D("irq is going to leave, irq current nest:%d",
120 (rt_int32_t)rt_atomic_load(&(rt_interrupt_nest)));
121 RT_OBJECT_HOOK_CALL(rt_interrupt_leave_hook,());
122 rt_atomic_sub(&(rt_interrupt_nest), 1);
123
124 }
125 RTM_EXPORT(rt_interrupt_leave);
126
127
128 /**
129 * @brief This function will return the nest of interrupt.
130 *
131 * User application can invoke this function to get whether current
132 * context is interrupt context.
133 *
134 * @return the number of nested interrupts.
135 */
rt_interrupt_get_nest(void)136 rt_weak rt_uint8_t rt_interrupt_get_nest(void)
137 {
138 rt_uint8_t ret;
139 rt_base_t level;
140
141 level = rt_hw_local_irq_disable();
142 ret = rt_atomic_load(&rt_interrupt_nest);
143 rt_hw_local_irq_enable(level);
144 return ret;
145 }
146 RTM_EXPORT(rt_interrupt_get_nest);
147
148 RTM_EXPORT(rt_hw_interrupt_disable);
149 RTM_EXPORT(rt_hw_interrupt_enable);
150
rt_hw_interrupt_is_disabled(void)151 rt_weak rt_bool_t rt_hw_interrupt_is_disabled(void)
152 {
153 return RT_FALSE;
154 }
155 RTM_EXPORT(rt_hw_interrupt_is_disabled);
156 /**@}*/
157
158