1 /*
2 * Copyright 2023 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "test_shared_irq.h"
8
9 struct shared_irq_fixture {
10 unsigned int irq1;
11 unsigned int irq2;
12 unsigned int irq1_table_idx;
13 unsigned int irq2_table_idx;
14 unsigned int irq_priority;
15 };
16
17 static struct shared_irq_fixture fixture;
18
reset_test_vector(void)19 static void reset_test_vector(void)
20 {
21 int i;
22
23 for (i = 0; i < TEST_VECTOR_SIZE; i++) {
24 test_vector[i] = 0;
25 }
26 }
27
dynamic_shared_irq_suite_after(void * data)28 static void dynamic_shared_irq_suite_after(void *data)
29 {
30 ARG_UNUSED(data);
31
32 /* note: no need to check the state of the SW ISR tables after
33 * all these disconnect operations. If there's something wrong
34 * it should be detected by dynamic_shared_irq_suite_before().
35 */
36 arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
37 test_isr_0, 0, 0);
38 arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
39 test_isr_1, (void *)1, 0);
40 arch_irq_disconnect_dynamic(fixture.irq2, fixture.irq_priority,
41 test_isr_2, (void *)2, 0);
42 }
43
dummy_isr(const void * data)44 static void dummy_isr(const void *data)
45 {
46 ARG_UNUSED(data);
47
48 test_vector[0] = TEST_DUMMY_ISR_VAL;
49 }
50
get_irq_slot(unsigned int start)51 static unsigned int get_irq_slot(unsigned int start)
52 {
53 unsigned int i, table_idx;
54
55 for (i = start; i <= CONFIG_GEN_IRQ_START_VECTOR + CONFIG_NUM_IRQS - 1; i++) {
56 table_idx = i - CONFIG_GEN_IRQ_START_VECTOR;
57
58 if (_sw_isr_table[table_idx].isr == &z_irq_spurious) {
59 test_vector[0] = 0;
60
61 /* check to see if we can trigger this IRQ */
62 arch_irq_connect_dynamic(i, IRQ_PRIORITY, dummy_isr,
63 NULL, 0);
64 irq_enable(i);
65 trigger_irq(i);
66
67 /* wait a bit */
68 k_busy_wait(100);
69
70 if (test_vector[0] == TEST_DUMMY_ISR_VAL) {
71 /* found a valid INTID */
72 irq_disable(i);
73
74 arch_irq_disconnect_dynamic(i, IRQ_PRIORITY,
75 dummy_isr, NULL, 0);
76 return i;
77 }
78 }
79 }
80
81 return TEST_INVALID_IRQ;
82 }
83
dynamic_shared_irq_suite_setup(void)84 static void *dynamic_shared_irq_suite_setup(void)
85 {
86 fixture.irq1 = get_irq_slot(CONFIG_GEN_IRQ_START_VECTOR);
87 zassert_true(fixture.irq1 != TEST_INVALID_IRQ,
88 "no suitable value found for irq1");
89 fixture.irq2 = get_irq_slot(fixture.irq1 + 1);
90 zassert_true(fixture.irq2 != TEST_INVALID_IRQ,
91 "no suitable value found for irq2");
92 fixture.irq_priority = IRQ_PRIORITY;
93
94 fixture.irq1_table_idx = fixture.irq1 - CONFIG_GEN_IRQ_START_VECTOR;
95 fixture.irq2_table_idx = fixture.irq2 - CONFIG_GEN_IRQ_START_VECTOR;
96
97 return NULL;
98 }
99
100 #if defined(CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET)
101 #define TABLE_OFFSET CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET
102 #else
103 #define TABLE_OFFSET 0
104 #endif
105
dynamic_shared_irq_suite_before(void * data)106 static void dynamic_shared_irq_suite_before(void *data)
107 {
108 ARG_UNUSED(data);
109
110 arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
111 test_isr_0, 0, 0);
112
113 zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].isr == test_isr_0,
114 "wrong _sw_isr_table ISR at irq1");
115 zassert_true(!_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg,
116 "wrong _sw_isr_table argument at irq1");
117 zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].client_num,
118 "wrong client number at irq1");
119
120 arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
121 test_isr_1, (void *)1, 0);
122
123 zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].isr == z_shared_isr,
124 "wrong _sw_isr_table ISR at irq1");
125 zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg ==
126 &z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET],
127 "wrong _sw_isr_table argument at irq1");
128 zassert_true(z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].client_num == 2,
129 "wrong client number at irq1");
130
131 zassert_true(client_exists_at_index(test_isr_0, 0, fixture.irq1_table_idx + TABLE_OFFSET,
132 0),
133 "unexpected client data for irq1, index 0");
134 zassert_true(client_exists_at_index(test_isr_1, (void *)1,
135 fixture.irq1_table_idx + TABLE_OFFSET, 1),
136 "unexpected client data for irq1, index 1");
137
138 arch_irq_connect_dynamic(fixture.irq2, fixture.irq_priority,
139 test_isr_2, (void *)2, 0);
140
141 zassert_true(_sw_isr_table[fixture.irq2_table_idx + TABLE_OFFSET].isr == test_isr_2,
142 "wrong _sw_isr_table ISR at irq2");
143 zassert_true(_sw_isr_table[fixture.irq2_table_idx + TABLE_OFFSET].arg == (void *)2,
144 "wrong _sw_isr_table argument at irq2");
145 zassert_true(!z_shared_sw_isr_table[fixture.irq2_table_idx + TABLE_OFFSET].client_num,
146 "wrong client number at irq2");
147
148 reset_test_vector();
149 }
150
151 /**
152 * @brief Test writing to a vector with a shared interrupt
153 *
154 * @ingroup kernel_interrupt_tests
155 *
156 * @details This tests if interrupts are dynamically shared successfully
157 * (i.e: multiple ISR/arg pairs are called whenever the interrupt
158 * they were registered for is triggered).
159 */
ZTEST(shared_irq_feature,test_dynamic_shared_irq_write)160 ZTEST(shared_irq_feature, test_dynamic_shared_irq_write)
161 {
162 int i;
163
164 irq_enable(fixture.irq1);
165 irq_enable(fixture.irq2);
166
167 trigger_irq(fixture.irq1);
168 trigger_irq(fixture.irq2);
169
170 /* wait 5ms before checking the results */
171 k_busy_wait(5000);
172
173 for (i = 0; i < TEST_VECTOR_SIZE; i++) {
174 zassert_true(test_vector[i] == result_vector[i],
175 "wrong test_vector value at %d: 0x%x vs 0x%x",
176 i, test_vector[i], result_vector[i]);
177 }
178
179 irq_disable(fixture.irq1);
180 irq_disable(fixture.irq2);
181 }
182
183 /**
184 * @brief Test writing to a vector after an ISR/arg disconnect.
185 *
186 * @ingroup kernel_interrupt_tests
187 *
188 * @details This tests if ISR/arg pairs are disconnected successfully
189 * and the interrupts are "unshared" whenever a single ISR/arg pair is
190 * left.
191 */
ZTEST(shared_irq_feature,test_dynamic_shared_irq_disconnect_write)192 ZTEST(shared_irq_feature, test_dynamic_shared_irq_disconnect_write)
193 {
194 int i;
195
196 /* remove test_isr_0/NULL pair. After this statement we expect
197 * irq1 to be unshared.
198 */
199 arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
200 test_isr_0, 0, 0);
201
202 zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].isr == test_isr_1,
203 "wrong _sw_isr_table ISR at irq1");
204 zassert_true(_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].arg == (void *)1,
205 "wrong _sw_isr_table arg at irq1");
206 zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx + TABLE_OFFSET].client_num,
207 "wrong client number at irq1");
208
209 irq_enable(fixture.irq1);
210 trigger_irq(fixture.irq1);
211
212 /* wait 5ms before checking the results */
213 k_busy_wait(5000);
214
215 for (i = 0; i < TEST_VECTOR_SIZE; i++) {
216 if (i == 1) {
217 zassert_true(test_vector[i] == result_vector[i],
218 "wrong test_vector at %d: 0x%x vs 0x%x",
219 i, test_vector[i], result_vector[i]);
220 continue;
221 }
222
223 zassert_true(!test_vector[i],
224 "wrong test_vector value at %d: 0x%x vs 0x%x",
225 i, test_vector[i], result_vector[i]);
226 }
227
228 irq_disable(fixture.irq1);
229 }
230
231 ZTEST_SUITE(shared_irq_feature, NULL,
232 dynamic_shared_irq_suite_setup,
233 dynamic_shared_irq_suite_before,
234 dynamic_shared_irq_suite_after,
235 NULL);
236