Zephyr API Documentation 4.2.0-rc3
A Scalable Open Source RTOS
 4.2.0-rc3
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#if defined(CONFIG_CPU_CORTEX_M)
11#include <cmsis_core.h>
12
13static 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
58static 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)
74
75static 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
88#else
89 uint64_t mpidr = GET_MPIDR();
90 uint8_t aff0 = MPIDR_AFFLVL(mpidr, 0);
91
92 gic_raise_sgi(irq, mpidr, BIT(aff0));
93#endif
94}
95
96#elif defined(CONFIG_ARC)
97static inline void trigger_irq(int irq)
98{
99 printk("Triggering irq : %d\n", irq);
100 z_arc_v2_aux_reg_write(_ARC_V2_AUX_IRQ_HINT, irq);
101}
102
103#elif defined(CONFIG_X86)
104
105#ifdef CONFIG_X2APIC
107#define VECTOR_MASK 0xFF
108#else
110#define LOAPIC_ICR_IPI_TEST 0x00004000U
111#endif
112
113/*
114 * We can emulate the interrupt by sending the IPI to
115 * core itself by the LOAPIC for x86 platform.
116 *
117 * In APIC mode, Write LOAPIC's ICR to trigger IPI,
118 * the LOAPIC_ICR_IPI_TEST 0x00004000U means:
119 * Delivery Mode: Fixed
120 * Destination Mode: Physical
121 * Level: Assert
122 * Trigger Mode: Edge
123 * Destination Shorthand: No Shorthand
124 * Destination: depends on cpu_id
125 *
126 * In X2APIC mode, this no longer works. We emulate the
127 * interrupt by writing the IA32_X2APIC_SELF_IPI MSR
128 * to send IPI to the core itself via LOAPIC also.
129 * According to SDM vol.3 chapter 10.12.11, the bit[7:0]
130 * for setting the vector is only needed.
131 */
132static inline void trigger_irq(int vector)
133{
134 uint8_t i;
135
136#ifdef CONFIG_X2APIC
137 x86_write_x2apic(LOAPIC_SELF_IPI, ((VECTOR_MASK & vector)));
138#else
139
140#ifdef CONFIG_SMP
141 int cpu_id = arch_curr_cpu()->id;
142#else
143 int cpu_id = 0;
144#endif
145 z_loapic_ipi(cpu_id, LOAPIC_ICR_IPI_TEST, vector);
146#endif /* CONFIG_X2APIC */
147
148 /*
149 * add some nop operations here to cost some cycles to make sure
150 * the IPI interrupt is handled before do our check.
151 */
152 for (i = 0; i < 10; i++) {
153 arch_nop();
154 }
155}
156
157#elif defined(CONFIG_ARCH_POSIX)
159
160static inline void trigger_irq(int irq)
161{
163}
164
165#elif defined(CONFIG_RISCV)
166#if defined(CONFIG_CLIC) || defined(CONFIG_NRFX_CLIC)
167void riscv_clic_irq_set_pending(uint32_t irq);
168static inline void trigger_irq(int irq)
169{
170 riscv_clic_irq_set_pending(irq);
171}
172#else
173static inline void trigger_irq(int irq)
174{
175 uint32_t mip;
176
177 __asm__ volatile("csrrs %0, mip, %1\n" : "=r"(mip) : "r"(1 << irq));
178}
179#endif
180#elif defined(CONFIG_XTENSA)
181static inline void trigger_irq(int irq)
182{
183#if XCHAL_NUM_INTERRUPTS > 32
184 switch (irq >> 5) {
185 case 0:
186 z_xt_set_intset(1 << irq);
187 break;
188 case 1:
189 z_xt_set_intset1(1 << irq);
190 break;
191#if XCHAL_NUM_INTERRUPTS > 64
192 case 2:
193 z_xt_set_intset2(1 << irq);
194 break;
195#endif
196#if XCHAL_NUM_INTERRUPTS > 96
197 case 3:
198 z_xt_set_intset3(1 << irq);
199 break;
200#endif
201 default:
202 break;
203 }
204#else
205 z_xt_set_intset(1 << irq);
206#endif
207}
208
209#elif defined(CONFIG_SPARC)
210extern void z_sparc_enter_irq(int);
211
212static inline void trigger_irq(int irq)
213{
214 z_sparc_enter_irq(irq);
215}
216
217#elif defined(CONFIG_MIPS)
218extern void z_mips_enter_irq(int);
219
220static inline void trigger_irq(int irq)
221{
222 z_mips_enter_irq(irq);
223}
224
225#elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_VIM)
226
227extern void z_vim_arm_enter_irq(int);
228
229static inline void trigger_irq(int irq)
230{
231 z_vim_arm_enter_irq(irq);
232}
233
234#elif defined(CONFIG_RX)
235#define IR_BASE_ADDRESS DT_REG_ADDR_BY_NAME(DT_NODELABEL(icu), IR)
236static inline void trigger_irq(int irq)
237{
238 __ASSERT(irq < CONFIG_NUM_IRQS, "attempting to trigger invalid IRQ (%u)", irq);
239 __ASSERT(irq >= CONFIG_GEN_IRQ_START_VECTOR, "attempting to trigger reserved IRQ (%u)",
240 irq);
241 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].isr(
242 _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].arg);
243}
244
245#else
246#define NO_TRIGGER_FROM_SW
247#endif
248
249#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_GEN_IRQ_START_VECTOR
Definition irq.h:14
#define CONFIG_NUM_IRQS
Definition irq.h:183
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 zassert_true(cond,...)
Assert that cond is true.
Definition ztest_assert.h:275
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)
static void printk(const char *fmt,...)
Print kernel debugging message.
Definition printk.h:51
__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