1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #ifndef INTERRUPT_UTIL_H_
8 #define INTERRUPT_UTIL_H_
9
10 #if defined(CONFIG_CPU_CORTEX_M)
11 #include <cmsis_core.h>
12
get_available_nvic_line(uint32_t initial_offset)13 static inline uint32_t get_available_nvic_line(uint32_t initial_offset)
14 {
15 int i;
16
17 for (i = initial_offset - 1; i >= 0; i--) {
18
19 if (NVIC_GetEnableIRQ(i) == 0) {
20 /*
21 * Interrupts configured statically with IRQ_CONNECT(.)
22 * are automatically enabled. NVIC_GetEnableIRQ()
23 * returning false, here, implies that the IRQ line is
24 * either not implemented or it is not enabled, thus,
25 * currently not in use by Zephyr.
26 */
27
28 /* Set the NVIC line to pending. */
29 NVIC_SetPendingIRQ(i);
30
31 if (NVIC_GetPendingIRQ(i)) {
32 /*
33 * If the NVIC line is pending, it is
34 * guaranteed that it is implemented; clear the
35 * line.
36 */
37 NVIC_ClearPendingIRQ(i);
38
39 if (!NVIC_GetPendingIRQ(i)) {
40 /*
41 * If the NVIC line can be successfully
42 * un-pended, it is guaranteed that it
43 * can be used for software interrupt
44 * triggering. Return the NVIC line
45 * number.
46 */
47 break;
48 }
49 }
50 }
51 }
52
53 zassert_true(i >= 0, "No available IRQ line\n");
54
55 return i;
56 }
57
trigger_irq(int irq)58 static inline void trigger_irq(int irq)
59 {
60 printk("Triggering irq : %d\n", irq);
61 #if defined(CONFIG_SOC_TI_LM3S6965_QEMU) || defined(CONFIG_CPU_CORTEX_M0) \
62 || defined(CONFIG_CPU_CORTEX_M0PLUS) || defined(CONFIG_CPU_CORTEX_M1)\
63 || defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
64 /* QEMU does not simulate the STIR register: this is a workaround */
65 NVIC_SetPendingIRQ(irq);
66 #else
67 NVIC->STIR = irq;
68 #endif
69 }
70
71 #elif defined(CONFIG_GIC)
72 #include <zephyr/drivers/interrupt_controller/gic.h>
73 #include <zephyr/dt-bindings/interrupt-controller/arm-gic.h>
74
trigger_irq(int irq)75 static inline void trigger_irq(int irq)
76 {
77 printk("Triggering irq : %d\n", irq);
78
79 /* Ensure that the specified IRQ number is a valid SGI interrupt ID */
80 zassert_true(irq <= 15, "%u is not a valid SGI interrupt ID", irq);
81
82 /*
83 * Generate a software generated interrupt and forward it to the
84 * requesting CPU.
85 */
86 #if CONFIG_GIC_VER <= 2
87 sys_write32(GICD_SGIR_TGTFILT_REQONLY | GICD_SGIR_SGIINTID(irq),
88 GICD_SGIR);
89 #else
90 uint64_t mpidr = GET_MPIDR();
91 uint8_t aff0 = MPIDR_AFFLVL(mpidr, 0);
92
93 gic_raise_sgi(irq, mpidr, BIT(aff0));
94 #endif
95 }
96
97 #elif defined(CONFIG_ARC)
trigger_irq(int irq)98 static inline void trigger_irq(int irq)
99 {
100 printk("Triggering irq : %d\n", irq);
101 z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, irq);
102 }
103
104 #elif defined(CONFIG_X86)
105
106 #ifdef CONFIG_X2APIC
107 #include <zephyr/drivers/interrupt_controller/loapic.h>
108 #define VECTOR_MASK 0xFF
109 #else
110 #include <zephyr/arch/arch_interface.h>
111 #define LOAPIC_ICR_IPI_TEST 0x00004000U
112 #endif
113
114 /*
115 * We can emulate the interrupt by sending the IPI to
116 * core itself by the LOAPIC for x86 platform.
117 *
118 * In APIC mode, Write LOAPIC's ICR to trigger IPI,
119 * the LOAPIC_ICR_IPI_TEST 0x00004000U means:
120 * Delivery Mode: Fixed
121 * Destination Mode: Physical
122 * Level: Assert
123 * Trigger Mode: Edge
124 * Destination Shorthand: No Shorthand
125 * Destination: depends on cpu_id
126 *
127 * In X2APIC mode, this no longer works. We emulate the
128 * interrupt by writing the IA32_X2APIC_SELF_IPI MSR
129 * to send IPI to the core itself via LOAPIC also.
130 * According to SDM vol.3 chapter 10.12.11, the bit[7:0]
131 * for setting the vector is only needed.
132 */
trigger_irq(int vector)133 static inline void trigger_irq(int vector)
134 {
135 uint8_t i;
136
137 #ifdef CONFIG_X2APIC
138 x86_write_x2apic(LOAPIC_SELF_IPI, ((VECTOR_MASK & vector)));
139 #else
140
141 #ifdef CONFIG_SMP
142 int cpu_id = arch_curr_cpu()->id;
143 #else
144 int cpu_id = 0;
145 #endif
146 z_loapic_ipi(cpu_id, LOAPIC_ICR_IPI_TEST, vector);
147 #endif /* CONFIG_X2APIC */
148
149 /*
150 * add some nop operations here to cost some cycles to make sure
151 * the IPI interrupt is handled before do our check.
152 */
153 for (i = 0; i < 10; i++) {
154 arch_nop();
155 }
156 }
157
158 #elif defined(CONFIG_ARCH_POSIX)
159 #include <zephyr/arch/posix/posix_soc_if.h>
160
trigger_irq(int irq)161 static inline void trigger_irq(int irq)
162 {
163 posix_sw_set_pending_IRQ(irq);
164 }
165
166 #elif defined(CONFIG_RISCV)
167 #if defined(CONFIG_NUCLEI_ECLIC) || defined(CONFIG_NRFX_CLIC)
168 void riscv_clic_irq_set_pending(uint32_t irq);
trigger_irq(int irq)169 static inline void trigger_irq(int irq)
170 {
171 riscv_clic_irq_set_pending(irq);
172 }
173 #else
trigger_irq(int irq)174 static inline void trigger_irq(int irq)
175 {
176 uint32_t mip;
177
178 __asm__ volatile ("csrrs %0, mip, %1\n"
179 : "=r" (mip)
180 : "r" (1 << irq));
181 }
182 #endif
183 #elif defined(CONFIG_XTENSA)
trigger_irq(int irq)184 static inline void trigger_irq(int irq)
185 {
186 z_xt_set_intset(BIT((unsigned int)irq));
187 }
188
189 #elif defined(CONFIG_SPARC)
190 extern void z_sparc_enter_irq(int);
191
trigger_irq(int irq)192 static inline void trigger_irq(int irq)
193 {
194 z_sparc_enter_irq(irq);
195 }
196
197 #elif defined(CONFIG_MIPS)
198 extern void z_mips_enter_irq(int);
199
trigger_irq(int irq)200 static inline void trigger_irq(int irq)
201 {
202 z_mips_enter_irq(irq);
203 }
204
205 #elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_VIM)
206
207 extern void z_vim_arm_enter_irq(int);
208
trigger_irq(int irq)209 static inline void trigger_irq(int irq)
210 {
211 z_vim_arm_enter_irq(irq);
212 }
213
214 #else
215 /* So far, Nios II does not support this */
216 #define NO_TRIGGER_FROM_SW
217 #endif
218
219 #endif /* INTERRUPT_UTIL_H_ */
220