c810c15f54ab9150724eaee85cb823d5043c6822
[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
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", __func__);
175                 flag = -1;
176                 return;
177         }
178
179         if (rte_intr_callback_unregister(intr_handle,
180                         test_interrupt_callback, arg) >= 0) {
181                 printf("%s: unexpectedly able to unregister itself\n",
182                         __func__);
183                 flag = -1;
184                 return;
185         }
186
187         if (test_interrupt_handle_compare(intr_handle,
188                 &(intr_handles[TEST_INTERRUPT_HANDLE_VALID])) == 0) {
189                 flag = 1;
190         }
191 }
192
193 static void
194 test_interrupt_callback_1(struct rte_intr_handle *intr_handle,
195         __attribute__((unused)) void *arg)
196 {
197         if (test_interrupt_handle_sanity_check(intr_handle) < 0) {
198                 printf("null or invalid intr_handle for %s\n", __func__);
199                 flag = -1;
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, ret;
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         ret = -1;
295
296         /* check if callback registered can be called */
297         flag = 0;
298         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
299         if (rte_intr_callback_register(&test_intr_handle,
300                         test_interrupt_callback, NULL) < 0) {
301                 printf("fail to register callback\n");
302                 goto out;
303         }
304         /* trigger an interrupt and then check if the callback can be called */
305         if (test_interrupt_trigger_interrupt() < 0) {
306                 printf("fail to trigger an interrupt\n");
307                 goto out;
308         }
309         /* check flag in 3 seconds */
310         for (count = 0; flag == 0 && count < 3; count++)
311                 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
312
313         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
314
315         if ((ret = rte_intr_callback_unregister(&test_intr_handle,
316                         test_interrupt_callback, NULL)) < 0) {
317                 printf("rte_intr_callback_unregister() failed with error "
318                         "code: %d\n", ret);
319                 goto out;
320         }
321
322         ret = -1;
323         
324         if (flag == 0) {
325                 printf("registered callback has not been called\n");
326                 goto out;
327         } else if (flag < 0) {
328                 printf("registered callback failed\n");
329                 ret = flag;
330                 goto out;
331         }
332
333         printf("start register/unregister test\n");
334
335         /* check if it will fail to register cb with intr_handle = NULL */
336         if (rte_intr_callback_register(NULL, test_interrupt_callback,
337                                                         NULL) == 0) {
338                 printf("unexpectedly register successfully with null "
339                         "intr_handle\n");
340                 goto out;
341         }
342
343         /* check if it will fail to register cb with invalid intr_handle */
344         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
345         if (rte_intr_callback_register(&test_intr_handle,
346                         test_interrupt_callback, NULL) == 0) {
347                 printf("unexpectedly register successfully with invalid "
348                         "intr_handle\n");
349                 goto out;
350         }
351
352         /* check if it will fail to register without callback */
353         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
354         if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) {
355                 printf("unexpectedly register successfully with "
356                         "null callback\n");
357                 goto out;
358         }
359
360         /* check if it will fail to unregister cb with intr_handle = NULL */
361         if (rte_intr_callback_unregister(NULL,
362                         test_interrupt_callback, NULL) > 0) {
363                 printf("unexpectedly unregister successfully with "
364                         "null intr_handle\n");
365                 goto out;
366         }
367
368         /* check if it will fail to unregister cb with invalid intr_handle */
369         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID];
370         if (rte_intr_callback_unregister(&test_intr_handle,
371                         test_interrupt_callback, NULL) > 0) {
372                 printf("unexpectedly unregister successfully with "
373                         "invalid intr_handle\n");
374                 goto out;
375         }
376
377         /* check if it is ok to register the same intr_handle twice */
378         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
379         if (rte_intr_callback_register(&test_intr_handle,
380                         test_interrupt_callback, NULL) < 0) {
381                 printf("it fails to register test_interrupt_callback\n");
382                 goto out;
383         }
384         if (rte_intr_callback_register(&test_intr_handle,
385                         test_interrupt_callback_1, NULL) < 0) {
386                 printf("it fails to register test_interrupt_callback_1\n");
387                 goto out;
388         }
389         /* check if it will fail to unregister with invalid parameter */
390         if (rte_intr_callback_unregister(&test_intr_handle,
391                         test_interrupt_callback, (void *)0xff) != 0) {
392                 printf("unexpectedly unregisters successfully with invalid arg\n");
393                 goto out;
394         }
395         if (rte_intr_callback_unregister(&test_intr_handle,
396                         test_interrupt_callback, NULL) <= 0) {
397                 printf("it fails to unregister test_interrupt_callback\n");
398                 goto out;
399         }
400         if (rte_intr_callback_unregister(&test_intr_handle,
401                         test_interrupt_callback_1, (void *)-1) <= 0) {
402                 printf("it fails to unregister test_interrupt_callback_1 "
403                         "for all\n");
404                 goto out;
405         }
406         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
407
408         printf("start interrupt enable/disable test\n");
409
410         /* check interrupt enable/disable functions */
411         if (test_interrupt_enable() < 0)
412                 goto out;
413         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
414
415         if (test_interrupt_disable() < 0)
416                 goto out;
417         rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL);
418
419         ret = 0;
420
421 out:
422         /* clear registered callbacks */
423         test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID];
424         rte_intr_callback_unregister(&test_intr_handle,
425                         test_interrupt_callback, (void *)-1);
426         rte_intr_callback_unregister(&test_intr_handle,
427                         test_interrupt_callback_1, (void *)-1);
428
429         rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL);
430         /* deinit */
431         test_interrupt_deinit();
432
433         return ret;
434 }
435