control.c (26327B)
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 * BCM Dispatch Control Operations (eg: attach, detach) 8 */ 9 10 #include <shared/alloc.h> 11 #include <sal/core/libc.h> 12 #include <sal/core/sync.h> 13 #include <bcm/debug.h> 14 15 #include <soc/drv.h> 16 #if defined(BCM_PETRA_SUPPORT) 17 #include <soc/dpp/drv.h> 18 #endif 19 #if defined(BCM_DFE_SUPPORT) 20 #include <soc/dfe/cmn/dfe_drv.h> 21 #endif 22 #if defined(BCM_DNXF_SUPPORT) 23 #include <soc/dnxf/cmn/dnxf_drv.h> 24 #endif 25 26 #include <bcm/error.h> 27 28 #include <bcm_int/dispatch.h> 29 #include <bcm_int/control.h> 30 #include <bcm_int/api_ref.h> 31 #include <bcm_int/api_xlate_port.h> 32 33 34 bcm_control_t *bcm_control[BCM_CONTROL_MAX] = {0}; 35 static uint32 bcm_control_available[BCM_CONTROL_MAX] = {0}; 36 37 /* Attach/detach callback */ 38 typedef struct bcm_control_cb_data_s { 39 bcm_attach_cb_t cb; 40 void *user_data; 41 } bcm_control_cb_data_t; 42 43 static bcm_control_cb_data_t bcm_control_cb[BCM_CONTROL_MAX]; 44 45 /* Detach retry information */ 46 static int bcm_control_detach_retry_set[BCM_CONTROL_MAX]; 47 static bcm_detach_retry_t bcm_control_detach_retry[BCM_CONTROL_MAX]; 48 49 /* Default detach retry 5 minutes, unless overridden by flags */ 50 #ifdef BCM_DETACH_POLL_INTERVAL_USECS_DEFAULT 51 #define _DETACH_POLL_INTERVAL_USECS BCM_DETACH_POLL_INTERVAL_USECS_DEFAULT 52 #else 53 #define _DETACH_POLL_INTERVAL_USECS 100000 /* 100 msecs */ 54 #endif 55 #ifdef BCM_DETACH_NUM_RETRIES_DEFAULT 56 #define _DETACH_NUM_RETRIES BCM_DETACH_NUM_RETRIES_DEFAULT 57 #else 58 #define _DETACH_NUM_RETRIES 3000 59 #endif 60 static bcm_detach_retry_t bcm_control_detach_retry_default = { 61 _DETACH_POLL_INTERVAL_USECS, /* Poll interval */ 62 _DETACH_NUM_RETRIES /* Number retries */ 63 }; 64 65 static sal_mutex_t _bcm_control_lock[BCM_CONTROL_MAX]; 66 67 #define CONTROL_LOCK(unit) \ 68 sal_mutex_take(_bcm_control_lock[unit], sal_mutex_FOREVER) 69 #define CONTROL_UNLOCK(unit) \ 70 sal_mutex_give(_bcm_control_lock[unit]) 71 72 #ifdef BCM_CONTROL_API_TRACKING 73 /* true if unit valid */ 74 uint32 bcm_control_unit_valid[BCM_CONTROL_MAX] = {0}; 75 76 /* API reference count */ 77 static uint32 bcm_control_unit_busy[BCM_CONTROL_MAX] = {0}; 78 79 /* lock for bcm_control_unit_valid/busy */ 80 static sal_mutex_t _bcm_busy_lock[BCM_CONTROL_MAX]; 81 82 #define BUSY_LOCK(unit) \ 83 sal_mutex_take(_bcm_busy_lock[unit], sal_mutex_FOREVER) 84 #define BUSY_UNLOCK(unit) \ 85 sal_mutex_give(_bcm_busy_lock[unit]) 86 87 #endif /* BCM_CONTROL_API_TRACKING */ 88 89 90 #define BCM_DEVICE_CONTROL_DESTROY(_unit_) \ 91 if (BCM_CONTROL(_unit_)->subtype != NULL) { \ 92 sal_free(BCM_CONTROL(_unit_)->subtype); \ 93 } \ 94 sal_free(BCM_CONTROL(_unit_)); \ 95 BCM_CONTROL(_unit_) = NULL; 96 97 /* 98 * BCM Dispatch Type name table 99 */ 100 #define BCM_DLIST_ENTRY(_dtype)\ 101 #_dtype, 102 103 static const char* _bcm_dtype_names[] = { 104 #include <bcm_int/bcm_dlist.h> 105 NULL, 106 }; 107 108 /* 109 * Name to dispatch type 110 */ 111 static bcm_dtype_t 112 _bcm_type_find(const char* name) 113 { 114 int i; 115 for(i = 0; i < bcmTypeCount; i++) { 116 if(!sal_strcmp(_bcm_dtype_names[i], name)) { 117 return i; 118 } 119 } 120 return bcmTypeNone; 121 } 122 123 124 /* 125 * The following are functions need to be dispatchable by type 126 * within this module only. 127 */ 128 129 /* _attach */ 130 #define BCM_DLIST_ENTRY(_dtype)\ 131 extern int _bcm_##_dtype##_attach(int, char*); 132 #include <bcm_int/bcm_dlist.h> 133 134 #define BCM_DLIST_ENTRY(_dtype)\ 135 _bcm_##_dtype##_attach, 136 137 static int (*_dispatch_attach[])(int, char*) = { 138 #include <bcm_int/bcm_dlist.h> 139 }; 140 141 /* _init */ 142 #define BCM_DLIST_ENTRY(_dtype)\ 143 extern int bcm_##_dtype##_init(int); 144 #include <bcm_int/bcm_dlist.h> 145 146 #define BCM_DLIST_ENTRY(_dtype)\ 147 bcm_##_dtype##_init, 148 149 static int (*_dispatch_init[])(int) = { 150 #include <bcm_int/bcm_dlist.h> 151 }; 152 153 /* _detach */ 154 #define BCM_DLIST_ENTRY(_dtype)\ 155 extern int _bcm_##_dtype##_detach(int); 156 #include <bcm_int/bcm_dlist.h> 157 158 #define BCM_DLIST_ENTRY(_dtype)\ 159 _bcm_##_dtype##_detach, 160 161 static int (*_dispatch_detach[])(int) = { 162 #include <bcm_int/bcm_dlist.h> 163 }; 164 165 /* run attach/detach callback for unit (or all units if unit is -1 */ 166 STATIC int 167 bcm_attach_run(int unit, bcm_device_state_t state, bcm_attach_info_t *data) 168 { 169 int rv = BCM_E_NONE; 170 bcm_control_cb_data_t *cb_data = &bcm_control_cb[unit]; 171 172 if (cb_data->cb != NULL) { 173 rv = cb_data->cb(unit, state, data, cb_data->user_data); 174 } 175 176 return rv; 177 } 178 /* 179 * Function: 180 * _bcm_attach 181 * Purpose: 182 * Creates control structure, related locks and calls the corresponding 183 * dispatch function. 184 * 185 * Parameters: 186 * unit - BCM device number or -1. 187 * type - Type of BCM API dispatch driver 188 * subtype - Argument to dispatch driver 189 * remunit - underlying remote unit 190 * early_attach - Set, if doing an attach_early_txrx 191 * Returns: 192 * BCM_E_XXX 193 */ 194 STATIC int 195 _bcm_attach(int unit, char *type, char *subtype, int remunit, int early_attach) 196 197 { 198 int rv; 199 bcm_attach_info_t data; 200 int len_subtype = 0; 201 202 LOG_INFO(BSL_LS_BCM_ATTACH, 203 (BSL_META_U(unit, 204 "STK %d: attach %s subtype %s as %d\n"), 205 unit, (NULL !=type) ? type: "N/A", 206 (NULL != subtype) ? subtype:"N/A", 207 remunit)); 208 209 /* Control lock initialization. */ 210 SAL_GLOBAL_LOCK; 211 if (unit < 0) { /* find a free unit */ 212 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 213 if (bcm_control_available[unit] == FALSE) { 214 break; 215 } 216 } 217 if (unit >= BCM_CONTROL_MAX) { 218 SAL_GLOBAL_UNLOCK; 219 return (BCM_E_FULL); 220 } 221 } 222 223 if (_bcm_control_lock[unit] == NULL) { 224 _bcm_control_lock[unit] = sal_mutex_create("bcm_control"); 225 } 226 227 if (_bcm_control_lock[unit] == NULL) { 228 SAL_GLOBAL_UNLOCK; 229 return (BCM_E_MEMORY); 230 } 231 232 bcm_control_available[unit] = TRUE; 233 SAL_GLOBAL_UNLOCK; 234 235 236 CONTROL_LOCK(unit); 237 /* 238 * Device attach can be done in two phases. 239 * 240 * bcm_attach_early_txrx() can be called to attach just TX and RX 241 * modules so the application can continue CPU TX/RX while complete 242 * BCM initialization is in progress too. 243 * 244 * bcm_attach() should follow any early attach operations so the SDK 245 * will be fully initialized and functional for further API calls. 246 * 247 * The regular attach sequence can be performed with bcm_attach(). This 248 * will initialize all the modules before returning. 249 * 250 * Similarly for detach also, bcm_detach_late_txrx() can be called to 251 * deinit all the modules except TX and RX so the application can 252 * continue packet TX/RX even during other modules are initialized. 253 */ 254 255 256 257 /* Check if unit is already attached. */ 258 if (BCM_CONTROL(unit) != NULL) { 259 /* Control structure is already intied when attach_early_txrx is called */ 260 if(!(BCM_CONTROL(unit)->attach_state == _bcmControlStateTxRxInited)) { 261 CONTROL_UNLOCK(unit); 262 return (BCM_E_EXISTS); 263 } 264 265 } 266 267 #ifdef BCM_CONTROL_API_TRACKING 268 { 269 int old_busy; 270 271 /* Create BUSY lock */ 272 if (_bcm_busy_lock[unit] == NULL) { 273 _bcm_busy_lock[unit] = sal_mutex_create("bcm_busy"); 274 } 275 if (_bcm_busy_lock[unit] == NULL) { 276 CONTROL_UNLOCK(unit); 277 return (BCM_E_MEMORY); 278 } 279 280 /* clear busy flag */ 281 BUSY_LOCK(unit); 282 old_busy = bcm_control_unit_busy[unit]; 283 bcm_control_unit_busy[unit] = 0; 284 BUSY_UNLOCK(unit); 285 if (old_busy != 0) { 286 287 LOG_ERROR(BSL_LS_BCM_ATTACH, 288 (BSL_META_U(unit, 289 "Unit %d busy at attach()\n"), 290 unit)); 291 292 } 293 } 294 #endif 295 296 data.unit = unit; 297 data.type = type; 298 data.subtype = subtype; 299 data.remunit = remunit; 300 301 if (!early_attach) { 302 rv = bcm_attach_run(unit, bcmDeviceStateAttach, &data); 303 if (BCM_FAILURE(rv)) { 304 CONTROL_UNLOCK(unit); 305 return (rv); 306 } 307 } 308 309 if (BCM_CONTROL(unit) == NULL) { 310 /* Allocate unit control structure. */ 311 BCM_CONTROL(unit) = sal_alloc(sizeof(bcm_control_t), "bcm_control"); 312 if (BCM_CONTROL(unit) == NULL) { 313 CONTROL_UNLOCK(unit); 314 return (BCM_E_MEMORY); 315 } 316 sal_memset(BCM_CONTROL(unit), 0, sizeof(bcm_control_t)); 317 } 318 if (subtype != NULL) { 319 len_subtype = sal_strlen(subtype); 320 BCM_CONTROL(unit)->subtype = sal_alloc(len_subtype+1, 321 "bcm_control subtype"); 322 if (BCM_CONTROL(unit)->subtype == NULL) { 323 BCM_DEVICE_CONTROL_DESTROY(unit); 324 CONTROL_UNLOCK(unit); 325 return (BCM_E_MEMORY); 326 } 327 sal_strncpy(BCM_CONTROL(unit)->subtype, subtype, len_subtype); 328 if (len_subtype) 329 BCM_CONTROL(unit)->subtype[len_subtype] = '\0'; 330 } 331 332 /* 333 * Assign dtype based on type string. The string was used for the dispatch table search, 334 * so we leave this alone for backwards compatibility with the rest of the code that calls bcm_attach(). 335 */ 336 if((BCM_CONTROL(unit)->dtype = _bcm_type_find(type)) == bcmTypeNone) { 337 BCM_DEVICE_CONTROL_DESTROY(unit); 338 CONTROL_UNLOCK(unit); 339 return (BCM_E_CONFIG); 340 } 341 342 BCM_CONTROL(unit)->unit = remunit; 343 BCM_CONTROL(unit)->name = type; 344 345 if (early_attach) { 346 BCM_CONTROL(unit)->attach_state = _bcmControlStateTxRxInit; 347 } 348 rv = _dispatch_attach[BCM_DTYPE(unit)](unit, subtype); 349 if (early_attach && BCM_SUCCESS(rv)) { 350 BCM_CONTROL(unit)->attach_state = _bcmControlStateTxRxInited; 351 } 352 353 if (BCM_FAILURE(rv)) { 354 BCM_DEVICE_CONTROL_DESTROY(unit); 355 CONTROL_UNLOCK(unit); 356 return (rv); 357 } 358 #ifdef BCM_CONTROL_API_TRACKING 359 BUSY_LOCK(unit); 360 bcm_control_unit_valid[unit] = TRUE; 361 BUSY_UNLOCK(unit); 362 #endif 363 364 CONTROL_UNLOCK(unit); 365 return (unit); 366 } 367 /* 368 * Function: 369 * bcm_attach_early_txrx 370 * Purpose: 371 * Create a BCM unit instance and initialise tx and rx modules only. 372 * Can be used only during warmboot to reduce tx and rx inactivity time, 373 * for strataXGS devices. 374 * 375 * Parameters: 376 * unit - BCM device number or -1. 377 * type - Type of BCM API dispatch driver 378 * subtype - Argument to dispatch driver 379 * remunit - underlying remote unit 380 * Returns: 381 * BCM_E_XXX 382 */ 383 int 384 bcm_attach_early_txrx(int unit, char *type, char *subtype, int remunit) 385 { 386 #ifdef BCM_ESW_SUPPORT 387 if ((type == NULL) && (SOC_IS_ESW(unit))) { 388 type = "esw"; 389 } else if (sal_strncmp(type, "esw", strlen(type))) { 390 return BCM_E_UNAVAIL; 391 } 392 return _bcm_attach(unit, type, subtype, remunit, 1); 393 #endif /* BCM_ESW_SUPPORT */ 394 395 return BCM_E_UNAVAIL; 396 } 397 /* 398 * Function: 399 * bcm_attach 400 * Purpose: 401 * Create a BCM unit instance. 402 * Parameters: 403 * unit - BCM device number or -1. 404 * type - Type of BCM API dispatch driver 405 * subtype - Argument to dispatch driver 406 * remunit - underlying remote unit 407 * Returns: 408 * BCM_E_XXX 409 */ 410 int 411 bcm_attach(int unit, char *type, char *subtype, int remunit) 412 { 413 if ((NULL == type) && (-1 == unit)) { 414 #ifdef BCM_ESW_SUPPORT 415 type = "esw"; 416 #else 417 return (BCM_E_CONFIG); 418 #endif 419 } 420 421 if (type == NULL) { 422 if (SOC_IS_TOMAHAWK3(unit)) { 423 #ifdef BCM_TOMAHAWK3_SUPPORT 424 type = "tomahawk3"; 425 #endif 426 } 427 428 #ifdef BCM_SHADOW_SUPPORT 429 else if (SOC_IS_SHADOW(unit)) { 430 type = "shadow"; 431 } 432 #endif 433 434 #ifdef BCM_PETRA_SUPPORT 435 else if (SOC_IS_ARAD(unit)) { 436 type = "petra"; 437 } 438 #endif 439 440 #ifdef BCM_DNX_SUPPORT 441 else if (SOC_IS_DNX(unit)) { 442 type = "dnx"; 443 } 444 #endif 445 446 #ifdef BCM_DFE_SUPPORT 447 else if (SOC_IS_DFE(unit)) { 448 type = "dfe"; 449 } 450 #endif 451 452 #ifdef BCM_DNXF_SUPPORT 453 else if (SOC_IS_DNXF(unit)) { 454 type = "dnxf"; 455 } 456 #endif 457 458 #ifdef BCM_ESW_SUPPORT 459 else { 460 type = "esw"; 461 } 462 #endif 463 } 464 465 if (NULL == type) { 466 BCM_DEVICE_CONTROL_DESTROY(unit); 467 CONTROL_UNLOCK(unit); 468 return (BCM_E_CONFIG); 469 } 470 471 return _bcm_attach(unit, type, subtype, remunit, 0); 472 } 473 474 #ifdef BCM_CONTROL_API_TRACKING 475 /* Wait for BCM units to become idle */ 476 STATIC int 477 _bcm_detach_wait(int unit) 478 { 479 int rv; 480 int i; 481 int busy; 482 bcm_detach_retry_t retry; 483 484 rv = bcm_detach_retry_get(unit, &retry); 485 486 if (BCM_SUCCESS(rv)) { 487 for (i = retry.num_retries; i > 0; i--) { 488 BUSY_LOCK(unit); 489 busy = bcm_control_unit_busy[unit]; 490 BUSY_UNLOCK(unit); 491 if (busy != 0) { 492 sal_usleep(retry.poll_usecs); 493 } else { 494 break; 495 } 496 } 497 sal_usleep(retry.poll_usecs); 498 rv = (i == 0) ? BCM_E_TIMEOUT : BCM_E_NONE; 499 } 500 501 return rv; 502 } 503 #endif 504 int 505 bcm_detach_late_txrx(int unit) { 506 int rv = 0; 507 if (!SOC_IS_ESW(unit)) { 508 rv = BCM_E_UNAVAIL; 509 return rv; 510 } 511 #ifdef BCM_ESW_SUPPORT 512 BCM_CONTROL(unit)->attach_state = _bcmControlStateDeinitLateTxRx; 513 rv = _dispatch_detach[BCM_DTYPE(unit)](unit); 514 if (BCM_SUCCESS(rv)) { 515 BCM_CONTROL(unit)->attach_state = _bcmControlStateDeinitAll; 516 } 517 #endif 518 return rv; 519 } 520 521 int 522 bcm_detach(int unit) 523 { 524 int rv = BCM_E_NONE; 525 bcm_attach_info_t data; 526 527 LOG_INFO(BSL_LS_BCM_ATTACH, 528 (BSL_META_U(unit, 529 "STK %d: unit being detached\n"), 530 unit)); 531 532 BCM_IF_ERROR_RETURN(bcm_attach_check(unit)); 533 534 CONTROL_LOCK(unit); 535 536 #ifdef BCM_CONTROL_API_TRACKING 537 /* any new calls on other threads will return BCM_E_UNIT */ 538 BUSY_LOCK(unit); 539 bcm_control_unit_valid[unit] = FALSE; 540 BUSY_UNLOCK(unit); 541 542 /* wait for other threads to complete BCM calls */ 543 rv = _bcm_detach_wait(unit); 544 if (BCM_FAILURE(rv)) { 545 CONTROL_UNLOCK(unit); 546 547 return rv; 548 } 549 #endif 550 rv = _dispatch_detach[BCM_DTYPE(unit)](unit); 551 552 /* Clean up port mappings */ 553 _bcm_api_xlate_port_cleanup(unit); 554 555 data.unit = unit; 556 data.type = BCM_CONTROL(unit)->name; 557 data.subtype = BCM_CONTROL(unit)->subtype; 558 data.remunit = BCM_CONTROL(unit)->unit; 559 560 if (BCM_SUCCESS(rv)) { 561 rv = bcm_attach_run(unit, bcmDeviceStateDetach, &data); 562 } 563 564 BCM_DEVICE_CONTROL_DESTROY(unit); 565 566 CONTROL_UNLOCK(unit); 567 #ifdef BCM_CONTROL_API_TRACKING 568 sal_mutex_destroy(_bcm_busy_lock[unit]); 569 _bcm_busy_lock[unit] = NULL; 570 #endif 571 sal_mutex_destroy(_bcm_control_lock[unit]); 572 _bcm_control_lock[unit] = NULL; 573 574 SAL_GLOBAL_LOCK; 575 bcm_control_available[unit] = FALSE; 576 SAL_GLOBAL_UNLOCK; 577 578 return rv; 579 } 580 581 /* _match */ 582 #define BCM_DLIST_ENTRY(_dtype)\ 583 extern int _bcm_##_dtype##_match(int, char *, char *); 584 #include <bcm_int/bcm_dlist.h> 585 586 #define BCM_DLIST_ENTRY(_dtype)\ 587 _bcm_##_dtype##_match, 588 589 static int (*_dispatch_match[])(int, char *, char *) = { 590 #include <bcm_int/bcm_dlist.h> 591 }; 592 593 int 594 bcm_find(char *type, char *subtype, int remunit) 595 { 596 int unit; 597 598 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 599 if (BCM_CONTROL(unit) == NULL) { 600 continue; 601 } 602 if (remunit != BCM_CONTROL(unit)->unit) { 603 continue; 604 } 605 if (type != NULL && 606 sal_strcmp(type, BCM_TYPE_NAME(unit)) != 0) { 607 continue; 608 } 609 if (subtype == NULL && BCM_CONTROL(unit)->subtype != NULL) { 610 continue; 611 } 612 if (subtype != NULL && BCM_CONTROL(unit)->subtype == NULL) { 613 continue; 614 } 615 if (subtype != NULL && 616 _dispatch_match[BCM_DTYPE(unit)] 617 (unit, subtype, BCM_CONTROL(unit)->subtype) != 0) { 618 continue; 619 } 620 return unit; 621 } 622 return BCM_E_NOT_FOUND; 623 } 624 625 int 626 bcm_attach_check(int unit) 627 { 628 if (!BCM_CONTROL_UNIT_LEGAL(unit)) { 629 return BCM_E_UNIT; 630 } 631 if (BCM_CONTROL(unit) == NULL) { 632 return BCM_E_UNIT; 633 } 634 return BCM_E_NONE; 635 } 636 637 int 638 bcm_attach_max(int *max_units) 639 { 640 int unit; 641 642 *max_units = -1; 643 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 644 if (BCM_CONTROL(unit) != NULL) { 645 *max_units = unit; 646 } 647 } 648 return BCM_E_NONE; 649 } 650 651 int 652 bcm_init(int unit) 653 { 654 int rv = BCM_E_NONE; 655 void *api_ptr = (void *)bcm_api_tbl; 656 int init_done = FALSE; 657 658 /* This should never be true; done to include api table */ 659 /* coverity[dead_error_condition] */ 660 /* coverity[dead_error_line] */ 661 if (api_ptr == NULL) { 662 return 0; 663 } 664 665 if (!BCM_CONTROL_UNIT_LEGAL(unit)) { 666 return BCM_E_UNIT; 667 } 668 if (BCM_CONTROL(unit) == NULL) { 669 670 if (!SOC_UNIT_VALID(unit)) { 671 return BCM_E_UNIT; 672 } 673 rv = bcm_attach(unit, NULL, NULL, unit); 674 if (rv < 0) { 675 return rv; 676 } 677 if (SOC_IS_XGS(unit) || 678 SOC_IS_DPP(unit) || 679 SOC_IS_DFE(unit) || 680 SOC_IS_DNXF(unit)) { 681 init_done = TRUE; 682 } 683 } 684 685 if (FALSE == init_done) { 686 /* Initialize port mappings */ 687 _bcm_api_xlate_port_init(unit); 688 689 rv = _dispatch_init[BCM_DTYPE(unit)](unit); 690 } 691 692 #ifdef BCM_CUSTOM_INIT_F 693 if(BCM_SUCCESS(rv)) { 694 extern int BCM_CUSTOM_INIT_F (int unit); 695 rv = BCM_CUSTOM_INIT_F (unit); 696 } 697 #endif /* BCM_CUSTOM_INIT_F */ 698 699 return rv; 700 } 701 702 703 /* 704 * Attach and detach dispatchable routines. 705 */ 706 int 707 _bcm_null_attach(int unit, char *subtype) 708 { 709 COMPILER_REFERENCE(subtype); 710 711 BCM_CONTROL(unit)->capability |= BCM_CAPA_LOCAL; 712 713 return BCM_E_NONE; 714 } 715 716 int 717 _bcm_null_detach(int unit) 718 { 719 return BCM_E_NONE; 720 } 721 722 723 #ifdef BCM_LOOP_SUPPORT 724 725 STATIC int 726 _bcm_loop_match(int unit, char *subtype_a, char *subtype_b) 727 { 728 COMPILER_REFERENCE(unit); 729 return sal_strcmp(subtype_a, subtype_b); 730 } 731 732 int 733 _bcm_loop_attach(int unit, char *subtype) 734 { 735 int dunit; 736 uint32 dcap; 737 738 COMPILER_REFERENCE(subtype); 739 740 dunit = BCM_CONTROL(unit)->unit; 741 742 BCM_CONTROL(unit)->chip_vendor = BCM_CONTROL(dunit)->chip_vendor; 743 BCM_CONTROL(unit)->chip_device = BCM_CONTROL(dunit)->chip_device; 744 BCM_CONTROL(unit)->chip_revision = BCM_CONTROL(dunit)->chip_revision; 745 dcap = BCM_CONTROL(dunit)->capability; 746 dcap &= ~(BCM_CAPA_REMOTE|BCM_CAPA_COMPOSITE); 747 BCM_CONTROL(unit)->capability |= BCM_CAPA_LOCAL | dcap; 748 return BCM_E_NONE; 749 } 750 751 int 752 _bcm_loop_detach(int unit) 753 { 754 return BCM_E_NONE; 755 } 756 #endif /* BCM_LOOP_SUPPORT */ 757 758 int 759 bcm_unit_valid(int unit) 760 { 761 return BCM_UNIT_VALID(unit); 762 } 763 764 int 765 bcm_unit_local(int unit) 766 { 767 return (BCM_UNIT_VALID(unit) && BCM_IS_LOCAL(unit)); 768 } 769 770 int 771 bcm_unit_remote(int unit) 772 { 773 return (BCM_UNIT_VALID(unit) && BCM_IS_REMOTE(unit)); 774 } 775 776 int 777 bcm_unit_max(void) 778 { 779 return BCM_CONTROL_MAX; 780 } 781 782 /* 783 * Get the local reference of a remote device for its controlling 784 * CPU. 785 */ 786 787 int 788 bcm_unit_remote_unit_get(int unit, int *remunit) 789 { 790 if (!BCM_UNIT_VALID(unit)) { 791 return BCM_E_NOT_FOUND; 792 } 793 794 if (remunit == NULL) { 795 return BCM_E_PARAM; 796 } 797 798 *remunit = BCM_CONTROL(unit)->unit; 799 800 return BCM_E_NONE; 801 } 802 803 /* 804 * Get the subtype string that identifies the CPU controlling 805 * the given unit. subtype must point to a preallocated buffer; 806 * maxlen is the maximum number of bytes that will be copied. 807 * 808 * returns the number of bytes copied or < 0 if an error occurs. 809 * 810 * NOTE: This is currently the CPU key (mac address) as a 811 * formatted string like 00:11:22:33:44:55. It should be 812 * converted to a CPU DB key with cpudb_key_parse. 813 */ 814 815 int 816 bcm_unit_subtype_get(int unit, char *subtype, int maxlen) 817 { 818 int minlen; 819 int stlen; 820 821 if (!BCM_UNIT_VALID(unit)) { 822 return BCM_E_NOT_FOUND; 823 } 824 825 if ((subtype == NULL) || (maxlen <= 0)) { 826 return BCM_E_PARAM; 827 } 828 829 if(BCM_CONTROL(unit)->subtype == NULL) { 830 return BCM_E_NOT_FOUND; 831 } 832 833 stlen = sal_strlen(BCM_CONTROL(unit)->subtype) + 1; 834 minlen = maxlen < stlen ? maxlen : stlen; 835 836 sal_memcpy(subtype, BCM_CONTROL(unit)->subtype, minlen); 837 838 return minlen; 839 } 840 841 /* 842 * Function: 843 * bcm_attach_register 844 * Purpose: 845 * Register a callback that will be called before 846 * BCM device attachment and after BCM device detachment. 847 * 848 * When bcm_attach() is called, the registered callback routine is 849 * called before BCM device attachment. When bcm_detach() is called, 850 * the registered callback routine is called after BCM device detachment. 851 * Parameters: 852 * unit - (IN) Unit number. 853 * cb - (IN) Callback function to register. 854 * user_data - (IN) Arbitrary value passed to callback function. 855 * Returns: 856 * BCM_E_XXX 857 * Notes: 858 * Registering for a unit less than zero will register the 859 * callback for all BCM units, otherwise the registration will be 860 * for a specific BCM unit. 861 */ 862 int 863 bcm_attach_register(int unit, bcm_attach_cb_t cb, void *user_data) 864 { 865 int i; 866 int first_index, last_index; 867 868 if (unit >= BCM_CONTROL_MAX) { 869 return BCM_E_UNIT; 870 } 871 872 if (unit < 0) { 873 /* Register for all units */ 874 first_index = 0; 875 last_index = COUNTOF(bcm_control_cb) - 1; 876 } else { 877 first_index = unit; 878 last_index = unit; 879 } 880 881 SAL_GLOBAL_LOCK; 882 for (i = first_index; i <= last_index; i++) { 883 bcm_control_cb[i].cb = cb; 884 bcm_control_cb[i].user_data = user_data; 885 } 886 SAL_GLOBAL_UNLOCK; 887 888 return BCM_E_NONE; 889 } 890 891 /* 892 * Function: 893 * bcm_attach_unregister 894 * Purpose: 895 * Unregister a previously registered attach callback. 896 * Parameters: 897 * unit - (IN) Unit number. 898 * cb - (IN) Callback function to unregister. 899 * user_data - (IN) Arbitrary value passed to callback function. 900 * Returns: 901 * BCM_E_XXX 902 * Notes: 903 * Unregistering for a unit less than zero will unregister the 904 * callback for all BCM units, otherwise the operation will be done 905 * for a specific BCM unit. 906 */ 907 int 908 bcm_attach_unregister(int unit, bcm_attach_cb_t cb, void *user_data) 909 { 910 int i; 911 int first_index, last_index; 912 int found = 0; 913 914 if (unit >= BCM_CONTROL_MAX) { 915 return BCM_E_UNIT; 916 } 917 918 if (unit < 0) { 919 /* Unregister for all units */ 920 first_index = 0; 921 last_index = COUNTOF(bcm_control_cb) - 1; 922 } else { 923 first_index = unit; 924 last_index = unit; 925 } 926 927 SAL_GLOBAL_LOCK; 928 for (i = first_index; i <= last_index; i++) { 929 if ((bcm_control_cb[i].cb == cb) && 930 (bcm_control_cb[i].user_data == user_data)) { 931 bcm_control_cb[i].cb = NULL; 932 bcm_control_cb[i].user_data = NULL; 933 found = 1; 934 } 935 } 936 SAL_GLOBAL_UNLOCK; 937 938 if (!found) { 939 return BCM_E_NOT_FOUND; 940 } 941 942 return BCM_E_NONE; 943 } 944 945 /* 946 * Function: 947 * bcm_detach_retry_set 948 * Purpose: 949 * Set the poll interval time between retries and the number of retries 950 * before bcm_detach() exits. 951 * 952 * The detach process checks whether there is any thread executing 953 * an API on the unit before it proceeds to unit detachment. 954 * If there is any API currently being executed, it tries 955 * again after waiting for the specified poll interval time. 956 * 957 * The default number of attempts for detach is 1 (num_retries = 1) 958 * Parameters: 959 * unit - (IN) Unit number 960 * retry - (IN) Poll interval and number of retries 961 * Returns: 962 * BCM_E_XXX 963 * Notes: 964 * A unit with a value less than zero will apply to all BCM units. 965 * Otherwise it will apply for a specific BCM unit. 966 * A NULL parameter will set back the default value. 967 */ 968 int 969 bcm_detach_retry_set(int unit, bcm_detach_retry_t *retry) 970 { 971 int i; 972 int first_index, last_index; 973 bcm_detach_retry_t *detach_ptr = &bcm_control_detach_retry_default; 974 975 if (unit >= BCM_CONTROL_MAX) { 976 return BCM_E_UNIT; 977 } 978 979 if (unit < 0) { 980 /* Register for all units */ 981 first_index = 0; 982 last_index = COUNTOF(bcm_control_detach_retry) - 1; 983 } else { 984 first_index = unit; 985 last_index = unit; 986 } 987 988 if (retry != NULL) { 989 detach_ptr = retry; 990 } 991 992 SAL_GLOBAL_LOCK; 993 for (i = first_index; i <= last_index; i++) { 994 bcm_control_detach_retry[i] = *detach_ptr; 995 bcm_control_detach_retry_set[i] = TRUE; 996 } 997 SAL_GLOBAL_UNLOCK; 998 999 return BCM_E_NONE; 1000 1001 } 1002 1003 /* 1004 * Function: 1005 * bcm_detach_retry_get 1006 * Purpose: 1007 * Get the poll interval time between retries and the number of retries 1008 * before bcm_detach() exits. 1009 * Parameters: 1010 * unit - (IN) Unit number 1011 * retry - (OUT) Poll interval and number of retries 1012 * Returns: 1013 * BCM_E_XXX 1014 */ 1015 int 1016 bcm_detach_retry_get(int unit, bcm_detach_retry_t *retry) 1017 { 1018 if ((unit < 0) || (unit >= BCM_CONTROL_MAX)) { 1019 return BCM_E_UNIT; 1020 } 1021 1022 if (retry == NULL) { 1023 return BCM_E_PARAM; 1024 } 1025 1026 SAL_GLOBAL_LOCK; 1027 /* If detach retry information was never set, then use default */ 1028 if (bcm_control_detach_retry_set[unit]) { 1029 *retry = bcm_control_detach_retry[unit]; 1030 } else { 1031 *retry = bcm_control_detach_retry_default; 1032 } 1033 SAL_GLOBAL_UNLOCK; 1034 1035 return BCM_E_NONE; 1036 } 1037 1038 #ifdef BCM_CONTROL_API_TRACKING 1039 /* 1040 * Function: 1041 * bcm_unit_refcount 1042 * Purpose: 1043 * Modify the reference count for a unit, and return a validity flag 1044 * Parameters: 1045 * unit - (IN) Unit number 1046 * delta - (IN) Change in reference count (typically 1 or -1) 1047 * Returns: 1048 * TRUE is the unit is valid; FALSE if not 1049 */ 1050 int 1051 bcm_unit_refcount(int unit, int delta) 1052 { 1053 int flag = FALSE; 1054 1055 if (BCM_CONTROL_UNIT_LEGAL(unit) && _bcm_busy_lock[unit] != NULL) { 1056 BUSY_LOCK(unit); 1057 flag = bcm_control_unit_valid[unit]; 1058 bcm_control_unit_busy[unit] += delta; 1059 BUSY_UNLOCK(unit); 1060 } 1061 1062 return flag; 1063 } 1064 #endif