1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 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 <rte_common.h> 39 #include <rte_cycles.h> 40 #include <rte_interrupts.h> 41 42 #include "test.h" 43 44 #define TEST_INTERRUPT_CHECK_INTERVAL 100 /* ms */ 45 46 /* predefined interrupt handle types */ 47 enum test_interrupt_handle_type { 48 TEST_INTERRUPT_HANDLE_INVALID, 49 TEST_INTERRUPT_HANDLE_VALID, 50 TEST_INTERRUPT_HANDLE_VALID_UIO, 51 TEST_INTERRUPT_HANDLE_VALID_ALARM, 52 TEST_INTERRUPT_HANDLE_CASE1, 53 TEST_INTERRUPT_HANDLE_MAX 54 }; 55 56 /* flag of if callback is called */ 57 static volatile int flag; 58 static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX]; 59 static enum test_interrupt_handle_type test_intr_type = 60 TEST_INTERRUPT_HANDLE_MAX; 61 62 #ifdef RTE_EXEC_ENV_LINUXAPP 63 union intr_pipefds{ 64 struct { 65 int pipefd[2]; 66 }; 67 struct { 68 int readfd; 69 int writefd; 70 }; 71 }; 72 73 static union intr_pipefds pfds; 74 75 /** 76 * Check if the interrupt handle is valid. 77 */ 78 static inline int 79 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle) 80 { 81 if (!intr_handle || intr_handle->fd < 0) 82 return -1; 83 84 return 0; 85 } 86 87 /** 88 * Initialization for interrupt test. 89 */ 90 static int 91 test_interrupt_init(void) 92 { 93 if (pipe(pfds.pipefd) < 0) 94 return -1; 95 96 intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1; 97 intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type = 98 RTE_INTR_HANDLE_UNKNOWN; 99 100 intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd; 101 intr_handles[TEST_INTERRUPT_HANDLE_VALID].type = 102 RTE_INTR_HANDLE_UNKNOWN; 103 104 intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].fd = pfds.readfd; 105 intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].type = 106 RTE_INTR_HANDLE_UIO; 107 108 intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].fd = pfds.readfd; 109 intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].type = 110 RTE_INTR_HANDLE_ALARM; 111 112 intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.writefd; 113 intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_UIO; 114 115 return 0; 116 } 117 118 /** 119 * Deinitialization for interrupt test. 120 */ 121 static int 122 test_interrupt_deinit(void) 123 { 124 close(pfds.pipefd[0]); 125 close(pfds.pipefd[1]); 126 127 return 0; 128 } 129 130 /** 131 * Write the pipe to simulate an interrupt. 132 */ 133 static int 134 test_interrupt_trigger_interrupt(void) 135 { 136 if (write(pfds.writefd, "1", 1) < 0) 137 return -1; 138 139 return 0; 140 } 141 142 /** 143 * Check if two interrupt handles are the same. 144 */ 145 static int 146 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l, 147 struct rte_intr_handle *intr_handle_r) 148 { 149 if (!intr_handle_l || !intr_handle_r) 150 return -1; 151 152 if (intr_handle_l->fd != intr_handle_r->fd || 153 intr_handle_l->type != intr_handle_r->type) 154 return -1; 155 156 return 0; 157 } 158 159 #else 160 /* to be implemented for bsd later */ 161 static inline int 162 test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle) 163 { 164 RTE_SET_USED(intr_handle); 165 166 return 0; 167 } 168 169 static int 170 test_interrupt_init(void) 171 { 172 return 0; 173 } 174 175 static int 176 test_interrupt_deinit(void) 177 { 178 return 0; 179 } 180 181 static int 182 test_interrupt_trigger_interrupt(void) 183 { 184 return 0; 185 } 186 187 static int 188 test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l, 189 struct rte_intr_handle *intr_handle_r) 190 { 191 (void)intr_handle_l; 192 (void)intr_handle_r; 193 194 return 0; 195 } 196 #endif /* RTE_EXEC_ENV_LINUXAPP */ 197 198 /** 199 * Callback for the test interrupt. 200 */ 201 static void 202 test_interrupt_callback(struct rte_intr_handle *intr_handle, void *arg) 203 { 204 if (test_intr_type >= TEST_INTERRUPT_HANDLE_MAX) { 205 printf("invalid interrupt type\n"); 206 flag = -1; 207 return; 208 } 209 210 if (test_interrupt_handle_sanity_check(intr_handle) < 0) { 211 printf("null or invalid intr_handle for %s\n", __func__); 212 flag = -1; 213 return; 214 } 215 216 if (rte_intr_callback_unregister(intr_handle, 217 test_interrupt_callback, arg) >= 0) { 218 printf("%s: unexpectedly able to unregister itself\n", 219 __func__); 220 flag = -1; 221 return; 222 } 223 224 if (test_interrupt_handle_compare(intr_handle, 225 &(intr_handles[test_intr_type])) == 0) 226 flag = 1; 227 } 228 229 /** 230 * Callback for the test interrupt. 231 */ 232 static void 233 test_interrupt_callback_1(struct rte_intr_handle *intr_handle, 234 __attribute__((unused)) void *arg) 235 { 236 if (test_interrupt_handle_sanity_check(intr_handle) < 0) { 237 printf("null or invalid intr_handle for %s\n", __func__); 238 flag = -1; 239 return; 240 } 241 } 242 243 /** 244 * Tests for rte_intr_enable(). 245 */ 246 static int 247 test_interrupt_enable(void) 248 { 249 struct rte_intr_handle test_intr_handle; 250 251 /* check with null intr_handle */ 252 if (rte_intr_enable(NULL) == 0) { 253 printf("unexpectedly enable null intr_handle successfully\n"); 254 return -1; 255 } 256 257 /* check with invalid intr_handle */ 258 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 259 if (rte_intr_enable(&test_intr_handle) == 0) { 260 printf("unexpectedly enable invalid intr_handle " 261 "successfully\n"); 262 return -1; 263 } 264 265 /* check with valid intr_handle */ 266 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 267 if (rte_intr_enable(&test_intr_handle) == 0) { 268 printf("unexpectedly enable a specific intr_handle " 269 "successfully\n"); 270 return -1; 271 } 272 273 /* check with specific valid intr_handle */ 274 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; 275 if (rte_intr_enable(&test_intr_handle) == 0) { 276 printf("unexpectedly enable a specific intr_handle " 277 "successfully\n"); 278 return -1; 279 } 280 281 /* check with valid handler and its type */ 282 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1]; 283 if (rte_intr_enable(&test_intr_handle) < 0) { 284 printf("fail to enable interrupt on a simulated handler\n"); 285 return -1; 286 } 287 288 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; 289 if (rte_intr_enable(&test_intr_handle) == 0) { 290 printf("unexpectedly enable a specific intr_handle " 291 "successfully\n"); 292 return -1; 293 } 294 295 return 0; 296 } 297 298 /** 299 * Tests for rte_intr_disable(). 300 */ 301 static int 302 test_interrupt_disable(void) 303 { 304 struct rte_intr_handle test_intr_handle; 305 306 /* check with null intr_handle */ 307 if (rte_intr_disable(NULL) == 0) { 308 printf("unexpectedly disable null intr_handle " 309 "successfully\n"); 310 return -1; 311 } 312 313 /* check with invalid intr_handle */ 314 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 315 if (rte_intr_disable(&test_intr_handle) == 0) { 316 printf("unexpectedly disable invalid intr_handle " 317 "successfully\n"); 318 return -1; 319 } 320 321 /* check with valid intr_handle */ 322 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 323 if (rte_intr_disable(&test_intr_handle) == 0) { 324 printf("unexpectedly disable a specific intr_handle " 325 "successfully\n"); 326 return -1; 327 } 328 329 /* check with specific valid intr_handle */ 330 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; 331 if (rte_intr_disable(&test_intr_handle) == 0) { 332 printf("unexpectedly disable a specific intr_handle " 333 "successfully\n"); 334 return -1; 335 } 336 337 /* check with valid handler and its type */ 338 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1]; 339 if (rte_intr_disable(&test_intr_handle) < 0) { 340 printf("fail to disable interrupt on a simulated handler\n"); 341 return -1; 342 } 343 344 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; 345 if (rte_intr_disable(&test_intr_handle) == 0) { 346 printf("unexpectedly disable a specific intr_handle " 347 "successfully\n"); 348 return -1; 349 } 350 351 return 0; 352 } 353 354 /** 355 * Check the full path of a specified type of interrupt simulated. 356 */ 357 static int 358 test_interrupt_full_path_check(enum test_interrupt_handle_type intr_type) 359 { 360 int count; 361 struct rte_intr_handle test_intr_handle; 362 363 flag = 0; 364 test_intr_handle = intr_handles[intr_type]; 365 test_intr_type = intr_type; 366 if (rte_intr_callback_register(&test_intr_handle, 367 test_interrupt_callback, NULL) < 0) { 368 printf("fail to register callback\n"); 369 return -1; 370 } 371 372 if (test_interrupt_trigger_interrupt() < 0) 373 return -1; 374 375 /* check flag */ 376 for (count = 0; flag == 0 && count < 3; count++) 377 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 378 379 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 380 if (rte_intr_callback_unregister(&test_intr_handle, 381 test_interrupt_callback, NULL) < 0) 382 return -1; 383 384 if (flag == 0) { 385 printf("callback has not been called\n"); 386 return -1; 387 } else if (flag < 0) { 388 printf("it has internal error in callback\n"); 389 return -1; 390 } 391 392 return 0; 393 } 394 395 /** 396 * Main function of testing interrupt. 397 */ 398 static int 399 test_interrupt(void) 400 { 401 int ret = -1; 402 struct rte_intr_handle test_intr_handle; 403 404 if (test_interrupt_init() < 0) { 405 printf("fail to initialize for testing interrupt\n"); 406 return -1; 407 } 408 409 printf("Check unknown valid interrupt full path\n"); 410 if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID) < 0) { 411 printf("failure occured during checking unknown valid " 412 "interrupt full path\n"); 413 goto out; 414 } 415 416 printf("Check valid UIO interrupt full path\n"); 417 if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_UIO) 418 < 0) { 419 printf("failure occured during checking valid UIO interrupt " 420 "full path\n"); 421 goto out; 422 } 423 424 printf("Check valid alarm interrupt full path\n"); 425 if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_ALARM) 426 < 0) { 427 printf("failure occured during checking valid alarm " 428 "interrupt full path\n"); 429 goto out; 430 } 431 432 printf("start register/unregister test\n"); 433 /* check if it will fail to register cb with intr_handle = NULL */ 434 if (rte_intr_callback_register(NULL, test_interrupt_callback, 435 NULL) == 0) { 436 printf("unexpectedly register successfully with null " 437 "intr_handle\n"); 438 goto out; 439 } 440 441 /* check if it will fail to register cb with invalid intr_handle */ 442 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 443 if (rte_intr_callback_register(&test_intr_handle, 444 test_interrupt_callback, NULL) == 0) { 445 printf("unexpectedly register successfully with invalid " 446 "intr_handle\n"); 447 goto out; 448 } 449 450 /* check if it will fail to register without callback */ 451 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 452 if (rte_intr_callback_register(&test_intr_handle, NULL, NULL) == 0) { 453 printf("unexpectedly register successfully with " 454 "null callback\n"); 455 goto out; 456 } 457 458 /* check if it will fail to unregister cb with intr_handle = NULL */ 459 if (rte_intr_callback_unregister(NULL, 460 test_interrupt_callback, NULL) > 0) { 461 printf("unexpectedly unregister successfully with " 462 "null intr_handle\n"); 463 goto out; 464 } 465 466 /* check if it will fail to unregister cb with invalid intr_handle */ 467 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 468 if (rte_intr_callback_unregister(&test_intr_handle, 469 test_interrupt_callback, NULL) > 0) { 470 printf("unexpectedly unregister successfully with " 471 "invalid intr_handle\n"); 472 goto out; 473 } 474 475 /* check if it is ok to register the same intr_handle twice */ 476 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 477 if (rte_intr_callback_register(&test_intr_handle, 478 test_interrupt_callback, NULL) < 0) { 479 printf("it fails to register test_interrupt_callback\n"); 480 goto out; 481 } 482 if (rte_intr_callback_register(&test_intr_handle, 483 test_interrupt_callback_1, NULL) < 0) { 484 printf("it fails to register test_interrupt_callback_1\n"); 485 goto out; 486 } 487 /* check if it will fail to unregister with invalid parameter */ 488 if (rte_intr_callback_unregister(&test_intr_handle, 489 test_interrupt_callback, (void *)0xff) != 0) { 490 printf("unexpectedly unregisters successfully with " 491 "invalid arg\n"); 492 goto out; 493 } 494 if (rte_intr_callback_unregister(&test_intr_handle, 495 test_interrupt_callback, NULL) <= 0) { 496 printf("it fails to unregister test_interrupt_callback\n"); 497 goto out; 498 } 499 if (rte_intr_callback_unregister(&test_intr_handle, 500 test_interrupt_callback_1, (void *)-1) <= 0) { 501 printf("it fails to unregister test_interrupt_callback_1 " 502 "for all\n"); 503 goto out; 504 } 505 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 506 507 printf("start interrupt enable/disable test\n"); 508 /* check interrupt enable/disable functions */ 509 if (test_interrupt_enable() < 0) { 510 printf("fail to check interrupt enabling\n"); 511 goto out; 512 } 513 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 514 515 if (test_interrupt_disable() < 0) { 516 printf("fail to check interrupt disabling\n"); 517 goto out; 518 } 519 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 520 521 ret = 0; 522 523 out: 524 printf("Clearing for interrupt tests\n"); 525 /* clear registered callbacks */ 526 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 527 rte_intr_callback_unregister(&test_intr_handle, 528 test_interrupt_callback, (void *)-1); 529 rte_intr_callback_unregister(&test_intr_handle, 530 test_interrupt_callback_1, (void *)-1); 531 532 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; 533 rte_intr_callback_unregister(&test_intr_handle, 534 test_interrupt_callback, (void *)-1); 535 rte_intr_callback_unregister(&test_intr_handle, 536 test_interrupt_callback_1, (void *)-1); 537 538 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; 539 rte_intr_callback_unregister(&test_intr_handle, 540 test_interrupt_callback, (void *)-1); 541 rte_intr_callback_unregister(&test_intr_handle, 542 test_interrupt_callback_1, (void *)-1); 543 544 rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL); 545 /* deinit */ 546 test_interrupt_deinit(); 547 548 return ret; 549 } 550 551 REGISTER_TEST_COMMAND(interrupt_autotest, test_interrupt); 552