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

l2station.c (64735B)


      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:        l2.c
      8  * Purpose:     Tomahawk3 L2 Station API internal functions
      9  */
     10 
     11 #include <shared/bsl.h>
     12 #include <soc/defs.h>
     13 #include <assert.h>
     14 #include <sal/core/libc.h>
     15 #include <soc/mem.h>
     16 #include <soc/cm.h>
     17 #include <soc/drv.h>
     18 #include <soc/register.h>
     19 #include <soc/memory.h>
     20 #include <soc/hash.h>
     21 #include <soc/l2x.h>
     22 #include <soc/triumph.h>
     23 #include <bcm/l2.h>
     24 #include <bcm/error.h>
     25 #include <bcm_int/esw/mbcm.h>
     26 #include <bcm_int/esw/l2.h>
     27 #include <bcm_int/esw/switch.h>
     28 #ifdef BCM_TOMAHAWK3_SUPPORT
     29 #include <soc/tomahawk3.h>
     30 #include <bcm_int/esw/tomahawk3.h>
     31 
     32 #define GPORT_TYPE(_gport) (((_gport) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK)
     33 
     34 #define _BCM_L2_STATION_ID_INVALID (-1)
     35 #define _BCM_L2_STATION_ID_BASE (1)
     36 #define _BCM_L2_STATION_ID_MAX  (0x1000000)
     37 
     38 /* To differentiate between overlay and underlay tcams */
     39 #define _BCM_L2_STATION_ENTRY_UNDERLAY (0)
     40 #define _BCM_L2_STATION_ENTRY_OVERLAY  (1)
     41 #define _BCM_L2_STATION_ENTRY_LEGACY   _BCM_L2_STATION_ENTRY_UNDERLAY
     42 
     43 #define _BCM_L2_STATION_ENTRY_INSTALLED      (1 << 0)
     44 
     45 #define _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE (1 << 1)
     46 
     47 #define _BCM_L2_STATION_ENTRY_TYPE_NON_TCAM  (1 << 2)
     48 
     49 #define _BCM_L2_STATION_TERM_FLAGS_MASK    (BCM_L2_STATION_IPV4       \
     50                                             | BCM_L2_STATION_IPV6     \
     51                                             | BCM_L2_STATION_ARP_RARP \
     52                                             | BCM_L2_STATION_MPLS)
     53 
     54 /*
     55  * Macro:
     56  *     ParamMax
     57  * Purpose:
     58  *     Determine maximum value that can be stored in the field.
     59  */
     60 #define ParamMax(_unit_, _mem_, _field_)                                      \
     61             ((soc_mem_field_length((_unit_), (_mem_) , (_field_)) < 32) ?     \
     62             ((1 << soc_mem_field_length((_unit_), (_mem_), (_field_))) - 1) : \
     63             (0xFFFFFFFFUL))                             
     64 /*
     65  * Macro:
     66  *     ParamCheck
     67  * Purpose:
     68  *     Check if value can fit in the field and return error if it exceeds
     69  *     the range. 
     70  */
     71 #define ParamCheck(_unit_, _mem_, _field_, _value_)                          \
     72         do {                                                                 \
     73             if (0 == ((uint32)(_value_) <=                                   \
     74                 (uint32)ParamMax((_unit_), (_mem_), (_field_)))) {           \
     75                     LOG_ERROR(BSL_LS_BCM_L2, \
     76                               (BSL_META("L2(unit %d) Error: _value_ %d > %d (max)" \
     77                                " mem (%d) field (%d).\n"), _unit_, (_value_),    \
     78                                (uint32)ParamMax((_unit_), (_mem_), (_field_)),  \
     79                                (_mem_), (_field_)));                            \
     80                     return (BCM_E_PARAM);                                    \
     81             }                                                                \
     82         } while(0)
     83 
     84 /*
     85  * Macro:
     86  *     SC_LOCK
     87  * Purpose:
     88  *     Lock take the Field control mutex
     89  */
     90 #define SC_LOCK(control) \
     91             sal_mutex_take((control)->sc_lock, sal_mutex_FOREVER)
     92 
     93 /*
     94  * Macro:
     95  *     SC_UNLOCK
     96  * Purpose:
     97  *     Lock take the station control mutex
     98  */
     99 #define SC_UNLOCK(control) \
    100             sal_mutex_give((control)->sc_lock);
    101 
    102 static int th3_l2_prio_with_no_free_entries = FALSE;
    103 static _bcm_l2_station_control_t *_th3_l2_station_control[BCM_MAX_NUM_UNITS] = {NULL};
    104 
    105 /*
    106  * Function:
    107  *     _bcm_th3_l2_station_control_get
    108  * Purpose:
    109  *     Get device station control structure pointer.
    110  * Parameters:
    111  *     unit  - (IN) BCM device number
    112  *     sc    - (OUT) Device station structure pointer. 
    113  * Retruns:
    114  *     BCM_E_XXX
    115  * Note:
    116  * Use this function to replace _bcm_l2_station_control_get
    117  */
    118 int
    119 _bcm_th3_l2_station_control_get(int unit, _bcm_l2_station_control_t **sc)
    120 {
    121 
    122     /* Input parameter check */
    123     if (NULL == sc) {
    124         return (BCM_E_PARAM);
    125     }
    126 
    127     if (NULL == _th3_l2_station_control[unit]) {
    128         return (BCM_E_INIT);
    129     }
    130 
    131     *sc = _th3_l2_station_control[unit];
    132 
    133     return (BCM_E_NONE);
    134 }
    135 
    136 /*
    137  * Function:
    138  *     _bcm_l2_station_control_deinit
    139  * Purpose:
    140  *     Uninitialize device station control information.
    141  * Parameters:
    142  *     unit  - (IN) BCM device number
    143  * Retruns:
    144  *     BCM_E_XXX
    145  */
    146 int
    147 _bcm_th3_l2_station_control_deinit(int unit)
    148 {
    149     _bcm_l2_station_control_t  *sc; /* Station control structure pointer. */
    150 
    151     sc = _th3_l2_station_control[unit];
    152     if (NULL == sc) {
    153         return (BCM_E_NONE);
    154     }
    155 
    156     BCM_IF_ERROR_RETURN
    157         (bcm_th3_l2_station_delete_all(unit));
    158 
    159     if (NULL != sc->entry_arr) {
    160         sal_free(sc->entry_arr);
    161         sc->entry_arr = NULL;
    162     }
    163 
    164     if (NULL != sc->entry_arr_2) {
    165         sal_free(sc->entry_arr_2);
    166         sc->entry_arr_2 = NULL;
    167     }
    168 
    169     if (NULL != sc->sc_lock) {
    170         sal_mutex_destroy(sc->sc_lock);
    171     }
    172 
    173     _th3_l2_station_control[unit] = NULL;
    174 
    175     sal_free(sc);
    176 
    177     return (BCM_E_NONE);
    178 }
    179 
    180 /*
    181  * Function:
    182  *     _bcm_th3_l2_station_control_init
    183  * Purpose:
    184  *     Initialize device station control information
    185  * Parameters:
    186  *     unit  - (IN) BCM device number
    187  * Retruns:
    188  *     BCM_E_XXX
    189  */
    190 int
    191 _bcm_th3_l2_station_control_init(int unit)
    192 {
    193     int                        rv;          /* Operation return status.     */
    194     _bcm_l2_station_control_t  *sc = NULL;  /* Station control structure.   */
    195     uint32                     mem_size;    /* Size of entry buffer.        */
    196     uint32                     max_entries; /* Max no. of entries in table. */
    197     int                        i;           /* Temporary iterator variable. */
    198 
    199     /* Deinit if control has already been initialized. */
    200     if (NULL != _th3_l2_station_control[unit]) {
    201         rv = _bcm_th3_l2_station_control_deinit(unit);
    202         if (BCM_FAILURE(rv)) {
    203             return (rv);
    204         }
    205     }
    206 
    207     /* Allocate the station control memory for this unit. */
    208     sc = (_bcm_l2_station_control_t *) sal_alloc
    209             (sizeof(_bcm_l2_station_control_t), "L2 station control");
    210     if (sc == NULL) {
    211         return (BCM_E_MEMORY);
    212     }
    213 
    214     sal_memset(sc, 0, sizeof(_bcm_l2_station_control_t));
    215 
    216     sc->last_allocated_sid = (_BCM_L2_STATION_ID_BASE - 1);
    217 
    218     max_entries = soc_mem_index_count(unit, MY_STATION_TCAMm);
    219 
    220     sc->entries_total = max_entries;
    221 
    222     sc->entries_free = max_entries;
    223 
    224     sc->entry_count = 0;
    225 
    226     mem_size = (max_entries * sizeof(_bcm_l2_station_entry_t *));
    227 
    228     sc->entry_arr = (_bcm_l2_station_entry_t **)
    229                         sal_alloc(mem_size, "L2 station entry pointers");
    230     if (sc->entry_arr == NULL) {
    231         sal_free(sc);
    232         sc = NULL;
    233         return (BCM_E_MEMORY);
    234     }
    235 
    236     for (i = 0; i < max_entries; i++) {
    237         sc->entry_arr[i] = NULL;
    238     }
    239 
    240     sc->sc_lock = sal_mutex_create("L2 station control.lock");
    241     if (NULL == sc->sc_lock) {
    242         sal_free(sc->entry_arr);
    243         sc->entry_arr = NULL;
    244         sal_free(sc);
    245         sc = NULL;
    246         return (BCM_E_MEMORY);
    247     }
    248 
    249     _th3_l2_station_control[unit] = sc;
    250 
    251     return (BCM_E_NONE);
    252 }
    253 
    254 STATIC int
    255 _bcm_th3_l2_port_mask_gport_resolve(int unit, bcm_gport_t gport,
    256                                     bcm_module_t *modid, bcm_port_t *port,
    257                                     bcm_trunk_t *trunk_id, int *id)
    258 {
    259     int rv = SOC_E_NONE;
    260 
    261     *modid = -1;
    262     *port = -1;
    263     *trunk_id = BCM_TRUNK_INVALID;
    264     *id = -1;
    265 
    266     if (SOC_GPORT_IS_TRUNK(gport)) {
    267         *trunk_id = SOC_GPORT_TRUNK_GET(gport);
    268     } else if (SOC_GPORT_IS_LOCAL(gport)) {
    269         *modid = SOC_BASE_MODID(unit);
    270         *port = SOC_GPORT_LOCAL_GET(gport);
    271     } else if (SOC_GPORT_IS_MODPORT(gport)) {
    272         *modid = 0; /*SOC_GPORT_MODPORT_MODID_GET(gport); should always be 0 */
    273         *port = SOC_GPORT_MODPORT_PORT_GET(gport);
    274     } else {
    275         rv = SOC_E_PORT;
    276     }
    277 
    278     return rv;
    279 }
    280 
    281 /*
    282  * Function:
    283  *     _bcm_th3_l2_station_entry_set
    284  * Purpose:
    285  *     Set a station entrie's parameters to entry buffer for hardware table
    286  *     write operation.
    287  * Parameters:
    288  *     unit       - (IN) BCM device number
    289  *     tcam_mem   - (IN) Hardware memory name.
    290  *     station    - (IN) Station parameters to be set in hardware.
    291  *     ent_p      - (IN) Software station entry pointer.
    292  * Returns:
    293  *     BCM_E_XXX
    294  */
    295 STATIC int
    296 _bcm_th3_l2_station_entry_set(int unit,
    297                               soc_mem_t tcam_mem,
    298                               bcm_l2_station_t *station,
    299                               _bcm_l2_station_entry_t *ent_p)
    300 {
    301     int gport_id = -1;
    302     bcm_port_t port_out = 0;
    303     bcm_module_t mod_out = 0;
    304     bcm_trunk_t trunk_id = BCM_TRUNK_INVALID;
    305     uint32 mod_port_data = 0; /* concatenated modid and port */
    306     bcm_port_t port_out_mask;
    307     bcm_module_t mod_out_mask;
    308     bcm_trunk_t trunk_id_mask = -1;  
    309     int gport_id_mask = -1;
    310     uint32 mod_port_mask = 0; /* concatenated modid and port */
    311     int rv=0;
    312     int num_bits_for_port;
    313 
    314     soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, VALIDf,
    315         (1 << soc_mem_field_length(unit, tcam_mem, VALIDf)) - 1);
    316 
    317     soc_mem_mac_addr_set(unit, tcam_mem, ent_p->tcam_ent,
    318                          MAC_ADDRf, station->dst_mac);
    319 
    320     soc_mem_mac_addr_set(unit, tcam_mem, ent_p->tcam_ent,
    321                          MAC_ADDR_MASKf, station->dst_mac_mask);
    322 
    323     soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    324                         VLAN_IDf, station->vlan);
    325 
    326     soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    327                         VLAN_ID_MASKf, station->vlan_mask);
    328 
    329     /* validate both src_port and src_port_mask has the same type */
    330     if (GPORT_TYPE(station->src_port) != GPORT_TYPE(station->src_port_mask)) {
    331         return BCM_E_PARAM;
    332     }
    333  
    334     if (BCM_GPORT_IS_SET(station->src_port)) {
    335         rv = _bcm_esw_gport_resolve(unit, station->src_port, 
    336                       &mod_out, 
    337                       &port_out, &trunk_id,
    338                       &gport_id);
    339         BCM_IF_ERROR_RETURN(rv);
    340 
    341         if (BCM_GPORT_IS_TRUNK(station->src_port)) {
    342             if (BCM_TRUNK_INVALID == trunk_id) {
    343                 return BCM_E_PORT;
    344             }
    345         } else {
    346             if ((mod_out == -1) || (port_out == -1)) {
    347                 return BCM_E_PORT;
    348             }
    349         }
    350 
    351         /* retrieve the port mask */
    352         rv = _bcm_th3_l2_port_mask_gport_resolve(unit,
    353                                                  station->src_port_mask,
    354                                                  &mod_out_mask,
    355                                                  &port_out_mask,
    356                                                  &trunk_id_mask,
    357                                                  &gport_id_mask);
    358         BCM_IF_ERROR_RETURN(rv);
    359     } else {
    360         port_out = station->src_port;
    361         port_out_mask = station->src_port_mask;
    362         mod_out = 0;
    363         mod_out_mask = 0;
    364     }
    365 
    366     if (trunk_id != BCM_TRUNK_INVALID) {
    367 
    368         /* and the SOURCE_FIELDf supports the trunk operation */
    369         SOC_IF_ERROR_RETURN(soc_mem_field32_fit(unit, tcam_mem, 
    370                             SOURCE_FIELD_MASKf,
    371                             1 << SOC_TRUNK_BIT_POS(unit)));
    372 
    373         mod_port_data = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id);
    374         mod_port_mask = trunk_id_mask & 
    375             ((1 << SOC_TRUNK_BIT_POS(unit)) - 1);
    376         mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit));
    377 
    378         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, SOURCE_FIELDf,
    379                             mod_port_data);
    380         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent, SOURCE_FIELD_MASKf,
    381                             mod_port_mask);
    382     } else {
    383             num_bits_for_port = _shr_popcount(
    384                              (unsigned int)SOC_PORT_ADDR_MAX(unit));
    385 
    386             mod_port_data = (mod_out << num_bits_for_port) | port_out;
    387             mod_port_mask = mod_out_mask & SOC_MODID_MAX(unit);
    388             mod_port_mask <<= num_bits_for_port;
    389             mod_port_mask |= (port_out_mask & SOC_PORT_ADDR_MAX(unit));
    390 
    391             /* Clear the trunk ID bit. */
    392             mod_port_data &= ~(1 << SOC_TRUNK_BIT_POS(unit));
    393 
    394             /* Must match on the T bit (which should be 0) for the devices
    395              * supporting the trunk operation with this field
    396              */
    397             if (BCM_GPORT_IS_SET(station->src_port)) {
    398                 if (soc_mem_field32_fit(unit, tcam_mem, SOURCE_FIELD_MASKf, 
    399                         1 << SOC_TRUNK_BIT_POS(unit)) == SOC_E_NONE) {
    400                     mod_port_mask |= (1 << SOC_TRUNK_BIT_POS(unit));
    401                 }
    402             }
    403 
    404             soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    405                                 SOURCE_FIELDf, mod_port_data);
    406             soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    407                                 SOURCE_FIELD_MASKf, mod_port_mask);
    408         }
    409 
    410         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    411                             MPLS_TERMINATION_ALLOWEDf,
    412                             ((station->flags & BCM_L2_STATION_MPLS) ? 1 : 0));
    413         
    414         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    415                             IPV4_TERMINATION_ALLOWEDf,
    416                             ((station->flags & BCM_L2_STATION_IPV4) ? 1 : 0));
    417 
    418         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    419                             IPV6_TERMINATION_ALLOWEDf,
    420                             ((station->flags & BCM_L2_STATION_IPV6) ? 1 : 0));
    421 
    422         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    423                             ARP_RARP_TERMINATION_ALLOWEDf,
    424                             ((station->flags & BCM_L2_STATION_ARP_RARP) ? 1 : 0));
    425         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    426                             COPY_TO_CPUf,
    427                             ((station->flags & BCM_L2_STATION_COPY_TO_CPU)
    428                             ? 1 : 0));
    429 
    430         soc_mem_field32_set(unit, tcam_mem, ent_p->tcam_ent,
    431                             DISCARDf,
    432                             ((station->flags & BCM_L2_STATION_DISCARD) ? 1 : 0));
    433 
    434     return BCM_E_NONE;
    435 }
    436 
    437 /*
    438  * Function:
    439  *     _bcm_th3_l2_station_entry_update
    440  * Purpose:
    441  *     Allocate an entry buffer and setup entry parameters for hardware write
    442  *     operation.
    443  * Parameters:
    444  *     unit       - (IN) BCM device number
    445  *     sid        - (IN) Station ID.
    446  *     station    - (IN) Station parameters to be set in hardware.
    447  *     ent_p      - (OUT) Pointer to Station entry type data.
    448  * Returns:
    449  *     BCM_E_XXX
    450  */
    451 STATIC int
    452 _bcm_th3_l2_station_entry_update(int unit,
    453                                  int sid,
    454                                  bcm_l2_station_t *station,
    455                                  _bcm_l2_station_entry_t *ent_p)
    456 {
    457     soc_mem_t   tcam_mem;    /* TCAM memory name.         */
    458     int         mem_size = 0; /* Entry buffer size.       */
    459 
    460     /* Input parameter check. */
    461     if (NULL == ent_p || NULL == station) {
    462         return (BCM_E_PARAM);
    463     }
    464 
    465     LOG_DEBUG(BSL_LS_BCM_L2,
    466               (BSL_META_U(unit,
    467                           "L2(unit %d) Info: (SID=%d) (idx=%d) (prio: o=%d n=%d) "
    468                            "- update.\n"), unit, sid, ent_p->hw_index, ent_p->prio,
    469                station->priority));
    470 
    471     if (ent_p->prio == station->priority) {
    472         ent_p->flags |= _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE;
    473     } else {
    474         ent_p->prio = station->priority;
    475     }
    476 
    477 
    478     tcam_mem = MY_STATION_TCAMm;
    479     mem_size = sizeof(my_station_tcam_entry_t);
    480 
    481     if (mem_size == 0) {
    482         /* Must be a valid mem_size value. */
    483         return (BCM_E_INTERNAL);
    484     }
    485 
    486     ent_p->tcam_ent = sal_alloc(mem_size, "L2 station entry buffer");
    487     if (ent_p->tcam_ent == NULL) {
    488         return (BCM_E_MEMORY);
    489     }
    490 
    491     sal_memset(ent_p->tcam_ent, 0, mem_size);
    492     
    493     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_entry_set(unit, tcam_mem, 
    494                            station, ent_p));
    495 
    496     return (BCM_E_NONE);
    497 }
    498 
    499 /*
    500  * Function:
    501  *     _bcm_th3_l2_station_entry_create
    502  * Purpose:
    503  *     Allocate an entry buffer and setup entry parameters for hardware write
    504  *     operation.
    505  * Parameters:
    506  *     unit       - (IN) BCM device number
    507  *     sid        - (IN) Station ID.
    508  *     station    - (IN) Station parameters to be set in hardware.
    509  *     ent_p      - (OUT) Pointer to Station entry type data.
    510  * Returns:
    511  *     BCM_E_XXX
    512  */
    513 STATIC int
    514 _bcm_th3_l2_station_entry_create(int unit,
    515                              int sid,
    516                              bcm_l2_station_t *station,
    517                              _bcm_l2_station_entry_t **ent_pp)
    518 {
    519     _bcm_l2_station_control_t *sc;           /* Station control structure. */
    520     int                       index;         /* Entry index.               */
    521     _bcm_l2_station_entry_t   *ent_p = NULL; /* L2 station entry pointer.  */
    522     soc_mem_t                 tcam_mem;      /* TCAM memory name.          */ 
    523     int                       mem_size = 0;  /* Entry buffer size.         */
    524     int                       rv;            /* Operation return status.   */
    525     int                       entries_total;
    526     _bcm_l2_station_entry_t   **entry_arr;
    527 
    528     /* Input parameter check. */
    529     if (NULL == station || NULL == ent_pp) {
    530         return (BCM_E_PARAM);
    531     }
    532     
    533     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
    534 
    535     if (0 == sc->entries_free) {
    536         return (BCM_E_RESOURCE);
    537     }
    538     entry_arr = (sc->entry_arr);
    539     entries_total = sc->entries_total;
    540 
    541     ent_p = (_bcm_l2_station_entry_t *)
    542         sal_alloc(sizeof(_bcm_l2_station_entry_t), "Sw L2 station entry");
    543     if (NULL == ent_p) {
    544         return (BCM_E_MEMORY);
    545     }
    546 
    547     sal_memset(ent_p, 0, sizeof(_bcm_l2_station_entry_t));
    548     ent_p->sid = sid;
    549     ent_p->prio = station->priority;
    550 
    551     if (0 == sc->entries_free) {
    552         sal_free(ent_p);
    553         return (BCM_E_RESOURCE);
    554     }
    555 
    556     /* Get the first free slot. */
    557     for (index = 0; index < entries_total; index++) {
    558         if (NULL == entry_arr[index]) {
    559             ent_p->hw_index = index;
    560             break;
    561         }
    562     }
    563 
    564     tcam_mem = MY_STATION_TCAMm;
    565     mem_size = sizeof(my_station_tcam_entry_t);
    566 
    567     if (mem_size == 0) {
    568         /* mem_size must be greater than zero. */
    569         sal_free(ent_p);
    570         return (BCM_E_INTERNAL);
    571     }
    572 
    573     ent_p->tcam_ent = sal_alloc(mem_size, "L2 station entry buffer");
    574     if (NULL == ent_p->tcam_ent) {
    575         sal_free(ent_p);
    576         return (BCM_E_MEMORY);
    577     }
    578 
    579     sal_memset(ent_p->tcam_ent, 0, mem_size);
    580 
    581     rv = _bcm_th3_l2_station_entry_set(unit, tcam_mem, station, ent_p);
    582     if (BCM_FAILURE(rv)) {
    583         sal_free(ent_p->tcam_ent);
    584         sal_free(ent_p);
    585         return (rv);
    586     }
    587 
    588     /* Decrement free entries count */
    589     sc->entries_free--;
    590     sc->entry_count++;
    591     sc->entry_arr[index] = ent_p;
    592 
    593     *ent_pp = ent_p;
    594 
    595     return (BCM_E_NONE);
    596 
    597 }
    598 
    599 /*
    600  * Function:
    601  *     _bcm_th3_l2_station_entry_prio_cmp
    602  * Purpose:
    603  *     Compare station entry priority values.
    604  * Parameters:
    605  *     prio_first   - (IN) First entry priority value.
    606  *     prio_second  - (IN) Second entry priority value.
    607  * Returns:
    608  *     0    - if both priority values are equal.
    609  *     -1   - if priority value of first entry is lower than second.
    610  *     1    - if priority value of first entry is greater than second.
    611  */
    612 STATIC int
    613 _bcm_th3_l2_station_entry_prio_cmp(int prio_first, int prio_second)
    614 {
    615     int rv; /* Comparison result. */
    616 
    617     if (prio_first == prio_second) {
    618         rv = 0;
    619     } else if (prio_first < prio_second) {
    620         rv = -1;
    621     } else {
    622         rv = 1;
    623     }
    624     return (rv);
    625 }
    626 
    627 /*
    628  * Function:
    629  *     _bcm_th3_l2_station_prio_move_required
    630  * Purpose:
    631  *     Check if entry move is required based on priority value.
    632  * Parameters:
    633  *     unit   - (IN) BCM device number
    634  *     ent_p  - (IN) Station entry for priority comparison.
    635  * Returns:
    636  *     TRUE   - Entry move is required based on priority comparison.
    637  *     FALSE  - Entry move is not required based on priority comparison.
    638  */
    639 STATIC int
    640 _bcm_th3_l2_station_prio_move_required(int unit, _bcm_l2_station_entry_t *ent_p)
    641 {
    642     _bcm_l2_station_control_t *sc;      /* station control structure.   */
    643     _bcm_l2_station_entry_t **entry_arr;/* station entry array pointer  */
    644     uint32                    count;    /* Maximum number of entries.   */
    645     int                       i;        /* Temporary iterator variable. */
    646     int                       ent_prio; /* Entry priority.              */
    647     int                       flag;     /* Flag value denotes if we are */
    648                                         /* before or after s_ent.       */
    649 
    650     /* Input parameter check. */
    651     if (NULL == ent_p) {
    652         return (BCM_E_INTERNAL);
    653     }
    654 
    655     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
    656 
    657     /* Get total number for entries supported. */
    658     count = sc->entries_total;
    659     entry_arr = (sc->entry_arr);
    660 
    661     /* Get the entry priority value. */
    662     ent_prio = ent_p->prio;
    663 
    664     /* Init flag value, we are before s_ent. */
    665     flag = -1;
    666 
    667     for (i = 0; i < count; i++) {
    668 
    669         if (entry_arr[i] == ent_p) {
    670             /* Now we are after s_ent. */
    671             flag = 1;
    672             continue;
    673         }
    674 
    675         if (NULL == entry_arr[i]) {
    676             continue;
    677         }
    678 
    679         if (-1 == flag) {
    680             if (_bcm_th3_l2_station_entry_prio_cmp(entry_arr[i]->prio,
    681                                                    ent_prio) < 0) {
    682 
    683                 LOG_DEBUG(BSL_LS_BCM_L2,
    684                           (BSL_META_U(unit,
    685                                       "L2(unit %d) Info: (SID=%d) found lower prio than "
    686                                        "(prio=%d).\n"), unit, ent_p->sid, ent_p->prio));
    687 
    688                 /*
    689                  * An entry  before s_ent has lower priority.
    690                  * So, move is required.
    691                  */
    692                 return (TRUE);
    693             }
    694         } else {
    695             if (_bcm_th3_l2_station_entry_prio_cmp(entry_arr[i]->prio,
    696                                                    ent_prio) > 0) {
    697                 LOG_DEBUG(BSL_LS_BCM_L2,
    698                           (BSL_META_U(unit,
    699                                       "L2(unit %d) Info: (SID=%d) found higher prio than "
    700                                        "(prio=%d).\n"), unit, ent_p->sid, ent_p->prio));
    701                 /*
    702                  * An entry after s_ent has higher priority than s_ent prio.
    703                  * So, move is required.
    704                  */
    705                 return (TRUE);
    706             }
    707         }
    708     }
    709 
    710     LOG_DEBUG(BSL_LS_BCM_L2,
    711               (BSL_META_U(unit,
    712                           "L2(unit %d) Info: (SID=%d) (prio=%d) no move.\n"),
    713                unit, ent_p->sid, ent_p->prio));
    714 
    715     return (FALSE);
    716 }
    717 
    718 /*
    719  * Function:
    720  *     _bcm_th3_l2_station_entry_move_check
    721  * Purpose:
    722  *     Calculate number of entries that need to be moved for installing the
    723  *     new station entry.
    724  * Parameters:
    725  *     unit                     - (IN) BCM device number
    726  *     null_index               - (IN) Free null entry hardware index.
    727  *     target_index             - (IN) Target hardware index for the entry.
    728  *     direction                - (IN) Direction of Move.
    729  *     shifted_entries_count    - (OUT) No. of entries to be moved.
    730  * Returns:
    731  *     BCM_E_NONE
    732  */
    733 STATIC int
    734 _bcm_th3_l2_station_entry_move_check(int unit, int null_index,
    735                                      int target_index, int direction,
    736                                      int *shifted_entries_count)
    737 {
    738     *shifted_entries_count += direction * (null_index - target_index);
    739 
    740     return (BCM_E_NONE);
    741 }
    742 
    743 /*
    744  * Function:
    745  *     _bcm_th3_l2_station_entry_dir_get
    746  * Purpose:
    747  *     Find out direction in which entries need to be moved for installing
    748  *     new station entry in hardware.
    749  * Parameters:
    750  *     unit             - (IN) BCM device number
    751  *     ent_p            - (IN) Station entry pointer.
    752  *     prev_null_index  - (IN) Location of previous null entry in hardware.
    753  *     next_null_index  - (IN) Location of next null entry in hardware.
    754  *     target_index     - (IN) Target index where entry needs to be installed.
    755  *     dir              - (OUT) Direction in which entries need to be moved.
    756  * Returns:
    757  *     BCM_E_XXX
    758  */
    759 STATIC int
    760 _bcm_th3_l2_station_entry_dir_get(int unit,
    761                                   _bcm_l2_station_entry_t *ent_p,
    762                                   int prev_null_index,
    763                                   int next_null_index,
    764                                   int target_index,
    765                                   int *dir)
    766 {
    767     _bcm_l2_station_control_t  *sc;                   /* Station control    */
    768                                                       /* strucutre.         */
    769     int                        shift_up = FALSE;      /* Shift UP status.   */
    770     int                        shift_down = FALSE;    /* Shift DOWN status. */
    771     int                        shift_up_amount = 0;   /* Shift UP amount.   */
    772     int                        shift_down_amount = 0; /* Shift DOWN amount. */
    773     int                        rv;                    /* Operation return   */
    774                                                       /* status.            */
    775 
    776     /* Input parameter check. */
    777     if (NULL == ent_p || NULL == dir) {
    778         return (BCM_E_PARAM);
    779     }
    780 
    781     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
    782 
    783     if (prev_null_index != -1) {
    784         rv = _bcm_th3_l2_station_entry_move_check(unit, prev_null_index,
    785                                                   target_index, -1,
    786                                                   &shift_up_amount);
    787         shift_up = BCM_SUCCESS(rv);
    788     } else {
    789         shift_up = FALSE;
    790     }
    791 
    792     if (next_null_index != -1) {
    793         rv = _bcm_th3_l2_station_entry_move_check(unit, next_null_index,
    794                                                   target_index, 1,
    795                                                   &shift_down_amount);
    796         shift_down = BCM_SUCCESS(rv);
    797     } else {
    798         shift_down = FALSE;
    799     }
    800 
    801     if (shift_up == TRUE) {
    802         if (shift_down == TRUE) {
    803             if (shift_up_amount < shift_down_amount) {
    804                 *dir = -1;
    805             } else {
    806                 *dir = 1;
    807             }
    808         } else {
    809             *dir = -1;
    810         }
    811     } else {
    812         if (shift_down == TRUE) {
    813             *dir = 1;
    814         } else {
    815             return FALSE;
    816         }
    817     }
    818     return TRUE;
    819 }
    820 
    821 /*
    822  * Function:
    823  *     _bcm_th3_l2_station_entry_move
    824  * Purpose:
    825  *     Move a station entry by a specified amount
    826  * Parameters:
    827  *     unit     - (IN) BCM device number
    828  *     s_ent    - (IN) Station entry pointer.
    829  *     amount   - (IN) Direction in which entries need to be moved.
    830  * Returns:
    831  *     BCM_E_XXX
    832  */
    833 STATIC int
    834 _bcm_th3_l2_station_entry_move(int unit,
    835                                _bcm_l2_station_entry_t *s_ent,
    836                                int amount)
    837 {
    838     _bcm_l2_station_control_t   *sc;          /* Station control structure. */
    839     _bcm_l2_station_entry_t   **entry_arr;    /* Station entry pointer . */
    840     int                         tcam_idx_old; /* Original entry TCAM index. */
    841     int                         tcam_idx_new; /* Entry new TCAM index.      */
    842     int                         rv;           /* Operation return status.   */
    843     soc_mem_t                   tcam_mem;     /* TCAM memory name.          */
    844     uint32                      entry[SOC_MAX_MEM_FIELD_WORDS]; /* Entry    */
    845                                                                 /* buffer.  */
    846     int                         count;
    847 
    848     /* Input parameter check. */
    849     if (s_ent == NULL) {
    850         return (BCM_E_PARAM);
    851     }
    852 
    853     /* Input parameter check. */
    854     if (amount == 0) {
    855         return (BCM_E_NONE);
    856     }
    857 
    858     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
    859 
    860     tcam_idx_old =  s_ent->hw_index;
    861 
    862     tcam_idx_new = tcam_idx_old + amount;
    863 
    864     LOG_DEBUG(BSL_LS_BCM_L2,
    865               (BSL_META_U(unit,
    866                           "L2(unit %d) Info: (SID=%d) move (oidx=%d nidx=%d) (amt=%d).\n"),
    867                unit, s_ent->sid, s_ent->hw_index, tcam_idx_new, amount));
    868 
    869     count = sc->entries_total;
    870     entry_arr = (sc->entry_arr);
    871 
    872     if (tcam_idx_old < 0 || tcam_idx_old >= count) {
    873         return (BCM_E_PARAM);
    874     }
    875 
    876     tcam_mem = MY_STATION_TCAMm;
    877 
    878     if (s_ent->flags & _BCM_L2_STATION_ENTRY_INSTALLED) {
    879         /* Clear entry buffer */
    880         sal_memset(entry, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    881 
    882         rv = soc_mem_read(unit, tcam_mem, MEM_BLOCK_ANY, tcam_idx_old, entry);
    883         BCM_IF_ERROR_RETURN(rv);
    884 
    885         rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, tcam_idx_new, entry);
    886         BCM_IF_ERROR_RETURN(rv);
    887 
    888         rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, tcam_idx_old,
    889                            soc_mem_entry_null(unit, tcam_mem));
    890         BCM_IF_ERROR_RETURN(rv);
    891     }
    892 
    893     if (th3_l2_prio_with_no_free_entries == FALSE) {
    894         entry_arr[s_ent->hw_index] = NULL;
    895     }
    896 
    897     entry_arr[tcam_idx_new] = s_ent;
    898 
    899     s_ent->hw_index = tcam_idx_new;
    900 
    901     return (BCM_E_NONE);
    902 }
    903 
    904 /*
    905  * Function:
    906  *     _bcm_th3_l2_station_entry_shift_down
    907  * Purpose:
    908  *     Shift entries down by one index to create a free entry at target
    909  *     index location.
    910  * Parameters:
    911  *     unit             - (IN) BCM device number
    912  *     target_index     - (IN) Target index for entry install operation.
    913  *     next_null_index  - (IN) Location of free entry after target index.
    914  * Returns:
    915  *     BCM_E_XXX
    916  */
    917 STATIC int
    918 _bcm_th3_l2_station_entry_shift_down(int unit,
    919                                      int overlay,
    920                                      int target_index,
    921                                      int next_null_index)
    922 {
    923     uint16                      empty_idx;   /* Empty index.               */
    924     _bcm_l2_station_control_t   *sc;         /* Station control structure. */
    925     _bcm_l2_station_entry_t     **entry_arr; /* Station entry pointer */
    926     int                         tmp_idx1;    /* Temporary index.           */
    927     int                         tmp_idx2;    /* Temporary index.           */ 
    928     int                         max_entries; /* Maximum entries supported. */
    929     int                         rv;          /* Operation return status.   */
    930 
    931     LOG_DEBUG(BSL_LS_BCM_L2,
    932               (BSL_META_U(unit,
    933                           "L2(unit %d) Info: Shift UP (tidx=%d null-idx=%d).\n"),
    934                unit, target_index, next_null_index));
    935 
    936     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
    937 
    938     empty_idx = next_null_index;
    939 
    940     max_entries = sc->entries_total;
    941     entry_arr = (sc->entry_arr);
    942 
    943     /*
    944      * Move entries one step down
    945      *     starting from the last entry
    946      * IDEA: 
    947      *     Move till empty_idx > target_index  
    948      */
    949     while (empty_idx > target_index) {
    950         if (empty_idx == 0) {
    951             tmp_idx1 = 0;
    952             tmp_idx2 = max_entries - 1;
    953 
    954             rv = _bcm_th3_l2_station_entry_move(unit,
    955                                                 entry_arr[max_entries - 1],
    956                                                 (tmp_idx1 - tmp_idx2));
    957             BCM_IF_ERROR_RETURN(rv);
    958         } else {
    959             tmp_idx1 = empty_idx;
    960             tmp_idx2 = (empty_idx - 1);
    961             rv = _bcm_th3_l2_station_entry_move(unit,
    962                                                 entry_arr[empty_idx - 1],
    963                                                 (tmp_idx1 - tmp_idx2));
    964             BCM_IF_ERROR_RETURN(rv);
    965 
    966             empty_idx--;
    967         }
    968     }
    969 
    970     return (BCM_E_NONE);
    971 }
    972 
    973 /*
    974  * Function:
    975  *     _bcm_th3_l2_station_entry_shift_up
    976  * Purpose:
    977  *     Shift entries up by one index to create a free entry at target
    978  *     index location.
    979  * Parameters:
    980  *     unit             - (IN) BCM device number
    981  *     target_index     - (IN) Target index for entry install operation.
    982  *     prev_null_index  - (IN) Location of free entry before target index.
    983  * Returns:
    984  *     BCM_E_XXX
    985  */
    986 STATIC int
    987 _bcm_th3_l2_station_entry_shift_up(int unit,
    988                                    int overlay,
    989                                    int target_index,
    990                                    int prev_null_index)
    991 {
    992     uint16                      empty_idx;   /* Empty index.               */
    993     _bcm_l2_station_control_t   *sc;         /* Station control structure. */
    994     _bcm_l2_station_entry_t     **entry_arr; /* Station entry pointer */
    995     int                         tmp_idx1;    /* Temporary index.           */
    996     int                         tmp_idx2;    /* Temporary index.           */ 
    997     int                         max_entries; /* Maximum entries supported. */
    998     int                         rv;          /* Operation return status.   */
    999 
   1000     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1001 
   1002     LOG_DEBUG(BSL_LS_BCM_L2,
   1003               (BSL_META_U(unit,
   1004                           "L2(unit %d) Info: Shift UP (tidx=%d null-idx=%d).\n"),
   1005                unit, target_index, prev_null_index));
   1006 
   1007     empty_idx = prev_null_index;
   1008 
   1009     max_entries = sc->entries_total;
   1010     entry_arr = (sc->entry_arr);
   1011 
   1012 
   1013     /*
   1014      * Move entries one step up
   1015      *     starting from the first entry
   1016      * IDEA: 
   1017      *     Move till empty_idx < target_index  
   1018      */
   1019     while (empty_idx < target_index) {
   1020         if (empty_idx == (max_entries - 1)) {
   1021             tmp_idx1 = max_entries - 1;
   1022             tmp_idx2 = 0;
   1023             rv = _bcm_th3_l2_station_entry_move(unit,
   1024                                                 entry_arr[0],
   1025                                                 (tmp_idx1 - tmp_idx2));
   1026             BCM_IF_ERROR_RETURN(rv);
   1027             empty_idx = 0;
   1028         } else {
   1029             tmp_idx1 = empty_idx;
   1030             tmp_idx2 = (empty_idx + 1);
   1031             rv = _bcm_th3_l2_station_entry_move(unit,
   1032                                                 entry_arr[empty_idx + 1],
   1033                                                 (tmp_idx1 - tmp_idx2));
   1034             BCM_IF_ERROR_RETURN(rv);
   1035 
   1036             empty_idx++;
   1037         }
   1038     }
   1039 
   1040     return (BCM_E_NONE);
   1041 }
   1042 
   1043 /*
   1044  * Function:
   1045  *     _bcm_th3_l2_station_entry_install
   1046  * Purpose:
   1047  *     Write a station entry to hardware
   1048  * Parameters:
   1049  *     unit     - (IN) BCM device number
   1050  *     ent_p    - (IN) Pointer to station entry.
   1051  * Returns:
   1052  *     BCM_E_XXX
   1053  */
   1054 STATIC int
   1055 _bcm_th3_l2_station_entry_install(int unit, _bcm_l2_station_entry_t *ent_p)
   1056 {
   1057     int     rv;         /* Operation return status. */ 
   1058     soc_mem_t tcam_mem; /* TCAM memory name.        */
   1059 
   1060     if (ent_p == NULL) {
   1061         return (BCM_E_PARAM);
   1062     }
   1063 
   1064     tcam_mem = MY_STATION_TCAMm;
   1065 
   1066     if (ent_p->tcam_ent == NULL) {
   1067         return (BCM_E_INTERNAL);
   1068     }
   1069 
   1070     LOG_DEBUG(BSL_LS_BCM_L2,
   1071               (BSL_META_U(unit,
   1072                           "L2(unit %d) Info: (SID=%d) - install (idx=%d).\n"),
   1073                unit, ent_p->sid, ent_p->hw_index));
   1074 
   1075     rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, ent_p->hw_index,
   1076                        ent_p->tcam_ent);
   1077 
   1078     sal_free(ent_p->tcam_ent);
   1079 
   1080     ent_p->tcam_ent = NULL;
   1081 
   1082     return (rv);
   1083 }
   1084 
   1085 
   1086 /*
   1087  * Function:
   1088  *     _bcm_th3_l2_station_entry_prio_install
   1089  * Purpose:
   1090  *     Install an entry based on priority value.
   1091  * Parameters:
   1092  *     unit     - (IN) BCM device number
   1093  *     ent_p    - (IN) Pointer to station entry.
   1094  * Returns:
   1095  *     BCM_E_XXX
   1096  */
   1097 STATIC int
   1098 _bcm_th3_l2_station_entry_prio_install(int unit, _bcm_l2_station_entry_t *ent_p)
   1099 {
   1100     _bcm_l2_station_control_t  *sc;                /* Control structure.     */
   1101     _bcm_l2_station_entry_t  **entry_arr;          /* L2 station entry       */
   1102     int                        idx_old;            /* Entry old TCAM index.  */
   1103     int                        idx_target;         /* Entry target index.    */
   1104     int                        prev_null_idx = -1; /* Prev NULL entry index. */
   1105     int                        next_null_idx = -1; /* Next NULL entry index. */
   1106     int                        temp;               /* Temporary variable.    */
   1107     int                        dir = -1;           /* -1 = UP, 1 = DOWN      */
   1108     int                        decr_on_shift_up = TRUE; /* Shift up status   */
   1109     int                        rv;                 /* Return status.         */
   1110     int                        flag_no_free_entries = FALSE; /* No free      */
   1111                                                    /* entries status         */
   1112     int                        max_entries; 
   1113     int                        free_entries; 
   1114     int                        overlay;
   1115     th3_l2_prio_with_no_free_entries = FALSE;
   1116 
   1117     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1118 
   1119 
   1120     if ((ent_p->flags & _BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE)
   1121         || (_bcm_th3_l2_station_prio_move_required(unit, ent_p) == FALSE)) {
   1122         goto end;
   1123     }
   1124 
   1125     idx_old = ent_p->hw_index;
   1126 
   1127     overlay = _BCM_L2_STATION_ENTRY_UNDERLAY;
   1128     max_entries = sc->entries_total;
   1129     entry_arr = (sc->entry_arr);
   1130     free_entries  = sc->entries_free;
   1131 
   1132     if (idx_old >= max_entries) {
   1133         return (BCM_E_INTERNAL);
   1134     }
   1135 
   1136     if (free_entries == 0) {
   1137         if ((ent_p->flags & _BCM_L2_STATION_ENTRY_INSTALLED) == 0) {
   1138             entry_arr[ent_p->hw_index] = NULL;
   1139             flag_no_free_entries = TRUE;
   1140         } else {
   1141             return (BCM_E_CONFIG);
   1142         }
   1143     }
   1144 
   1145     for (idx_target = 0; idx_target < max_entries; idx_target++) {
   1146 
   1147         /* Skip the entry itself. */
   1148         if (ent_p == entry_arr[idx_target]) {
   1149             continue;
   1150         }
   1151 
   1152         if (NULL == entry_arr[idx_target]) {
   1153             /* Store the null slot index. */
   1154             prev_null_idx = idx_target;
   1155             continue;
   1156         }
   1157 
   1158         if (_bcm_th3_l2_station_entry_prio_cmp(ent_p->prio,
   1159                                                entry_arr[idx_target]->prio) > 0) {
   1160             /* Found the entry with priority lower than ent_p prio. */
   1161             break;
   1162         }
   1163     }
   1164 
   1165     temp = idx_target;
   1166 
   1167     if (idx_target != (max_entries - 1)) {
   1168         /*  Find next empty slot after ent_p. */
   1169         for (; temp < max_entries; temp++) {
   1170             if (entry_arr[temp] == NULL) {
   1171                 next_null_idx = temp;
   1172                 break;
   1173             }
   1174         }
   1175     }
   1176 
   1177     /* Put the entry back. */
   1178     if (flag_no_free_entries == TRUE) {
   1179         entry_arr[ent_p->hw_index] = ent_p;
   1180     }
   1181 
   1182     /* No empty slot found. */
   1183     if (prev_null_idx == -1 && next_null_idx == -1) {
   1184         return (BCM_E_CONFIG);
   1185     }
   1186 
   1187     if (idx_target == max_entries) {
   1188         /* Target location is after the last installed entry. */
   1189         if (prev_null_idx == (max_entries - 1)) {
   1190             idx_target = prev_null_idx;
   1191             goto only_move;
   1192         } else {
   1193             idx_target = (max_entries - 1);
   1194             decr_on_shift_up = FALSE;
   1195         }
   1196     }
   1197 
   1198     if (_bcm_th3_l2_station_entry_dir_get(unit,
   1199                                          ent_p,
   1200                                          prev_null_idx,
   1201                                          next_null_idx,
   1202                                          idx_target,
   1203                                          &dir) == FALSE) {
   1204         return (BCM_E_PARAM);
   1205     }
   1206 
   1207     if (dir == 1) {
   1208         /* 
   1209          * Move the entry at the target index to target_index+1. This may
   1210          * mean shifting more entries down to make room. In other words,
   1211          * shift the target index and any that follow it down 1 as far as the
   1212          * next empty index.
   1213          */
   1214         if (entry_arr[idx_target] != NULL) {
   1215             BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_entry_shift_down(unit,
   1216                                     overlay, idx_target, next_null_idx));
   1217         }
   1218     } else {
   1219         if (decr_on_shift_up == TRUE) {
   1220             idx_target--;
   1221             LOG_DEBUG(BSL_LS_BCM_L2,
   1222                       (BSL_META_U(unit,
   1223                                   "L2(unit %d) Info: Decr. on Shift UP (idx_tgt=%d).\n"),
   1224                        unit, idx_target));
   1225         }
   1226 
   1227         if (entry_arr[idx_target] != NULL) {
   1228             /* coverity[negative_returns] */
   1229             BCM_IF_ERROR_RETURN (_bcm_th3_l2_station_entry_shift_up(unit,
   1230                                      overlay, idx_target, prev_null_idx));
   1231         }
   1232     }
   1233 
   1234     /* Move the entry from old index to new index. */
   1235 only_move:
   1236     if ((idx_target - ent_p->hw_index) != 0) {
   1237 
   1238         if (flag_no_free_entries == TRUE) {
   1239             th3_l2_prio_with_no_free_entries = TRUE;
   1240         }
   1241 
   1242         rv = _bcm_th3_l2_station_entry_move(unit, ent_p,
   1243                 (idx_target - ent_p->hw_index));
   1244 
   1245         if (BCM_FAILURE(rv)) {
   1246             th3_l2_prio_with_no_free_entries = FALSE;
   1247             return (rv);
   1248         }
   1249 
   1250         th3_l2_prio_with_no_free_entries = FALSE;
   1251     }
   1252 
   1253 end:
   1254 
   1255     ent_p->flags &= ~_BCM_L2_STATION_ENTRY_PRIO_NO_CHANGE;
   1256 
   1257     rv = _bcm_th3_l2_station_entry_install(unit, ent_p);
   1258     if (BCM_FAILURE(rv)) {
   1259         return rv;
   1260     }
   1261     return (BCM_E_NONE);
   1262 }
   1263 
   1264 /*
   1265  * Function: 
   1266  *     _bcm_th3_l2_station_entry_get
   1267  * Purpose:
   1268  *     Get station entry details by performing
   1269  *     lookup using station ID.
   1270  * Parameters:
   1271  *     unit  - (IN) BCM device number
   1272  *     sid   - (IN) Station ID.
   1273  *     ent_p - (OUT) Station look up result.
   1274  * Retruns:
   1275  *     BCM_E_XXX
   1276  */
   1277 int
   1278 _bcm_th3_l2_station_entry_get(int unit,
   1279                               int sid,
   1280                               _bcm_l2_station_entry_t **ent_p)
   1281 {
   1282     _bcm_l2_station_control_t *sc;   /* Station control structure pointer. */
   1283     _bcm_l2_station_entry_t **entry_arr;
   1284     int                       index; /* Entry index.                       */
   1285     int                       count;
   1286     /* Input parameter check. */
   1287     if (ent_p == NULL) {
   1288         return (BCM_E_PARAM);
   1289     }
   1290 
   1291     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1292 
   1293     count = sc->entries_total;
   1294     entry_arr = (sc->entry_arr);
   1295 
   1296     for (index = 0; index < count; index++) {
   1297 
   1298         if (entry_arr[index] == NULL) {
   1299             continue;
   1300         }
   1301 
   1302         if (sid == entry_arr[index]->sid) {
   1303             *ent_p = entry_arr[index];
   1304             LOG_DEBUG(BSL_LS_BCM_L2,
   1305                       (BSL_META_U(unit,
   1306                                   "L2(unit %d) Info: (SID=%d) - found (idx=%d).\n"),
   1307                        unit, sid, index));
   1308             return (BCM_E_NONE);
   1309         }
   1310     }
   1311 
   1312     LOG_DEBUG(BSL_LS_BCM_L2,
   1313               (BSL_META_U(unit,
   1314                           "L2(unit %d) Info: (SID=%d) - not found (idx=%d).\n"),
   1315                unit, sid, index));
   1316 
   1317     /* L2 station entry with ID == sid not found. */
   1318     return (BCM_E_NOT_FOUND);
   1319 }
   1320 
   1321 /*
   1322  * Function:
   1323  *     _bcm_th3_l2_station_param_check
   1324  * Purpose:
   1325  *     Validate L2 station user input parameters.
   1326  * Parameters:
   1327  *     unit         - (IN) BCM device number
   1328  *     station      - (IN) Station information for lookup by hardware.
   1329  *     station_id   - (IN) Station entry ID.
   1330  * Returns:
   1331  *     BCM_E_XXX
   1332  */
   1333 STATIC int
   1334 _bcm_th3_l2_station_param_check(int unit, bcm_l2_station_t *station,
   1335                                 int station_id)
   1336 {
   1337     soc_mem_t tcam_mem; /* Hardware table name.     */
   1338     bcm_gport_t gport_id;
   1339     bcm_port_t port_out;
   1340     bcm_module_t mod_out;
   1341     bcm_trunk_t trunk_id;
   1342     uint32 mod_port_data = 0; /* concatenated modid and port */
   1343     int num_bits_for_port;
   1344 
   1345     /* Input parameter check. */
   1346     if (NULL == station) {
   1347         return (BCM_E_PARAM);
   1348     }
   1349 
   1350     if (station->flags & BCM_L2_STATION_FCOE) {
   1351         /* FCoE Termination is not supported */
   1352         return (BCM_E_UNAVAIL);
   1353     }
   1354 
   1355     if (station->flags & BCM_L2_STATION_OAM) {
   1356         return (BCM_E_UNAVAIL);
   1357     }
   1358 
   1359     
   1360     tcam_mem = MY_STATION_TCAMm;
   1361     ParamCheck(unit, tcam_mem, VLAN_IDf, station->vlan);
   1362     ParamCheck(unit, tcam_mem, VLAN_ID_MASKf, station->vlan_mask);
   1363 
   1364     if (GPORT_TYPE(station->src_port) != GPORT_TYPE(station->src_port_mask)) {
   1365                return BCM_E_PARAM;
   1366     }
   1367        num_bits_for_port = _shr_popcount(
   1368                               (unsigned int)SOC_PORT_ADDR_MAX(unit));
   1369        if (BCM_GPORT_IS_SET(station->src_port)) {
   1370            BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, 
   1371                       station->src_port,
   1372                       &mod_out,
   1373                       &port_out, &trunk_id,
   1374                       &gport_id));
   1375            if (BCM_GPORT_IS_TRUNK(station->src_port)) {
   1376                if (BCM_TRUNK_INVALID == trunk_id) {
   1377                    return BCM_E_PORT;
   1378                }
   1379 
   1380                mod_port_data = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id);
   1381            } else {
   1382                if ((-1 == mod_out) || (-1 == port_out)) {
   1383                    return BCM_E_PORT;
   1384                }
   1385                mod_port_data = (mod_out << num_bits_for_port) | port_out;
   1386            }
   1387        } else {
   1388            int my_modid;
   1389            BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit,&my_modid));
   1390            port_out = station->src_port;
   1391            mod_port_data = station->src_port | 
   1392                            (my_modid << num_bits_for_port);
   1393        } 
   1394 
   1395        if (SOC_MEM_FIELD_VALID(unit, tcam_mem, SOURCE_FIELDf)) {
   1396            ParamCheck(unit, tcam_mem, SOURCE_FIELDf, mod_port_data);
   1397        } else {
   1398            ParamCheck(unit, tcam_mem, ING_PORT_NUMf, port_out);
   1399        }
   1400 
   1401     return (BCM_E_NONE);
   1402 }
   1403 
   1404 /*
   1405  * Function:
   1406  *     bcm_th3_l2_station_add
   1407  * Purpose:
   1408  *     Create an entry with specified ID or generated ID and install
   1409  *     the entry in hardware.
   1410  * Parameters:
   1411  *     unit         - (IN) BCM device number
   1412  *     station_id   - (IN/OUT) Station entry ID.
   1413  *     station      - (IN) Station information for lookup by hardware.
   1414  * Returns:
   1415  *     BCM_E_XXX
   1416  */
   1417 int
   1418 bcm_th3_l2_station_add(int unit,
   1419                       int *station_id,
   1420                       bcm_l2_station_t *station)
   1421 {
   1422     _bcm_l2_station_control_t *sc;         /* Control structure.       */
   1423     _bcm_l2_station_entry_t   *ent = NULL; /* Entry pointer.           */
   1424     int                       rv;          /* Operation return status. */
   1425     int                       sid = -1;    /* Entry ID.                */
   1426 
   1427     /* Input parameter check. */
   1428     if (NULL == station || NULL == station_id)  {
   1429         return (BCM_E_PARAM);
   1430     }
   1431 
   1432     /* ID needs to be passed for replace operation. */
   1433     if ((station->flags & BCM_L2_STATION_REPLACE)
   1434         && !(station->flags & BCM_L2_STATION_WITH_ID)) {
   1435         return (BCM_E_PARAM);
   1436     }
   1437 
   1438     rv = _bcm_th3_l2_station_param_check(unit, station, *station_id);
   1439     if (BCM_FAILURE(rv)) {
   1440         return (BCM_E_PARAM);
   1441     }
   1442 
   1443     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1444 
   1445     SC_LOCK(sc);
   1446 
   1447     if (station->flags & BCM_L2_STATION_WITH_ID) {
   1448         if ((sc->last_allocated_sid < *station_id) &&
   1449             (*station_id <= _BCM_L2_STATION_ID_MAX)) {
   1450             sc->last_allocated_sid = *station_id;
   1451         }
   1452         sid = *station_id;
   1453     } else {
   1454         sid = ++sc->last_allocated_sid;
   1455 
   1456         if (_BCM_L2_STATION_ID_MAX < sid) {
   1457             sc->last_allocated_sid = _BCM_L2_STATION_ID_MAX;
   1458 
   1459             for (sid = _BCM_L2_STATION_ID_BASE;
   1460                  sid <= _BCM_L2_STATION_ID_MAX; sid++) {
   1461                 if (BCM_E_NOT_FOUND == 
   1462                         _bcm_th3_l2_station_entry_get(unit, sid, &ent)) {
   1463                     break;
   1464                 }
   1465             }
   1466         }
   1467 
   1468         *station_id = sid;
   1469     }
   1470 
   1471     rv = _bcm_th3_l2_station_entry_get(unit, sid, &ent);
   1472 
   1473     /* For replace operation, entry must exist. */
   1474     if (BCM_FAILURE(rv)
   1475         && (station->flags & BCM_L2_STATION_REPLACE)) {
   1476         LOG_ERROR(BSL_LS_BCM_L2,
   1477                   (BSL_META_U(unit,
   1478                               "L2(unit %d) Error: Replace (SID=%d) - Invalid (%s).\n"),
   1479                    unit, sid, bcm_errmsg(rv)));
   1480         SC_UNLOCK(sc);
   1481         return (rv);
   1482     }
   1483 
   1484     /* For non-replace operations, entry must not exist. */
   1485     if (BCM_SUCCESS(rv)
   1486         && (0 == (station->flags & BCM_L2_STATION_REPLACE))) {
   1487         LOG_INFO(BSL_LS_BCM_L2,
   1488                   (BSL_META_U(unit,
   1489                               "L2(unit %d) Error: (SID=%d) add - failed (%s).\n"),
   1490                    unit, sid, bcm_errmsg(rv)));
   1491         SC_UNLOCK(sc);
   1492         return (BCM_E_EXISTS);
   1493     }
   1494 
   1495     if (0 == (station->flags & BCM_L2_STATION_REPLACE)) {
   1496         rv = _bcm_th3_l2_station_entry_create(unit, sid, station, &ent);
   1497         if (BCM_FAILURE(rv)) {
   1498             LOG_INFO(BSL_LS_BCM_L2,
   1499                      (BSL_META_U(unit,
   1500                                  "L2(unit %d) Error: Station (SID=%d) add - failed (%s).\n"),
   1501                       unit, sid, bcm_errmsg(rv)));
   1502             SC_UNLOCK(sc);
   1503             return (rv);
   1504         }
   1505     } else {
   1506         rv = _bcm_th3_l2_station_entry_update(unit, sid, station, ent);
   1507         if (BCM_FAILURE(rv)) {
   1508             LOG_ERROR(BSL_LS_BCM_L2,
   1509                       (BSL_META_U(unit,
   1510                                   "L2(unit %d) Error: Station (SID=%d) update - failed (%s).\n"),
   1511                        unit, sid, bcm_errmsg(rv)));
   1512             SC_UNLOCK(sc);
   1513             return (rv);
   1514         }
   1515     }
   1516 
   1517     rv = _bcm_th3_l2_station_entry_prio_install(unit, ent);
   1518     if (BCM_FAILURE(rv)) {
   1519         if (NULL != ent->tcam_ent) {
   1520             sal_free(ent->tcam_ent);
   1521         }
   1522         LOG_ERROR(BSL_LS_BCM_L2,
   1523                   (BSL_META_U(unit,
   1524                               "L2(unit %d) Error: (SID=%d) install - failed (%s).\n"),
   1525                    unit, sid, bcm_errmsg(rv)));
   1526         SC_UNLOCK(sc);
   1527         return (rv);
   1528     }
   1529 
   1530     /* Mark the entry as installed. */
   1531     ent->flags |= _BCM_L2_STATION_ENTRY_INSTALLED;
   1532 
   1533     SC_UNLOCK(sc);
   1534     return (rv);
   1535 }
   1536 
   1537 /*
   1538  * Function:
   1539  *     bcm_th3_l2_station_delete
   1540  * Purpose:
   1541  *     Deallocate the memory used to track an entry and remove the entry
   1542  *     from hardware
   1543  * Parameters:
   1544  *     unit         - (IN) BCM device number
   1545  *     station_id   - (IN) Station entry ID
   1546  * Returns:
   1547  *     BCM_E_XXX
   1548  */
   1549 int
   1550 bcm_th3_l2_station_delete(int unit, int station_id)
   1551 {
   1552     _bcm_l2_station_entry_t     *s_ent = NULL; /* Entry pointer.           */
   1553     _bcm_l2_station_entry_t     **entry_arr = NULL; /* Entry pointer.      */
   1554     _bcm_l2_station_control_t   *sc = NULL;    /* Control structure.       */
   1555     int                         rv;            /* Operation return status. */
   1556     soc_mem_t                   tcam_mem;      /* TCMA memory name.        */
   1557 
   1558     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1559 
   1560     SC_LOCK(sc);
   1561 
   1562     /* Get the entry by ID. */
   1563     rv = _bcm_th3_l2_station_entry_get(unit, station_id, &s_ent);
   1564     if (BCM_FAILURE(rv)) {
   1565         SC_UNLOCK(sc);
   1566         return (rv);
   1567     }
   1568 
   1569     entry_arr = (sc->entry_arr);
   1570 
   1571     tcam_mem = MY_STATION_TCAMm;
   1572 
   1573     /* Remove the entry from hardware by clearing the index. */
   1574     rv = soc_mem_write(unit, tcam_mem, MEM_BLOCK_ALL, s_ent->hw_index,
   1575                        soc_mem_entry_null(unit, tcam_mem));
   1576     if (BCM_FAILURE(rv)) {
   1577         SC_UNLOCK(sc);
   1578         return (rv);
   1579     }
   1580 
   1581     /* Free tcam buffer. */
   1582     if (NULL != s_ent->tcam_ent) {
   1583         sal_free(s_ent->tcam_ent);
   1584     }
   1585 
   1586     /* Remove the entry pointer from the list. */
   1587     entry_arr[s_ent->hw_index] = NULL;
   1588 
   1589     /* Increment free entries count. */
   1590     sc->entries_free++;
   1591     sc->entry_count--;
   1592 
   1593     /* Free the entry. */
   1594     sal_free(s_ent);
   1595     
   1596     /* Rset the last_allocated_sid */
   1597     if (station_id == sc->last_allocated_sid) {
   1598         --sc->last_allocated_sid;
   1599     }
   1600 
   1601     SC_UNLOCK(sc);
   1602 
   1603     return (rv);
   1604 }
   1605 
   1606 /*
   1607  * Function:
   1608  *     _bcm_th3_l2_station_entry_delete_all
   1609  * Purpose:
   1610  *     Deallocate all memory used to track entries and remove entries from
   1611  *     hardware.
   1612  * Parameters:
   1613  *     unit     - (IN) BCM device number
   1614  *     overlay  - (IN) Overlay/Underlay identification
   1615  * Returns:
   1616  *     BCM_E_XXX
   1617  */
   1618 STATIC int
   1619 _bcm_th3_l2_station_entry_delete_all(int unit, int overlay)
   1620 {
   1621     _bcm_l2_station_control_t   *sc = NULL; /* Control strucutre.       */
   1622     _bcm_l2_station_entry_t    **entry_arr = NULL; /* Entry array.      */
   1623     int                         rv;         /* Operation return status. */
   1624     int                         index;      /* Entry index.             */
   1625     int                         max_entries;
   1626 
   1627     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1628 
   1629     SC_LOCK(sc);
   1630 
   1631     max_entries = (overlay == _BCM_L2_STATION_ENTRY_OVERLAY) ?
   1632                       sc->entries_total_2 : sc->entries_total;
   1633     entry_arr = (overlay == _BCM_L2_STATION_ENTRY_OVERLAY) ?
   1634                     (sc->entry_arr_2) : (sc->entry_arr);
   1635 
   1636     if (NULL == entry_arr) {
   1637         SC_UNLOCK(sc);
   1638         return (BCM_E_NONE);
   1639     }
   1640 
   1641     for (index = 0; index < max_entries; index++) {
   1642 
   1643         if (NULL == entry_arr[index]) {
   1644             continue;
   1645         }
   1646 
   1647         rv = bcm_th3_l2_station_delete(unit, entry_arr[index]->sid);
   1648 
   1649         if (BCM_FAILURE(rv)) {
   1650             SC_UNLOCK(sc);
   1651             return (rv);
   1652         }
   1653     }
   1654 
   1655     SC_UNLOCK(sc);
   1656 
   1657     return (BCM_E_NONE);
   1658 }
   1659 
   1660 /*
   1661  * Function:
   1662  *     bcm_th3_l2_station_delete_all
   1663  * Purpose:
   1664  *     Deallocate all memory used to track entries and remove entries from
   1665  *     hardware.
   1666  * Parameters:
   1667  *     unit     - (IN) BCM device number
   1668  * Returns:
   1669  *     BCM_E_XXX
   1670  */
   1671 int
   1672 bcm_th3_l2_station_delete_all(int unit)
   1673 {
   1674     int rv;
   1675 
   1676     rv = _bcm_th3_l2_station_entry_delete_all(unit,
   1677              _BCM_L2_STATION_ENTRY_UNDERLAY);
   1678 
   1679    return rv;
   1680 }
   1681 
   1682 /*
   1683  * Function:
   1684  *     bcm_th3_l2_station_get
   1685  * Purpose:
   1686  *     Get station information for a given station ID.
   1687  * Parameters:
   1688  *     unit         - (IN) BCM device number
   1689  *     station_id   - (IN) Station entry ID.
   1690  *     station      - (OUT) Station entry lookup information.
   1691  * Returns:
   1692  *     BCM_E_XXX
   1693  */
   1694 int
   1695 bcm_th3_l2_station_get(int unit, int station_id, bcm_l2_station_t *station)
   1696 {
   1697     _bcm_l2_station_entry_t     *s_ent = NULL; /* Entry pointer           */
   1698     _bcm_l2_station_control_t   *sc = NULL;    /* Control structure       */
   1699     int                         rv;            /* Operation return status */
   1700     soc_mem_t                   tcam_mem;      /* TCAM memory name        */
   1701     uint32                      entry[SOC_MAX_MEM_FIELD_WORDS]; /* Entry   */
   1702                                                                 /* buffer  */
   1703     int src_field;
   1704     int src_mask_field;
   1705     _bcm_gport_dest_t src;
   1706     _bcm_gport_dest_t src_mask;
   1707     int num_bits_for_port;
   1708 
   1709     /* Input parameter check. */
   1710     if (station == NULL) {
   1711         return (BCM_E_PARAM);
   1712     }
   1713 
   1714     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1715     SC_LOCK(sc);
   1716 
   1717     /* Get the entry by ID. */
   1718     rv = _bcm_th3_l2_station_entry_get(unit, station_id, &s_ent);
   1719     if (BCM_FAILURE(rv)) {
   1720         SC_UNLOCK(sc);
   1721         return (rv);
   1722     }
   1723 
   1724     tcam_mem = MY_STATION_TCAMm;
   1725 
   1726     /* Clear entry buffer. */
   1727     sal_memset(entry, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   1728 
   1729     rv = soc_mem_read(unit, tcam_mem, MEM_BLOCK_ANY, s_ent->hw_index, entry);
   1730     if (BCM_FAILURE(rv)) {
   1731         SC_UNLOCK(sc);
   1732         return (rv);
   1733     }
   1734 
   1735     station->priority = s_ent->prio;
   1736 
   1737     soc_mem_mac_addr_get(unit, tcam_mem, entry,
   1738                          MAC_ADDRf, station->dst_mac);
   1739 
   1740     soc_mem_mac_addr_get(unit, tcam_mem, entry,
   1741                          MAC_ADDR_MASKf, station->dst_mac_mask);
   1742 
   1743     station->vlan = soc_mem_field32_get(unit, tcam_mem, entry, VLAN_IDf);
   1744 
   1745     station->vlan_mask = soc_mem_field32_get(unit, tcam_mem, entry,
   1746                                              VLAN_ID_MASKf);
   1747 
   1748     _bcm_gport_dest_t_init(&src);
   1749     _bcm_gport_dest_t_init(&src_mask);
   1750 
   1751     src_field= soc_mem_field32_get(unit, tcam_mem, entry,
   1752                    SOURCE_FIELDf);
   1753     src_mask_field = soc_mem_field32_get(unit, tcam_mem, entry,
   1754                         SOURCE_FIELD_MASKf);
   1755 
   1756     if ((src_field >> SOC_TRUNK_BIT_POS(unit)) & 0x1) {
   1757         src.tgid = src_field & ((1 << SOC_TRUNK_BIT_POS(unit)) - 1);
   1758         src.gport_type = _SHR_GPORT_TYPE_TRUNK;
   1759         src_mask.tgid = src_mask_field & 
   1760         ((1 << SOC_TRUNK_BIT_POS(unit)) - 1);
   1761             src_mask.gport_type = _SHR_GPORT_TYPE_TRUNK;
   1762     } else {
   1763         src.port = src_field & SOC_PORT_ADDR_MAX(unit);
   1764         src.modid = (src_field - src.port) /
   1765                         (SOC_PORT_ADDR_MAX(unit) + 1);
   1766         src.gport_type = _SHR_GPORT_TYPE_MODPORT;
   1767         num_bits_for_port = _shr_popcount(
   1768                             (unsigned int)SOC_PORT_ADDR_MAX(unit));
   1769         src_mask.port = src_mask_field & SOC_PORT_ADDR_MAX(unit);
   1770         src_mask.gport_type = _SHR_GPORT_TYPE_MODPORT;
   1771         src_mask.modid = (src_mask_field >> num_bits_for_port) & 
   1772                              SOC_MODID_MAX(unit);
   1773     }
   1774 
   1775     BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &src,
   1776                         &(station->src_port)));
   1777     BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &src_mask,
   1778                         &(station->src_port_mask)));
   1779 
   1780     if (soc_mem_field32_get(unit, tcam_mem, entry,
   1781                             MPLS_TERMINATION_ALLOWEDf)) {
   1782             station->flags |= BCM_L2_STATION_MPLS;
   1783     }
   1784 
   1785     if (soc_mem_field32_get(unit, tcam_mem, entry,
   1786                             IPV4_TERMINATION_ALLOWEDf)) {
   1787         station->flags |= BCM_L2_STATION_IPV4;
   1788     }
   1789 
   1790     if (soc_mem_field32_get(unit, tcam_mem, entry,
   1791                             IPV6_TERMINATION_ALLOWEDf)) {
   1792         station->flags |= BCM_L2_STATION_IPV6;
   1793     }
   1794 
   1795     if (soc_mem_field32_get(unit, tcam_mem, entry,
   1796                             ARP_RARP_TERMINATION_ALLOWEDf)) {
   1797         station->flags |= BCM_L2_STATION_ARP_RARP;
   1798     }
   1799 
   1800     if (soc_mem_field32_get(unit, tcam_mem, entry,
   1801                             COPY_TO_CPUf)) {
   1802         station->flags |= BCM_L2_STATION_COPY_TO_CPU;
   1803     }
   1804 
   1805     if (soc_mem_field32_get(unit, tcam_mem, entry, DISCARDf)) {
   1806         station->flags |= BCM_L2_STATION_DISCARD;
   1807     }
   1808 
   1809     SC_UNLOCK(sc);
   1810 
   1811     return (rv);
   1812 }
   1813 
   1814 /*
   1815  * Function:
   1816  *     bcm_th3_l2_station_size_get
   1817  * Purpose:
   1818  *     Get number of entries supported by L2 station API
   1819  * Parameters:
   1820  *     unit   - (IN) BCM device number
   1821  *     size   - (OUT) Station entry ID
   1822  * Returns:
   1823  *     BCM_E_XXX
   1824  */
   1825 int
   1826 bcm_th3_l2_station_size_get(int unit, int *size)       
   1827 {
   1828     _bcm_l2_station_control_t   *sc = NULL; /* Station control structure. */
   1829     
   1830     /* Input parameter check */
   1831     if (size == NULL) {
   1832         return (BCM_E_PARAM);
   1833     }
   1834 
   1835     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1836     SC_LOCK(sc);
   1837 
   1838     *size = sc->entries_total;
   1839 
   1840     SC_UNLOCK(sc);
   1841 
   1842     return (BCM_E_NONE);
   1843 }
   1844 
   1845 /*
   1846  * Function:
   1847  *     _bcm_th3_l2_station_entry_last_sid_set
   1848  * Purpose:
   1849  *     Set the current last station id for L2 station.
   1850  * Parameters:
   1851  *     unit    - (IN) BCM device number
   1852  *     overlay - (IN) Overlay/Underlay identification (not used in the rev)
   1853  *     sid     - (IN) Station ID.
   1854  * Returns:
   1855  *     BCM_E_XXX
   1856  */
   1857 int
   1858 _bcm_th3_l2_station_entry_last_sid_set(int unit, int overlay, int sid)
   1859 {
   1860     _bcm_l2_station_control_t *sc = NULL;
   1861 
   1862     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1863 
   1864     if (sid) {
   1865         sc->last_allocated_sid = sid;
   1866     } else {
   1867         sc->last_allocated_sid = _BCM_L2_STATION_ID_BASE - 1;
   1868     }
   1869 
   1870     return BCM_E_NONE;
   1871 }
   1872 
   1873 /*
   1874  * Function:
   1875  *     bcm_th3_l2_station_traverse
   1876  * Purpose:
   1877  *     Walk through station entries and executed user supplied callback function
   1878  * Parameters:
   1879  *     unit      - (IN) BCM device number
   1880  *     trav_fn   - (IN) Caller supplied function to execute for each entry
   1881  *     user_data - (IN) Argument list for the callback function
   1882  * Returns:
   1883  *     BCM_E_XXX
   1884  */
   1885 int
   1886 bcm_th3_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn,
   1887                             void *user_data) 
   1888 {
   1889     _bcm_l2_station_control_t *sc = NULL; /* Station control structure */
   1890     int                       index; /* Entry index */
   1891     int                       count;
   1892     int                       rv = BCM_E_NONE;
   1893     _bcm_l2_station_entry_t   *s_ent = NULL;
   1894     bcm_l2_station_t          l2_station;
   1895     int                       station_id;
   1896 
   1897     /* Input parameter check */
   1898     if (!trav_fn) {
   1899         return BCM_E_PARAM;
   1900     }
   1901     
   1902     memset((void *)(&l2_station), 0, sizeof(bcm_l2_station_t));
   1903     
   1904     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1905 
   1906     count = sc->entries_total;
   1907     
   1908     for (index = 0; index < count; index++) {
   1909 
   1910         s_ent = sc->entry_arr[index]; /* H/W index */
   1911         
   1912         if (s_ent == NULL) {
   1913             continue;
   1914         }
   1915 
   1916         station_id = sc->entry_arr[index]->sid; /* Get S/W handle */
   1917             
   1918         rv = bcm_th3_l2_station_get(unit, station_id, &l2_station);
   1919 
   1920         if (BCM_FAILURE(rv)) {
   1921             break;
   1922         }
   1923         
   1924         rv = trav_fn(unit, &l2_station, user_data);
   1925 
   1926         if (BCM_FAILURE(rv)) {
   1927             LOG_DEBUG(BSL_LS_BCM_L2,
   1928                       (BSL_META_U(unit,
   1929                           "L2(unit %d) Info: Traverse (SID=%d)/(idx=%d) entry failed.\n"),
   1930                        unit, station_id, index));
   1931             break;
   1932         }
   1933     }
   1934 
   1935     return rv;
   1936 }
   1937 
   1938 #ifdef BCM_WARM_BOOT_SUPPORT
   1939 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */
   1940 /*
   1941  * Function:
   1942  *     _bcm_th3_l2_station_entry_reload
   1943  * Purpose:
   1944  *     Re-construct L2 station control structure software state
   1945  *     from installed hardware entries
   1946  * Parameters:
   1947  *     unit       - (IN) BCM device number
   1948  * Returns:
   1949  *     BCM_E_XXX
   1950  */
   1951 STATIC int
   1952 _bcm_th3_l2_station_entry_reload(int unit, int overlay)
   1953 {
   1954     _bcm_l2_station_control_t *sc;               /* Pointer to station        */
   1955                                                  /* control structure.        */
   1956     int                       rv;                /* Operation return status.  */
   1957     uint32                    *tcam_buf = NULL;  /* Buffer to store TCAM      */
   1958                                                  /* table entries.            */
   1959     int                       entry_mem_size;    /* Size of TCAM table entry. */
   1960     int                       index;             /* Table index iterator.     */
   1961     _bcm_l2_station_entry_t   *s_ent_p;          /* Station table entry.      */
   1962     my_station_tcam_entry_t   *my_station_ent;   /* Table entry pointer.      */
   1963 
   1964 
   1965     entry_mem_size = sizeof(my_station_tcam_entry_t);
   1966 
   1967     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_get(unit, &sc));
   1968 
   1969     SC_LOCK(sc);
   1970 
   1971     /* Allocate buffer to store the DMAed table entries. */
   1972     tcam_buf = soc_cm_salloc(unit, entry_mem_size * sc->entries_total,
   1973                               "STATION TCAM buffer");
   1974     if (NULL == tcam_buf) {
   1975         SC_UNLOCK(sc);
   1976         return (BCM_E_MEMORY);
   1977     }
   1978     /* Initialize the entry buffer. */
   1979     sal_memset(tcam_buf, 0, entry_mem_size * sc->entries_total);
   1980 
   1981     /* Read the table entries into the buffer. */
   1982     rv = soc_mem_read_range(unit, MY_STATION_TCAMm, MEM_BLOCK_ALL,
   1983                             0, (sc->entries_total - 1), tcam_buf);
   1984     if (BCM_FAILURE(rv)) {
   1985         goto cleanup;
   1986     }
   1987 
   1988     /* Iterate over the table entries. */
   1989     for (index = 0; index < sc->entries_total; index++) {
   1990 
   1991         my_station_ent = soc_mem_table_idx_to_pointer(unit, MY_STATION_TCAMm,
   1992                              my_station_tcam_entry_t *, tcam_buf, index);
   1993 
   1994         if (0 == soc_MY_STATION_TCAMm_field32_get(unit, my_station_ent,
   1995                                                   VALIDf)) {
   1996             continue;
   1997         }
   1998 
   1999         s_ent_p = (_bcm_l2_station_entry_t *)sal_alloc(
   2000                                              sizeof(_bcm_l2_station_entry_t),
   2001                                              "Sw L2 station entry");
   2002         if (NULL == s_ent_p) {
   2003             rv = BCM_E_MEMORY;
   2004             goto cleanup;
   2005         }
   2006 
   2007         sal_memset(s_ent_p, 0, sizeof(_bcm_l2_station_entry_t));
   2008 
   2009         s_ent_p->sid = ++sc->last_allocated_sid;
   2010         s_ent_p->prio = (sc->entries_total - index);
   2011         sc->entries_free--;
   2012         sc->entry_count++;
   2013         sc->entry_arr[index] = s_ent_p;
   2014         
   2015         s_ent_p->hw_index = index;
   2016         s_ent_p->flags |= _BCM_L2_STATION_ENTRY_INSTALLED;
   2017     }
   2018 
   2019 cleanup:
   2020 
   2021     SC_UNLOCK(sc);
   2022 
   2023     if (tcam_buf) {
   2024         soc_cm_sfree(unit, tcam_buf);
   2025     }
   2026 
   2027     return (rv);
   2028 }
   2029 
   2030 /*
   2031  * Function:
   2032  *     _bcm_th3_l2_station_reload
   2033  * Purpose:
   2034  *     Re-construct L2 station control structure software state
   2035  *     from installed hardware entries
   2036  * Parameters:
   2037  *     unit       - (IN) BCM device number
   2038  * Returns:
   2039  *     BCM_E_XXX
   2040  */
   2041 int
   2042 _bcm_th3_l2_station_reload(int unit)
   2043 {
   2044     int rv;
   2045 
   2046     rv = _bcm_th3_l2_station_entry_reload(unit, _BCM_L2_STATION_ENTRY_UNDERLAY);
   2047 
   2048     return rv;
   2049 }
   2050 
   2051 
   2052 #endif /* BCM_TRIUMPH_SUPPORT */
   2053 #endif /* BCM_WARM_BOOT_SUPPORT */
   2054 #endif /* BCM_TOMAHAWK3_SUPPORT */