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

bcmx.c (58209B)


      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  * File:        bcmx.c
      8  * Purpose:     Basic infrastructure code for BCMX
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <shared/alloc.h>
     14 #include <sal/core/libc.h>
     15 
     16 #include <bcmx/lport.h>
     17 #include <bcmx/bcmx.h>
     18 #include <bcmx/rx.h>
     19 #include <bcmx/l2.h>
     20 #include <bcmx/link.h>
     21 
     22 #include <bcm/port.h>
     23 #include <bcm/stack.h>
     24 #include <bcm_int/rpc/rlink.h>
     25 
     26 #include "bcmx_int.h"
     27 #include "api_ref.h"
     28 
     29 
     30 /*
     31  * BCMX Port Information
     32  *
     33  * BCMX Port information will be kept in a 'hash' table
     34  * rather than an array indexed by the 'lport' value.  This allows
     35  * BCMX interfaces to take a 'gport' any place where 'lport' is present.
     36  *
     37  * The GPORT types that are used for BCMX ports are:
     38  *     MODPORT - For devices with module id
     39  *     DEVPORT - For devices with NO module id
     40  */
     41 
     42 /* BCMX Port Information Hash Table */
     43 #define BCMX_PORT_HASH_COUNT          73        /* Prime */
     44 #define BCMX_PORT_HASH_INDEX(_key)    \
     45     (((unsigned int)(_key)) % BCMX_PORT_HASH_COUNT)
     46 
     47 typedef struct _bcmx_port_info_s _bcmx_port_info_t;
     48 
     49 /* List to maintain ports in the order in which ports were added in BCMX */
     50 typedef struct _bcmx_port_list_s {
     51     _bcmx_port_info_t  *prev;
     52     _bcmx_port_info_t  *next;
     53 } _bcmx_port_list_t;
     54 
     55 /* Hash Table Data Structure */
     56 struct _bcmx_port_info_s {
     57     bcmx_lport_t       lport;         /* Logical port number, hash key*/
     58     _bcmx_port_t       port;          /* BCMX port data struct */
     59     _bcmx_port_info_t  *prev;
     60     _bcmx_port_info_t  *next;
     61     _bcmx_port_list_t  list;          /* Use for ordered port list */
     62 };
     63 
     64 /* Port Information Hash Table */
     65 static _bcmx_port_info_t  *_bcmx_port_info[BCMX_PORT_HASH_COUNT];
     66 
     67 /* Port List */
     68 static _bcmx_port_info_t *_bcmx_port_list_first = NULL;
     69 static _bcmx_port_info_t *_bcmx_port_list_last  = NULL;
     70 
     71 
     72 /*
     73  * Port Mapping - DEVPORT hash
     74  *
     75  * Definitions for faster search based on gport DEVPORT hash key
     76  * (key is composed of unit/port)
     77  */
     78 typedef struct _bcmx_devport_hash_s  _bcmx_devport_hash_t;
     79 struct _bcmx_devport_hash_s {
     80     bcm_gport_t           key;        /* Hash key, gport DEVPORT */
     81     _bcmx_port_info_t     *port_info; /* Reference to port info object */
     82     _bcmx_devport_hash_t  *next;
     83     _bcmx_devport_hash_t  *prev;
     84 };
     85 static _bcmx_devport_hash_t  *_bcmx_devport_hash[BCMX_PORT_HASH_COUNT];
     86 
     87 
     88 /*
     89  * BCMX Uport <-> Lport Mapping
     90  */
     91 _bcmx_uport_hash_t *_bcmx_uport_hash[BCMX_UPORT_HASH_COUNT];
     92 
     93 /* Application definition for Uport */
     94 bcmx_uport_create_f bcmx_uport_create;
     95 bcmx_lport_remove_notify_f bcmx_lport_remove_notify;
     96 
     97 /*
     98  * Default Uport
     99  *
    100  * If application 'uport' definition is not provided, the default
    101  * uport is applied (see _bcmx_uport_create_default).
    102  * The default uport is of type 'int'.
    103  * Values are assigned starting with the lowest unused integer number
    104  * (this assignment logic is the same* as the one used before
    105  * 'lport' was converted to 'gport').
    106  */
    107 #define BCMX_UPORT_TO_INT(_uport)    PTR_TO_INT(_uport)
    108 
    109 
    110 /*
    111  * BCMX unit list
    112  */
    113 int bcmx_unit_list[BCMX_UNITS_MAX];
    114 int bcmx_unit_count;
    115 
    116 /* Cache for device->CPU port map */
    117 bcmx_lport_t bcmx_lport_local_cpu[BCM_CONTROL_MAX];
    118 
    119 sal_mutex_t bcmx_config_lock;
    120 
    121 
    122 /*
    123  * BCMX generic conversion routines for destinations
    124  *
    125  * Check macros
    126  */
    127 #define BCMX_DEST_MODID_PORT_FLAG_CHECK(_flags) \
    128     if (((_flags) | BCMX_DEST_GPORT_AWARE) != BCMX_DEST_GPORT_AWARE) { \
    129         return BCM_E_PARAM; \
    130     }
    131 
    132 #define BCMX_DEST_UNIT_PORT_FLAG_CHECK(_flags) \
    133     BCMX_DEST_MODID_PORT_FLAG_CHECK(_flags)
    134 
    135 
    136 
    137 /*
    138  * DEPRECATED
    139  */
    140 int bcmx_lport_max = 0;       /* Number of lports supported */
    141 _bcmx_port_t *_bcmx_port;
    142 bcmx_lport_t _bcmx_lport_first = BCMX_LPORT_INVALID;
    143 bcmx_uport_t _bcmx_uport_invalid = BCMX_UPORT_INVALID;
    144 
    145 
    146 
    147 /****************************************************************
    148  * Internal Functions
    149  */
    150 
    151 STATIC INLINE void
    152 _bcmx_uport_remove(bcmx_uport_t uport)
    153 {
    154     _bcmx_uport_hash_t *uph;
    155     int h_idx;
    156 
    157     h_idx = BCMX_UPORT_HASH(uport);
    158     uph = _bcmx_uport_hash[h_idx];
    159     while (uph != NULL) {
    160         if (BCMX_UPORT_EQ(uph->uport, uport)) {
    161             break;
    162         }
    163         uph = uph->next;
    164     }
    165 
    166     if (uph == NULL) {  /* Not there */
    167         return;
    168     }
    169 
    170     /* Is this the first entry? */
    171     if (uph->prev == NULL) {  /* Yes */
    172         _bcmx_uport_hash[h_idx] = uph->next;
    173     } else {
    174         uph->prev->next = uph->next;
    175     }
    176 
    177     /* Is this the last entry? */
    178     if (uph->next != NULL) {  /* No */
    179         uph->next->prev = uph->prev;
    180     }
    181 
    182     sal_free(uph);
    183 }
    184 
    185 STATIC INLINE _bcmx_uport_hash_t *
    186 _bcmx_uport_add(bcmx_uport_t uport, bcmx_lport_t lport)
    187 {
    188     _bcmx_uport_hash_t *uph;
    189     int h_idx;
    190 
    191     h_idx = BCMX_UPORT_HASH(uport);
    192 
    193     uph = sal_alloc(sizeof(_bcmx_uport_hash_t), "bcmx_uport_add");
    194     if (uph == NULL) {
    195         return NULL;
    196     }
    197 
    198     uph->uport = uport;
    199     uph->lport = lport;
    200     uph->prev = NULL;
    201     uph->next = _bcmx_uport_hash[h_idx];
    202     if (uph->next != NULL) {
    203         uph->next->prev = uph;
    204     }
    205     _bcmx_uport_hash[h_idx] = uph;
    206 
    207     return uph;
    208 }
    209 
    210 
    211 /*
    212  * Function:
    213  *     _bcmx_uport_create_default
    214  * Purpose:
    215  *     Return a new user port number using the default
    216  *     definition for uport (integer).
    217  * Parameters:
    218  *     none
    219  * Returns:
    220  *     A new 'uport' value.
    221  * Notes:
    222  *    Assumes lock is held.
    223  */
    224 STATIC bcmx_uport_t
    225 _bcmx_uport_create_default(void)
    226 {
    227     int  i = 0;
    228 
    229     /* Find lowest unused uport integer */
    230     while(bcmx_uport_to_lport(BCMX_UPORT_CAST(i)) != BCMX_LPORT_INVALID) {
    231         i++;
    232     }
    233 
    234     return BCMX_UPORT_CAST(i);
    235 }
    236 
    237 
    238 /*
    239  * Function:
    240  *     _bcmx_devport_hash_add
    241  * Purpose:
    242  *     Add the port information reference to the devport hash
    243  *     table array.
    244  * Parameters:
    245  *     unit      - Device number
    246  *     port      - Device port number
    247  *     port_info - Pointer to port information object
    248  * Returns:
    249  *     Pointer to added devport hash, if successful.
    250  *     NULL, on failure to allocate struct.
    251  * Notes:
    252  *     Assumes lock is held.
    253  */
    254 STATIC _bcmx_devport_hash_t *
    255 _bcmx_devport_hash_add(int unit, bcm_port_t port, _bcmx_port_info_t *port_info)
    256 {
    257     bcm_gport_t           key;
    258     int                   index;
    259     _bcmx_devport_hash_t  *devport;
    260 
    261     if ((devport = sal_alloc(sizeof(_bcmx_devport_hash_t),
    262                              "bcmx_devport_add")) == NULL) {
    263         return NULL;
    264     }
    265 
    266     BCM_GPORT_DEVPORT_SET(key, unit, port);
    267     index = BCMX_PORT_HASH_INDEX(key);
    268 
    269     devport->key = key;
    270     devport->port_info = port_info;
    271     devport->prev = NULL;
    272     devport->next = _bcmx_devport_hash[index];
    273     if (devport->next != NULL) {
    274         devport->next->prev = devport;
    275     }
    276     _bcmx_devport_hash[index] = devport;
    277 
    278     return devport;
    279 }
    280 
    281 
    282 /*
    283  * Function:
    284  *     _bcmx_devport_hash_remove
    285  * Purpose:
    286  *     Remove devport hash information for given BCM unit/port.
    287  * Parameters:
    288  *     unit - Device number
    289  *     port - Device port number
    290  * Returns:
    291  *     None
    292  * Notes:
    293  *     Assumes lock is held.
    294  */
    295 STATIC void
    296 _bcmx_devport_hash_remove(int unit, bcm_port_t port)
    297 {
    298     bcm_gport_t           key;
    299     int                   index;
    300     _bcmx_devport_hash_t  *devport;
    301 
    302     BCM_GPORT_DEVPORT_SET(key, unit, port);
    303     index = BCMX_PORT_HASH_INDEX(key);
    304 
    305 
    306     devport = _bcmx_devport_hash[index];
    307     while (devport != NULL) {
    308         if (devport->key == key) {
    309             break;
    310         }
    311         devport = devport->next;
    312     }
    313 
    314     if (devport == NULL) {  /* Not found */
    315         return;
    316     }
    317 
    318     /* Check first entry */
    319     if (devport->prev == NULL) {  /* Yes */
    320         _bcmx_devport_hash[index] = devport->next;
    321     } else {
    322         devport->prev->next = devport->next;
    323     }
    324 
    325     /* Check last entry */
    326     if (devport->next != NULL) {  /* No */
    327         devport->next->prev = devport->prev;
    328     }
    329 
    330     sal_free(devport);
    331 }
    332 
    333 
    334 /*
    335  * Function:
    336  *     _bcmx_port_info_find
    337  * Purpose:
    338  *     Find the BCMX port information for a given lport key.
    339  * Parameters:
    340  *     lport     - BCMX logical port number (gport format)
    341  *     tbl_index - (OUT) Table array index for given port
    342  * Returns:
    343  *     Pointer to BCXM port information struct, if key was found.
    344  *     NULL, on failure to find key.
    345  * Notes:
    346  *     Assumes lock is held.
    347  */
    348 STATIC _bcmx_port_info_t*
    349 _bcmx_port_info_find(bcmx_lport_t lport, int *tbl_index)
    350 {
    351     _bcmx_port_info_t  *port_info = NULL;
    352 
    353     *tbl_index = BCMX_PORT_HASH_INDEX(lport);
    354 
    355     port_info = _bcmx_port_info[*tbl_index];
    356     while (port_info != NULL) {
    357         if (port_info->lport == lport) {
    358             break;
    359         }
    360         port_info = port_info->next;
    361     }
    362 
    363     return port_info;
    364 }
    365 
    366 
    367 /*
    368  * Function:
    369  *     _bcmx_port_add
    370  * Purpose:
    371  *     Add the port information into the BCMX port hash
    372  *     table array.
    373  * Parameters:
    374  *     unit  - Device number
    375  *     port  - Device port number
    376  *     flags - Port flags BCMX_PORT_F_xxx
    377  * Returns:
    378  *     BCM_E_NONE     - Success
    379  *     BCM_E_EXISTS   - Port already exist in BCMX port table
    380  *     BCM_E_RESOURCE - Could not allocate port information structure
    381  * Notes:
    382  *     Assumes lock is held.
    383  */
    384 STATIC int
    385 _bcmx_port_add(int unit, bcm_port_t port, bcm_gport_t lport, uint32 flags)
    386 {
    387     int                index;
    388     bcm_port_t         modport;
    389     bcm_module_t       modid;
    390     bcmx_uport_t       uport;
    391     _bcmx_port_info_t  *port_info;
    392 
    393     /* BCMX lport should unique */
    394     if (_bcmx_port_info_find(lport, &index) != NULL) {
    395         return BCM_E_EXISTS;
    396     }
    397 
    398     if ((port_info = sal_alloc(sizeof(_bcmx_port_info_t),
    399                                "bcmx_port_info_add")) == NULL) {
    400         return BCM_E_RESOURCE;
    401     }
    402 
    403     if (BCM_GPORT_IS_MODPORT(lport)) {
    404         modport = BCM_GPORT_MODPORT_PORT_GET(lport);
    405         modid   = BCM_GPORT_MODPORT_MODID_GET(lport);
    406     } else {
    407         modport = port;
    408         modid   = -1;
    409     }
    410 
    411     /* Set uport */
    412     if (bcmx_uport_create != NULL) {
    413         uport = bcmx_uport_create(lport, unit, port, flags);
    414     } else {
    415         /* Use default uport assignment */
    416         uport = _bcmx_uport_create_default();
    417     }
    418     /* Update uport <-> lport map table */
    419     if (_bcmx_uport_add(uport, lport) == NULL) {
    420         LOG_WARN(BSL_LS_BCMX_COMMON,
    421                  (BSL_META_U(unit,
    422                              "BCMX: Failed to add uport hash, "
    423                              "u %d, p %d\n"), unit, port));
    424     }
    425 
    426     /* Set Cache CPU port */
    427     if (flags & BCMX_PORT_F_CPU) {
    428         bcmx_lport_local_cpu[unit] = lport;
    429     }
    430 
    431     /* Set BCMX port information */
    432     port_info->lport         = lport;
    433     port_info->port.bcm_unit = unit;
    434     port_info->port.bcm_port = port;
    435     port_info->port.modid    = modid;
    436     port_info->port.modport  = modport;
    437     port_info->port.uport    = uport;
    438     port_info->port.flags    = flags;
    439 
    440     /* Update hash table link list */
    441     index           = BCMX_PORT_HASH_INDEX(lport);
    442     port_info->prev = NULL;
    443     port_info->next = _bcmx_port_info[index];
    444     if (port_info->next != NULL) {
    445         port_info->next->prev = port_info;
    446     }
    447     _bcmx_port_info[index] = port_info;
    448 
    449     /* Update port list */
    450     if (_bcmx_port_list_first == NULL) {
    451         _bcmx_port_list_first = port_info;
    452     }
    453     if (_bcmx_port_list_last != NULL) {
    454         _bcmx_port_list_last->list.next = port_info;
    455     }
    456     port_info->list.prev = _bcmx_port_list_last;            
    457     port_info->list.next = NULL;
    458     _bcmx_port_list_last = port_info;
    459 
    460     /* Update devport hash table */
    461     if (_bcmx_devport_hash_add(unit, port, port_info) == NULL) {
    462         LOG_WARN(BSL_LS_BCMX_COMMON,
    463                  (BSL_META_U(unit,
    464                              "BCMX: Failed to add devport hash, "
    465                              "u %d, p %d\n"), unit, port));
    466     }
    467 
    468     return BCM_E_NONE;
    469 }
    470 
    471 
    472 /*
    473  * Function:
    474  *     _bcmx_port_info_remove_by_unit
    475  * Purpose:
    476  *     Remove all port information associated with the given unit.
    477  * Parameters:
    478  *     unit - Device number to remove ports for
    479  * Returns:
    480  *     BCM_E_NONE - Success
    481  * Notes:
    482  *     Assumes lock is held.
    483  */
    484 STATIC int
    485 _bcmx_port_info_remove_by_unit(int unit)
    486 {
    487     int                i;
    488     _bcmx_port_info_t  *port_info;
    489     _bcmx_port_info_t  *next;
    490 
    491     /* Check each link list in port table */
    492     for (i = 0; i < BCMX_PORT_HASH_COUNT; i++) {
    493 
    494         port_info = _bcmx_port_info[i];
    495 
    496         /* Check each entry in link list */
    497         while (port_info != NULL) {
    498             next = port_info->next;
    499 
    500             /* Remove port if unit matches */
    501             if (port_info->port.bcm_unit == unit) {
    502 
    503                 /* Clear uport */
    504                 if (bcmx_lport_remove_notify != NULL) {
    505                     bcmx_lport_remove_notify(port_info->lport,
    506                                              port_info->port.uport);
    507                 }
    508                 /* Update uport <-> lport map table */
    509                 _bcmx_uport_remove(port_info->port.uport);
    510 
    511                 /* Update devport hash table */
    512                 _bcmx_devport_hash_remove(port_info->port.bcm_unit,
    513                                           port_info->port.bcm_port);
    514 
    515                 /* Update hash table */
    516                 /* Check first entry */
    517                 if (port_info->prev == NULL) {  /* Yes */
    518                     _bcmx_port_info[i] = port_info->next;
    519                 } else {
    520                     port_info->prev->next = port_info->next;
    521                 }
    522                 /* Check last entry */
    523                 if (port_info->next != NULL) {  /* No */
    524                     port_info->next->prev = port_info->prev;
    525                 }
    526 
    527                 /* Update port list */
    528                 if (_bcmx_port_list_first == port_info) {
    529                     _bcmx_port_list_first = port_info->list.next;
    530                 }
    531                 if (_bcmx_port_list_last == port_info) {
    532                     _bcmx_port_list_last = port_info->list.prev;
    533                 }
    534                 if (port_info->list.prev != NULL) {
    535                     port_info->list.prev->list.next = port_info->list.next;
    536                 }
    537                 if (port_info->list.next != NULL) {
    538                     port_info->list.next->list.prev = port_info->list.prev;
    539                 }
    540                 
    541                 sal_free(port_info);
    542             }
    543 
    544             port_info = next;
    545         }
    546     }
    547 
    548     /* Clear cached CPU port info */
    549     bcmx_lport_local_cpu[unit] = BCMX_LPORT_INVALID; 
    550 
    551     return BCM_E_NONE;
    552 }
    553 
    554 
    555 /*
    556  * Function:
    557  *     _bcmx_lport_flags_get
    558  * Purpose:
    559  *     Get the port flags for given lport.
    560  * Parameters:
    561  *     lport - The port to get flags for
    562  *     flags - (OUT) Flags for given port
    563  * Returns:
    564  *     BCM_E_XXX
    565  * Notes:
    566  */
    567 STATIC int
    568 _bcmx_lport_flags_get(bcmx_lport_t lport, uint32 *flags)
    569 {
    570     int                rv = BCM_E_NOT_FOUND;
    571     int                index;
    572     _bcmx_port_info_t  *port_info;
    573 
    574     BCMX_READY_CHECK;
    575     BCMX_LPORT_CHECK(lport);
    576 
    577     BCMX_CONFIG_LOCK;
    578     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
    579         *flags = port_info->port.flags;
    580         rv = BCM_E_NONE;
    581     }
    582     BCMX_CONFIG_UNLOCK;
    583 
    584     return rv;
    585 }
    586 
    587 
    588 /*
    589  * Function:
    590  *     _bcmx_lport_flags_set
    591  * Purpose:
    592  *     Set the port flags for given lport.
    593  * Parameters:
    594  *     lport - The port to set flags for
    595  *     flags - Flags for given port
    596  * Returns:
    597  *     BCM_E_XXX
    598  * Notes:
    599  */
    600 STATIC int
    601 _bcmx_lport_flags_set(bcmx_lport_t lport, uint32 flags)
    602 {
    603     int                rv = BCM_E_NOT_FOUND;
    604     int                index;
    605     _bcmx_port_info_t  *port_info;
    606 
    607     BCMX_READY_CHECK;
    608     BCMX_LPORT_CHECK(lport);
    609 
    610     BCMX_CONFIG_LOCK;
    611     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
    612         port_info->port.flags = flags;
    613         rv = BCM_E_NONE;
    614     }
    615     BCMX_CONFIG_UNLOCK;
    616 
    617     return rv;
    618 }
    619 
    620 
    621 /*
    622  * Function:
    623  *     _bcmx_port_flags_create
    624  * Purpose:
    625  *     Create the BCMX port flags for the given port.
    626  * Parameters:
    627  *     unit - unit
    628  * Returns:
    629  *     BCM_E_XXX
    630  * Notes:
    631  */
    632 STATIC int
    633 _bcmx_port_flags_create(bcm_port_config_t *config,
    634                         bcm_port_t port, uint32 *flags)
    635 {
    636     uint32 port_flags;
    637 
    638     port_flags = BCMX_PORT_F_VALID;
    639     if (BCM_PBMP_MEMBER(config->cpu, port)) {
    640         port_flags |= BCMX_PORT_F_CPU;
    641     }
    642     if (BCM_PBMP_MEMBER(config->hg, port)) {
    643         port_flags |= BCMX_PORT_F_HG;
    644     }
    645     if (BCM_PBMP_MEMBER(config->fe, port)) {
    646         port_flags |= BCMX_PORT_F_FE;
    647     }
    648     if (BCM_PBMP_MEMBER(config->ge, port)) {
    649         port_flags |= BCMX_PORT_F_GE;
    650     }
    651     if (BCM_PBMP_MEMBER(config->xe, port)) {
    652         port_flags |= BCMX_PORT_F_XE;
    653     }
    654     if (BCM_PBMP_MEMBER(config->ce, port)) {
    655         port_flags |= BCMX_PORT_F_CE;
    656     }
    657     if (BCM_PBMP_MEMBER(config->stack_int, port)) {
    658         port_flags |= BCMX_PORT_F_STACK_INT;
    659     }
    660     if (BCM_PBMP_MEMBER(config->stack_ext, port)) {
    661         port_flags |= BCMX_PORT_F_STACK_EXT;
    662     }
    663 
    664     *flags = port_flags;
    665     return BCM_E_NONE;
    666 }
    667 
    668 /*
    669  * Function:
    670  *     _bcmx_port_changed
    671  * Purpose:
    672  *     Update internal BCMX information for the given port
    673  * Parameters:
    674  *     port - port
    675  * Returns:
    676  *     BCM_E_XXX
    677  * Notes:
    678  */
    679 int
    680 _bcmx_port_changed(bcmx_lport_t lport)
    681 {
    682     int rv = BCM_E_PORT;
    683     int bcm_unit;
    684     bcm_port_config_t config;
    685     bcm_port_t bcm_port;
    686     uint32 port_flags;
    687     
    688     bcm_unit = bcmx_lport_bcm_unit(lport);
    689     bcm_port = bcmx_lport_bcm_port(lport);
    690 
    691     if (bcm_unit >= 0 && bcm_port >= 0) {
    692         rv = bcm_port_config_get(bcm_unit, &config);
    693         if (BCM_SUCCESS(rv)) {
    694             rv = _bcmx_port_flags_create(&config, bcm_port, &port_flags);
    695             if (BCM_SUCCESS(rv)) {
    696                 rv = _bcmx_lport_flags_set(lport, port_flags);
    697             }
    698         }
    699     }
    700 
    701     return rv;
    702 }
    703 
    704 /*
    705  * Function:
    706  *     _bcmx_port_changed_callback
    707  * Purpose:
    708  *     Update cached port information when called
    709  * Parameters:
    710  *     port - port
    711  *     info - port info
    712  * Returns:
    713  *     void
    714  * Notes:
    715  *     Registered with bcmx linkscan to track port changes.
    716  *     Limitation: will not catch changes to ports if the
    717  *       port link state is always down.
    718  */
    719 STATIC void
    720 _bcmx_port_changed_callback(bcmx_lport_t lport, bcm_port_info_t *info)
    721 {
    722     COMPILER_REFERENCE(info);
    723     (void)_bcmx_port_changed(lport);
    724 }
    725 
    726 /*
    727  * Function:
    728  *     bcmx_lport_first
    729  * Purpose:
    730  *     Return the first lport found in the BCMX port information table.
    731  * Parameters:
    732  *     none
    733  * Returns:
    734  *     First BCMX logical port found in the BCMX port information table.
    735  *     (-1) on empty table
    736  * Notes:
    737  *     - The 'first' port returned is the first port added in BCMX.
    738  *     - This routine should have been private to BCMX, but is exposed
    739  *       to maintain support of existing public macros.
    740  */
    741 bcmx_lport_t
    742 bcmx_lport_first(void)
    743 {
    744     bcmx_lport_t  lport_first = BCMX_LPORT_INVALID;
    745 
    746     if (!BCMX_READY) {
    747         return BCMX_LPORT_INVALID;
    748     }
    749 
    750     BCMX_CONFIG_LOCK;
    751     if (_bcmx_port_list_first != NULL) {
    752         lport_first = _bcmx_port_list_first->lport;
    753     }
    754     BCMX_CONFIG_UNLOCK;
    755 
    756     return lport_first;
    757 }
    758 
    759 
    760 /*
    761  * Function:
    762  *     bcmx_lport_next
    763  * Purpose:
    764  *     Return the lport next to the given port in the BCMX port
    765  *     information table.
    766  * Parameters:
    767  *     lport - BCMX logical port number (gport format)
    768  * Returns:
    769  *     Next lport to given port in the BCMX port information table.
    770  *     (-1) if no more ports is found.
    771  * Notes:
    772  *     - The 'next' port returned is the port that was added in BCMX
    773  *       after the specified port.
    774  *     - This routine should have been private to BCMX, but is exposed
    775  *       to maintain support of existing public macros.
    776  */
    777 bcmx_lport_t
    778 bcmx_lport_next(bcmx_lport_t lport)
    779 {
    780     bcmx_lport_t       lport_next = BCMX_LPORT_INVALID;
    781     int                index;
    782     _bcmx_port_info_t  *port_info;
    783 
    784     if (!BCMX_READY || !BCMX_IS_LPORT(lport)) {
    785         return BCMX_LPORT_INVALID;
    786     }
    787 
    788     BCMX_CONFIG_LOCK;
    789     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
    790         /* Get next one */
    791         if (port_info->list.next != NULL) {
    792             lport_next = port_info->list.next->lport;
    793         }
    794     }
    795     BCMX_CONFIG_UNLOCK;
    796 
    797     return lport_next;
    798 }
    799 
    800 
    801 /*
    802  * Function:
    803  *     bcmx_lport_init
    804  * Purpose:
    805  *     Initialize the internal BCMX port information structures.
    806  * Parameters:
    807  *     none
    808  * Returns:
    809  *     BCM_E_MEMORY if unable to allocate structures
    810  * Notes:
    811  *     Destroys all current information and initializes structures
    812  *     Destroys user port info; does not make callouts that they're
    813  *     disappearing.
    814  */
    815 int
    816 bcmx_lport_init(void)
    817 {
    818     int                   i;
    819     _bcmx_port_info_t     *port_info;
    820     _bcmx_port_info_t     *port_info_next;
    821     _bcmx_uport_hash_t    *uport_next;
    822     _bcmx_devport_hash_t  *devport;
    823     _bcmx_devport_hash_t  *devport_next;
    824 
    825     BCMX_INIT_CHECK;
    826 
    827     BCMX_CONFIG_LOCK;
    828 
    829     /* Clear BCMX port information table */
    830     for (i = 0; i < BCMX_PORT_HASH_COUNT; i++) {
    831         port_info = _bcmx_port_info[i];
    832         while (port_info != NULL) {
    833             port_info_next = port_info->next;
    834             sal_free(port_info);
    835             port_info = port_info_next;
    836         }
    837         _bcmx_port_info[i] = NULL;
    838     }
    839 
    840     /* Clear port lists */
    841     _bcmx_port_list_first = NULL;
    842     _bcmx_port_list_last  = NULL;
    843 
    844     /* Clear out BCMX uport <-> lport mapping */
    845     for (i = 0; i < BCMX_UPORT_HASH_COUNT; i++) {
    846         while (_bcmx_uport_hash[i] != NULL) {
    847             uport_next = _bcmx_uport_hash[i]->next;
    848             sal_free(_bcmx_uport_hash[i]);
    849             _bcmx_uport_hash[i] = uport_next;
    850         }
    851         _bcmx_uport_hash[i] = NULL;
    852     }
    853 
    854     /* Clear devport hash table */
    855     for (i = 0; i < BCMX_PORT_HASH_COUNT; i++) {
    856         devport = _bcmx_devport_hash[i];
    857         while (devport != NULL) {
    858             devport_next = devport->next;
    859             sal_free(devport);
    860             devport = devport_next;
    861         }
    862         _bcmx_devport_hash[i] = NULL;
    863     }
    864 
    865     /* Clear cache CPU port */
    866     for (i = 0; i < BCM_CONTROL_MAX; i++) {
    867         bcmx_lport_local_cpu[i] = BCMX_LPORT_INVALID;
    868     }
    869 
    870     BCMX_CONFIG_UNLOCK;
    871 
    872     return BCM_E_NONE;
    873 }
    874 
    875 
    876 /*
    877  * Function:
    878  *     bcmx_init
    879  * Purpose:
    880  *     Initialize the BCMX subsystem.
    881  * Returns:
    882  *     BCM_E_NONE if successful
    883  *     BCM_E_MEMORY if unable to allocate structures
    884  * Notes:
    885  *     Initialize mutex.
    886  */
    887 int
    888 bcmx_init(void)
    889 {
    890     int   rv = BCM_E_NONE;
    891     void  *api_ptr = (void *)bcmx_api_tbl;
    892 
    893     /* This should never be true; done to include api table */
    894     if (api_ptr == NULL) {
    895     /*
    896      * Coverity
    897      * Defencive check
    898      * coverity[dead_error_line]
    899      */
    900         return 0;
    901     }
    902 
    903     if (bcmx_config_lock == NULL) {
    904         bcmx_config_lock = sal_mutex_create("bcmx_init");
    905         if (bcmx_config_lock == NULL) {
    906             return BCM_E_MEMORY;
    907         }
    908     }
    909     
    910     /* Reset port information tables */
    911     rv = bcmx_lport_init();
    912 
    913     /* Register with linkscan to track port changes */
    914     bcmx_linkscan_register(_bcmx_port_changed_callback);
    915     
    916     return rv;
    917 }
    918 
    919 
    920 /*
    921  * Function:
    922  *     bcmx_uport_create_callback_set
    923  * Purpose:
    924  *     Set the callback for uport create.
    925  * Parameters:
    926  *     create_callback - Function to callback on
    927  * Returns:
    928  *     BCM_E_XXX
    929  * Notes:
    930  *     Call with NULL pointer to turn off the callback.
    931  */
    932 int
    933 bcmx_uport_create_callback_set(bcmx_uport_create_f create_callback)
    934 {
    935     bcmx_uport_create = create_callback;
    936     return BCM_E_NONE;
    937 }
    938 
    939 
    940 /*
    941  * Function:
    942  *     bcmx_device_attach
    943  * Purpose:
    944  *     Make BCMX aware of the indicated device.
    945  * Parameters:
    946  *     bcm_unit - The BCM (dispatch) unit number of the device
    947  * Returns:
    948  *     BCM_E_XXX
    949  * Notes:
    950  *     This should only be used for "normal" units.
    951  */
    952 int
    953 bcmx_device_attach(int bcm_unit)
    954 {
    955     uint32 port_flags;
    956     bcm_port_config_t config;
    957     bcm_port_t port;
    958     int i;
    959     int rv;
    960     bcm_gport_t lport[BCM_PBMP_PORT_MAX];
    961     
    962     if (bcmx_config_lock == NULL) {
    963         BCM_IF_ERROR_RETURN(bcmx_init());
    964     }
    965 
    966     /* Gather information that requires RPC call before applying lock */
    967     rv = bcm_port_config_get(bcm_unit, &config);
    968     if (rv < 0) {
    969         LOG_WARN(BSL_LS_BCMX_COMMON,
    970                  (BSL_META("BCMX: Could not get port config %d: %s\n"),
    971                   rv, bcm_errmsg(rv)));
    972         return rv;
    973     }
    974 
    975     LOG_VERBOSE(BSL_LS_BCMX_COMMON,
    976                 (BSL_META("BCMX: Attaching unit %d\n"),
    977                  bcm_unit));
    978     BCMX_CONFIG_LOCK;
    979     /* See if the unit is on the list of those known */
    980     for (i = 0; i < bcmx_unit_count; i++) {
    981         if (bcm_unit == bcmx_unit_list[i]) {
    982             BCMX_CONFIG_UNLOCK;
    983             LOG_ERROR(BSL_LS_BCMX_COMMON,
    984                       (BSL_META("BCMX: unit exists\n")));
    985             return BCM_E_EXISTS;
    986         }
    987     }
    988     if (bcmx_unit_count >= BCMX_UNITS_MAX) {
    989         BCMX_CONFIG_UNLOCK;
    990         return BCM_E_RESOURCE;
    991     }
    992     bcmx_unit_list[bcmx_unit_count++] = bcm_unit;
    993 
    994     i = 0;
    995     BCM_PBMP_ITER(config.all, port) {
    996 
    997         _bcmx_port_flags_create(&config, port, &port_flags);
    998 
    999         /* Add port */
   1000         rv = _bcmx_port_add(bcm_unit, port, lport[i], port_flags);
   1001         if (BCM_FAILURE(rv)) {
   1002             LOG_WARN(BSL_LS_BCMX_COMMON,
   1003                      (BSL_META("BCMX: Failed to add lport 0x%x (unit %d, port %d). "
   1004                                "%d: %s.\n"),
   1005                       lport[i], bcm_unit, port, rv, bcm_errmsg(rv)));
   1006 
   1007             /* If BCM_E_EXISTS, do not exit, try remaining ports */
   1008             if (rv != BCM_E_EXISTS) {
   1009                 BCMX_CONFIG_UNLOCK;
   1010                 return rv;
   1011             }
   1012         }
   1013         i++;
   1014     }
   1015 
   1016     BCMX_CONFIG_UNLOCK;
   1017 
   1018     /*
   1019      * Check modules that are running that need to know about
   1020      * new units
   1021      */
   1022     rv = bcmx_rx_device_add(bcm_unit);
   1023     if (rv < 0) {
   1024         LOG_WARN(BSL_LS_BCMX_COMMON,
   1025                  (BSL_META("BCMX: Failed to add unit to RX, "
   1026                            "u %d.  %d: %s\n"), bcm_unit, rv, bcm_errmsg(rv)));
   1027     }
   1028 
   1029     rv = bcmx_l2_device_add(bcm_unit);
   1030     if (rv < 0 && rv != BCM_E_UNAVAIL) {
   1031         LOG_WARN(BSL_LS_BCMX_COMMON,
   1032                  (BSL_META("BCMX: Failed to add unit for L2 notify, "
   1033                            "u %d.  %d: %s\n"), bcm_unit, rv, bcm_errmsg(rv)));
   1034     }
   1035 
   1036     rv = bcmx_linkscan_device_add(bcm_unit);
   1037     if (rv < 0) {
   1038         LOG_WARN(BSL_LS_BCMX_COMMON,
   1039                  (BSL_META("BCMX: Failed to add unit for linkscan, "
   1040                            "u %d.  %d: %s\n"), bcm_unit, rv, bcm_errmsg(rv)));
   1041     }
   1042 
   1043     return BCM_E_NONE;
   1044 }
   1045 
   1046 
   1047 /*
   1048  * Function:
   1049  *     bcmx_device_detach
   1050  * Purpose:
   1051  *     Remove unit from BCMX configuration.
   1052  * Parameters:
   1053  *     bcm_unit - The BCM (dispatch) unit number of the device
   1054  * Returns:
   1055  *     BCM_E_XXX
   1056  */
   1057 int
   1058 bcmx_device_detach(int bcm_unit)
   1059 {
   1060     int i, j;
   1061     int found = FALSE;
   1062 #if defined(BCM_RPC_SUPPORT)
   1063     int rv;
   1064 #endif
   1065 
   1066     BCMX_INIT_CHECK;
   1067 
   1068     LOG_VERBOSE(BSL_LS_BCMX_COMMON,
   1069                 (BSL_META("BCMX: Detaching unit %d\n"),
   1070                  bcm_unit));
   1071 
   1072     BCMX_CONFIG_LOCK;
   1073 
   1074     /* First, look for the unit on the list of known units */
   1075     for (i = 0; i < bcmx_unit_count; i++) {
   1076         if (bcm_unit == bcmx_unit_list[i]) {
   1077             found = TRUE;
   1078             for (j = i + 1; j < bcmx_unit_count; j++) {
   1079                 bcmx_unit_list[j - 1] = bcmx_unit_list[j];
   1080             }
   1081             bcmx_unit_count--;
   1082             break;
   1083         }
   1084     }
   1085     if (!found) {
   1086         BCMX_CONFIG_UNLOCK;
   1087         return BCM_E_NOT_FOUND;
   1088     }
   1089 
   1090     /* Remove all port information for given unit */
   1091     _bcmx_port_info_remove_by_unit(bcm_unit);
   1092 
   1093     BCMX_CONFIG_UNLOCK;
   1094 
   1095     /* De-register rlink facilities in case local */
   1096     bcmx_rx_device_remove(bcm_unit);
   1097     bcmx_linkscan_device_remove(bcm_unit);
   1098     bcmx_l2_device_remove(bcm_unit);
   1099 
   1100 #if defined(BCM_RPC_SUPPORT)
   1101     /* Detach device from rlink */
   1102     if ((rv = bcm_rlink_device_detach(bcm_unit)) < 0) {
   1103         LOG_WARN(BSL_LS_BCMX_COMMON,
   1104                  (BSL_META("BCMX(unit %d): Rlink device detach failed: %d\n"),
   1105                   bcm_unit, rv));
   1106     }
   1107 #endif
   1108 
   1109     return BCM_E_NONE;
   1110 }
   1111 
   1112 
   1113 /*
   1114  * Function:
   1115  *     bcmx_lport_valid
   1116  * Purpose:
   1117  *     Check if given LPORT is an existing valid BCMX logical port.
   1118  * Parameters:
   1119  *     lport - The logical port
   1120  * Returns:
   1121  *     TRUE  - LPORT is valid and exists
   1122  *     FALSE - LPORT value is invalid or it does not exist
   1123  */
   1124 int
   1125 bcmx_lport_valid(bcmx_lport_t lport)
   1126 {
   1127     int                index;
   1128     _bcmx_port_info_t  *port_info;
   1129 
   1130     if (!BCMX_READY || !BCMX_IS_LPORT(lport)) {
   1131         return FALSE;
   1132     }
   1133 
   1134     BCMX_CONFIG_LOCK;
   1135     port_info = _bcmx_port_info_find(lport, &index);
   1136     BCMX_CONFIG_UNLOCK;
   1137 
   1138     return (port_info != NULL);
   1139 }
   1140 
   1141 
   1142 /****************************************************************
   1143  *
   1144  * CPU port accessor
   1145  */
   1146 
   1147 /*
   1148  * Function:
   1149  *     bcmx_lport_local_cpu_get
   1150  * Purpose:
   1151  *     Get the lport associated to the device CPU port.
   1152  * Parameters:
   1153  *     bcm_unit - Device number
   1154  *     lport    - (OUT) BCMX logical port
   1155  * Returns:
   1156  *     BCM_E_NONE on success; sets lport to the CPU port.
   1157  *     BCM_E_NOT_FOUND otherwise; lport is set to BCMX_LPORT_INVALID
   1158  * Notes:
   1159  */
   1160 int
   1161 bcmx_lport_local_cpu_get(int bcm_unit, bcmx_lport_t *lport)
   1162 {
   1163     BCMX_READY_CHECK;
   1164     BCMX_PARAM_NULL_CHECK(lport);
   1165 
   1166     *lport = bcmx_lport_local_cpu[bcm_unit];
   1167     if (bcmx_lport_local_cpu[bcm_unit] == BCMX_LPORT_INVALID) {
   1168         return BCM_E_NOT_FOUND;
   1169     }
   1170 
   1171     return BCM_E_NONE;
   1172 }
   1173 
   1174 
   1175 /****************************************************************
   1176  *
   1177  * Logical and User port functions
   1178  */
   1179 
   1180 /*
   1181  * Function:
   1182  *     bcmx_uport_get
   1183  * Purpose:
   1184  *     Get the uport associated with an lport.
   1185  * Parameters:
   1186  *     lport - The BCMX logical port
   1187  * Returns:
   1188  *     The uport for the given lport.
   1189  *     'uport' is invalid on failure (lport not found)
   1190  *     You can also use the macro BCMX_UPORT_GET.
   1191  */
   1192 bcmx_uport_t
   1193 bcmx_uport_get(bcmx_lport_t lport)
   1194 {
   1195     int                index;
   1196     _bcmx_port_info_t  *port_info;
   1197     bcmx_uport_t       uport = BCMX_UPORT_INVALID;
   1198 
   1199     if (!BCMX_READY || !BCMX_IS_LPORT(lport)) {
   1200         return BCMX_UPORT_INVALID;
   1201     }
   1202 
   1203     BCMX_CONFIG_LOCK;
   1204     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
   1205         uport = port_info->port.uport;
   1206     }
   1207     BCMX_CONFIG_UNLOCK;
   1208 
   1209     return uport;
   1210 }
   1211 
   1212 
   1213 /*
   1214  * Function:
   1215  *     bcmx_uport_set
   1216  * Purpose:
   1217  *     Set the uport associated with an lport.
   1218  * Parameters:
   1219  *     lport - The BCMX logical port
   1220  *     uport - The user port
   1221  * Returns:
   1222  *     BCM_E_XXX;
   1223  *     Returns an error if the uport is already bound to a
   1224  *     different lport.
   1225  */
   1226 int
   1227 bcmx_uport_set(bcmx_lport_t lport, bcmx_uport_t uport)
   1228 {
   1229     int                 rv = BCM_E_NONE;
   1230     int                 index;
   1231     _bcmx_port_info_t   *port_info;
   1232     bcmx_lport_t        tmp_lport;
   1233 
   1234     BCMX_READY_CHECK;
   1235     BCMX_LPORT_CHECK(lport);
   1236 
   1237     BCMX_CONFIG_LOCK;
   1238 
   1239     /* Invalid uport: clear current lport <-> uport */
   1240     if (uport == BCMX_UPORT_INVALID) {
   1241         if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
   1242             _bcmx_uport_remove(port_info->port.uport);
   1243             port_info->port.uport = uport;
   1244         } else {
   1245             rv = BCM_E_PORT;
   1246         }
   1247 
   1248         BCMX_CONFIG_UNLOCK;
   1249         return rv;
   1250     }
   1251 
   1252     /* See if uport is already mapped to a logical port */
   1253     tmp_lport = BCMX_UPORT_TO_LPORT(uport);
   1254     if (BCMX_LPORT_VALID(tmp_lport)) {
   1255         /* Check if logical port is same, if so, nothing to do, return ok */
   1256         if (tmp_lport != lport) {
   1257             rv = BCM_E_EXISTS;
   1258         }
   1259 
   1260         BCMX_CONFIG_UNLOCK;
   1261         return rv;
   1262     }
   1263 
   1264     /* Update lport <-> uport */
   1265     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
   1266 
   1267         /* Update uport <-> lport mapping, if different */
   1268         if (port_info->port.uport != uport) {
   1269             if (_bcmx_uport_add(uport, lport) == NULL) {
   1270                 rv = BCM_E_MEMORY;
   1271             } else {
   1272                 _bcmx_uport_remove(port_info->port.uport);
   1273                 port_info->port.uport = uport;
   1274             }
   1275         }
   1276 
   1277     } else {
   1278         rv = BCM_E_PORT;
   1279     }
   1280 
   1281     BCMX_CONFIG_UNLOCK;
   1282 
   1283     return rv;
   1284 }
   1285 
   1286 
   1287 /*
   1288  * Function:
   1289  *     bcmx_lport_to_unit_port
   1290  * Purpose:
   1291  *     Map an LPORT to a BCM dispatch unit/port pair.
   1292  * Parameters:
   1293  *     lport - The port to map
   1294  *     unit  - (OUT) Device unit mapped to lport
   1295  *     port  - (OUT) Device port mapped to lport
   1296  * Returns:
   1297  *     BCM_E_XXX
   1298  * Notes:
   1299  */
   1300 int
   1301 bcmx_lport_to_unit_port(bcmx_lport_t lport, int *unit, bcm_port_t *port)
   1302 {
   1303     int                rv = BCM_E_PORT;
   1304     int                index;
   1305     _bcmx_port_info_t  *port_info;
   1306 
   1307     BCMX_READY_CHECK;
   1308     BCMX_LPORT_CHECK(lport);
   1309     BCMX_PARAM_NULL_CHECK(unit);
   1310     BCMX_PARAM_NULL_CHECK(port);
   1311 
   1312     BCMX_CONFIG_LOCK;
   1313     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
   1314         *unit = port_info->port.bcm_unit;
   1315         *port = port_info->port.bcm_port;
   1316         rv = BCM_E_NONE;
   1317     }
   1318     BCMX_CONFIG_UNLOCK;
   1319 
   1320     return rv;
   1321 }
   1322 
   1323 
   1324 /*
   1325  * Function:
   1326  *     bcmx_lport_to_modid_port
   1327  * Purpose:
   1328  *     Map an LPORT to a device module ID and physical port.
   1329  * Parameters:
   1330  *     lport - The port to map
   1331  *     modid - (OUT) System mod id mapped to lport
   1332  *     port  - (OUT) Unit's port mapped to lport
   1333  * Returns:
   1334  *     BCM_E_XXX
   1335  * Notes:
   1336  */
   1337 int
   1338 bcmx_lport_to_modid_port(bcmx_lport_t lport,
   1339                          int *modid, bcm_port_t *modport)
   1340 {
   1341     int                rv = BCM_E_PORT;
   1342     int                index;
   1343     _bcmx_port_info_t  *port_info;
   1344 
   1345     BCMX_READY_CHECK;
   1346     BCMX_LPORT_CHECK(lport);
   1347     BCMX_PARAM_NULL_CHECK(modid);
   1348     BCMX_PARAM_NULL_CHECK(modport);
   1349 
   1350     BCMX_CONFIG_LOCK;
   1351     if ((port_info = _bcmx_port_info_find(lport, &index)) != NULL) {
   1352         *modid = port_info->port.modid;
   1353         *modport  = port_info->port.modport;
   1354         rv = BCM_E_NONE;
   1355     }
   1356     BCMX_CONFIG_UNLOCK;
   1357 
   1358     return rv;
   1359 }
   1360 
   1361 
   1362 /*
   1363  * Function:
   1364  *     bcmx_lport_to_modid
   1365  * Purpose:
   1366  *     Map an LPORT to its mod id, if appropriate.
   1367  * Parameters:
   1368  *     lport - The lport to lookup
   1369  *     modid - (OUT) Returns the modid for given port
   1370  * Returns:
   1371  *     BCM_E_XXX
   1372  */
   1373 int
   1374 bcmx_lport_to_modid(bcmx_lport_t lport, int *modid)
   1375 {
   1376     int         rv;
   1377     bcm_port_t  modport;
   1378 
   1379     rv = bcmx_lport_to_modid_port(lport, modid, &modport);
   1380 
   1381     return rv;
   1382 }
   1383 
   1384 
   1385 /*
   1386  * Function:
   1387  *     bcmx_unit_port_to_lport
   1388  * Purpose:
   1389  *     Map BCM unit and port number to logical port.
   1390  * Parameters:
   1391  *     unit - BCM unit to map
   1392  *     port - Unit's port to map
   1393  * Returns:
   1394  *     lport value
   1395  * Notes:
   1396  */
   1397 bcmx_lport_t
   1398 bcmx_unit_port_to_lport(int unit, bcm_port_t port)
   1399 {
   1400     bcmx_lport_t          lport = BCMX_LPORT_INVALID;
   1401     bcm_gport_t           key;
   1402     int                   index;
   1403     _bcmx_devport_hash_t  *devport;
   1404 
   1405     if (!BCMX_READY) {
   1406         return BCMX_LPORT_INVALID;
   1407     }
   1408 
   1409     BCMX_CONFIG_LOCK;
   1410 
   1411     BCM_GPORT_DEVPORT_SET(key, unit, port);
   1412     index = BCMX_PORT_HASH_INDEX(key);
   1413 
   1414     devport = _bcmx_devport_hash[index];
   1415     while (devport != NULL) {
   1416         if (devport->key == key) {
   1417             if (devport->port_info != NULL) {
   1418                 lport = devport->port_info->lport;
   1419             }
   1420             break;
   1421         }
   1422         devport = devport->next;
   1423     }
   1424 
   1425     BCMX_CONFIG_UNLOCK;   
   1426 
   1427     return lport;
   1428 }
   1429 
   1430 
   1431 /*
   1432  * Function:
   1433  *     bcmx_modid_port_to_lport
   1434  * Purpose:
   1435  *     Map module ID and physical port to logical port.
   1436  * Parameters:
   1437  *     modid - System mod id to map
   1438  *     port  - Unit's port to map
   1439  * Returns:
   1440  *     lport value
   1441  * Notes:
   1442  */
   1443 bcmx_lport_t
   1444 bcmx_modid_port_to_lport(int modid, bcm_port_t port)
   1445 {
   1446     bcmx_lport_t       lport = BCMX_LPORT_INVALID;
   1447     bcm_gport_t        key;
   1448     int                index;
   1449     _bcmx_port_info_t  *port_info;
   1450 
   1451     if (!BCMX_READY) {
   1452         return BCMX_LPORT_INVALID;
   1453     }
   1454 
   1455     /* Generate hash key (gport value) from mod/port */
   1456     BCM_GPORT_MODPORT_SET(key, modid, port);
   1457     
   1458     BCMX_CONFIG_LOCK;
   1459     if ((port_info = _bcmx_port_info_find(key, &index)) != NULL) {
   1460         if ((port_info->port.modid == modid) &&
   1461             (port_info->port.modport == port)) {
   1462             lport = key;
   1463         }
   1464     }
   1465     BCMX_CONFIG_UNLOCK;
   1466 
   1467     return lport;
   1468 }
   1469 
   1470 
   1471 /*
   1472  * Function:
   1473  *     bcmx_uport_to_lport
   1474  * Purpose:
   1475  *     Map a user port to a BCMX lport.
   1476  * Parameters:
   1477  *     uport - The user port
   1478  * Returns:
   1479  *     lport; may be invalid if uport not found.
   1480  *     You can also use the macro BCMX_UPORT_TO_LPORT
   1481  */
   1482 bcmx_lport_t
   1483 bcmx_uport_to_lport(bcmx_uport_t uport)
   1484 {
   1485     _bcmx_uport_hash_t  *cur;
   1486     bcmx_lport_t        lport = BCMX_LPORT_INVALID;
   1487 
   1488     if (!BCMX_READY) {
   1489         return BCMX_LPORT_INVALID;
   1490     }
   1491 
   1492     BCMX_CONFIG_LOCK;
   1493     cur = _bcmx_uport_hash[BCMX_UPORT_HASH(uport)];
   1494     while (cur != NULL) {
   1495         if (BCMX_UPORT_EQ(uport, cur->uport)) {
   1496             lport = cur->lport;
   1497             break;
   1498         }
   1499         cur = cur->next;
   1500     }
   1501     BCMX_CONFIG_UNLOCK;
   1502 
   1503     return lport;
   1504 }
   1505 
   1506 
   1507 /*
   1508  * Function:
   1509  *     bcmx_modid_to_bcm_unit
   1510  * Purpose:
   1511  *     Get the device unit number associated with given module id.
   1512  * Parameters:
   1513  *     modid    - Device module id
   1514  *     bcm_unit - (OUT) The device unit number for given module id
   1515  * Returns:
   1516  *     BCM_E_XXX
   1517  */
   1518 int
   1519 bcmx_modid_to_bcm_unit(int modid, int *bcm_unit)
   1520 {
   1521     int                rv = BCM_E_NOT_FOUND;
   1522     int                i;
   1523     _bcmx_port_info_t  *port_info;
   1524 
   1525     BCMX_READY_CHECK;
   1526     BCMX_PARAM_NULL_CHECK(bcm_unit);
   1527 
   1528     BCMX_CONFIG_LOCK;
   1529 
   1530     /* Check each list */
   1531     for (i = 0; i < BCMX_PORT_HASH_COUNT; i++) {
   1532         port_info = _bcmx_port_info[i];
   1533 
   1534         /* Check each entry in link list */
   1535         while (port_info != NULL) {
   1536             if (port_info->port.modid == modid) {
   1537                 *bcm_unit = port_info->port.bcm_unit;
   1538                 rv = BCM_E_NONE;
   1539                 break;
   1540             }
   1541             port_info = port_info->next;
   1542         }
   1543     }
   1544 
   1545     BCMX_CONFIG_UNLOCK;
   1546 
   1547     return rv;
   1548 }
   1549 
   1550 /*
   1551  * Function:
   1552  *     bcmx_uport_to_unit_port
   1553  * Purpose:
   1554  *     Map a user port to BCM unit and port pair.
   1555  * Parameters:
   1556  *     uport    - The user port
   1557  *     bcm_unit - (OUT) BCM unit
   1558  *     bcm_port - (OUT) BCM port
   1559  * Returns:
   1560  *     BCM_E_XXX
   1561  */
   1562 int
   1563 bcmx_uport_to_unit_port(bcmx_uport_t uport,
   1564                         int *bcm_unit, bcm_port_t *bcm_port)
   1565 {
   1566     int           rv = BCM_E_NOT_FOUND;
   1567     bcmx_lport_t  lport;
   1568 
   1569     BCMX_READY_CHECK;
   1570     BCMX_PARAM_NULL_CHECK(bcm_unit);
   1571     BCMX_PARAM_NULL_CHECK(bcm_port);
   1572 
   1573     BCMX_CONFIG_LOCK;
   1574     if ((lport = bcmx_uport_to_lport(uport)) != BCMX_LPORT_INVALID) {
   1575         rv = bcmx_lport_to_unit_port(lport, bcm_unit, bcm_port);
   1576     }
   1577     BCMX_CONFIG_UNLOCK;
   1578 
   1579     return rv;
   1580 }
   1581 
   1582 
   1583 /*
   1584  * NOTE
   1585  * The following wrapper routines are necessary to maintain
   1586  * support of old public macros.
   1587  */
   1588 int
   1589 bcmx_lport_bcm_unit(bcmx_lport_t lport)
   1590 {
   1591     int         unit = -1;
   1592     bcm_port_t  port = -1;
   1593 
   1594     (void)bcmx_lport_to_unit_port(lport, &unit, &port);
   1595 
   1596     return unit;
   1597 }
   1598 
   1599 bcm_port_t
   1600 bcmx_lport_bcm_port(bcmx_lport_t lport)
   1601 {
   1602     int         unit = -1;
   1603     bcm_port_t  port = -1;
   1604 
   1605     (void)bcmx_lport_to_unit_port(lport, &unit, &port);
   1606 
   1607     return port;
   1608 }
   1609 
   1610 int
   1611 bcmx_lport_modid(bcmx_lport_t lport)
   1612 {
   1613     int         modid = -1;
   1614     bcm_port_t  modport = -1;
   1615 
   1616     (void)bcmx_lport_to_modid_port(lport, &modid, &modport);
   1617 
   1618     return modid;
   1619 }
   1620 
   1621 bcm_port_t
   1622 bcmx_lport_modport(bcmx_lport_t lport)
   1623 {
   1624     int         modid = -1;
   1625     bcm_port_t  modport = -1;
   1626 
   1627     (void)bcmx_lport_to_modid_port(lport, &modid, &modport);
   1628 
   1629     return modport;
   1630 }
   1631 
   1632 uint32
   1633 bcmx_lport_flags(bcmx_lport_t lport)
   1634 {
   1635     uint32  flags = 0x0;
   1636 
   1637     (void)_bcmx_lport_flags_get(lport, &flags);
   1638 
   1639     return flags;
   1640 }
   1641 
   1642 
   1643 /*
   1644  * Function:
   1645  *     _bcmx_port_info_dump
   1646  * Purpose:
   1647  *     Displays internal BCMX port information table.
   1648  *     Used for debugging purposes.
   1649  * Parameters:
   1650  *     none
   1651  * Returns:
   1652  *     BCM_E_XXX
   1653  */
   1654 int
   1655 _bcmx_port_info_dump(void)
   1656 {
   1657     int                i;
   1658     _bcmx_port_info_t  *port_info;
   1659 
   1660     BCMX_INIT_CHECK;
   1661 
   1662     LOG_INFO(BSL_LS_BCMX_COMMON,
   1663              (BSL_META("BCMX port info dump\n")));
   1664 
   1665     BCMX_CONFIG_LOCK;
   1666 
   1667     /* Iterate over hash table link list */
   1668     for (i  = 0; i < BCMX_PORT_HASH_COUNT; i++) {
   1669         port_info = _bcmx_port_info[i];
   1670 
   1671         /* Check each entry in link list */
   1672         while (port_info != NULL) {
   1673             LOG_INFO(BSL_LS_BCMX_COMMON,
   1674                      (BSL_META(" %d: lport=0x%x unit=%d port=%d uport=%d flags=0x%x "
   1675                       "modid=%d modport=%d\n"),
   1676                       i, port_info->lport,
   1677                       port_info->port.bcm_unit, port_info->port.bcm_port,
   1678                       PTR_TO_INT(port_info->port.uport), port_info->port.flags,
   1679                       port_info->port.modid, port_info->port.modport));
   1680             port_info = port_info->next;
   1681         }
   1682     }
   1683 
   1684     BCMX_CONFIG_UNLOCK;
   1685 
   1686     return BCM_E_NONE;
   1687 }
   1688 
   1689 
   1690 /*
   1691  * BCMX Generic Conversion Destination Functions
   1692  *
   1693  * The following set of internal conversion routines for destination
   1694  * to/from BCMX/BCM handle both, old and new gport, BCM port formats.
   1695  *
   1696  * The BCMX driver should use these new routines rather than
   1697  * the previous conversion routines (e.g. bcmx_lport_to_modid_port)
   1698  * which only converts to/from old BCM port format.
   1699  *
   1700  * In addition, these generic routines will help with the current work
   1701  * in progress at the BCM layer to have all APIs handle the new gport
   1702  * format.
   1703  */
   1704  
   1705 /*
   1706  * Function:
   1707  *     _bcmx_dest_bcmx_t_init
   1708  * Purpose:
   1709  *     Initializer routine for BCMX destination structure.
   1710  * Parameters:
   1711  *     dest_bcmx - (OUT) Pointer to structure to initialize
   1712  * Returns:
   1713  *     None
   1714  */
   1715 void
   1716 _bcmx_dest_bcmx_t_init(_bcmx_dest_bcmx_t *dest_bcmx)
   1717 {
   1718     if (dest_bcmx != NULL) {
   1719         dest_bcmx->port  = BCMX_LPORT_INVALID;
   1720         dest_bcmx->trunk = BCM_TRUNK_INVALID;
   1721         dest_bcmx->mcast = -1;
   1722     }
   1723 }
   1724 
   1725 /*
   1726  * Function:
   1727  *     _bcmx_dest_bcm_t_init
   1728  * Purpose:
   1729  *     Initializer routine for BCM destination structure.
   1730  * Parameters:
   1731  *     dest_bcm - (OUT) Pointer to structure to initialize
   1732  * Returns:
   1733  *     None
   1734  */
   1735 void
   1736 _bcmx_dest_bcm_t_init(_bcmx_dest_bcm_t *dest_bcm)
   1737 {
   1738      if (dest_bcm != NULL) {
   1739          dest_bcm->unit        = -1;
   1740          dest_bcm->port        = BCM_GPORT_INVALID;
   1741          dest_bcm->module_id   = -1;
   1742          dest_bcm->module_port = BCM_GPORT_INVALID;
   1743          dest_bcm->trunk       = BCM_TRUNK_INVALID;
   1744          dest_bcm->mcast       = -1;
   1745      }
   1746 }
   1747 
   1748 /*
   1749  * Function:
   1750  *     _bcmx_dest_to_bcm
   1751  * Purpose:
   1752  *     Converts BCMX to BCM destination information.
   1753  *
   1754  *     Translation of data is on flags setting and one in following order:
   1755  *     (a) If MCAST flag is set, set mcast field using old format
   1756  *     (b) If TRUNK flag is set, set trunk field using old format
   1757  *     (c) Else,
   1758  *         (c.1) If logical port is in GPORT format:
   1759  *               - If GPORT_AWARE flag is set, direct assignment to port field,
   1760  *                 with the exception of DEVPORT.  See notes below.
   1761  *               - Else, convert to old non-gport format based on GPORT type
   1762  *         (c.2) Else, error
   1763  * Parameters:
   1764  *     from_bcmx - BCMX destination information to convert
   1765  *     to_bcm    - (OUT) Returns converted BCM destination information
   1766  *     flags     - (IN/OUT) Indicates what is being converted
   1767  * Returns:
   1768  *     BCM_E_NONE - Success
   1769  *     BCM_E_xxx  - Failure
   1770  * Notes:
   1771  * (1) A BLACK HOLE gport is being handled at the BCMX layer by setting
   1772  *     the 'discard' flag (if any).   The extra type check can be removed
   1773  *     once BCM handles the BLACK HOLE gport type.
   1774  * (2) Note that when GPORT format is returned, the GPORT value is
   1775  *     returned in both members "port" and "module_port".
   1776  * (3) If given logical port is a DEVPORT, port will return
   1777  *     in old BCM port format regardless of flag.  The unit in DEVPORT
   1778  *     has meaning only in BCMX.
   1779  */
   1780 int
   1781 _bcmx_dest_to_bcm(_bcmx_dest_bcmx_t *from_bcmx, _bcmx_dest_bcm_t *to_bcm,
   1782                   uint32 *flags)
   1783 {
   1784     uint32  flags_out = 0x0;
   1785 
   1786     BCMX_PARAM_NULL_CHECK(to_bcm);
   1787     BCMX_PARAM_NULL_CHECK(from_bcmx);
   1788     BCMX_PARAM_NULL_CHECK(flags);
   1789 
   1790     _bcmx_dest_bcm_t_init(to_bcm);
   1791 
   1792     /* Convert to BCM */
   1793 
   1794     /* Check MCAST flag first */
   1795     if (*flags & BCMX_DEST_MCAST) {
   1796         flags_out |= BCMX_DEST_MCAST;
   1797         to_bcm->mcast = from_bcmx->mcast;
   1798 
   1799     } else if (*flags & BCMX_DEST_TRUNK) {
   1800         /* Check TRUNK flag next */
   1801         flags_out |= BCMX_DEST_TRUNK;
   1802         to_bcm->trunk = from_bcmx->trunk;
   1803 
   1804     } else {
   1805         
   1806         if (BCM_GPORT_IS_SET(from_bcmx->port)) {
   1807             /*
   1808              * If GPORT_AWARE flag is set, direct assignment
   1809              * (BCM can handle gport format).
   1810              */
   1811             if (*flags & BCMX_DEST_GPORT_AWARE) {
   1812                 flags_out |= BCMX_DEST_GPORT_AWARE;
   1813                 to_bcm->port = from_bcmx->port;
   1814                 to_bcm->module_port = from_bcmx->port;
   1815 
   1816                 /* Get also the 'unit' and 'module-id', if applicable */
   1817                 if (BCM_GPORT_IS_MODPORT(from_bcmx->port) ||
   1818                     BCM_GPORT_IS_DEVPORT(from_bcmx->port)) {
   1819                     bcm_port_t  port_tmp = -1;
   1820 
   1821                     (void)bcmx_lport_to_unit_port(from_bcmx->port,
   1822                                                   &to_bcm->unit,
   1823                                                   &port_tmp);
   1824                     /*
   1825                      * If DEVPORT, set the port to old format
   1826                      * since the unit in DEVPORT is in BCMX context and
   1827                      * has no meaning in the corresponding remote device.
   1828                      */
   1829                     if (BCM_GPORT_IS_DEVPORT(from_bcmx->port)) {
   1830                         to_bcm->port = port_tmp;
   1831                         to_bcm->module_port = port_tmp;
   1832                     }
   1833 
   1834                     (void)bcmx_lport_to_modid_port(from_bcmx->port,
   1835                                                    &to_bcm->module_id,
   1836                                                    &port_tmp);
   1837                 }
   1838 
   1839             } else {
   1840                 /*
   1841                  * Convert gport to old format based on GPORT type:
   1842                  *     MCAST           ==> set mcast flag, set mcast
   1843                  *     TRUNK           ==> set trunk flag, set trunk
   1844                  *     BLACK_HOLE      ==> set discard flag, set port
   1845                  *     LOCAL_CPU       ==> set local_cpu flag, set port
   1846                  *     MODPORT/DEVPORT ==> set unit/port and mod/port
   1847                  *     Other           ==> direct assignment
   1848                  */
   1849                 if (BCM_GPORT_IS_MCAST(from_bcmx->port)) {
   1850                     flags_out |= BCMX_DEST_MCAST;
   1851                     to_bcm->mcast = BCM_GPORT_MCAST_GET(from_bcmx->port);
   1852                     
   1853                 } else if (BCM_GPORT_IS_TRUNK(from_bcmx->port)) {
   1854                     flags_out |= BCMX_DEST_TRUNK;
   1855                     to_bcm->trunk = BCM_GPORT_TRUNK_GET(from_bcmx->port);
   1856 
   1857                 } else if (BCM_GPORT_IS_BLACK_HOLE(from_bcmx->port)) {
   1858                     flags_out |= (BCMX_DEST_DISCARD | BCMX_DEST_GPORT_AWARE);
   1859                     to_bcm->port = from_bcmx->port;
   1860                     to_bcm->module_port = from_bcmx->port;
   1861 
   1862                 } else if (BCM_GPORT_IS_LOCAL_CPU(from_bcmx->port)) {
   1863                     flags_out |= (BCMX_DEST_LOCAL_CPU | BCMX_DEST_GPORT_AWARE);
   1864                     to_bcm->port = from_bcmx->port;
   1865                     to_bcm->module_port = from_bcmx->port;
   1866 
   1867                 } else if (BCM_GPORT_IS_MODPORT(from_bcmx->port) ||
   1868                            BCM_GPORT_IS_DEVPORT(from_bcmx->port)) {
   1869                     /*
   1870                      * NOTE that bcmx_lport_to_modid_port() returns
   1871                      * success when it finds an existing bcmx logical port
   1872                      * (so, some calls could return a modid = -1, but a valid
   1873                      * bcm port number, in cases when the device does not
   1874                      * have a module id assigned to id.
   1875                      */
   1876                     BCM_IF_ERROR_RETURN
   1877                         (bcmx_lport_to_unit_port(from_bcmx->port,
   1878                                                  &to_bcm->unit,
   1879                                                  &to_bcm->port));
   1880                     BCM_IF_ERROR_RETURN
   1881                         (bcmx_lport_to_modid_port(from_bcmx->port,
   1882                                                   &to_bcm->module_id,
   1883                                                   &to_bcm->module_port));
   1884                 } else {
   1885                     flags_out |= BCMX_DEST_GPORT_AWARE;
   1886                     to_bcm->port = from_bcmx->port;
   1887                     to_bcm->module_port = from_bcmx->port;
   1888                 }
   1889             }
   1890 
   1891         } else {
   1892             return BCM_E_PORT;
   1893         }
   1894     }
   1895 
   1896     *flags = flags_out;
   1897 
   1898     return BCM_E_NONE;
   1899 }
   1900 
   1901 /*
   1902  * Function:
   1903  *     _bcmx_dest_from_bcm
   1904  * Purpose:
   1905  *     Converts BCM to BCMX destination information.
   1906  *
   1907  *     Translation of data is on flags setting and one in following order:
   1908  *     (a) If MCAST flag is set, set mcast field using old format
   1909  *     (b) If TRUNK flag is set, set trunk field using old format
   1910  *     (c) Else,
   1911  *         (c.1) If port (either 'port' or 'module_port') is in GPORT format,
   1912  *               direct assignment to BCMX port field
   1913  *         (c.2) Else, translate BCM old format, unit/port or mod/port, to
   1914  *               BCMX lport
   1915  *
   1916  * Parameters:
   1917  *     to_bcmx  - (OUT) Returns converted BCMX destination information
   1918  *     from_bcm - BCM destination information to convert
   1919  *     flags    - (IN/OUT) Indicates what is being converted
   1920  * Returns:
   1921  *     BCM_E_NONE - Success
   1922  *     BCM_E_xxx  - Failure
   1923  */
   1924 int
   1925 _bcmx_dest_from_bcm(_bcmx_dest_bcmx_t *to_bcmx, _bcmx_dest_bcm_t *from_bcm,
   1926                     uint32 *flags)
   1927 {
   1928     uint32  flags_out = 0x0;
   1929 
   1930     BCMX_PARAM_NULL_CHECK(to_bcmx);
   1931     BCMX_PARAM_NULL_CHECK(from_bcm);
   1932     BCMX_PARAM_NULL_CHECK(flags);
   1933 
   1934     _bcmx_dest_bcmx_t_init(to_bcmx);
   1935 
   1936     /* Check MCAST flag first */
   1937     if (*flags & BCMX_DEST_MCAST) {
   1938         flags_out |= BCMX_DEST_MCAST;
   1939         to_bcmx->mcast = from_bcm->mcast;
   1940 
   1941     } else if (*flags & BCMX_DEST_TRUNK) {
   1942         /* Check TRUNK flag next */
   1943         flags_out |= BCMX_DEST_TRUNK;
   1944         to_bcmx->trunk = from_bcm->trunk;
   1945 
   1946     } else {
   1947         /* BCMX lport is always returning in GPORT format */
   1948         flags_out |= BCMX_DEST_GPORT_AWARE;
   1949 
   1950         /*
   1951          * If port is in GPORT format ==> direct assigment
   1952          * NOTE: Use either 'port' or 'module_port' value.
   1953          *       If both are 'valid' gport values, they need to be
   1954          *       the same.
   1955          *
   1956          * Otherwise get the BCMX lport from old format.
   1957          * Try mod/port pair first, if fails, try unit/port
   1958          */
   1959         if (BCM_GPORT_IS_SET(from_bcm->port) && 
   1960             BCM_GPORT_IS_SET(from_bcm->module_port)) {
   1961             if (from_bcm->port != from_bcm->module_port) {
   1962                 return BCM_E_PORT;
   1963             }
   1964             to_bcmx->port = (bcmx_lport_t) from_bcm->port;
   1965 
   1966         } else if (BCM_GPORT_IS_SET(from_bcm->port)) {
   1967             to_bcmx->port = (bcmx_lport_t) from_bcm->port;
   1968 
   1969         } else if (BCM_GPORT_IS_SET(from_bcm->module_port)) {
   1970             to_bcmx->port = (bcmx_lport_t) from_bcm->module_port;
   1971 
   1972         } else {
   1973             /* Convert from old format */
   1974             to_bcmx->port = bcmx_modid_port_to_lport(from_bcm->module_id,
   1975                                                      from_bcm->module_port);
   1976             if (to_bcmx->port == BCMX_LPORT_INVALID) {
   1977                 to_bcmx->port = bcmx_unit_port_to_lport(from_bcm->unit,
   1978                                                         from_bcm->port);
   1979             }
   1980 
   1981             if (to_bcmx->port == BCMX_LPORT_INVALID) {
   1982                 return BCM_E_PORT;
   1983             }
   1984         }
   1985     }
   1986 
   1987     *flags = flags_out;
   1988 
   1989     return BCM_E_NONE;
   1990 }
   1991 
   1992 
   1993 /*
   1994  * Function:
   1995  *     _bcmx_dest_to_modid_port
   1996  * Purpose:
   1997  *     Converts BCMX logical port to BCM module/port destination in
   1998  *     old or new port format, based on flags.
   1999  * Parameters:
   2000  *     port       - BCMX logical port to convert
   2001  *     bcm_module - (OUT) Returns BCM module id (when in old format)
   2002  *     bcm_port   - (OUT) Returns BCM port in old or new gport format
   2003  *     flags      - Indicates whether to convert to old or new BCM port format
   2004  * Returns:
   2005  *     BCM_E_NONE - Success
   2006  *     BCM_E_xxx  - Failure
   2007  * Notes:
   2008  *     Valid flags are:
   2009  *     BCMX_DEST_GPORT_AWARE - Convert to new gport format
   2010  */
   2011 int
   2012 _bcmx_dest_to_modid_port(bcmx_lport_t port,
   2013                          bcm_module_t *bcm_module, bcm_port_t *bcm_port,
   2014                          uint32 flags)
   2015 {
   2016     uint32             flags_orig = flags;
   2017     _bcmx_dest_bcm_t   to_bcm;
   2018     _bcmx_dest_bcmx_t  from_bcmx;
   2019 
   2020     BCMX_DEST_MODID_PORT_FLAG_CHECK(flags);
   2021 
   2022     _bcmx_dest_bcmx_t_init(&from_bcmx);
   2023     from_bcmx.port = port;
   2024 
   2025     BCM_IF_ERROR_RETURN(_bcmx_dest_to_bcm(&from_bcmx, &to_bcm, &flags));
   2026 
   2027     if ((to_bcm.module_port == BCM_GPORT_INVALID) ||
   2028         ((flags_orig & BCMX_DEST_GPORT_AWARE) &&
   2029          !BCM_GPORT_IS_SET(to_bcm.module_port))) {
   2030         return BCM_E_PORT;
   2031     }
   2032 
   2033     *bcm_module = to_bcm.module_id;
   2034     *bcm_port   = to_bcm.module_port;
   2035 
   2036     return BCM_E_NONE;
   2037 }
   2038 
   2039 
   2040 /*
   2041  * Function:
   2042  *     _bcmx_dest_from_modid_port
   2043  * Purpose:
   2044  *     Converts BCM module/port, in old or new gport format, to
   2045  *     BCMX logical port destination.
   2046  * Parameters:
   2047  *     port       - (OUT) Returns BCMX logical port
   2048  *     bcm_module - BCM module id to convert
   2049  *     bcm_port   - BCM port to convert (in old or new gport format)
   2050  *     flags      - Not used currently, but valid flag must be passed in
   2051  * Returns:
   2052  *     BCM_E_NONE - Success
   2053  *     BCM_E_xxx  - Failure
   2054  * Notes:
   2055  *     Valid flags are:
   2056  *     BCMX_DEST_GPORT_AWARE - No effect when converting 'from' BCM
   2057  */
   2058 int
   2059 _bcmx_dest_from_modid_port(bcmx_lport_t *port,
   2060                            bcm_module_t bcm_module, bcm_port_t bcm_port,
   2061                            uint32 flags)
   2062 {
   2063     _bcmx_dest_bcm_t   from_bcm;
   2064     _bcmx_dest_bcmx_t  to_bcmx;
   2065 
   2066     BCMX_DEST_MODID_PORT_FLAG_CHECK(flags);
   2067 
   2068     _bcmx_dest_bcm_t_init(&from_bcm);
   2069     from_bcm.module_id   = bcm_module;
   2070     from_bcm.module_port = bcm_port;
   2071 
   2072     BCM_IF_ERROR_RETURN(_bcmx_dest_from_bcm(&to_bcmx, &from_bcm, &flags));
   2073 
   2074     *port = to_bcmx.port;
   2075 
   2076     return BCM_E_NONE;
   2077 }
   2078 
   2079 /*
   2080  * Function:
   2081  *     _bcmx_dest_to_unit_port
   2082  * Purpose:
   2083  *     Converts BCMX logical port to BCM unit/port destination in
   2084  *     old or new port format, based on flags.
   2085  * Parameters:
   2086  *     port     - BCMX logical port to convert
   2087  *     bcm_unit - (OUT) Returns BCM device unit
   2088  *     bcm_port - (OUT) Returns BCM port in old or new gport format
   2089  *     flags    - Indicates whether to convert to old or new BCM port format
   2090  * Returns:
   2091  *     BCM_E_NONE - Success
   2092  *     BCM_E_xxx  - Failure
   2093  * Notes:
   2094  *     Valid flags are:
   2095  *     BCMX_DEST_GPORT_AWARE - Convert to new gport format
   2096  *
   2097  *     If given 'port' is a DEVPORT, 'bcm_port' will return
   2098  *     in old BCM port format regardless of flag.  The unit in DEVPORT
   2099  *     has meaning only in BCMX.
   2100  */
   2101 int
   2102 _bcmx_dest_to_unit_port(bcmx_lport_t port,
   2103                         int *bcm_unit, bcm_port_t *bcm_port,
   2104                         uint32 flags)
   2105 {
   2106     uint32             flags_orig = flags;
   2107     _bcmx_dest_bcm_t   to_bcm;
   2108     _bcmx_dest_bcmx_t  from_bcmx;
   2109 
   2110     BCMX_DEST_UNIT_PORT_FLAG_CHECK(flags);
   2111 
   2112     _bcmx_dest_bcmx_t_init(&from_bcmx);
   2113     from_bcmx.port = port;
   2114 
   2115     BCM_IF_ERROR_RETURN(_bcmx_dest_to_bcm(&from_bcmx, &to_bcm, &flags));
   2116 
   2117     if ((to_bcm.unit == -1) ||
   2118         (to_bcm.port == BCM_GPORT_INVALID) ||
   2119         (!BCM_GPORT_IS_DEVPORT(from_bcmx.port) &&
   2120          ((flags_orig & BCMX_DEST_GPORT_AWARE) &&
   2121           !BCM_GPORT_IS_SET(to_bcm.port)))) {
   2122         return BCM_E_PORT;
   2123     }
   2124 
   2125     *bcm_unit = to_bcm.unit;
   2126     *bcm_port = to_bcm.port;
   2127 
   2128     return BCM_E_NONE;
   2129 }
   2130 
   2131 /*
   2132  * Function:
   2133  *     _bcmx_dest_from_unit_port
   2134  * Purpose:
   2135  *     Converts BCM unit/port, in old or new gport format, to
   2136  *     BCMX logical port destination.
   2137  * Parameters:
   2138  *     port     - (OUT) Returns BCMX logical port
   2139  *     bcm_unit - BCM device unit to convert
   2140  *     bcm_port - BCM port to convert (in old or new gport format)
   2141  *     flags    - Not used currently, but valid flag must be passed in
   2142  * Returns:
   2143  *     BCM_E_NONE - Success
   2144  *     BCM_E_xxx  - Failure
   2145  * Notes:
   2146  *     Valid flags are:
   2147  *     BCMX_DEST_GPORT_AWARE - No effect when converting 'from' BCM
   2148  */
   2149 int
   2150 _bcmx_dest_from_unit_port(bcmx_lport_t *port,
   2151                           int bcm_unit, bcm_port_t bcm_port,
   2152                           uint32 flags)
   2153 {
   2154     _bcmx_dest_bcm_t   from_bcm;
   2155     _bcmx_dest_bcmx_t  to_bcmx;
   2156 
   2157     BCMX_DEST_UNIT_PORT_FLAG_CHECK(flags);
   2158 
   2159     _bcmx_dest_bcm_t_init(&from_bcm);
   2160     from_bcm.unit = bcm_unit;
   2161     from_bcm.port = bcm_port;
   2162 
   2163     BCM_IF_ERROR_RETURN(_bcmx_dest_from_bcm(&to_bcmx, &from_bcm, &flags));
   2164 
   2165     *port = to_bcmx.port;
   2166 
   2167     return BCM_E_NONE;
   2168 }
   2169 
   2170 /*
   2171  * Function:
   2172  *     _bcmx_error_check
   2173  * Purpose:
   2174  *     Checks given BCM error code as follows:
   2175  *     - If error code is BCM_E_UNAVAIL and unit is fabric,
   2176  *       'rv' value is unchanged and function returns successful.
   2177  *     - If error code is successful or matches the ignore code,
   2178  *       'rv' and function returns successful.
   2179  *     - Else, 'rv' and function returns failure code.
   2180  * Parameters:
   2181  *     unit   - Device unit
   2182  *     check  - Error code to be checked
   2183  *     ignore - Error code to ignore (treated as BCM_E_NONE)
   2184  *     rv     - (IN/OUT) Returns value based on above logic.
   2185  * Returns:
   2186  *    BCM_E_NONE    - Successful, given error code to check is:
   2187  *                      is a successful error code, or
   2188  *                      matches ignore code, or
   2189  *                      is BCM_E_UNAVAIL on a fabric unit
   2190  *    BCM_E_XXX     - Failure
   2191  */
   2192 int
   2193 _bcmx_error_check(int unit, int check, int ignore, int *rv)
   2194 {
   2195     if (BCMX_FABRIC_E_UNAVAIL(unit, check)) {
   2196         return BCM_E_NONE;
   2197     }
   2198 
   2199     if (check == ignore) {
   2200         check = BCM_E_NONE;
   2201     }
   2202 
   2203     *rv = check;
   2204     
   2205     return *rv;
   2206 }