build: make ring mempool driver mandatory
[dpdk.git] / app / test / test_interrupts.c
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
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
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
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
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
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
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
175 test_interrupt_init(void)
176 {
177         return 0;
178 }
179
180 static int
181 test_interrupt_deinit(void)
182 {
183         return 0;
184 }
185
186 static int
187 test_interrupt_trigger_interrupt(void)
188 {
189         return 0;
190 }
191
192 static int
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
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
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
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
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
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
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_TEST_COMMAND(interrupt_autotest, test_interrupt);