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 if (rte_intr_callback_unregister(&test_intr_handle, 374 test_interrupt_callback, &test_intr_handle) < 0) 375 return -1; 376 377 if (flag == 0) { 378 printf("callback has not been called\n"); 379 return -1; 380 } else if (flag < 0) { 381 printf("it has internal error in callback\n"); 382 return -1; 383 } 384 385 return 0; 386 } 387 388 /** 389 * Main function of testing interrupt. 390 */ 391 static int 392 test_interrupt(void) 393 { 394 int ret = -1; 395 struct rte_intr_handle test_intr_handle; 396 397 if (test_interrupt_init() < 0) { 398 printf("fail to initialize for testing interrupt\n"); 399 return -1; 400 } 401 402 printf("Check unknown valid interrupt full path\n"); 403 if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID) < 0) { 404 printf("failure occurred during checking unknown valid " 405 "interrupt full path\n"); 406 goto out; 407 } 408 409 printf("Check valid UIO interrupt full path\n"); 410 if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_UIO) 411 < 0) { 412 printf("failure occurred during checking valid UIO interrupt " 413 "full path\n"); 414 goto out; 415 } 416 417 printf("Check valid device event interrupt full path\n"); 418 if (test_interrupt_full_path_check( 419 TEST_INTERRUPT_HANDLE_VALID_DEV_EVENT) < 0) { 420 printf("failure occurred during checking valid device event " 421 "interrupt full path\n"); 422 goto out; 423 } 424 425 printf("Check valid alarm interrupt full path\n"); 426 if (test_interrupt_full_path_check( 427 TEST_INTERRUPT_HANDLE_VALID_ALARM) < 0) { 428 printf("failure occurred during checking valid alarm " 429 "interrupt full path\n"); 430 goto out; 431 } 432 433 printf("start register/unregister test\n"); 434 /* check if it will fail to register cb with intr_handle = NULL */ 435 if (rte_intr_callback_register(NULL, test_interrupt_callback, 436 NULL) == 0) { 437 printf("unexpectedly register successfully with null " 438 "intr_handle\n"); 439 goto out; 440 } 441 442 /* check if it will fail to register cb with invalid intr_handle */ 443 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 444 if (rte_intr_callback_register(&test_intr_handle, 445 test_interrupt_callback, &test_intr_handle) == 0) { 446 printf("unexpectedly register successfully with invalid " 447 "intr_handle\n"); 448 goto out; 449 } 450 451 /* check if it will fail to register without callback */ 452 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 453 if (rte_intr_callback_register(&test_intr_handle, NULL, &test_intr_handle) == 0) { 454 printf("unexpectedly register successfully with " 455 "null callback\n"); 456 goto out; 457 } 458 459 /* check if it will fail to unregister cb with intr_handle = NULL */ 460 if (rte_intr_callback_unregister(NULL, 461 test_interrupt_callback, NULL) > 0) { 462 printf("unexpectedly unregister successfully with " 463 "null intr_handle\n"); 464 goto out; 465 } 466 467 /* check if it will fail to unregister cb with invalid intr_handle */ 468 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; 469 if (rte_intr_callback_unregister(&test_intr_handle, 470 test_interrupt_callback, &test_intr_handle) > 0) { 471 printf("unexpectedly unregister successfully with " 472 "invalid intr_handle\n"); 473 goto out; 474 } 475 476 /* check if it is ok to register the same intr_handle twice */ 477 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 478 if (rte_intr_callback_register(&test_intr_handle, 479 test_interrupt_callback, &test_intr_handle) < 0) { 480 printf("it fails to register test_interrupt_callback\n"); 481 goto out; 482 } 483 if (rte_intr_callback_register(&test_intr_handle, 484 test_interrupt_callback_1, &test_intr_handle) < 0) { 485 printf("it fails to register test_interrupt_callback_1\n"); 486 goto out; 487 } 488 /* check if it will fail to unregister with invalid parameter */ 489 if (rte_intr_callback_unregister(&test_intr_handle, 490 test_interrupt_callback, (void *)0xff) != 0) { 491 printf("unexpectedly unregisters successfully with " 492 "invalid arg\n"); 493 goto out; 494 } 495 if (rte_intr_callback_unregister(&test_intr_handle, 496 test_interrupt_callback, &test_intr_handle) <= 0) { 497 printf("it fails to unregister test_interrupt_callback\n"); 498 goto out; 499 } 500 if (rte_intr_callback_unregister(&test_intr_handle, 501 test_interrupt_callback_1, (void *)-1) <= 0) { 502 printf("it fails to unregister test_interrupt_callback_1 " 503 "for all\n"); 504 goto out; 505 } 506 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 507 508 printf("start interrupt enable/disable test\n"); 509 /* check interrupt enable/disable functions */ 510 if (test_interrupt_enable() < 0) { 511 printf("fail to check interrupt enabling\n"); 512 goto out; 513 } 514 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 515 516 if (test_interrupt_disable() < 0) { 517 printf("fail to check interrupt disabling\n"); 518 goto out; 519 } 520 rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); 521 522 ret = 0; 523 524 out: 525 printf("Clearing for interrupt tests\n"); 526 /* clear registered callbacks */ 527 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; 528 rte_intr_callback_unregister(&test_intr_handle, 529 test_interrupt_callback, (void *)-1); 530 rte_intr_callback_unregister(&test_intr_handle, 531 test_interrupt_callback_1, (void *)-1); 532 533 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; 534 rte_intr_callback_unregister(&test_intr_handle, 535 test_interrupt_callback, (void *)-1); 536 rte_intr_callback_unregister(&test_intr_handle, 537 test_interrupt_callback_1, (void *)-1); 538 539 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; 540 rte_intr_callback_unregister(&test_intr_handle, 541 test_interrupt_callback, (void *)-1); 542 rte_intr_callback_unregister(&test_intr_handle, 543 test_interrupt_callback_1, (void *)-1); 544 545 test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_DEV_EVENT]; 546 rte_intr_callback_unregister(&test_intr_handle, 547 test_interrupt_callback, (void *)-1); 548 rte_intr_callback_unregister(&test_intr_handle, 549 test_interrupt_callback_1, (void *)-1); 550 551 rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL); 552 /* deinit */ 553 test_interrupt_deinit(); 554 555 return ret; 556 } 557 558 REGISTER_TEST_COMMAND(interrupt_autotest, test_interrupt); 559