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 419