1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/sw_isr_table.h>
8 #include <zephyr/arch/cpu.h>
9 #include <zephyr/irq.h>
10 #include <zephyr/sys/__assert.h>
11 /*
12 * Common code for arches that use software ISR tables (CONFIG_GEN_ISR_TABLES)
13 */
14
15 #ifdef CONFIG_DYNAMIC_INTERRUPTS
16
17 #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS
18
19 struct irq_parent_offset {
20 unsigned int irq;
21 unsigned int offset;
22 };
23
24 #define INIT_IRQ_PARENT_OFFSET(i, o) { \
25 .irq = i, \
26 .offset = o, \
27 }
28
29 #define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR)
30
31 #ifdef CONFIG_2ND_LEVEL_INTERRUPTS
32
33 #define CAT_2ND_LVL_LIST(i, base) \
34 INIT_IRQ_PARENT_OFFSET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET, \
35 IRQ_INDEX_TO_OFFSET(i, base))
36 static struct irq_parent_offset lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS]
37 = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,),
38 CONFIG_2ND_LVL_ISR_TBL_OFFSET) };
39
40 #endif/* CONFIG_2ND_LEVEL_INTERRUPTS */
41
42 #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
43
44 #define CAT_3RD_LVL_LIST(i, base) \
45 INIT_IRQ_PARENT_OFFSET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET, \
46 IRQ_INDEX_TO_OFFSET(i, base))
47 static struct irq_parent_offset lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS]
48 = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,),
49 CONFIG_3RD_LVL_ISR_TBL_OFFSET) };
50
51 #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
52
get_parent_offset(unsigned int parent_irq,struct irq_parent_offset list[],unsigned int length)53 unsigned int get_parent_offset(unsigned int parent_irq,
54 struct irq_parent_offset list[],
55 unsigned int length)
56 {
57 unsigned int i;
58 unsigned int offset = 0U;
59
60 for (i = 0U; i < length; ++i) {
61 if (list[i].irq == parent_irq) {
62 offset = list[i].offset;
63 break;
64 }
65 }
66
67 __ASSERT(i != length, "Invalid argument: %i", parent_irq);
68
69 return offset;
70 }
71
72 #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
73
z_isr_install(unsigned int irq,void (* routine)(const void *),const void * param)74 void z_isr_install(unsigned int irq, void (*routine)(const void *),
75 const void *param)
76 {
77 unsigned int table_idx;
78
79 /*
80 * Do not assert on the IRQ enable status for ARM GIC since the SGI
81 * type interrupts are always enabled and attempting to install an ISR
82 * for them will cause the assertion to fail.
83 */
84 #ifndef CONFIG_GIC
85 __ASSERT(!irq_is_enabled(irq), "IRQ %d is enabled", irq);
86 #endif /* !CONFIG_GIC */
87
88 #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS
89 unsigned int level;
90 unsigned int parent_irq;
91 unsigned int parent_offset;
92
93 level = irq_get_level(irq);
94
95 if (level == 2U) {
96 parent_irq = irq_parent_level_2(irq);
97 parent_offset = get_parent_offset(parent_irq,
98 lvl2_irq_list,
99 CONFIG_NUM_2ND_LEVEL_AGGREGATORS);
100 table_idx = parent_offset + irq_from_level_2(irq);
101 }
102 #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
103 else if (level == 3U) {
104 parent_irq = irq_parent_level_3(irq);
105 parent_offset = get_parent_offset(parent_irq,
106 lvl3_irq_list,
107 CONFIG_NUM_3RD_LEVEL_AGGREGATORS);
108 table_idx = parent_offset + irq_from_level_3(irq);
109 }
110 #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
111 else {
112 table_idx = irq;
113 }
114
115 table_idx -= CONFIG_GEN_IRQ_START_VECTOR;
116 #else
117 table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR;
118 #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
119
120 /* If dynamic IRQs are enabled, then the _sw_isr_table is in RAM and
121 * can be modified
122 */
123 _sw_isr_table[table_idx].arg = param;
124 _sw_isr_table[table_idx].isr = routine;
125 }
126
127 /* Some architectures don't/can't interpret flags or priority and have
128 * no more processing to do than this. Provide a generic fallback.
129 */
arch_irq_connect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void *),const void * parameter,uint32_t flags)130 int __weak arch_irq_connect_dynamic(unsigned int irq,
131 unsigned int priority,
132 void (*routine)(const void *),
133 const void *parameter,
134 uint32_t flags)
135 {
136 ARG_UNUSED(flags);
137 ARG_UNUSED(priority);
138
139 z_isr_install(irq, routine, parameter);
140 return irq;
141 }
142
143 #endif /* CONFIG_DYNAMIC_INTERRUPTS */
144