6e3dec31a0de7be9b808fc69716e87b2f56c1054
[dpdk.git] / app / test / test_interrupts.c
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 1000 /* 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 in 3 seconds */
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 static struct test_command interrupt_cmd = {
552         .command = "interrupt_autotest",
553         .callback = test_interrupt,
554 };
555 REGISTER_TEST_COMMAND(interrupt_cmd);