doc: whitespace changes in licenses
[dpdk.git] / app / test / test_interrupts.c
1 /*-
2  *  BSD LICENSE
3  *
4  *  Copyright(c) 2010-2013 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 enum test_interrupt_handl_type {
49         TEST_INTERRUPT_HANDLE_INVALID,
50         TEST_INTERRUPT_HANDLE_VALID,
51         TEST_INTERRUPT_HANDLE_CASE1,
52         TEST_INTERRUPT_HANDLE_MAX
53 };
54
55 static volatile int flag;
56 static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX];
57
58 #ifdef RTE_EXEC_ENV_LINUXAPP
59 union intr_pipefds{
60         struct {
61                 int pipefd[2];
62         };
63         struct {
64                 int readfd;
65                 int writefd;
66         };
67 };
68
69 static union intr_pipefds pfds;
70
71 static inline int
72 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
73 {
74         if (!intr_handle || intr_handle->fd < 0)
75                 return -1;
76
77         return 0;
78 }
79
80 static int
81 test_interrupt_init(void)
82 {
83         if (pipe(pfds.pipefd) < 0)
84                 return -1;
85
86         intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1;
87         intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type = RTE_INTR_HANDLE_UNKNOWN;
88
89         intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd;
90         intr_handles[TEST_INTERRUPT_HANDLE_VALID].type = RTE_INTR_HANDLE_UNKNOWN;
91
92         intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.readfd;
93         intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_ALARM;
94
95         return 0;
96 }
97
98 static int
99 test_interrupt_deinit(void)
100 {
101         close(pfds.pipefd[0]);
102         close(pfds.pipefd[1]);
103
104         return 0;
105 }
106
107 static int
108 test_interrupt_trigger_interrupt(void)
109 {
110         if (write(pfds.writefd, "1", 1) < 0)
111                 return -1;
112
113         return 0;
114 }
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 baremetal 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 static void
170 test_interrupt_callback(struct rte_intr_handle *intr_handle, void *arg)
171 {
172         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
173                 printf("null or invalid intr_handle for %s\n", __func__);
174                 flag = -1;
175                 return;
176         }
177
178         if (rte_intr_callback_unregister(intr_handle,
179                         test_interrupt_callback, arg) >= 0) {
180                 printf("%s: unexpectedly able to unregister itself\n",
181                         __func__);
182                 flag = -1;
183                 return;
184         }
185
186         if (test_interrupt_handle_compare(intr_handle,
187                 &(intr_handles[TEST_INTERRUPT_HANDLE_VALID])) == 0) {
188                 flag = 1;
189         }
190 }
191
192 static void
193 test_interrupt_callback_1(struct rte_intr_handle *intr_handle,
194         __attribute__((unused)) void *arg)
195 {
196         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
197                 printf("null or invalid intr_handle for %s\n", __func__);
198                 flag = -1;
199                 return;
200         }
201 }
202
203 static int
204 test_interrupt_enable(void)
205 {
206         struct rte_intr_handle test_intr_handle;
207
208         /* check with null intr_handle */
209         if (rte_intr_enable(NULL) == 0) {
210                 printf("unexpectedly enable null intr_handle successfully\n");
211                 return -1;
212         }
213
214         /* check with invalid intr_handle */
215         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
216         if (rte_intr_enable(&test_intr_handle) == 0) {
217                 printf("unexpectedly enable invalid intr_handle "
218                         "successfully\n");
219                 return -1;
220         }
221
222         /* check with valid intr_handle */
223         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
224         if (rte_intr_enable(&test_intr_handle) == 0) {
225                 printf("unexpectedly enable a specific intr_handle "
226                         "successfully\n");
227                 return -1;
228         }
229
230         /* check with specific valid intr_handle */
231         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
232         if (rte_intr_enable(&test_intr_handle) == 0) {
233                 printf("unexpectedly enable a specific intr_handle "
234                         "successfully\n");
235                 return -1;
236         }
237
238         return 0;
239 }
240
241 static int
242 test_interrupt_disable(void)
243 {
244         struct rte_intr_handle test_intr_handle;
245
246         /* check with null intr_handle */
247         if (rte_intr_disable(NULL) == 0) {
248                 printf("unexpectedly disable null intr_handle "
249                         "successfully\n");
250                 return -1;
251         }
252
253         /* check with invalid intr_handle */
254         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
255         if (rte_intr_disable(&test_intr_handle) == 0) {
256                 printf("unexpectedly disable invalid intr_handle "
257                         "successfully\n");
258                 return -1;
259         }
260
261         /* check with valid intr_handle */
262         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
263         if (rte_intr_disable(&test_intr_handle) == 0) {
264                 printf("unexpectedly disable a specific intr_handle "
265                         "successfully\n");
266                 return -1;
267         }
268
269         /* check with specific valid intr_handle */
270         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
271         if (rte_intr_disable(&test_intr_handle) == 0) {
272                 printf("unexpectedly disable a specific intr_handle "
273                         "successfully\n");
274                 return -1;
275         }
276
277         return 0;
278 }
279
280 int
281 test_interrupt(void)
282 {
283         int count, ret;
284         struct rte_intr_handle test_intr_handle;
285
286         if (test_interrupt_init() < 0) {
287                 printf("fail to do test init\n");
288                 return -1;
289         }
290
291         printf("check if callback registered can be called\n");
292
293         ret = -1;
294
295         /* check if callback registered can be called */
296         flag = 0;
297         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
298         if (rte_intr_callback_register(&test_intr_handle,
299                         test_interrupt_callback, NULL) < 0) {
300                 printf("fail to register callback\n");
301                 goto out;
302         }
303         /* trigger an interrupt and then check if the callback can be called */
304         if (test_interrupt_trigger_interrupt() < 0) {
305                 printf("fail to trigger an interrupt\n");
306                 goto out;
307         }
308         /* check flag in 3 seconds */
309         for (count = 0; flag == 0 && count < 3; count++)
310                 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
311
312         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
313
314         if ((ret = rte_intr_callback_unregister(&test_intr_handle,
315                         test_interrupt_callback, NULL)) < 0) {
316                 printf("rte_intr_callback_unregister() failed with error "
317                         "code: %d\n", ret);
318                 goto out;
319         }
320
321         ret = -1;
322         
323         if (flag == 0) {
324                 printf("registered callback has not been called\n");
325                 goto out;
326         } else if (flag < 0) {
327                 printf("registered callback failed\n");
328                 ret = flag;
329                 goto out;
330         }
331
332         printf("start register/unregister test\n");
333
334         /* check if it will fail to register cb with intr_handle = NULL */
335         if (rte_intr_callback_register(NULL, test_interrupt_callback,
336                                                         NULL) == 0) {
337                 printf("unexpectedly register successfully with null "
338                         "intr_handle\n");
339                 goto out;
340         }
341
342         /* check if it will fail to register cb with invalid intr_handle */
343         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
344         if (rte_intr_callback_register(&test_intr_handle,
345                         test_interrupt_callback, NULL) == 0) {
346                 printf("unexpectedly register successfully with invalid "
347                         "intr_handle\n");
348                 goto out;
349         }
350
351         /* check if it will fail to register without callback */
352         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
353         if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) {
354                 printf("unexpectedly register successfully with "
355                         "null callback\n");
356                 goto out;
357         }
358
359         /* check if it will fail to unregister cb with intr_handle = NULL */
360         if (rte_intr_callback_unregister(NULL,
361                         test_interrupt_callback, NULL) > 0) {
362                 printf("unexpectedly unregister successfully with "
363                         "null intr_handle\n");
364                 goto out;
365         }
366
367         /* check if it will fail to unregister cb with invalid intr_handle */
368         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
369         if (rte_intr_callback_unregister(&test_intr_handle,
370                         test_interrupt_callback, NULL) > 0) {
371                 printf("unexpectedly unregister successfully with "
372                         "invalid intr_handle\n");
373                 goto out;
374         }
375
376         /* check if it is ok to register the same intr_handle twice */
377         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
378         if (rte_intr_callback_register(&test_intr_handle,
379                         test_interrupt_callback, NULL) < 0) {
380                 printf("it fails to register test_interrupt_callback\n");
381                 goto out;
382         }
383         if (rte_intr_callback_register(&test_intr_handle,
384                         test_interrupt_callback_1, NULL) < 0) {
385                 printf("it fails to register test_interrupt_callback_1\n");
386                 goto out;
387         }
388         /* check if it will fail to unregister with invalid parameter */
389         if (rte_intr_callback_unregister(&test_intr_handle,
390                         test_interrupt_callback, (void *)0xff) != 0) {
391                 printf("unexpectedly unregisters successfully with invalid arg\n");
392                 goto out;
393         }
394         if (rte_intr_callback_unregister(&test_intr_handle,
395                         test_interrupt_callback, NULL) <= 0) {
396                 printf("it fails to unregister test_interrupt_callback\n");
397                 goto out;
398         }
399         if (rte_intr_callback_unregister(&test_intr_handle,
400                         test_interrupt_callback_1, (void *)-1) <= 0) {
401                 printf("it fails to unregister test_interrupt_callback_1 "
402                         "for all\n");
403                 goto out;
404         }
405         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
406
407         printf("start interrupt enable/disable test\n");
408
409         /* check interrupt enable/disable functions */
410         if (test_interrupt_enable() < 0)
411                 goto out;
412         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
413
414         if (test_interrupt_disable() < 0)
415                 goto out;
416         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
417
418         ret = 0;
419
420 out:
421         /* clear registered callbacks */
422         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
423         rte_intr_callback_unregister(&test_intr_handle,
424                         test_interrupt_callback, (void *)-1);
425         rte_intr_callback_unregister(&test_intr_handle,
426                         test_interrupt_callback_1, (void *)-1);
427
428         rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL);
429         /* deinit */
430         test_interrupt_deinit();
431
432         return ret;
433 }
434