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