remove version in all files
[dpdk.git] / app / test / test_interrupts.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 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
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <unistd.h>
38
39 #include <cmdline_parse.h>
40
41 #include <rte_common.h>
42 #include <rte_cycles.h>
43 #include <rte_interrupts.h>
44
45 #include "test.h"
46
47 #define TEST_INTERRUPT_CHECK_INTERVAL 1000 /* ms */
48
49 enum test_interrupt_handl_type {
50         TEST_INTERRUPT_HANDLE_INVALID,
51         TEST_INTERRUPT_HANDLE_VALID,
52         TEST_INTERRUPT_HANDLE_CASE1,
53         TEST_INTERRUPT_HANDLE_MAX
54 };
55
56 static volatile int flag;
57 static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX];
58
59 #ifdef RTE_EXEC_ENV_LINUXAPP
60 union intr_pipefds{
61         struct {
62                 int pipefd[2];
63         };
64         struct {
65                 int readfd;
66                 int writefd;
67         };
68 };
69
70 static union intr_pipefds pfds;
71
72 static inline int
73 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
74 {
75         if (!intr_handle || intr_handle->fd < 0)
76                 return -1;
77
78         return 0;
79 }
80
81 static int
82 test_interrupt_init(void)
83 {
84         if (pipe(pfds.pipefd) < 0)
85                 return -1;
86
87         intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1;
88         intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type = RTE_INTR_HANDLE_UNKNOWN;
89
90         intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd;
91         intr_handles[TEST_INTERRUPT_HANDLE_VALID].type = RTE_INTR_HANDLE_UNKNOWN;
92
93         intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.readfd;
94         intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_ALARM;
95
96         return 0;
97 }
98
99 static int
100 test_interrupt_deinit(void)
101 {
102         close(pfds.pipefd[0]);
103         close(pfds.pipefd[1]);
104
105         return 0;
106 }
107
108 static int
109 test_interrupt_trigger_interrupt(void)
110 {
111         if (write(pfds.writefd, "1", 1) < 0)
112                 return -1;
113
114         return 0;
115 }
116
117 static int
118 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
119                                 struct rte_intr_handle *intr_handle_r)
120 {
121         if (!intr_handle_l || !intr_handle_r)
122                 return -1;
123
124         if (intr_handle_l->fd != intr_handle_r->fd ||
125                 intr_handle_l->type != intr_handle_r->type)
126                 return -1;
127
128         return 0;
129 }
130
131 #else
132 /* to be implemented for baremetal later */
133 static inline int
134 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle)
135 {
136         RTE_SET_USED(intr_handle);
137
138         return 0;
139 }
140
141 static int
142 test_interrupt_init(void)
143 {
144         return 0;
145 }
146
147 static int
148 test_interrupt_deinit(void)
149 {
150         return 0;
151 }
152
153 static int
154 test_interrupt_trigger_interrupt(void)
155 {
156         return 0;
157 }
158
159 static int
160 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l,
161                                 struct rte_intr_handle *intr_handle_r)
162 {
163         (void)intr_handle_l;
164         (void)intr_handle_r;
165
166         return 0;
167 }
168 #endif /* RTE_EXEC_ENV_LINUXAPP */
169
170 static void
171 test_interrupt_callback(struct rte_intr_handle *intr_handle, void *arg)
172 {
173         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
174                 printf("null or invalid intr_handle for %s\n", __FUNCTION__);
175                 return;
176         }
177
178         if (rte_intr_callback_unregister(intr_handle,
179                         test_interrupt_callback, arg) <= 0) {
180                 printf("fail to unregister callback\n");
181                 return;
182         }
183
184         if (test_interrupt_handle_compare(intr_handle,
185                 &(intr_handles[TEST_INTERRUPT_HANDLE_VALID])) == 0) {
186                 flag = 1;
187         }
188 }
189
190 static void
191 test_interrupt_callback_1(struct rte_intr_handle *intr_handle, void *arg)
192 {
193         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
194                 printf("null or invalid intr_handle for %s\n", __FUNCTION__);
195                 return;
196         }
197         if (rte_intr_callback_unregister(intr_handle,
198                         test_interrupt_callback_1, arg) <= 0) {
199                 printf("fail to unregister callback\n");
200                 return;
201         }
202 }
203
204 static int
205 test_interrupt_enable(void)
206 {
207         struct rte_intr_handle test_intr_handle;
208
209         /* check with null intr_handle */
210         if (rte_intr_enable(NULL) == 0) {
211                 printf("unexpectedly enable null intr_handle successfully\n");
212                 return -1;
213         }
214
215         /* check with invalid intr_handle */
216         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
217         if (rte_intr_enable(&test_intr_handle) == 0) {
218                 printf("unexpectedly enable invalid intr_handle "
219                         "successfully\n");
220                 return -1;
221         }
222
223         /* check with valid intr_handle */
224         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
225         if (rte_intr_enable(&test_intr_handle) == 0) {
226                 printf("unexpectedly enable a specific intr_handle "
227                         "successfully\n");
228                 return -1;
229         }
230
231         /* check with specific valid intr_handle */
232         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
233         if (rte_intr_enable(&test_intr_handle) == 0) {
234                 printf("unexpectedly enable a specific intr_handle "
235                         "successfully\n");
236                 return -1;
237         }
238
239         return 0;
240 }
241
242 static int
243 test_interrupt_disable(void)
244 {
245         struct rte_intr_handle test_intr_handle;
246
247         /* check with null intr_handle */
248         if (rte_intr_disable(NULL) == 0) {
249                 printf("unexpectedly disable null intr_handle "
250                         "successfully\n");
251                 return -1;
252         }
253
254         /* check with invalid intr_handle */
255         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
256         if (rte_intr_disable(&test_intr_handle) == 0) {
257                 printf("unexpectedly disable invalid intr_handle "
258                         "successfully\n");
259                 return -1;
260         }
261
262         /* check with valid intr_handle */
263         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
264         if (rte_intr_disable(&test_intr_handle) == 0) {
265                 printf("unexpectedly disable a specific intr_handle "
266                         "successfully\n");
267                 return -1;
268         }
269
270         /* check with specific valid intr_handle */
271         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1];
272         if (rte_intr_disable(&test_intr_handle) == 0) {
273                 printf("unexpectedly disable a specific intr_handle "
274                         "successfully\n");
275                 return -1;
276         }
277
278         return 0;
279 }
280
281 int
282 test_interrupt(void)
283 {
284         int count = 0, ret = -1;
285         struct rte_intr_handle test_intr_handle;
286
287         if (test_interrupt_init() < 0) {
288                 printf("fail to do test init\n");
289                 return -1;
290         }
291
292         printf("check if callback registered can be called\n");
293
294         /* check if callback registered can be called */
295         flag = 0;
296         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
297         if (rte_intr_callback_register(&test_intr_handle,
298                         test_interrupt_callback, NULL) < 0) {
299                 printf("fail to register callback\n");
300                 goto out;
301         }
302         /* trigger an interrupt and then check if the callback can be called */
303         if (test_interrupt_trigger_interrupt() < 0) {
304                 printf("fail to trigger an interrupt\n");
305                 goto out;
306         }
307         /* check flag in 3 seconds */
308         while (flag == 0 && count++ < 3)
309                 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
310         if (flag == 0) {
311                 printf("registered callback has not been called\n");
312                 goto out;
313         }
314         rte_delay_ms(1000);
315
316         printf("start register/unregister test\n");
317
318         /* check if it will fail to register cb with intr_handle = NULL */
319         if (rte_intr_callback_register(NULL, test_interrupt_callback,
320                                                         NULL) == 0) {
321                 printf("unexpectedly register successfully with null "
322                         "intr_handle\n");
323                 goto out;
324         }
325
326         /* check if it will fail to register cb with invalid intr_handle */
327         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
328         if (rte_intr_callback_register(&test_intr_handle,
329                         test_interrupt_callback, NULL) == 0) {
330                 printf("unexpectedly register successfully with invalid "
331                         "intr_handle\n");
332                 goto out;
333         }
334
335         /* check if it will fail to register without callback */
336         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
337         if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) {
338                 printf("unexpectedly register successfully with "
339                         "null callback\n");
340                 goto out;
341         }
342
343         /* check if it will fail to unregister cb with intr_handle = NULL */
344         if (rte_intr_callback_unregister(NULL,
345                         test_interrupt_callback, NULL) > 0) {
346                 printf("unexpectedly unregister successfully with "
347                         "null intr_handle\n");
348                 goto out;
349         }
350
351         /* check if it will fail to unregister cb with invalid intr_handle */
352         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
353         if (rte_intr_callback_unregister(&test_intr_handle,
354                         test_interrupt_callback, NULL) > 0) {
355                 printf("unexpectedly unregister successfully with "
356                         "invalid intr_handle\n");
357                 goto out;
358         }
359
360         /* check if it is ok to register the same intr_handle twice */
361         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
362         if (rte_intr_callback_register(&test_intr_handle,
363                         test_interrupt_callback, NULL) < 0) {
364                 printf("it fails to register test_interrupt_callback\n");
365                 goto out;
366         }
367         if (rte_intr_callback_register(&test_intr_handle,
368                         test_interrupt_callback_1, NULL) < 0) {
369                 printf("it fails to register test_interrupt_callback_1\n");
370                 goto out;
371         }
372         /* check if it will fail to unregister with invalid parameter */
373         if (rte_intr_callback_unregister(&test_intr_handle,
374                         test_interrupt_callback, (void *)0xff) != 0) {
375                 printf("unexpectedly unregisters successfully with invalid arg\n");
376                 goto out;
377         }
378         if (rte_intr_callback_unregister(&test_intr_handle,
379                         test_interrupt_callback, NULL) <= 0) {
380                 printf("it fails to unregister test_interrupt_callback\n");
381                 goto out;
382         }
383         if (rte_intr_callback_unregister(&test_intr_handle,
384                         test_interrupt_callback_1, (void *)-1) <= 0) {
385                 printf("it fails to unregister test_interrupt_callback_1 "
386                         "for all\n");
387                 goto out;
388         }
389         rte_delay_ms(1000);
390
391         printf("start interrupt enable/disable test\n");
392
393         /* check interrupt enable/disable functions */
394         if (test_interrupt_enable() < 0)
395                 goto out;
396         rte_delay_ms(1000);
397
398         if (test_interrupt_disable() < 0)
399                 goto out;
400         rte_delay_ms(1000);
401
402         ret = 0;
403
404 out:
405         /* clear registered callbacks */
406         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
407         rte_intr_callback_unregister(&test_intr_handle,
408                         test_interrupt_callback, (void *)-1);
409         rte_intr_callback_unregister(&test_intr_handle,
410                         test_interrupt_callback_1, (void *)-1);
411
412         rte_delay_ms(2000);
413         /* deinit */
414         test_interrupt_deinit();
415
416         return ret;
417 }
418