Line data Source code
1 1 : /*
2 : * Copyright (c) 2014, Wind River Systems, Inc.
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : * @brief Software-managed ISR table
10 : *
11 : * Data types for a software-managed ISR table, with a parameter per-ISR.
12 : */
13 :
14 : #ifndef ZEPHYR_INCLUDE_SW_ISR_TABLE_H_
15 : #define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_
16 :
17 : #if !defined(_ASMLANGUAGE)
18 : #include <zephyr/device.h>
19 : #include <zephyr/sys/iterable_sections.h>
20 : #include <zephyr/types.h>
21 : #include <zephyr/toolchain.h>
22 : #include <zephyr/sys/util.h>
23 :
24 : #ifdef __cplusplus
25 : extern "C" {
26 : #endif
27 :
28 : /* Default vector for the IRQ vector table */
29 : void _isr_wrapper(void);
30 :
31 : /* Spurious interrupt handler. Throws an error if called */
32 : void z_irq_spurious(const void *unused);
33 :
34 : /*
35 : * Note the order: arg first, then ISR. This allows a table entry to be
36 : * loaded arg -> r0, isr -> r3 in _isr_wrapper with one ldmia instruction,
37 : * on ARM Cortex-M (Thumb2).
38 : */
39 : struct _isr_table_entry {
40 : const void *arg;
41 : void (*isr)(const void *);
42 : };
43 :
44 : /* The software ISR table itself, an array of these structures indexed by the
45 : * irq line
46 : */
47 : extern
48 : #ifndef CONFIG_DYNAMIC_INTERRUPTS
49 : const
50 : #endif
51 : struct _isr_table_entry _sw_isr_table[];
52 :
53 : struct _irq_parent_entry {
54 : const struct device *dev;
55 : unsigned int level;
56 : unsigned int irq;
57 : unsigned int offset;
58 : };
59 :
60 : /**
61 : * @cond INTERNAL_HIDDEN
62 : */
63 :
64 : /* Mapping between aggregator level to order */
65 : #define Z_STR_L2 2ND
66 : #define Z_STR_L3 3RD
67 : /**
68 : * @brief Get the Software ISR table offset Kconfig for the given aggregator level
69 : *
70 : * @param l Aggregator level, must be 2 or 3
71 : *
72 : * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if second level aggregator,
73 : * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if third level aggregator
74 : */
75 : #define Z_SW_ISR_TBL_KCONFIG_BY_ALVL(l) CONCAT(CONFIG_, CONCAT(Z_STR_L, l), _LVL_ISR_TBL_OFFSET)
76 :
77 : /**
78 : * INTERNAL_HIDDEN @endcond
79 : */
80 :
81 : /**
82 : * @brief Get an interrupt controller node's level base ISR table offset.
83 : *
84 : * @param node_id node identifier of the interrupt controller
85 : *
86 : * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if node_id is a second level aggregator,
87 : * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if it is a third level aggregator
88 : */
89 1 : #define INTC_BASE_ISR_TBL_OFFSET(node_id) \
90 : Z_SW_ISR_TBL_KCONFIG_BY_ALVL(DT_INTC_GET_AGGREGATOR_LEVEL(node_id))
91 :
92 : /**
93 : * @brief Get the SW ISR table offset for an instance of interrupt controller
94 : *
95 : * @param inst DT_DRV_COMPAT interrupt controller driver instance number
96 : *
97 : * @return Software ISR table offset of the interrupt controller
98 : */
99 1 : #define INTC_INST_ISR_TBL_OFFSET(inst) \
100 : (INTC_BASE_ISR_TBL_OFFSET(DT_DRV_INST(inst)) + (inst * CONFIG_MAX_IRQ_PER_AGGREGATOR))
101 :
102 : /**
103 : * @brief Get the SW ISR table offset for a child interrupt controller
104 : *
105 : * @details This macro is a alternative form of the `INTC_INST_ISR_TBL_OFFSET`. This is used by
106 : * pseudo interrupt controller devices that are child of a main interrupt controller device.
107 : *
108 : * @param node_id node identifier of the child interrupt controller
109 : *
110 : * @return Software ISR table offset of the child
111 : */
112 1 : #define INTC_CHILD_ISR_TBL_OFFSET(node_id) \
113 : (INTC_BASE_ISR_TBL_OFFSET(node_id) + \
114 : (DT_NODE_CHILD_IDX(node_id) * CONFIG_MAX_IRQ_PER_AGGREGATOR))
115 :
116 : /**
117 : * @brief Register an interrupt controller with the software ISR table
118 : *
119 : * @param _name Name of the interrupt controller (must be unique)
120 : * @param _dev Pointer to the interrupt controller device instance
121 : * @param _irq Interrupt controller IRQ number
122 : * @param _offset Software ISR table offset of the interrupt controller
123 : * @param _level Interrupt controller aggregator level
124 : */
125 1 : #define IRQ_PARENT_ENTRY_DEFINE(_name, _dev, _irq, _offset, _level) \
126 : static const STRUCT_SECTION_ITERABLE_ALTERNATE(intc_table, _irq_parent_entry, _name) = { \
127 : .dev = _dev, \
128 : .level = _level, \
129 : .irq = _irq, \
130 : .offset = _offset, \
131 : }
132 :
133 : /*
134 : * Data structure created in a special binary .intlist section for each
135 : * configured interrupt. gen_irq_tables.py pulls this out of the binary and
136 : * uses it to create the IRQ vector table and the _sw_isr_table.
137 : *
138 : * More discussion in include/linker/intlist.ld
139 : *
140 : * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled.
141 : * See _isr_list_sname used otherwise.
142 : */
143 : struct _isr_list {
144 : /** IRQ line number */
145 : int32_t irq;
146 : /** Flags for this IRQ, see ISR_FLAG_* definitions */
147 : int32_t flags;
148 : /** ISR to call */
149 : void *func;
150 : /** Parameter for non-direct IRQs */
151 : const void *param;
152 : };
153 :
154 : /*
155 : * Data structure created in a special binary .intlist section for each
156 : * configured interrupt. gen_isr_tables.py pulls this out of the binary and
157 : * uses it to create linker script chunks that would place interrupt table entries
158 : * in the right place in the memory.
159 : *
160 : * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled.
161 : * See _isr_list used otherwise.
162 : */
163 : struct _isr_list_sname {
164 : /** IRQ line number */
165 : int32_t irq;
166 : /** Flags for this IRQ, see ISR_FLAG_* definitions */
167 : int32_t flags;
168 : /** The section name */
169 : const char sname[];
170 : };
171 :
172 : #ifdef CONFIG_SHARED_INTERRUPTS
173 : struct z_shared_isr_table_entry {
174 : struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS];
175 : size_t client_num;
176 : };
177 :
178 : void z_shared_isr(const void *data);
179 :
180 : extern
181 : #ifndef CONFIG_DYNAMIC_INTERRUPTS
182 : const
183 : #endif
184 : struct z_shared_isr_table_entry z_shared_sw_isr_table[];
185 : #endif /* CONFIG_SHARED_INTERRUPTS */
186 :
187 : /** This interrupt gets put directly in the vector table */
188 1 : #define ISR_FLAG_DIRECT BIT(0)
189 :
190 : #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y)
191 : #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y
192 :
193 :
194 : #if defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION)
195 :
196 : #define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id)
197 : #define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id
198 :
199 : #define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id)
200 : #define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id
201 :
202 : #define _MK_ISR_SECTION_NAME(prefix, file, counter) \
203 : "." Z_STRINGIFY(prefix) "." file "." Z_STRINGIFY(counter)
204 :
205 : #define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter)
206 : #define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter)
207 :
208 : /* Separated macro to create ISR table entry only.
209 : * Used by Z_ISR_DECLARE and ISR tables generation script.
210 : */
211 : #define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \
212 : static Z_DECL_ALIGN(struct _isr_table_entry) \
213 : __attribute__((section(sect))) \
214 : __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \
215 : .arg = (const void *)(param), \
216 : .isr = (void (*)(const void *))(void *)(func) \
217 : }
218 :
219 : #define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \
220 : _Z_ISR_DECLARE_C(irq, flags, func, param, counter)
221 :
222 : #define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \
223 : _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \
224 : static Z_DECL_ALIGN(struct _isr_list_sname) Z_GENERIC_SECTION(.intList) __used \
225 : _MK_ISR_NAME(func, counter) = {irq, flags, {_MK_ISR_ELEMENT_SECTION(counter)}}
226 :
227 : /* Create an entry for _isr_table to be then placed by the linker.
228 : * An instance of struct _isr_list which gets put in the .intList
229 : * section is created with the name of the section where _isr_table entry is placed to be then
230 : * used by isr generation script to create linker script chunk.
231 : */
232 : #define Z_ISR_DECLARE(irq, flags, func, param) \
233 : BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \
234 : Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__)
235 :
236 :
237 : /* Separated macro to create ISR Direct table entry only.
238 : * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script.
239 : */
240 : #define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \
241 : COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \
242 : static Z_DECL_ALIGN(uintptr_t) \
243 : __attribute__((section(sect))) \
244 : __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \
245 : ), ( \
246 : void __attribute__((section(sect))) __attribute__((naked)) \
247 : /* clang-format off */ \
248 : __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) (void) { \
249 : __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \
250 : } \
251 : /* clang-format on */ \
252 : ))
253 :
254 : #define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \
255 : _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter)
256 :
257 : #define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \
258 : _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \
259 : static Z_DECL_ALIGN(struct _isr_list_sname) Z_GENERIC_SECTION(.intList) \
260 : __used _MK_ISR_NAME(func, counter) = { \
261 : irq, \
262 : ISR_FLAG_DIRECT | (flags), \
263 : _MK_IRQ_ELEMENT_SECTION(counter)}
264 :
265 : /* Create an entry to irq table and place it in specific section which name is then placed
266 : * in an instance of struct _isr_list to be then used by the isr generation script to create
267 : * the linker script chunks.
268 : */
269 : #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \
270 : BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \
271 : IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \
272 : "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \
273 : Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__)
274 :
275 :
276 : #else /* defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */
277 :
278 : /* Create an instance of struct _isr_list which gets put in the .intList
279 : * section. This gets consumed by gen_isr_tables.py which creates the vector
280 : * and/or SW ISR tables.
281 : */
282 : #define Z_ISR_DECLARE(irq, flags, func, param) \
283 : static Z_DECL_ALIGN(struct _isr_list) Z_GENERIC_SECTION(.intList) \
284 : __used _MK_ISR_NAME(func, __COUNTER__) = \
285 : {irq, flags, (void *)&func, (const void *)param}
286 :
287 : /* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration.
288 : * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled.
289 : */
290 : #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \
291 : Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL)
292 :
293 : #endif
294 :
295 0 : #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR)
296 :
297 : #ifdef CONFIG_DYNAMIC_INTERRUPTS
298 : void z_isr_install(unsigned int irq, void (*routine)(const void *),
299 : const void *param);
300 :
301 : #ifdef CONFIG_SHARED_INTERRUPTS
302 : int z_isr_uninstall(unsigned int irq, void (*routine)(const void *),
303 : const void *param);
304 : #endif /* CONFIG_SHARED_INTERRUPTS */
305 : #endif
306 :
307 : #ifdef __cplusplus
308 : }
309 : #endif
310 :
311 : #endif /* _ASMLANGUAGE */
312 :
313 : #endif /* ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ */
|