Zephyr API Documentation 4.4.0
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
interrupt_util.h
Go to the documentation of this file.
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#define k_str_out_count(s) k_str_out((s), sizeof(s) - 1)
11
12#if defined(CONFIG_CPU_ARM9)
13static inline void trigger_irq(int irq)
14{
15 ARG_UNUSED(irq);
16
17 IF_DISABLED(CONFIG_COMPILER_WARNINGS_AS_ERRORS,
18 (#warning "No generic ways to trigger IRQ of ARM9"))
19}
20#elif defined(CONFIG_CPU_CORTEX_M)
21#include <cmsis_core.h>
22
23static inline uint32_t get_available_nvic_line(uint32_t initial_offset)
24{
25 int i;
26
27 for (i = initial_offset - 1; i >= 0; i--) {
28
29 if (NVIC_GetEnableIRQ(i) == 0) {
30 /*
31 * Interrupts configured statically with IRQ_CONNECT(.)
32 * are automatically enabled. NVIC_GetEnableIRQ()
33 * returning false, here, implies that the IRQ line is
34 * either not implemented or it is not enabled, thus,
35 * currently not in use by Zephyr.
36 */
37
38 /* Set the NVIC line to pending. */
39 NVIC_SetPendingIRQ(i);
40
41 if (NVIC_GetPendingIRQ(i)) {
42 /*
43 * If the NVIC line is pending, it is
44 * guaranteed that it is implemented; clear the
45 * line.
46 */
47 NVIC_ClearPendingIRQ(i);
48
49 if (!NVIC_GetPendingIRQ(i)) {
50 /*
51 * If the NVIC line can be successfully
52 * un-pended, it is guaranteed that it
53 * can be used for software interrupt
54 * triggering. Return the NVIC line
55 * number.
56 */
57 break;
58 }
59 }
60 }
61 }
62
63 zassert_true(i >= 0, "No available IRQ line\n");
64
65 return i;
66}
67
68static inline void trigger_irq(int irq)
69{
70 k_str_out_count("Triggering irq\n");
71#if defined(CONFIG_SOC_TI_LM3S6965_QEMU) || defined(CONFIG_CPU_CORTEX_M0) || \
72 defined(CONFIG_CPU_CORTEX_M0PLUS) || defined(CONFIG_CPU_CORTEX_M1) || \
73 defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
74 /* QEMU does not simulate the STIR register: this is a workaround */
75 NVIC_SetPendingIRQ(irq);
76#else
77 NVIC->STIR = irq;
78#endif
79}
80
81#elif defined(CONFIG_GIC)
84
85static inline void trigger_irq(int irq)
86{
87 k_str_out_count("Triggering irq\n");
88
89 /* Ensure that the specified IRQ number is a valid SGI interrupt ID */
90 zassert_true(irq <= 15, "%u is not a valid SGI interrupt ID", irq);
91
92 /*
93 * Generate a software generated interrupt and forward it to the
94 * requesting CPU.
95 */
96#if CONFIG_GIC_VER <= 2
98#else
99 uint64_t mpidr = GET_MPIDR();
100 uint8_t aff0 = MPIDR_AFFLVL(mpidr, 0);
101
102 gic_raise_sgi(irq, mpidr, BIT(aff0));
103#endif
104}
105
106#elif defined(CONFIG_ARC)
107static inline void trigger_irq(int irq)
108{
109 k_str_out_count("Triggering irq\n");
110 z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, irq);
111}
112
113#elif defined(CONFIG_X86)
114
115#ifdef CONFIG_X2APIC
117#define VECTOR_MASK 0xFF
118#else
120#define LOAPIC_ICR_IPI_TEST 0x00004000U
121#endif
122
123/*
124 * We can emulate the interrupt by sending the IPI to
125 * core itself by the LOAPIC for x86 platform.
126 *
127 * In APIC mode, Write LOAPIC's ICR to trigger IPI,
128 * the LOAPIC_ICR_IPI_TEST 0x00004000U means:
129 * Delivery Mode: Fixed
130 * Destination Mode: Physical
131 * Level: Assert
132 * Trigger Mode: Edge
133 * Destination Shorthand: No Shorthand
134 * Destination: depends on cpu_id
135 *
136 * In X2APIC mode, this no longer works. We emulate the
137 * interrupt by writing the IA32_X2APIC_SELF_IPI MSR
138 * to send IPI to the core itself via LOAPIC also.
139 * According to SDM vol.3 chapter 10.12.11, the bit[7:0]
140 * for setting the vector is only needed.
141 */
142static inline void trigger_irq(int vector)
143{
144 uint8_t i;
145
146#ifdef CONFIG_X2APIC
147 x86_write_x2apic(LOAPIC_SELF_IPI, ((VECTOR_MASK & vector)));
148#else
149
150#ifdef CONFIG_SMP
151 int cpu_id = arch_curr_cpu()->id;
152#else
153 int cpu_id = 0;
154#endif
155 z_loapic_ipi(cpu_id, LOAPIC_ICR_IPI_TEST, vector);
156#endif /* CONFIG_X2APIC */
157
158 /*
159 * add some nop operations here to cost some cycles to make sure
160 * the IPI interrupt is handled before do our check.
161 */
162 for (i = 0; i < 10; i++) {
163 arch_nop();
164 }
165}
166
167#elif defined(CONFIG_ARCH_POSIX)
169
170static inline void trigger_irq(int irq)
171{
173}
174
175#elif defined(CONFIG_RISCV)
176#if defined(CONFIG_HAZARD3_INTC)
177#include <hardware/irq.h>
178#endif
179
180#if defined(CONFIG_CLIC) || defined(CONFIG_NRFX_CLIC)
181void riscv_clic_irq_set_pending(uint32_t irq);
182static inline void trigger_irq(int irq)
183{
184 riscv_clic_irq_set_pending(irq);
185}
186#elif defined(CONFIG_HAZARD3_INTC)
187static inline void trigger_irq(int irq)
188{
189 irq_set_pending(irq);
190}
191#else
192static inline void trigger_irq(int irq)
193{
194 uint32_t mip;
195
196 __asm__ volatile("csrrs %0, mip, %1\n" : "=r"(mip) : "r"(1 << irq));
197}
198#endif
199#elif defined(CONFIG_XTENSA)
200static inline void trigger_irq(int irq)
201{
202#if XCHAL_NUM_INTERRUPTS > 32
203 switch (irq >> 5) {
204 case 0:
205 z_xt_set_intset(1 << (irq & 0x1f));
206 break;
207 case 1:
208 z_xt_set_intset1(1 << (irq & 0x1f));
209 break;
210#if XCHAL_NUM_INTERRUPTS > 64
211 case 2:
212 z_xt_set_intset2(1 << (irq & 0x1f));
213 break;
214#endif
215#if XCHAL_NUM_INTERRUPTS > 96
216 case 3:
217 z_xt_set_intset3(1 << (irq & 0x1f));
218 break;
219#endif
220 default:
221 break;
222 }
223#else
224 z_xt_set_intset(1 << irq);
225#endif
226}
227
228#elif defined(CONFIG_SPARC)
229extern void z_sparc_enter_irq(int);
230
231static inline void trigger_irq(int irq)
232{
233 z_sparc_enter_irq(irq);
234}
235
236#elif defined(CONFIG_MIPS)
237extern void z_mips_enter_irq(int);
238
239static inline void trigger_irq(int irq)
240{
241 z_mips_enter_irq(irq);
242}
243
244#elif defined(CONFIG_OPENRISC)
245extern void z_openrisc_enter_irq(int);
246
247static inline void trigger_irq(int irq)
248{
249 z_openrisc_enter_irq(irq);
250}
251
252#elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_TI_VIM)
253
254extern void z_vim_arm_enter_irq(int);
255
256static inline void trigger_irq(int irq)
257{
258 z_vim_arm_enter_irq(irq);
259}
260
261#elif defined(CONFIG_RX)
262#define IR_BASE_ADDRESS DT_REG_ADDR_BY_NAME(DT_NODELABEL(icu), IR)
263static inline void trigger_irq(int irq)
264{
265 __ASSERT(irq < CONFIG_NUM_IRQS, "attempting to trigger invalid IRQ (%u)", irq);
266 __ASSERT(irq >= CONFIG_GEN_IRQ_START_VECTOR, "attempting to trigger reserved IRQ (%u)",
267 irq);
268 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].isr(
269 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].arg);
270}
271
272#else
273#define NO_TRIGGER_FROM_SW
274#endif
275
276#endif /* INTERRUPT_UTIL_H_ */
static ALWAYS_INLINE _cpu_t * arch_curr_cpu(void)
Definition arch_inlines.h:17
#define MPIDR_AFFLVL(mpidr, aff_level)
Definition cpu.h:101
#define GET_MPIDR()
Definition cpu.h:104
#define CONFIG_NUM_IRQS
Definition irq.h:59
#define CONFIG_GEN_IRQ_START_VECTOR
Definition irq.h:14
Driver for ARM Generic Interrupt Controller.
void gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff, uint16_t target_list)
raise SGI to target cores
#define GICD_SGIR
Definition gic.h:181
#define GICD_SGIR_SGIINTID(x)
Definition gic.h:259
#define GICD_SGIR_TGTFILT_REQONLY
Definition gic.h:251
static void arch_nop(void)
Do nothing and return.
#define BIT(n)
Unsigned integer with bit position n set (signed in assembly language).
Definition util_macro.h:44
#define IF_DISABLED(_flag, _code)
Insert code if _flag is not defined as 1.
Definition util_macro.h:302
#define zassert_true(cond,...)
Assert that cond is true.
Definition ztest_assert.h:278
#define k_str_out_count(s)
Definition interrupt_util.h:10
static void x86_write_x2apic(unsigned int reg, uint64_t val)
Write 64-bit value to the local APIC in x2APIC mode.
Definition loapic.h:118
#define LOAPIC_SELF_IPI
Definition loapic.h:42
void posix_sw_set_pending_IRQ(unsigned int IRQn)
__UINT32_TYPE__ uint32_t
Definition stdint.h:90
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
__UINT8_TYPE__ uint8_t
Definition stdint.h:88
static ALWAYS_INLINE void sys_write32(uint32_t data, mem_addr_t addr)
Definition sys-io-common.h:70