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