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