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
dynamic_shared_irq_suite_before(void * data)100 static void dynamic_shared_irq_suite_before(void *data)
101 {
102 ARG_UNUSED(data);
103
104 arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
105 test_isr_0, 0, 0);
106
107 zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == test_isr_0,
108 "wrong _sw_isr_table ISR at irq1");
109 zassert_true(!_sw_isr_table[fixture.irq1_table_idx].arg,
110 "wrong _sw_isr_table argument at irq1");
111 zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx].client_num,
112 "wrong client number at irq1");
113
114 arch_irq_connect_dynamic(fixture.irq1, fixture.irq_priority,
115 test_isr_1, (void *)1, 0);
116
117 zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == z_shared_isr,
118 "wrong _sw_isr_table ISR at irq1");
119 zassert_true(_sw_isr_table[fixture.irq1_table_idx].arg ==
120 &z_shared_sw_isr_table[fixture.irq1_table_idx],
121 "wrong _sw_isr_table argument at irq1");
122 zassert_true(z_shared_sw_isr_table[fixture.irq1_table_idx].client_num == 2,
123 "wrong client number at irq1");
124
125 zassert_true(client_exists_at_index(test_isr_0, 0, fixture.irq1_table_idx, 0),
126 "unexpected client data for irq1, index 0");
127 zassert_true(client_exists_at_index(test_isr_1, (void *)1, fixture.irq1_table_idx, 1),
128 "unexpected client data for irq1, index 1");
129
130 arch_irq_connect_dynamic(fixture.irq2, fixture.irq_priority,
131 test_isr_2, (void *)2, 0);
132
133 zassert_true(_sw_isr_table[fixture.irq2_table_idx].isr == test_isr_2,
134 "wrong _sw_isr_table ISR at irq2");
135 zassert_true(_sw_isr_table[fixture.irq2_table_idx].arg == (void *)2,
136 "wrong _sw_isr_table argument at irq2");
137 zassert_true(!z_shared_sw_isr_table[fixture.irq2_table_idx].client_num,
138 "wrong client number at irq2");
139
140 reset_test_vector();
141 }
142
143 /**
144 * @brief Test writing to a vector with a shared interrupt
145 *
146 * @ingroup kernel_interrupt_tests
147 *
148 * @details This tests if interrupts are dynamically shared successfully
149 * (i.e: multiple ISR/arg pairs are called whenever the interrupt
150 * they were registered for is triggered).
151 */
ZTEST(shared_irq_feature,test_dynamic_shared_irq_write)152 ZTEST(shared_irq_feature, test_dynamic_shared_irq_write)
153 {
154 int i;
155
156 irq_enable(fixture.irq1);
157 irq_enable(fixture.irq2);
158
159 trigger_irq(fixture.irq1);
160 trigger_irq(fixture.irq2);
161
162 /* wait 5ms before checking the results */
163 k_busy_wait(5000);
164
165 for (i = 0; i < TEST_VECTOR_SIZE; i++) {
166 zassert_true(test_vector[i] == result_vector[i],
167 "wrong test_vector value at %d: 0x%x vs 0x%x",
168 i, test_vector[i], result_vector[i]);
169 }
170
171 irq_disable(fixture.irq1);
172 irq_disable(fixture.irq2);
173 }
174
175 /**
176 * @brief Test writing to a vector after an ISR/arg disconnect.
177 *
178 * @ingroup kernel_interrupt_tests
179 *
180 * @details This tests if ISR/arg pairs are disconnected successfully
181 * and the interrupts are "unshared" whenever a single ISR/arg pair is
182 * left.
183 */
ZTEST(shared_irq_feature,test_dynamic_shared_irq_disconnect_write)184 ZTEST(shared_irq_feature, test_dynamic_shared_irq_disconnect_write)
185 {
186 int i;
187
188 /* remove test_isr_0/NULL pair. After this statement we expect
189 * irq1 to be unshared.
190 */
191 arch_irq_disconnect_dynamic(fixture.irq1, fixture.irq_priority,
192 test_isr_0, 0, 0);
193
194 zassert_true(_sw_isr_table[fixture.irq1_table_idx].isr == test_isr_1,
195 "wrong _sw_isr_table ISR at irq1");
196 zassert_true(_sw_isr_table[fixture.irq1_table_idx].arg == (void *)1,
197 "wrong _sw_isr_table arg at irq1");
198 zassert_true(!z_shared_sw_isr_table[fixture.irq1_table_idx].client_num,
199 "wrong client number at irq1");
200
201 irq_enable(fixture.irq1);
202 trigger_irq(fixture.irq1);
203
204 /* wait 5ms before checking the results */
205 k_busy_wait(5000);
206
207 for (i = 0; i < TEST_VECTOR_SIZE; i++) {
208 if (i == 1) {
209 zassert_true(test_vector[i] == result_vector[i],
210 "wrong test_vector at %d: 0x%x vs 0x%x",
211 i, test_vector[i], result_vector[i]);
212 continue;
213 }
214
215 zassert_true(!test_vector[i],
216 "wrong test_vector value at %d: 0x%x vs 0x%x",
217 i, test_vector[i], result_vector[i]);
218 }
219
220 irq_disable(fixture.irq1);
221 }
222
223 ZTEST_SUITE(shared_irq_feature, NULL,
224 dynamic_shared_irq_suite_setup,
225 dynamic_shared_irq_suite_before,
226 dynamic_shared_irq_suite_after,
227 NULL);
228