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 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | /* * Copyright (c) 2014, Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Software-managed ISR table * * Data types for a software-managed ISR table, with a parameter per-ISR. */ #ifndef ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ #define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ #if !defined(_ASMLANGUAGE) #include <zephyr/device.h> #include <zephyr/sys/iterable_sections.h> #include <zephyr/types.h> #include <zephyr/toolchain.h> #include <zephyr/sys/util.h> #ifdef __cplusplus extern "C" { #endif /* Default vector for the IRQ vector table */ void _isr_wrapper(void); /* Spurious interrupt handler. Throws an error if called */ void z_irq_spurious(const void *unused); /* * Note the order: arg first, then ISR. This allows a table entry to be * loaded arg -> r0, isr -> r3 in _isr_wrapper with one ldmia instruction, * on ARM Cortex-M (Thumb2). */ struct _isr_table_entry { const void *arg; void (*isr)(const void *); }; /* The software ISR table itself, an array of these structures indexed by the * irq line */ extern struct _isr_table_entry _sw_isr_table[]; struct _irq_parent_entry { const struct device *dev; unsigned int level; unsigned int irq; unsigned int offset; }; /** * @cond INTERNAL_HIDDEN */ /* Mapping between aggregator level to order */ #define Z_STR_L2 2ND #define Z_STR_L3 3RD /** * @brief Get the Software ISR table offset Kconfig for the given aggregator level * * @param l Aggregator level, must be 2 or 3 * * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if second level aggregator, * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if third level aggregator */ #define Z_SW_ISR_TBL_KCONFIG_BY_ALVL(l) CONCAT(CONFIG_, CONCAT(Z_STR_L, l), _LVL_ISR_TBL_OFFSET) /** * INTERNAL_HIDDEN @endcond */ /** * @brief Get an interrupt controller node's level base ISR table offset. * * @param node_id node identifier of the interrupt controller * * @return `CONFIG_2ND_LVL_ISR_TBL_OFFSET` if node_id is a second level aggregator, * `CONFIG_3RD_LVL_ISR_TBL_OFFSET` if it is a third level aggregator */ #define INTC_BASE_ISR_TBL_OFFSET(node_id) \ Z_SW_ISR_TBL_KCONFIG_BY_ALVL(DT_INTC_GET_AGGREGATOR_LEVEL(node_id)) /** * @brief Get the SW ISR table offset for an instance of interrupt controller * * @param inst DT_DRV_COMPAT interrupt controller driver instance number * * @return Software ISR table offset of the interrupt controller */ #define INTC_INST_ISR_TBL_OFFSET(inst) \ (INTC_BASE_ISR_TBL_OFFSET(DT_DRV_INST(inst)) + (inst * CONFIG_MAX_IRQ_PER_AGGREGATOR)) /** * @brief Get the SW ISR table offset for a child interrupt controller * * @details This macro is a alternative form of the `INTC_INST_ISR_TBL_OFFSET`. This is used by * pseudo interrupt controller devices that are child of a main interrupt controller device. * * @param node_id node identifier of the child interrupt controller * * @return Software ISR table offset of the child */ #define INTC_CHILD_ISR_TBL_OFFSET(node_id) \ (INTC_BASE_ISR_TBL_OFFSET(node_id) + \ (DT_NODE_CHILD_IDX(node_id) * CONFIG_MAX_IRQ_PER_AGGREGATOR)) /** * @brief Register an interrupt controller with the software ISR table * * @param _name Name of the interrupt controller (must be unique) * @param _dev Pointer to the interrupt controller device instance * @param _irq Interrupt controller IRQ number * @param _offset Software ISR table offset of the interrupt controller * @param _level Interrupt controller aggregator level */ #define IRQ_PARENT_ENTRY_DEFINE(_name, _dev, _irq, _offset, _level) \ static const STRUCT_SECTION_ITERABLE_ALTERNATE(intc_table, _irq_parent_entry, _name) = { \ .dev = _dev, \ .level = _level, \ .irq = _irq, \ .offset = _offset, \ } /* * Data structure created in a special binary .intlist section for each * configured interrupt. gen_irq_tables.py pulls this out of the binary and * uses it to create the IRQ vector table and the _sw_isr_table. * * More discussion in include/linker/intlist.ld * * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled. * See _isr_list_sname used otherwise. */ struct _isr_list { /** IRQ line number */ int32_t irq; /** Flags for this IRQ, see ISR_FLAG_* definitions */ int32_t flags; /** ISR to call */ void *func; /** Parameter for non-direct IRQs */ const void *param; }; /* * Data structure created in a special binary .intlist section for each * configured interrupt. gen_isr_tables.py pulls this out of the binary and * uses it to create linker script chunks that would place interrupt table entries * in the right place in the memory. * * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. * See _isr_list used otherwise. */ struct _isr_list_sname { /** IRQ line number */ int32_t irq; /** Flags for this IRQ, see ISR_FLAG_* definitions */ int32_t flags; /** The section name */ const char sname[]; }; #ifdef CONFIG_SHARED_INTERRUPTS struct z_shared_isr_table_entry { struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; size_t client_num; }; void z_shared_isr(const void *data); extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #endif /* CONFIG_SHARED_INTERRUPTS */ /** This interrupt gets put directly in the vector table */ #define ISR_FLAG_DIRECT BIT(0) #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y) #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y #if defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) #define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) #define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id #define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) #define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id #define _MK_ISR_SECTION_NAME(prefix, file, counter) \ "." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter) #define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter) #define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter) /* Separated macro to create ISR table entry only. * Used by Z_ISR_DECLARE and ISR tables generation script. */ #define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \ static Z_DECL_ALIGN(struct _isr_table_entry) \ __attribute__((section(sect))) \ __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \ .arg = (const void *)(param), \ .isr = (void (*)(const void *))(void *)(func) \ } #define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ _Z_ISR_DECLARE_C(irq, flags, func, param, counter) #define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \ static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ __used _MK_ISR_NAME(func, counter) = \ {irq, flags, _MK_ISR_ELEMENT_SECTION(counter)} /* Create an entry for _isr_table to be then placed by the linker. * An instance of struct _isr_list which gets put in the .intList * section is created with the name of the section where _isr_table entry is placed to be then * used by isr generation script to create linker script chunk. */ #define Z_ISR_DECLARE(irq, flags, func, param) \ BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \ Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__) /* Separated macro to create ISR Direct table entry only. * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script. */ #define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \ COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \ static Z_DECL_ALIGN(uintptr_t) \ __attribute__((section(sect))) \ __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \ ), ( \ static void __attribute__((section(sect))) __attribute__((naked)) \ __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) { \ __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \ } \ )) #define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) #define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \ static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ __used _MK_ISR_NAME(func, counter) = { \ irq, \ ISR_FLAG_DIRECT | (flags), \ _MK_IRQ_ELEMENT_SECTION(counter)} /* Create an entry to irq table and place it in specific section which name is then placed * in an instance of struct _isr_list to be then used by the isr generation script to create * the linker script chunks. */ #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \ IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \ "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \ Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__) #else /* defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ /* Create an instance of struct _isr_list which gets put in the .intList * section. This gets consumed by gen_isr_tables.py which creates the vector * and/or SW ISR tables. */ #define Z_ISR_DECLARE(irq, flags, func, param) \ static Z_DECL_ALIGN(struct _isr_list) Z_GENERIC_SECTION(.intList) \ __used _MK_ISR_NAME(func, __COUNTER__) = \ {irq, flags, (void *)&func, (const void *)param} /* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration. * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled. */ #define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL) #endif #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR) #ifdef CONFIG_DYNAMIC_INTERRUPTS void z_isr_install(unsigned int irq, void (*routine)(const void *), const void *param); #ifdef CONFIG_SHARED_INTERRUPTS int z_isr_uninstall(unsigned int irq, void (*routine)(const void *), const void *param); #endif /* CONFIG_SHARED_INTERRUPTS */ #endif #ifdef __cplusplus } #endif #endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_SW_ISR_TABLE_H_ */ |