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