xref: /dpdk/app/test/test_interrupts.c (revision dada9ef6edc59015b6674b5a95258787c71401b0)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <unistd.h>
38 
39 #include <cmdline_parse.h>
40 
41 #include <rte_common.h>
42 #include <rte_cycles.h>
43 #include <rte_interrupts.h>
44 
45 #include "test.h"
46 
47 #define TEST_INTERRUPT_CHECK_INTERVAL 1000 /* ms */
48 
49 enum test_interrupt_handl_type {
50 	TEST_INTERRUPT_HANDLE_INVALID,
51 	TEST_INTERRUPT_HANDLE_VALID,
52 	TEST_INTERRUPT_HANDLE_CASE1,
53 	TEST_INTERRUPT_HANDLE_MAX
54 };
55 
56 static volatile int flag;
57 static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX];
58 
59 #ifdef RTE_EXEC_ENV_LINUXAPP
60 union intr_pipefds{
61 	struct {
62 		int pipefd[2];
63 	};
64 	struct {
65 		int readfd;
66 		int writefd;
67 	};
68 };
69 
70 static union intr_pipefds pfds;
71 
72 static inline int
73 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
74 {
75 	if (!intr_handle || intr_handle->fd < 0)
76 		return -1;
77 
78 	return 0;
79 }
80 
81 static int
82 test_interrupt_init(void)
83 {
84 	if (pipe(pfds.pipefd) < 0)
85 		return -1;
86 
87 	intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1;
88 	intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type = RTE_INTR_HANDLE_UNKNOWN;
89 
90 	intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd;
91 	intr_handles[TEST_INTERRUPT_HANDLE_VALID].type = RTE_INTR_HANDLE_UNKNOWN;
92 
93 	intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.readfd;
94 	intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_ALARM;
95 
96 	return 0;
97 }
98 
99 static int
100 test_interrupt_deinit(void)
101 {
102 	close(pfds.pipefd[0]);
103 	close(pfds.pipefd[1]);
104 
105 	return 0;
106 }
107 
108 static int
109 test_interrupt_trigger_interrupt(void)
110 {
111 	if (write(pfds.writefd, "1", 1) < 0)
112 		return -1;
113 
114 	return 0;
115 }
116 
117 static int
118 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
119 				struct rte_intr_handle *intr_handle_r)
120 {
121 	if (!intr_handle_l || !intr_handle_r)
122 		return -1;
123 
124 	if (intr_handle_l->fd != intr_handle_r->fd ||
125 		intr_handle_l->type != intr_handle_r->type)
126 		return -1;
127 
128 	return 0;
129 }
130 
131 #else
132 /* to be implemented for baremetal later */
133 static inline int
134 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
135 {
136 	RTE_SET_USED(intr_handle);
137 
138 	return 0;
139 }
140 
141 static int
142 test_interrupt_init(void)
143 {
144 	return 0;
145 }
146 
147 static int
148 test_interrupt_deinit(void)
149 {
150 	return 0;
151 }
152 
153 static int
154 test_interrupt_trigger_interrupt(void)
155 {
156 	return 0;
157 }
158 
159 static int
160 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
161 				struct rte_intr_handle *intr_handle_r)
162 {
163 	(void)intr_handle_l;
164 	(void)intr_handle_r;
165 
166 	return 0;
167 }
168 #endif /* RTE_EXEC_ENV_LINUXAPP */
169 
170 static void
171 test_interrupt_callback(struct rte_intr_handle *intr_handle, void *arg)
172 {
173 	if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
174 		printf("null or invalid intr_handle for %s\n", __FUNCTION__);
175 		return;
176 	}
177 
178 	if (rte_intr_callback_unregister(intr_handle,
179 			test_interrupt_callback, arg) <= 0) {
180 		printf("fail to unregister callback\n");
181 		return;
182 	}
183 
184 	if (test_interrupt_handle_compare(intr_handle,
185 		&(intr_handles[TEST_INTERRUPT_HANDLE_VALID])) == 0) {
186 		flag = 1;
187 	}
188 }
189 
190 static void
191 test_interrupt_callback_1(struct rte_intr_handle *intr_handle, void *arg)
192 {
193 	if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
194 		printf("null or invalid intr_handle for %s\n", __FUNCTION__);
195 		return;
196 	}
197 	if (rte_intr_callback_unregister(intr_handle,
198 			test_interrupt_callback_1, arg) <= 0) {
199 		printf("fail to unregister callback\n");
200 		return;
201 	}
202 }
203 
204 static int
205 test_interrupt_enable(void)
206 {
207 	struct rte_intr_handle test_intr_handle;
208 
209 	/* check with null intr_handle */
210 	if (rte_intr_enable(NULL) == 0) {
211 		printf("unexpectedly enable null intr_handle successfully\n");
212 		return -1;
213 	}
214 
215 	/* check with invalid intr_handle */
216 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
217 	if (rte_intr_enable(&test_intr_handle) == 0) {
218 		printf("unexpectedly enable invalid intr_handle "
219 			"successfully\n");
220 		return -1;
221 	}
222 
223 	/* check with valid intr_handle */
224 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
225 	if (rte_intr_enable(&test_intr_handle) == 0) {
226 		printf("unexpectedly enable a specific intr_handle "
227 			"successfully\n");
228 		return -1;
229 	}
230 
231 	/* check with specific valid intr_handle */
232 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
233 	if (rte_intr_enable(&test_intr_handle) == 0) {
234 		printf("unexpectedly enable a specific intr_handle "
235 			"successfully\n");
236 		return -1;
237 	}
238 
239 	return 0;
240 }
241 
242 static int
243 test_interrupt_disable(void)
244 {
245 	struct rte_intr_handle test_intr_handle;
246 
247 	/* check with null intr_handle */
248 	if (rte_intr_disable(NULL) == 0) {
249 		printf("unexpectedly disable null intr_handle "
250 			"successfully\n");
251 		return -1;
252 	}
253 
254 	/* check with invalid intr_handle */
255 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
256 	if (rte_intr_disable(&test_intr_handle) == 0) {
257 		printf("unexpectedly disable invalid intr_handle "
258 			"successfully\n");
259 		return -1;
260 	}
261 
262 	/* check with valid intr_handle */
263 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
264 	if (rte_intr_disable(&test_intr_handle) == 0) {
265 		printf("unexpectedly disable a specific intr_handle "
266 			"successfully\n");
267 		return -1;
268 	}
269 
270 	/* check with specific valid intr_handle */
271 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
272 	if (rte_intr_disable(&test_intr_handle) == 0) {
273 		printf("unexpectedly disable a specific intr_handle "
274 			"successfully\n");
275 		return -1;
276 	}
277 
278 	return 0;
279 }
280 
281 int
282 test_interrupt(void)
283 {
284 	int count = 0, ret = -1;
285 	struct rte_intr_handle test_intr_handle;
286 
287 	if (test_interrupt_init() < 0) {
288 		printf("fail to do test init\n");
289 		return -1;
290 	}
291 
292 	printf("check if callback registered can be called\n");
293 
294 	/* check if callback registered can be called */
295 	flag = 0;
296 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
297 	if (rte_intr_callback_register(&test_intr_handle,
298 			test_interrupt_callback, NULL) < 0) {
299 		printf("fail to register callback\n");
300 		goto out;
301 	}
302 	/* trigger an interrupt and then check if the callback can be called */
303 	if (test_interrupt_trigger_interrupt() < 0) {
304 		printf("fail to trigger an interrupt\n");
305 		goto out;
306 	}
307 	/* check flag in 3 seconds */
308 	while (flag == 0 && count++ < 3)
309 		rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
310 	if (flag == 0) {
311 		printf("registered callback has not been called\n");
312 		goto out;
313 	}
314 	rte_delay_ms(1000);
315 
316 	printf("start register/unregister test\n");
317 
318 	/* check if it will fail to register cb with intr_handle = NULL */
319 	if (rte_intr_callback_register(NULL, test_interrupt_callback,
320 							NULL) == 0) {
321 		printf("unexpectedly register successfully with null "
322 			"intr_handle\n");
323 		goto out;
324 	}
325 
326 	/* check if it will fail to register cb with invalid intr_handle */
327 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
328 	if (rte_intr_callback_register(&test_intr_handle,
329 			test_interrupt_callback, NULL) == 0) {
330 		printf("unexpectedly register successfully with invalid "
331 			"intr_handle\n");
332 		goto out;
333 	}
334 
335 	/* check if it will fail to register without callback */
336 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
337 	if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) {
338 		printf("unexpectedly register successfully with "
339 			"null callback\n");
340 		goto out;
341 	}
342 
343 	/* check if it will fail to unregister cb with intr_handle = NULL */
344 	if (rte_intr_callback_unregister(NULL,
345 			test_interrupt_callback, NULL) > 0) {
346 		printf("unexpectedly unregister successfully with "
347 			"null intr_handle\n");
348 		goto out;
349 	}
350 
351 	/* check if it will fail to unregister cb with invalid intr_handle */
352 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
353 	if (rte_intr_callback_unregister(&test_intr_handle,
354 			test_interrupt_callback, NULL) > 0) {
355 		printf("unexpectedly unregister successfully with "
356 			"invalid intr_handle\n");
357 		goto out;
358 	}
359 
360 	/* check if it is ok to register the same intr_handle twice */
361 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
362 	if (rte_intr_callback_register(&test_intr_handle,
363 			test_interrupt_callback, NULL) < 0) {
364 		printf("it fails to register test_interrupt_callback\n");
365 		goto out;
366 	}
367 	if (rte_intr_callback_register(&test_intr_handle,
368 			test_interrupt_callback_1, NULL) < 0) {
369 		printf("it fails to register test_interrupt_callback_1\n");
370 		goto out;
371 	}
372 	/* check if it will fail to unregister with invalid parameter */
373 	if (rte_intr_callback_unregister(&test_intr_handle,
374 			test_interrupt_callback, (void *)0xff) != 0) {
375 		printf("unexpectedly unregisters successfully with invalid arg\n");
376 		goto out;
377 	}
378 	if (rte_intr_callback_unregister(&test_intr_handle,
379 			test_interrupt_callback, NULL) <= 0) {
380 		printf("it fails to unregister test_interrupt_callback\n");
381 		goto out;
382 	}
383 	if (rte_intr_callback_unregister(&test_intr_handle,
384 			test_interrupt_callback_1, (void *)-1) <= 0) {
385 		printf("it fails to unregister test_interrupt_callback_1 "
386 			"for all\n");
387 		goto out;
388 	}
389 	rte_delay_ms(1000);
390 
391 	printf("start interrupt enable/disable test\n");
392 
393 	/* check interrupt enable/disable functions */
394 	if (test_interrupt_enable() < 0)
395 		goto out;
396 	rte_delay_ms(1000);
397 
398 	if (test_interrupt_disable() < 0)
399 		goto out;
400 	rte_delay_ms(1000);
401 
402 	ret = 0;
403 
404 out:
405 	/* clear registered callbacks */
406 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
407 	rte_intr_callback_unregister(&test_intr_handle,
408 			test_interrupt_callback, (void *)-1);
409 	rte_intr_callback_unregister(&test_intr_handle,
410 			test_interrupt_callback_1, (void *)-1);
411 
412 	rte_delay_ms(2000);
413 	/* deinit */
414 	test_interrupt_deinit();
415 
416 	return ret;
417 }
418 
419