Zephyr API Documentation 4.5.99
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_CORTEX_M)
13#include <cmsis_core.h>
14
15static inline uint32_t get_available_nvic_line(uint32_t initial_offset)
16{
17 int i;
18
19 for (i = initial_offset - 1; i >= 0; i--) {
20
21 if (NVIC_GetEnableIRQ(i) == 0) {
22 /*
23 * Interrupts configured statically with IRQ_CONNECT(.)
24 * are automatically enabled. NVIC_GetEnableIRQ()
25 * returning false, here, implies that the IRQ line is
26 * either not implemented or it is not enabled, thus,
27 * currently not in use by Zephyr.
28 */
29
30 /* Set the NVIC line to pending. */
31 NVIC_SetPendingIRQ(i);
32
33 if (NVIC_GetPendingIRQ(i)) {
34 /*
35 * If the NVIC line is pending, it is
36 * guaranteed that it is implemented; clear the
37 * line.
38 */
39 NVIC_ClearPendingIRQ(i);
40
41 if (!NVIC_GetPendingIRQ(i)) {
42 /*
43 * If the NVIC line can be successfully
44 * un-pended, it is guaranteed that it
45 * can be used for software interrupt
46 * triggering. Return the NVIC line
47 * number.
48 */
49 break;
50 }
51 }
52 }
53 }
54
55 zassert_true(i >= 0, "No available IRQ line\n");
56
57 return i;
58}
59
60static inline void trigger_irq(int irq)
61{
62 k_str_out_count("Triggering irq\n");
63#if defined(CONFIG_SOC_TI_LM3S6965_QEMU) || defined(CONFIG_CPU_CORTEX_M0) || \
64 defined(CONFIG_CPU_CORTEX_M0PLUS) || defined(CONFIG_CPU_CORTEX_M1) || \
65 defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
66 /* QEMU does not simulate the STIR register: this is a workaround */
67 NVIC_SetPendingIRQ(irq);
68#else
69 NVIC->STIR = irq;
70#endif
71}
72
73#elif defined(CONFIG_GIC)
76
77static inline void trigger_irq(int irq)
78{
79 k_str_out_count("Triggering irq\n");
80
81 /* Ensure that the specified IRQ number is a valid SGI interrupt ID */
82 zassert_true(irq <= 15, "%u is not a valid SGI interrupt ID", irq);
83
84 /*
85 * Generate a software generated interrupt and forward it to the
86 * requesting CPU.
87 */
88#if CONFIG_GIC_VER <= 2
90#else
91 uint64_t mpidr = GET_MPIDR();
92 uint8_t aff0 = MPIDR_AFFLVL(mpidr, 0);
93
94 gic_raise_sgi(irq, mpidr, BIT(aff0));
95#endif
96}
97
98#elif defined(CONFIG_ARC)
99static inline void trigger_irq(int irq)
100{
101 k_str_out_count("Triggering irq\n");
102 z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, irq);
103}
104
105#elif defined(CONFIG_X86)
106
107#ifdef CONFIG_X2APIC
109#define VECTOR_MASK 0xFF
110#else
112#define LOAPIC_ICR_IPI_TEST 0x00004000U
113#endif
114
115/*
116 * We can emulate the interrupt by sending the IPI to
117 * core itself by the LOAPIC for x86 platform.
118 *
119 * In APIC mode, Write LOAPIC's ICR to trigger IPI,
120 * the LOAPIC_ICR_IPI_TEST 0x00004000U means:
121 * Delivery Mode: Fixed
122 * Destination Mode: Physical
123 * Level: Assert
124 * Trigger Mode: Edge
125 * Destination Shorthand: No Shorthand
126 * Destination: depends on cpu_id
127 *
128 * In X2APIC mode, this no longer works. We emulate the
129 * interrupt by writing the IA32_X2APIC_SELF_IPI MSR
130 * to send IPI to the core itself via LOAPIC also.
131 * According to SDM vol.3 chapter 10.12.11, the bit[7:0]
132 * for setting the vector is only needed.
133 */
134static inline void trigger_irq(int vector)
135{
136 uint8_t i;
137
138#ifdef CONFIG_X2APIC
139 x86_write_x2apic(LOAPIC_SELF_IPI, ((VECTOR_MASK & vector)));
140#else
141
142#ifdef CONFIG_SMP
143 int cpu_id = arch_curr_cpu()->id;
144#else
145 int cpu_id = 0;
146#endif
147 z_loapic_ipi(cpu_id, LOAPIC_ICR_IPI_TEST, vector);
148#endif /* CONFIG_X2APIC */
149
150 /*
151 * add some nop operations here to cost some cycles to make sure
152 * the IPI interrupt is handled before do our check.
153 */
154 for (i = 0; i < 10; i++) {
155 arch_nop();
156 }
157}
158
159#elif defined(CONFIG_ARCH_POSIX)
160#include <zephyr/arch/posix/posix_soc_if.h>
161
162static inline void trigger_irq(int irq)
163{
164 posix_sw_set_pending_IRQ(irq);
165}
166
167#elif defined(CONFIG_RISCV)
168#if defined(CONFIG_HAZARD3_INTC)
169#include <hardware/irq.h>
170#endif
171
172#if defined(CONFIG_CLIC) || defined(CONFIG_NRFX_CLIC)
173void riscv_clic_irq_set_pending(uint32_t irq);
174static inline void trigger_irq(int irq)
175{
176 riscv_clic_irq_set_pending(irq);
177}
178#elif defined(CONFIG_HAZARD3_INTC)
179static inline void trigger_irq(int irq)
180{
181 irq_set_pending(irq);
182}
183#elif defined(CONFIG_MAX32_RV32_INTC)
185static inline void trigger_irq(int irq)
186{
188}
189#elif defined(CONFIG_RISCV_S_MODE)
190/* In S-mode mip is read-only; set bits via sip (SSIP is writable via sip) */
191static inline void trigger_irq(int irq)
192{
193 uint32_t sip;
194
195 __asm__ volatile("csrrs %0, sip, %1\n" : "=r"(sip) : "r"(1 << irq));
196}
197#elif defined(CONFIG_PLIC_SUPPORTS_SOFT_INTERRUPT)
200
201static inline void trigger_irq(int irq)
202{
203 unsigned int level = irq_get_level(irq);
204
205 if (level == 1) {
206 uint32_t mip;
207
208 __asm__ volatile("csrrs %0, mip, %1\n" : "=r"(mip) : "r"(1 << irq));
209 } else {
211 }
212}
213#else
214static inline void trigger_irq(int irq)
215{
216 uint32_t mip;
217
218 __asm__ volatile("csrrs %0, mip, %1\n" : "=r"(mip) : "r"(1 << irq));
219}
220#endif
221#elif defined(CONFIG_XTENSA)
222static inline void trigger_irq(int irq)
223{
224#if XCHAL_NUM_INTERRUPTS > 32
225 switch (irq >> 5) {
226 case 0:
227 z_xt_set_intset(1 << (irq & 0x1f));
228 break;
229 case 1:
230 z_xt_set_intset1(1 << (irq & 0x1f));
231 break;
232#if XCHAL_NUM_INTERRUPTS > 64
233 case 2:
234 z_xt_set_intset2(1 << (irq & 0x1f));
235 break;
236#endif
237#if XCHAL_NUM_INTERRUPTS > 96
238 case 3:
239 z_xt_set_intset3(1 << (irq & 0x1f));
240 break;
241#endif
242 default:
243 break;
244 }
245#else
246 z_xt_set_intset(1 << irq);
247#endif
248}
249
250#elif defined(CONFIG_SPARC)
251extern void z_sparc_enter_irq(int);
252
253static inline void trigger_irq(int irq)
254{
255 z_sparc_enter_irq(irq);
256}
257
258#elif defined(CONFIG_MIPS)
259extern void z_mips_enter_irq(int);
260
261static inline void trigger_irq(int irq)
262{
263 z_mips_enter_irq(irq);
264}
265
266#elif defined(CONFIG_OPENRISC)
267extern void z_openrisc_enter_irq(int);
268
269static inline void trigger_irq(int irq)
270{
271 z_openrisc_enter_irq(irq);
272}
273
274#elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_TI_VIM)
275
276extern void z_vim_arm_enter_irq(int);
277
278static inline void trigger_irq(int irq)
279{
280 z_vim_arm_enter_irq(irq);
281}
282
283#elif defined(CONFIG_RX)
284#define IR_BASE_ADDRESS DT_REG_ADDR_BY_NAME(DT_NODELABEL(icu), IR)
285static inline void trigger_irq(int irq)
286{
287 __ASSERT(irq < CONFIG_NUM_IRQS, "attempting to trigger invalid IRQ (%u)", irq);
288 __ASSERT(irq >= CONFIG_GEN_IRQ_START_VECTOR, "attempting to trigger reserved IRQ (%u)",
289 irq);
290 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].isr(
291 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].arg);
292}
293
294#elif defined(CONFIG_HEXAGON)
295
296/* Posts the interrupt through the Hexagon VM, the same hypercall the arch's
297 * irq_offload() uses.
298 */
299extern int hexagon_irq_trigger(unsigned int irq);
300
301static inline void trigger_irq(int irq)
302{
303 hexagon_irq_trigger((unsigned int)irq);
304}
305
306#elif defined(CONFIG_TRICORE)
308
309static inline void trigger_irq(int irq)
310{
312}
313
314#else
315#define NO_TRIGGER_FROM_SW
316#endif
317
318#endif /* INTERRUPT_UTIL_H_ */
Arm GIC interrupt controller devicetree macros.
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.
static struct _cpu * arch_curr_cpu(void)
Return the CPU struct for the currently executing CPU.
#define BIT(n)
Unsigned integer with bit position n set (signed in assembly language).
Definition util_macro.h:44
static void sys_write32(uint32_t data, mm_reg_t addr)
Write 32 bits to a memory mapped register.
#define zassert_true(cond,...)
Assert that cond is true.
Definition ztest_assert.h:298
Public API for the Infineon AURIX Interrupt Router (IR).
void intc_aurix_ir_irq_raise(unsigned int irq)
Raise an AURIX interrupt source by IRQ number.
MAX32 RV32 interrupt controller API.
void intc_max32_rv32_irq_set_pending(int source)
Set a pending interrupt in the controller.
#define k_str_out_count(s)
Definition interrupt_util.h:10
Public interface for multi-level interrupts.
static unsigned int irq_get_level(unsigned int irq)
Return IRQ level This routine returns the interrupt level number of the provided interrupt.
Definition irq_multilevel.h:62
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
Driver for Platform Level Interrupt Controller (PLIC).
void riscv_plic_irq_set_pending(uint32_t irq)
Set interrupt as pending.
__UINT32_TYPE__ uint32_t
Definition stdint.h:90
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
__UINT8_TYPE__ uint8_t
Definition stdint.h:88