openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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