ipoll.c (14231B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Functions for polling IRQs instead of using hardware interrupts. 8 * Primarily intended for board bringup and debugging. 9 */ 10 11 #include <sal/core/libc.h> 12 #include <sal/core/spl.h> 13 #include <sal/core/sync.h> 14 15 16 #ifdef BCM_DNX_SUPPORT 17 #include <soc/dnx/dnx_err_recovery_manager_utils.h> 18 #endif 19 20 #include <soc/drv.h> 21 #include <soc/ipoll.h> 22 #ifdef BCM_CMICM_SUPPORT 23 #include <soc/cmicm.h> 24 #endif 25 26 #ifndef IPOLL_THREAD_DELAY 27 #define IPOLL_THREAD_DELAY 0 28 #endif 29 30 #ifndef IPOLL_THREAD_PRIO 31 #define IPOLL_THREAD_PRIO 100 32 #endif 33 34 #ifdef SEPARATE_PKTDMA_INTR_HANDLER 35 #ifndef IPOLL_PKTDMA_THREAD_PRIO 36 #define IPOLL_PKTDMA_THREAD_PRIO 99 37 #endif 38 #endif 39 40 41 typedef struct ipoll_ctrl_s { 42 void *data; 43 ipoll_handler_t handler; 44 int paused; 45 } ipoll_ctrl_t; 46 47 static ipoll_ctrl_t _ictrl[SOC_MAX_NUM_DEVICES]; 48 static int _ihandlers; 49 50 #define CMCx_IRQ0_STAT(_dev,_cmc) \ 51 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT0_OFFSET(_cmc)) 52 #define CMCx_IRQ1_STAT(_dev,_cmc) \ 53 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT1_OFFSET(_cmc)) 54 #define CMCx_IRQ2_STAT(_dev,_cmc) \ 55 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT2_OFFSET(_cmc)) 56 #define CMCx_IRQ3_STAT(_dev,_cmc) \ 57 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT3_OFFSET(_cmc)) 58 #define CMCx_IRQ4_STAT(_dev,_cmc) \ 59 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT4_OFFSET(_cmc)) 60 #define CMCx_IRQ5_STAT(_dev,_cmc) \ 61 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT5_OFFSET(_cmc)) 62 #define CMCx_IRQ6_STAT(_dev,_cmc) \ 63 soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT6_OFFSET(_cmc)) 64 /* 65 * Function: 66 * soc_cmic_ipoll_handler 67 * Description: 68 * Main CMIC interrupt handler in polled IRQ mode 69 * Parameters: 70 * dev - device number 71 * Returns: 72 * Nothing 73 */ 74 STATIC void 75 soc_cmic_ipoll_handler(int dev) 76 { 77 if (soc_pci_read(dev, CMIC_IRQ_STAT) & SOC_IRQ_MASK(dev)) { 78 _ictrl[dev].handler(_ictrl[dev].data); 79 } else { 80 if ((soc_feature(dev, soc_feature_extended_cmic_error)) || 81 (soc_feature(dev, soc_feature_short_cmic_error))) { 82 if(soc_pci_read(dev, CMIC_IRQ_STAT_1) & SOC_IRQ1_MASK(dev) || 83 soc_pci_read(dev, CMIC_IRQ_STAT_2) & SOC_IRQ2_MASK(dev)) { 84 _ictrl[dev].handler(_ictrl[dev].data); 85 } 86 } 87 } 88 } 89 90 /* 91 * Function: 92 * soc_cmicm_ipoll_handler 93 * Description: 94 * Main CMICm interrupt handler in polled IRQ mode 95 * Parameters: 96 * dev - device number 97 * Returns: 98 * Nothing 99 */ 100 STATIC void 101 soc_cmicm_ipoll_handler(int dev) 102 { 103 #ifdef BCM_CMICM_SUPPORT 104 int cmc; 105 106 cmc = SOC_PCI_CMC(dev); 107 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 108 if ((CMCx_IRQ0_STAT(dev, cmc) & SOC_CMCx_IRQ0_MASK(dev, cmc)) || 109 (CMCx_IRQ1_STAT(dev, cmc) & SOC_CMCx_IRQ1_MASK(dev, cmc)) || 110 (CMCx_IRQ2_STAT(dev, cmc) & SOC_CMCx_IRQ2_MASK(dev, cmc))) { 111 _ictrl[dev].handler(_ictrl[dev].data); 112 } else { 113 if (soc_feature(dev, soc_feature_cmicm_multi_dma_cmc)) { 114 if ((CMCx_IRQ0_STAT(dev, SOC_ARM_CMC(dev, 0)) & 115 SOC_CMCx_IRQ0_MASK(dev, SOC_ARM_CMC(dev, 0))) || 116 (CMCx_IRQ0_STAT(dev, SOC_ARM_CMC(dev, 1)) & 117 SOC_CMCx_IRQ0_MASK(dev, SOC_ARM_CMC(dev, 1)))) { 118 _ictrl[dev].handler(_ictrl[dev].data); 119 } 120 } 121 if (soc_feature(dev, soc_feature_extended_cmic_error) || 122 soc_feature(dev, soc_feature_short_cmic_error)) { 123 if ((CMCx_IRQ3_STAT(dev, cmc) & SOC_CMCx_IRQ3_MASK(dev,cmc)) || 124 (CMCx_IRQ4_STAT(dev, cmc) & SOC_CMCx_IRQ4_MASK(dev,cmc))) { 125 _ictrl[dev].handler(_ictrl[dev].data); 126 } 127 if (soc_feature(dev, soc_feature_cmicm_extended_interrupts)) { 128 if ((CMCx_IRQ5_STAT(dev, cmc) & SOC_CMCx_IRQ5_MASK(dev,cmc)) || 129 (CMCx_IRQ6_STAT(dev, cmc) & SOC_CMCx_IRQ6_MASK(dev,cmc))) { 130 _ictrl[dev].handler(_ictrl[dev].data); 131 } 132 } 133 } 134 if (soc_feature(dev, soc_feature_cmicm_extended_interrupts)) { 135 #ifdef BCM_CMICDV2_SUPPORT 136 if (soc_feature(dev, soc_feature_cmicd_v2)) { 137 if ((CMCx_IRQ3_STAT(dev, cmc) & SOC_CMCx_IRQ3_MASK(dev,cmc)) || 138 (CMCx_IRQ4_STAT(dev, cmc) & SOC_CMCx_IRQ4_MASK(dev,cmc)) || 139 (CMCx_IRQ5_STAT(dev, cmc) & SOC_CMCx_IRQ5_MASK(dev,cmc))) { 140 _ictrl[dev].handler(_ictrl[dev].data); 141 } 142 #ifdef BCM_CMICDV4_SUPPORT 143 if (soc_feature(dev, soc_feature_cmicd_v4)) { 144 if (CMCx_IRQ6_STAT(dev, cmc) & SOC_CMCx_IRQ6_MASK(dev,cmc)) { 145 _ictrl[dev].handler(_ictrl[dev].data); 146 } 147 } 148 #endif /* BCM_CMICDV4_SUPPORT */ 149 } 150 #endif /* BCM_CMICDV2_SUPPORT */ 151 } 152 } 153 #endif 154 #endif 155 } 156 157 158 /* 159 * Function: 160 * soc_cmicx_ipoll_handler 161 * Description: 162 * Main CMICx interrupt handler in polled IRQ mode 163 * Parameters: 164 * dev - device number 165 * Returns: 166 * Nothing 167 */ 168 STATIC void 169 soc_cmicx_ipoll_handler(int dev) 170 { 171 #ifdef BCM_CMICX_SUPPORT 172 /* 173 For cmicx, soc_cmicx_intr will check interrupt stat and mask 174 */ 175 _ictrl[dev].handler(_ictrl[dev].data); 176 #endif 177 } 178 179 /* 180 * Function: 181 * soc_ipoll_thread 182 * Description: 183 * Thread context for interrupt handlers in polled IRQ mode 184 * Parameters: 185 * data - poll delay in usecs (passed as pointer) 186 * Returns: 187 * Nothing 188 */ 189 STATIC void 190 soc_ipoll_thread(void *data) 191 { 192 int dev, spl, udelay; 193 194 udelay = PTR_TO_INT(data); 195 196 #ifdef BCM_DNX_SUPPORT 197 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS(); 198 #endif 199 200 while (_ihandlers) { 201 202 spl = sal_splhi(); 203 204 for (dev = 0; dev < SOC_MAX_NUM_DEVICES; dev++) { 205 if (_ictrl[dev].handler != NULL && !_ictrl[dev].paused) { 206 if (soc_feature(dev, soc_feature_cmicm)) { 207 soc_cmicm_ipoll_handler(dev); 208 } else if (soc_feature(dev, soc_feature_cmicx)){ 209 soc_cmicx_ipoll_handler(dev); 210 } else { 211 soc_cmic_ipoll_handler(dev); 212 } 213 } 214 } 215 216 sal_spl(spl); 217 218 if (udelay) { 219 sal_usleep(udelay); 220 } else { 221 sal_thread_yield(); 222 } 223 } 224 225 #ifdef BCM_DNX_SUPPORT 226 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS(); 227 #endif 228 229 sal_thread_exit(0); 230 } 231 232 /* 233 * Function: 234 * soc_ipoll_connect 235 * Description: 236 * Install interrupt handler in polled IRQ mode 237 * Parameters: 238 * dev - device number 239 * handler - interrupt handler 240 * data - interrupt handler data 241 * Return Value: 242 * BCM_E_NONE 243 * BCM_E_XXX - an error occurred 244 * Notes: 245 * The first handler installed be cause the polling 246 * thread to be created. 247 */ 248 int 249 soc_ipoll_connect(int dev, ipoll_handler_t handler, void *data) 250 { 251 int spl; 252 int udelay, prio; 253 int start_thread = 0; 254 255 if (dev >= SOC_MAX_NUM_DEVICES) { 256 return SOC_E_PARAM; 257 } 258 259 spl = sal_splhi(); 260 261 if (_ictrl[dev].handler == NULL) { 262 if (_ihandlers++ == 0) { 263 /* Create thread if first handler */ 264 start_thread = 1; 265 } 266 } 267 _ictrl[dev].handler = handler; 268 _ictrl[dev].data = data; 269 _ictrl[dev].paused = 0; 270 271 sal_spl(spl); 272 273 if (start_thread) { 274 udelay = soc_property_get(dev, spn_POLLED_IRQ_DELAY, IPOLL_THREAD_DELAY); 275 prio = soc_property_get(dev, spn_POLLED_IRQ_PRIORITY, IPOLL_THREAD_PRIO); 276 #ifdef ADAPTER_SERVER_MODE 277 if (SOC_IS_DNX(dev)) { 278 /* reduce CPU overhead for CModel */ 279 udelay = udelay * 100; 280 } 281 #endif 282 283 sal_thread_create("bcmPOLL", 284 SAL_THREAD_STKSZ, prio, 285 soc_ipoll_thread, INT_TO_PTR(udelay)); 286 } 287 288 return SOC_E_NONE; 289 } 290 291 /* 292 * Function: 293 * soc_ipoll_disconnect 294 * Description: 295 * Uninstall interrupt handler from polled IRQ mode 296 * Parameters: 297 * dev - device number 298 * Return Value: 299 * BCM_E_NONE 300 * BCM_E_XXX - an error occurred 301 * Notes: 302 * When the last handler is uninstalled the polling 303 * thread will terminate. 304 */ 305 int 306 soc_ipoll_disconnect(int dev) 307 { 308 int spl; 309 310 if (dev >= SOC_MAX_NUM_DEVICES) { 311 return SOC_E_PARAM; 312 } 313 314 spl = sal_splhi(); 315 316 if (_ictrl[dev].handler != NULL) { 317 _ictrl[dev].handler = NULL; 318 _ictrl[dev].data = NULL; 319 _ihandlers--; 320 } 321 322 sal_spl(spl); 323 324 return SOC_E_NONE; 325 } 326 327 /* 328 * Function: 329 * soc_ipoll_pause 330 * Description: 331 * Temporarily suspend IRQ polling 332 * Parameters: 333 * dev - device number 334 * Return Value: 335 * BCM_E_NONE 336 * BCM_E_XXX - an error occurred 337 */ 338 int 339 soc_ipoll_pause(int dev) 340 { 341 int spl; 342 343 if (dev >= SOC_MAX_NUM_DEVICES) { 344 return SOC_E_PARAM; 345 } 346 347 spl = sal_splhi(); 348 349 _ictrl[dev].paused++; 350 351 sal_spl(spl); 352 353 return SOC_E_NONE; 354 } 355 356 /* 357 * Function: 358 * soc_ipoll_continue 359 * Description: 360 * Resume suspended IRQ polling 361 * Parameters: 362 * dev - device number 363 * Return Value: 364 * BCM_E_NONE 365 * BCM_E_XXX - an error occurred 366 */ 367 int 368 soc_ipoll_continue(int dev) 369 { 370 int spl; 371 372 if (dev >= SOC_MAX_NUM_DEVICES) { 373 return SOC_E_PARAM; 374 } 375 376 spl = sal_splhi(); 377 378 _ictrl[dev].paused--; 379 380 sal_spl(spl); 381 382 return SOC_E_NONE; 383 } 384 385 #ifdef SEPARATE_PKTDMA_INTR_HANDLER 386 static ipoll_ctrl_t _pktdma_ictrl[SOC_MAX_NUM_DEVICES]; 387 static int _pktdma_ihandlers; 388 /* 389 * Function: 390 * soc_cmicm_pktdma_ipoll_handler 391 * Description: 392 * CMICm Packet DMA dedicated interrupt handler in polled IRQ mode 393 * Parameters: 394 * dev - device number 395 * Returns: 396 * Nothing 397 */ 398 STATIC void 399 soc_cmicm_pktdma_ipoll_handler(int dev) 400 { 401 #ifdef BCM_CMICM_SUPPORT 402 int cmc; 403 404 cmc = SOC_PCI_CMC(dev); 405 #if defined(BCM_SAND_SUPPORT) 406 if ((CMCx_IRQ0_STAT(dev, cmc) & SOC_CMCx_IRQ0_MASK(dev, cmc)) || 407 (CMCx_IRQ1_STAT(dev, cmc) & SOC_CMCx_IRQ1_MASK(dev, cmc)) || 408 (CMCx_IRQ2_STAT(dev, cmc) & SOC_CMCx_IRQ2_MASK(dev, cmc))) { 409 _pktdma_ictrl[dev].handler(_pktdma_ictrl[dev].data); 410 } 411 #endif 412 #endif 413 } 414 415 /* 416 * Function: 417 * soc_cmicx_pktdma_ipoll_handler 418 * Description: 419 * CMICx Packet DMA dedicated interrupt handler in polled IRQ mode 420 * Parameters: 421 * dev - device number 422 * Returns: 423 * Nothing 424 */ 425 STATIC void 426 soc_cmicx_pktdma_ipoll_handler(int dev) 427 { 428 #ifdef BCM_CMICX_SUPPORT 429 _pktdma_ictrl[dev].handler(_pktdma_ictrl[dev].data); 430 #endif 431 } 432 433 /* 434 * Function: 435 * soc_ipoll_pktdma_thread 436 * Description: 437 * Thread context for Packet DMA interrupt handlers in polled IRQ mode 438 * Parameters: 439 * data - poll delay in usecs (passed as pointer) 440 * Returns: 441 * Nothing 442 */ 443 STATIC void 444 soc_ipoll_pktdma_thread(void *data) 445 { 446 int dev, spl, udelay; 447 448 udelay = PTR_TO_INT(data); 449 450 #ifdef BCM_DNX_SUPPORT 451 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS(); 452 #endif 453 454 while (_pktdma_ihandlers) { 455 456 spl = sal_splhi(); 457 458 for (dev = 0; dev < SOC_MAX_NUM_DEVICES; dev++) { 459 if (_pktdma_ictrl[dev].handler != NULL && !_pktdma_ictrl[dev].paused) { 460 if (soc_feature(dev, soc_feature_cmicm)) { 461 soc_cmicm_pktdma_ipoll_handler(dev); 462 } else if (soc_feature(dev, soc_feature_cmicx)){ 463 soc_cmicx_pktdma_ipoll_handler(dev); 464 } 465 } 466 } 467 468 sal_spl(spl); 469 470 if (udelay) { 471 sal_usleep(udelay); 472 } else { 473 sal_thread_yield(); 474 } 475 } 476 477 #ifdef BCM_DNX_SUPPORT 478 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS(); 479 #endif 480 481 sal_thread_exit(0); 482 } 483 484 /* 485 * Function: 486 * soc_ipoll_pktdma_connect 487 * Description: 488 * Install Packet DMA interrupt handler in polled IRQ mode 489 * Parameters: 490 * dev - device number 491 * handler - interrupt handler 492 * data - interrupt handler data 493 * Return Value: 494 * BCM_E_NONE 495 * BCM_E_XXX - an error occurred 496 * Notes: 497 * The first handler installed be cause the polling 498 * thread to be created. 499 */ 500 int 501 soc_ipoll_pktdma_connect(int dev, ipoll_handler_t handler, void *data) 502 { 503 int spl; 504 int udelay, prio; 505 int start_thread = 0; 506 507 if (dev >= SOC_MAX_NUM_DEVICES) { 508 return SOC_E_PARAM; 509 } 510 511 spl = sal_splhi(); 512 513 if (_pktdma_ictrl[dev].handler == NULL) { 514 if (_pktdma_ihandlers++ == 0) { 515 /* Create thread if first handler */ 516 start_thread = 1; 517 } 518 } 519 _pktdma_ictrl[dev].handler = handler; 520 _pktdma_ictrl[dev].data = data; 521 _pktdma_ictrl[dev].paused = 0; 522 523 sal_spl(spl); 524 525 if (start_thread) { 526 udelay = soc_property_suffix_num_get(dev, -1, spn_CUSTOM_FEATURE, "polled_pktdma_irq_delay", IPOLL_THREAD_DELAY); 527 prio = soc_property_suffix_num_get(dev, -1, spn_CUSTOM_FEATURE, "polled_pktdma_irq_priority", IPOLL_PKTDMA_THREAD_PRIO); 528 #ifdef ADAPTER_SERVER_MODE 529 if (SOC_IS_DNX(dev)) { 530 /* reduce CPU overhead for CModel */ 531 udelay = udelay * 100; 532 } 533 #endif 534 535 sal_thread_create("bcmPKTDMAPOLL", 536 SAL_THREAD_STKSZ, prio, 537 soc_ipoll_pktdma_thread, INT_TO_PTR(udelay)); 538 } 539 540 return SOC_E_NONE; 541 } 542 543 /* 544 * Function: 545 * soc_ipoll_pktdma_disconnect 546 * Description: 547 * Uninstall Packt DMA interrupt handler from polled IRQ mode 548 * Parameters: 549 * dev - device number 550 * Return Value: 551 * BCM_E_NONE 552 * BCM_E_XXX - an error occurred 553 * Notes: 554 * When the last handler is uninstalled the polling 555 * thread will terminate. 556 */ 557 int 558 soc_ipoll_pktdma_disconnect(int dev) 559 { 560 int spl; 561 562 if (dev >= SOC_MAX_NUM_DEVICES) { 563 return SOC_E_PARAM; 564 } 565 566 spl = sal_splhi(); 567 568 if (_pktdma_ictrl[dev].handler != NULL) { 569 _pktdma_ictrl[dev].handler = NULL; 570 _pktdma_ictrl[dev].data = NULL; 571 _pktdma_ihandlers--; 572 } 573 574 sal_spl(spl); 575 576 return SOC_E_NONE; 577 } 578 #endif