xref: /dpdk/app/test/test_interrupts.c (revision 2f45703c17acb943aaded9f79676fd56a72542b2)
1 /*-
2  *  BSD LICENSE
3  *
4  *  Copyright(c) 2010-2014 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 #include <stdio.h>
35 #include <stdint.h>
36 #include <unistd.h>
37 
38 #include <rte_common.h>
39 #include <rte_cycles.h>
40 #include <rte_interrupts.h>
41 
42 #include "test.h"
43 
44 #define TEST_INTERRUPT_CHECK_INTERVAL 100 /* ms */
45 
46 /* predefined interrupt handle types */
47 enum test_interrupt_handle_type {
48 	TEST_INTERRUPT_HANDLE_INVALID,
49 	TEST_INTERRUPT_HANDLE_VALID,
50 	TEST_INTERRUPT_HANDLE_VALID_UIO,
51 	TEST_INTERRUPT_HANDLE_VALID_ALARM,
52 	TEST_INTERRUPT_HANDLE_CASE1,
53 	TEST_INTERRUPT_HANDLE_MAX
54 };
55 
56 /* flag of if callback is called */
57 static volatile int flag;
58 static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX];
59 static enum test_interrupt_handle_type test_intr_type =
60 				TEST_INTERRUPT_HANDLE_MAX;
61 
62 #ifdef RTE_EXEC_ENV_LINUXAPP
63 union intr_pipefds{
64 	struct {
65 		int pipefd[2];
66 	};
67 	struct {
68 		int readfd;
69 		int writefd;
70 	};
71 };
72 
73 static union intr_pipefds pfds;
74 
75 /**
76  * Check if the interrupt handle is valid.
77  */
78 static inline int
79 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
80 {
81 	if (!intr_handle || intr_handle->fd < 0)
82 		return -1;
83 
84 	return 0;
85 }
86 
87 /**
88  * Initialization for interrupt test.
89  */
90 static int
91 test_interrupt_init(void)
92 {
93 	if (pipe(pfds.pipefd) < 0)
94 		return -1;
95 
96 	intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1;
97 	intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type =
98 					RTE_INTR_HANDLE_UNKNOWN;
99 
100 	intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd;
101 	intr_handles[TEST_INTERRUPT_HANDLE_VALID].type =
102 					RTE_INTR_HANDLE_UNKNOWN;
103 
104 	intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].fd = pfds.readfd;
105 	intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].type =
106 					RTE_INTR_HANDLE_UIO;
107 
108 	intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].fd = pfds.readfd;
109 	intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].type =
110 					RTE_INTR_HANDLE_ALARM;
111 
112 	intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.writefd;
113 	intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_UIO;
114 
115 	return 0;
116 }
117 
118 /**
119  * Deinitialization for interrupt test.
120  */
121 static int
122 test_interrupt_deinit(void)
123 {
124 	close(pfds.pipefd[0]);
125 	close(pfds.pipefd[1]);
126 
127 	return 0;
128 }
129 
130 /**
131  * Write the pipe to simulate an interrupt.
132  */
133 static int
134 test_interrupt_trigger_interrupt(void)
135 {
136 	if (write(pfds.writefd, "1", 1) < 0)
137 		return -1;
138 
139 	return 0;
140 }
141 
142 /**
143  * Check if two interrupt handles are the same.
144  */
145 static int
146 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
147 				struct rte_intr_handle *intr_handle_r)
148 {
149 	if (!intr_handle_l || !intr_handle_r)
150 		return -1;
151 
152 	if (intr_handle_l->fd != intr_handle_r->fd ||
153 		intr_handle_l->type != intr_handle_r->type)
154 		return -1;
155 
156 	return 0;
157 }
158 
159 #else
160 /* to be implemented for bsd later */
161 static inline int
162 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
163 {
164 	RTE_SET_USED(intr_handle);
165 
166 	return 0;
167 }
168 
169 static int
170 test_interrupt_init(void)
171 {
172 	return 0;
173 }
174 
175 static int
176 test_interrupt_deinit(void)
177 {
178 	return 0;
179 }
180 
181 static int
182 test_interrupt_trigger_interrupt(void)
183 {
184 	return 0;
185 }
186 
187 static int
188 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
189 				struct rte_intr_handle *intr_handle_r)
190 {
191 	(void)intr_handle_l;
192 	(void)intr_handle_r;
193 
194 	return 0;
195 }
196 #endif /* RTE_EXEC_ENV_LINUXAPP */
197 
198 /**
199  * Callback for the test interrupt.
200  */
201 static void
202 test_interrupt_callback(struct rte_intr_handle *intr_handle, void *arg)
203 {
204 	if (test_intr_type >= TEST_INTERRUPT_HANDLE_MAX) {
205 		printf("invalid interrupt type\n");
206 		flag = -1;
207 		return;
208 	}
209 
210 	if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
211 		printf("null or invalid intr_handle for %s\n", __func__);
212 		flag = -1;
213 		return;
214 	}
215 
216 	if (rte_intr_callback_unregister(intr_handle,
217 			test_interrupt_callback, arg) >= 0) {
218 		printf("%s: unexpectedly able to unregister itself\n",
219 			__func__);
220 		flag = -1;
221 		return;
222 	}
223 
224 	if (test_interrupt_handle_compare(intr_handle,
225 			&(intr_handles[test_intr_type])) == 0)
226 		flag = 1;
227 }
228 
229 /**
230  * Callback for the test interrupt.
231  */
232 static void
233 test_interrupt_callback_1(struct rte_intr_handle *intr_handle,
234 	__attribute__((unused)) void *arg)
235 {
236 	if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
237 		printf("null or invalid intr_handle for %s\n", __func__);
238 		flag = -1;
239 		return;
240 	}
241 }
242 
243 /**
244  * Tests for rte_intr_enable().
245  */
246 static int
247 test_interrupt_enable(void)
248 {
249 	struct rte_intr_handle test_intr_handle;
250 
251 	/* check with null intr_handle */
252 	if (rte_intr_enable(NULL) == 0) {
253 		printf("unexpectedly enable null intr_handle successfully\n");
254 		return -1;
255 	}
256 
257 	/* check with invalid intr_handle */
258 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
259 	if (rte_intr_enable(&test_intr_handle) == 0) {
260 		printf("unexpectedly enable invalid intr_handle "
261 			"successfully\n");
262 		return -1;
263 	}
264 
265 	/* check with valid intr_handle */
266 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
267 	if (rte_intr_enable(&test_intr_handle) == 0) {
268 		printf("unexpectedly enable a specific intr_handle "
269 			"successfully\n");
270 		return -1;
271 	}
272 
273 	/* check with specific valid intr_handle */
274 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
275 	if (rte_intr_enable(&test_intr_handle) == 0) {
276 		printf("unexpectedly enable a specific intr_handle "
277 			"successfully\n");
278 		return -1;
279 	}
280 
281 	/* check with valid handler and its type */
282 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
283 	if (rte_intr_enable(&test_intr_handle) < 0) {
284 		printf("fail to enable interrupt on a simulated handler\n");
285 		return -1;
286 	}
287 
288 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
289 	if (rte_intr_enable(&test_intr_handle) == 0) {
290 		printf("unexpectedly enable a specific intr_handle "
291 			"successfully\n");
292 		return -1;
293 	}
294 
295 	return 0;
296 }
297 
298 /**
299  * Tests for rte_intr_disable().
300  */
301 static int
302 test_interrupt_disable(void)
303 {
304 	struct rte_intr_handle test_intr_handle;
305 
306 	/* check with null intr_handle */
307 	if (rte_intr_disable(NULL) == 0) {
308 		printf("unexpectedly disable null intr_handle "
309 			"successfully\n");
310 		return -1;
311 	}
312 
313 	/* check with invalid intr_handle */
314 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
315 	if (rte_intr_disable(&test_intr_handle) == 0) {
316 		printf("unexpectedly disable invalid intr_handle "
317 			"successfully\n");
318 		return -1;
319 	}
320 
321 	/* check with valid intr_handle */
322 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
323 	if (rte_intr_disable(&test_intr_handle) == 0) {
324 		printf("unexpectedly disable a specific intr_handle "
325 			"successfully\n");
326 		return -1;
327 	}
328 
329 	/* check with specific valid intr_handle */
330 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
331 	if (rte_intr_disable(&test_intr_handle) == 0) {
332 		printf("unexpectedly disable a specific intr_handle "
333 			"successfully\n");
334 		return -1;
335 	}
336 
337 	/* check with valid handler and its type */
338 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
339 	if (rte_intr_disable(&test_intr_handle) < 0) {
340 		printf("fail to disable interrupt on a simulated handler\n");
341 		return -1;
342 	}
343 
344 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
345 	if (rte_intr_disable(&test_intr_handle) == 0) {
346 		printf("unexpectedly disable a specific intr_handle "
347 			"successfully\n");
348 		return -1;
349 	}
350 
351 	return 0;
352 }
353 
354 /**
355  * Check the full path of a specified type of interrupt simulated.
356  */
357 static int
358 test_interrupt_full_path_check(enum test_interrupt_handle_type intr_type)
359 {
360 	int count;
361 	struct rte_intr_handle test_intr_handle;
362 
363 	flag = 0;
364 	test_intr_handle = intr_handles[intr_type];
365 	test_intr_type = intr_type;
366 	if (rte_intr_callback_register(&test_intr_handle,
367 			test_interrupt_callback, NULL) < 0) {
368 		printf("fail to register callback\n");
369 		return -1;
370 	}
371 
372 	if (test_interrupt_trigger_interrupt() < 0)
373 		return -1;
374 
375 	/* check flag */
376 	for (count = 0; flag == 0 && count < 3; count++)
377 		rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
378 
379 	rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
380 	if (rte_intr_callback_unregister(&test_intr_handle,
381 			test_interrupt_callback, NULL) < 0)
382 		return -1;
383 
384 	if (flag == 0) {
385 		printf("callback has not been called\n");
386 		return -1;
387 	} else if (flag < 0) {
388 		printf("it has internal error in callback\n");
389 		return -1;
390 	}
391 
392 	return 0;
393 }
394 
395 /**
396  * Main function of testing interrupt.
397  */
398 static int
399 test_interrupt(void)
400 {
401 	int ret = -1;
402 	struct rte_intr_handle test_intr_handle;
403 
404 	if (test_interrupt_init() < 0) {
405 		printf("fail to initialize for testing interrupt\n");
406 		return -1;
407 	}
408 
409 	printf("Check unknown valid interrupt full path\n");
410 	if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID) < 0) {
411 		printf("failure occured during checking unknown valid "
412 						"interrupt full path\n");
413 		goto out;
414 	}
415 
416 	printf("Check valid UIO interrupt full path\n");
417 	if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_UIO)
418 									< 0) {
419 		printf("failure occured during checking valid UIO interrupt "
420 								"full path\n");
421 		goto out;
422 	}
423 
424 	printf("Check valid alarm interrupt full path\n");
425 	if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_ALARM)
426 									< 0) {
427 		printf("failure occured during checking valid alarm "
428 						"interrupt full path\n");
429 		goto out;
430 	}
431 
432 	printf("start register/unregister test\n");
433 	/* check if it will fail to register cb with intr_handle = NULL */
434 	if (rte_intr_callback_register(NULL, test_interrupt_callback,
435 							NULL) == 0) {
436 		printf("unexpectedly register successfully with null "
437 			"intr_handle\n");
438 		goto out;
439 	}
440 
441 	/* check if it will fail to register cb with invalid intr_handle */
442 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
443 	if (rte_intr_callback_register(&test_intr_handle,
444 			test_interrupt_callback, NULL) == 0) {
445 		printf("unexpectedly register successfully with invalid "
446 			"intr_handle\n");
447 		goto out;
448 	}
449 
450 	/* check if it will fail to register without callback */
451 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
452 	if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) {
453 		printf("unexpectedly register successfully with "
454 			"null callback\n");
455 		goto out;
456 	}
457 
458 	/* check if it will fail to unregister cb with intr_handle = NULL */
459 	if (rte_intr_callback_unregister(NULL,
460 			test_interrupt_callback, NULL) > 0) {
461 		printf("unexpectedly unregister successfully with "
462 			"null intr_handle\n");
463 		goto out;
464 	}
465 
466 	/* check if it will fail to unregister cb with invalid intr_handle */
467 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
468 	if (rte_intr_callback_unregister(&test_intr_handle,
469 			test_interrupt_callback, NULL) > 0) {
470 		printf("unexpectedly unregister successfully with "
471 			"invalid intr_handle\n");
472 		goto out;
473 	}
474 
475 	/* check if it is ok to register the same intr_handle twice */
476 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
477 	if (rte_intr_callback_register(&test_intr_handle,
478 			test_interrupt_callback, NULL) < 0) {
479 		printf("it fails to register test_interrupt_callback\n");
480 		goto out;
481 	}
482 	if (rte_intr_callback_register(&test_intr_handle,
483 			test_interrupt_callback_1, NULL) < 0) {
484 		printf("it fails to register test_interrupt_callback_1\n");
485 		goto out;
486 	}
487 	/* check if it will fail to unregister with invalid parameter */
488 	if (rte_intr_callback_unregister(&test_intr_handle,
489 			test_interrupt_callback, (void *)0xff) != 0) {
490 		printf("unexpectedly unregisters successfully with "
491 							"invalid arg\n");
492 		goto out;
493 	}
494 	if (rte_intr_callback_unregister(&test_intr_handle,
495 			test_interrupt_callback, NULL) <= 0) {
496 		printf("it fails to unregister test_interrupt_callback\n");
497 		goto out;
498 	}
499 	if (rte_intr_callback_unregister(&test_intr_handle,
500 			test_interrupt_callback_1, (void *)-1) <= 0) {
501 		printf("it fails to unregister test_interrupt_callback_1 "
502 			"for all\n");
503 		goto out;
504 	}
505 	rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
506 
507 	printf("start interrupt enable/disable test\n");
508 	/* check interrupt enable/disable functions */
509 	if (test_interrupt_enable() < 0) {
510 		printf("fail to check interrupt enabling\n");
511 		goto out;
512 	}
513 	rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
514 
515 	if (test_interrupt_disable() < 0) {
516 		printf("fail to check interrupt disabling\n");
517 		goto out;
518 	}
519 	rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
520 
521 	ret = 0;
522 
523 out:
524 	printf("Clearing for interrupt tests\n");
525 	/* clear registered callbacks */
526 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
527 	rte_intr_callback_unregister(&test_intr_handle,
528 			test_interrupt_callback, (void *)-1);
529 	rte_intr_callback_unregister(&test_intr_handle,
530 			test_interrupt_callback_1, (void *)-1);
531 
532 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
533 	rte_intr_callback_unregister(&test_intr_handle,
534 			test_interrupt_callback, (void *)-1);
535 	rte_intr_callback_unregister(&test_intr_handle,
536 			test_interrupt_callback_1, (void *)-1);
537 
538 	test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
539 	rte_intr_callback_unregister(&test_intr_handle,
540 			test_interrupt_callback, (void *)-1);
541 	rte_intr_callback_unregister(&test_intr_handle,
542 			test_interrupt_callback_1, (void *)-1);
543 
544 	rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL);
545 	/* deinit */
546 	test_interrupt_deinit();
547 
548 	return ret;
549 }
550 
551 REGISTER_TEST_COMMAND(interrupt_autotest, test_interrupt);
552