New upstream version 17.08
[deb_dpdk.git] / test / 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 100 /* 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(void *arg)
203 {
204         struct rte_intr_handle *intr_handle = arg;
205         if (test_intr_type >= TEST_INTERRUPT_HANDLE_MAX) {
206                 printf("invalid interrupt type\n");
207                 flag = -1;
208                 return;
209         }
210
211         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
212                 printf("null or invalid intr_handle for %s\n", __func__);
213                 flag = -1;
214                 return;
215         }
216
217         if (rte_intr_callback_unregister(intr_handle,
218                         test_interrupt_callback, arg) >= 0) {
219                 printf("%s: unexpectedly able to unregister itself\n",
220                         __func__);
221                 flag = -1;
222                 return;
223         }
224
225         if (test_interrupt_handle_compare(intr_handle,
226                         &(intr_handles[test_intr_type])) == 0)
227                 flag = 1;
228 }
229
230 /**
231  * Callback for the test interrupt.
232  */
233 static void
234 test_interrupt_callback_1(void *arg)
235 {
236         struct rte_intr_handle *intr_handle = arg;
237         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
238                 printf("null or invalid intr_handle for %s\n", __func__);
239                 flag = -1;
240                 return;
241         }
242 }
243
244 /**
245  * Tests for rte_intr_enable().
246  */
247 static int
248 test_interrupt_enable(void)
249 {
250         struct rte_intr_handle test_intr_handle;
251
252         /* check with null intr_handle */
253         if (rte_intr_enable(NULL) == 0) {
254                 printf("unexpectedly enable null intr_handle successfully\n");
255                 return -1;
256         }
257
258         /* check with invalid intr_handle */
259         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
260         if (rte_intr_enable(&test_intr_handle) == 0) {
261                 printf("unexpectedly enable invalid intr_handle "
262                         "successfully\n");
263                 return -1;
264         }
265
266         /* check with valid intr_handle */
267         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
268         if (rte_intr_enable(&test_intr_handle) == 0) {
269                 printf("unexpectedly enable a specific intr_handle "
270                         "successfully\n");
271                 return -1;
272         }
273
274         /* check with specific valid intr_handle */
275         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
276         if (rte_intr_enable(&test_intr_handle) == 0) {
277                 printf("unexpectedly enable a specific intr_handle "
278                         "successfully\n");
279                 return -1;
280         }
281
282         /* check with valid handler and its type */
283         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
284         if (rte_intr_enable(&test_intr_handle) < 0) {
285                 printf("fail to enable interrupt on a simulated handler\n");
286                 return -1;
287         }
288
289         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
290         if (rte_intr_enable(&test_intr_handle) == 0) {
291                 printf("unexpectedly enable a specific intr_handle "
292                         "successfully\n");
293                 return -1;
294         }
295
296         return 0;
297 }
298
299 /**
300  * Tests for rte_intr_disable().
301  */
302 static int
303 test_interrupt_disable(void)
304 {
305         struct rte_intr_handle test_intr_handle;
306
307         /* check with null intr_handle */
308         if (rte_intr_disable(NULL) == 0) {
309                 printf("unexpectedly disable null intr_handle "
310                         "successfully\n");
311                 return -1;
312         }
313
314         /* check with invalid intr_handle */
315         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
316         if (rte_intr_disable(&test_intr_handle) == 0) {
317                 printf("unexpectedly disable invalid intr_handle "
318                         "successfully\n");
319                 return -1;
320         }
321
322         /* check with valid intr_handle */
323         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
324         if (rte_intr_disable(&test_intr_handle) == 0) {
325                 printf("unexpectedly disable a specific intr_handle "
326                         "successfully\n");
327                 return -1;
328         }
329
330         /* check with specific valid intr_handle */
331         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
332         if (rte_intr_disable(&test_intr_handle) == 0) {
333                 printf("unexpectedly disable a specific intr_handle "
334                         "successfully\n");
335                 return -1;
336         }
337
338         /* check with valid handler and its type */
339         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
340         if (rte_intr_disable(&test_intr_handle) < 0) {
341                 printf("fail to disable interrupt on a simulated handler\n");
342                 return -1;
343         }
344
345         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
346         if (rte_intr_disable(&test_intr_handle) == 0) {
347                 printf("unexpectedly disable a specific intr_handle "
348                         "successfully\n");
349                 return -1;
350         }
351
352         return 0;
353 }
354
355 /**
356  * Check the full path of a specified type of interrupt simulated.
357  */
358 static int
359 test_interrupt_full_path_check(enum test_interrupt_handle_type intr_type)
360 {
361         int count;
362         struct rte_intr_handle test_intr_handle;
363
364         flag = 0;
365         test_intr_handle = intr_handles[intr_type];
366         test_intr_type = intr_type;
367         if (rte_intr_callback_register(&test_intr_handle,
368                         test_interrupt_callback, &test_intr_handle) < 0) {
369                 printf("fail to register callback\n");
370                 return -1;
371         }
372
373         if (test_interrupt_trigger_interrupt() < 0)
374                 return -1;
375
376         /* check flag */
377         for (count = 0; flag == 0 && count < 3; count++)
378                 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
379
380         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
381         if (rte_intr_callback_unregister(&test_intr_handle,
382                         test_interrupt_callback, &test_intr_handle) < 0)
383                 return -1;
384
385         if (flag == 0) {
386                 printf("callback has not been called\n");
387                 return -1;
388         } else if (flag < 0) {
389                 printf("it has internal error in callback\n");
390                 return -1;
391         }
392
393         return 0;
394 }
395
396 /**
397  * Main function of testing interrupt.
398  */
399 static int
400 test_interrupt(void)
401 {
402         int ret = -1;
403         struct rte_intr_handle test_intr_handle;
404
405         if (test_interrupt_init() < 0) {
406                 printf("fail to initialize for testing interrupt\n");
407                 return -1;
408         }
409
410         printf("Check unknown valid interrupt full path\n");
411         if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID) < 0) {
412                 printf("failure occurred during checking unknown valid "
413                                                 "interrupt full path\n");
414                 goto out;
415         }
416
417         printf("Check valid UIO interrupt full path\n");
418         if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_UIO)
419                                                                         < 0) {
420                 printf("failure occurred during checking valid UIO interrupt "
421                                                                 "full path\n");
422                 goto out;
423         }
424
425         printf("Check valid alarm interrupt full path\n");
426         if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_ALARM)
427                                                                         < 0) {
428                 printf("failure occurred during checking valid alarm "
429                                                 "interrupt full path\n");
430                 goto out;
431         }
432
433         printf("start register/unregister test\n");
434         /* check if it will fail to register cb with intr_handle = NULL */
435         if (rte_intr_callback_register(NULL, test_interrupt_callback,
436                                                         NULL) == 0) {
437                 printf("unexpectedly register successfully with null "
438                         "intr_handle\n");
439                 goto out;
440         }
441
442         /* check if it will fail to register cb with invalid intr_handle */
443         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
444         if (rte_intr_callback_register(&test_intr_handle,
445                         test_interrupt_callback, &test_intr_handle) == 0) {
446                 printf("unexpectedly register successfully with invalid "
447                         "intr_handle\n");
448                 goto out;
449         }
450
451         /* check if it will fail to register without callback */
452         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
453         if (rte_intr_callback_register(&test_intr_handle, NULL, &test_intr_handle) == 0) {
454                 printf("unexpectedly register successfully with "
455                         "null callback\n");
456                 goto out;
457         }
458
459         /* check if it will fail to unregister cb with intr_handle = NULL */
460         if (rte_intr_callback_unregister(NULL,
461                         test_interrupt_callback, NULL) > 0) {
462                 printf("unexpectedly unregister successfully with "
463                         "null intr_handle\n");
464                 goto out;
465         }
466
467         /* check if it will fail to unregister cb with invalid intr_handle */
468         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
469         if (rte_intr_callback_unregister(&test_intr_handle,
470                         test_interrupt_callback, &test_intr_handle) > 0) {
471                 printf("unexpectedly unregister successfully with "
472                         "invalid intr_handle\n");
473                 goto out;
474         }
475
476         /* check if it is ok to register the same intr_handle twice */
477         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
478         if (rte_intr_callback_register(&test_intr_handle,
479                         test_interrupt_callback, &test_intr_handle) < 0) {
480                 printf("it fails to register test_interrupt_callback\n");
481                 goto out;
482         }
483         if (rte_intr_callback_register(&test_intr_handle,
484                         test_interrupt_callback_1, &test_intr_handle) < 0) {
485                 printf("it fails to register test_interrupt_callback_1\n");
486                 goto out;
487         }
488         /* check if it will fail to unregister with invalid parameter */
489         if (rte_intr_callback_unregister(&test_intr_handle,
490                         test_interrupt_callback, (void *)0xff) != 0) {
491                 printf("unexpectedly unregisters successfully with "
492                                                         "invalid arg\n");
493                 goto out;
494         }
495         if (rte_intr_callback_unregister(&test_intr_handle,
496                         test_interrupt_callback, &test_intr_handle) <= 0) {
497                 printf("it fails to unregister test_interrupt_callback\n");
498                 goto out;
499         }
500         if (rte_intr_callback_unregister(&test_intr_handle,
501                         test_interrupt_callback_1, (void *)-1) <= 0) {
502                 printf("it fails to unregister test_interrupt_callback_1 "
503                         "for all\n");
504                 goto out;
505         }
506         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
507
508         printf("start interrupt enable/disable test\n");
509         /* check interrupt enable/disable functions */
510         if (test_interrupt_enable() < 0) {
511                 printf("fail to check interrupt enabling\n");
512                 goto out;
513         }
514         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
515
516         if (test_interrupt_disable() < 0) {
517                 printf("fail to check interrupt disabling\n");
518                 goto out;
519         }
520         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
521
522         ret = 0;
523
524 out:
525         printf("Clearing for interrupt tests\n");
526         /* clear registered callbacks */
527         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
528         rte_intr_callback_unregister(&test_intr_handle,
529                         test_interrupt_callback, (void *)-1);
530         rte_intr_callback_unregister(&test_intr_handle,
531                         test_interrupt_callback_1, (void *)-1);
532
533         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO];
534         rte_intr_callback_unregister(&test_intr_handle,
535                         test_interrupt_callback, (void *)-1);
536         rte_intr_callback_unregister(&test_intr_handle,
537                         test_interrupt_callback_1, (void *)-1);
538
539         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM];
540         rte_intr_callback_unregister(&test_intr_handle,
541                         test_interrupt_callback, (void *)-1);
542         rte_intr_callback_unregister(&test_intr_handle,
543                         test_interrupt_callback_1, (void *)-1);
544
545         rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL);
546         /* deinit */
547         test_interrupt_deinit();
548
549         return ret;
550 }
551
552 REGISTER_TEST_COMMAND(interrupt_autotest, test_interrupt);