update Intel copyright years to 2014
[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 <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