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