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