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

trunk.c (125122B)


      1 /*
      2  * $ID: trunk.c,v 1.0 Broadcom SDK $
      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  * Tomahawk 3 Trunking (Ether)
      8  */
      9 #include <soc/mem.h>
     10 #include <bcm/error.h>
     11 
     12 #include <bcm_int/esw/mbcm.h>
     13 #include <bcm_int/esw/link.h>
     14 #include <bcm_int/esw/trunk.h>
     15 #include <bcm_int/esw/switch.h>
     16 
     17 #include <bcm_int/esw/stack.h>
     18 #include <bcm_int/esw_dispatch.h>
     19 
     20 #include <bcm_int/esw/tomahawk3.h>
     21 
     22 #include <bcm_int/esw/portctrl.h>
     23 
     24 #ifdef BCM_TOMAHAWK3_SUPPORT
     25 
     26 #define _BCM_TH3_TRUNK_NUM_MAX              144
     27 #define _BCM_TH3_PORTS_PER_TRUNK_MAX        64
     28 #define _BCM_TH3_TRUNK_FAILOVER_PORT_NUM    8
     29 
     30 /*
     31  * Trunk Membership Info
     32  * TH3 supports 64 ports per trunk and does NOT support stacking or HiGig
     33  */
     34 typedef struct {
     35     uint8  num_ports;                         /* Number of ports in the trunk */
     36     uint16 *port;/* Device Ports in the trunk */
     37     uint32 *member_flags; /* Flags for the port */
     38 #ifdef BCM_WARM_BOOT_SUPPORT
     39     uint8  recovered_from_scache;
     40 #endif
     41 } _th3_member_info_t;
     42 
     43 typedef struct {
     44     _th3_member_info_t *member_info;
     45 } _th3_trunk_member_info_t;
     46 
     47 /* Pointer to array of trunks that will be allocated in init. */
     48 STATIC _th3_trunk_member_info_t *_th3_trunk_member_info[BCM_MAX_NUM_UNITS];
     49 
     50 #define MEMBER_INFO(_unit_, _tid_) (_th3_trunk_member_info[_unit_]->member_info[_tid_])
     51 
     52 /* Port to the Trunk ID Mapping */
     53 STATIC uint8 *_th3_port_to_tid_map[BCM_MAX_NUM_UNITS];
     54 
     55 /*
     56  * Hardware Trunk Failover:
     57  *
     58  * For the devices which support hardware trunk failover, the failover
     59  * configuration must be retained if it is one of the standard models 
     60  * for the retrieval function to use the same encoding as the set function.
     61  *
     62  * Note: The trunk members stored in _th3_tinfo_t's port array do not 
     63  *       include those members with the BCM_TRUNK_MEMBER_EGRESS_DISABLE set.
     64  */
     65 typedef struct {
     66     uint8         num_ports;
     67     uint8         *psc; 
     68     uint16        *port;
     69     uint32        *flags;
     70 } _th3_hw_tinfo_t;
     71 
     72 typedef struct {
     73     _th3_hw_tinfo_t *hw_tinfo;
     74 } _th3_trunk_hwfail_t;
     75 
     76 STATIC _th3_trunk_hwfail_t *_th3_trunk_hwfail[BCM_MAX_NUM_UNITS];
     77 
     78 /* ----------------------- */
     79 /* Software Trunk Failover */
     80 /* ----------------------- */
     81 
     82 /* Even without hardware failover support, given the high speed link
     83  * change notification possible with devices, a port that has been
     84  * indicated as link down can cause the trunk_group table to be immediately
     85  * updated with the link down port removed.
     86  *
     87  * Note: The trunk members stored in _th3_tinfo_t's port array do not
     88  *       include those members with the BCM_TRUNK_MEMBER_EGRESS_DISABLE set.
     89  *       If a trunk member port is down, it'll be removed from_th3_tinfo_t's
     90  *       port array by _bcm_th3_trunk_swfailover_trigger.
     91  */
     92 typedef struct {
     93     uint8         rtag;
     94     uint16        num_ports;
     95     uint16        *port;
     96     uint32        *member_flags;
     97     uint32        flags;
     98 } _th3_tinfo_t;
     99 
    100 typedef struct {
    101     uint8         mymodid;
    102 #if (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
    103     bcm_trunk_t   trunk[SOC_MAX_NUM_PP_PORTS];
    104 #else
    105     bcm_trunk_t   trunk[SOC_MAX_NUM_PORTS]; /* If port is not a member of any
    106                                                trunk group, trunk = 0; else
    107                                                trunk = trunk id + 1. */
    108 #endif
    109     _th3_tinfo_t *tinfo;
    110 } _th3_trunk_swfail_t;
    111 
    112 STATIC _th3_trunk_swfail_t *_th3_trunk_swfail[BCM_MAX_NUM_UNITS];
    113 
    114 
    115 #if 1
    116 /* fields from FAST_TRUNK_PORTS_1 and FAST_TRUNK_PORTS_2 */
    117 static soc_field_t      _th3_fast_portf[64] = {
    118     TRUNK_MEMBER_0f, TRUNK_MEMBER_1f, TRUNK_MEMBER_2f, TRUNK_MEMBER_3f,
    119     TRUNK_MEMBER_4f, TRUNK_MEMBER_5f, TRUNK_MEMBER_6f, TRUNK_MEMBER_7f,
    120     TRUNK_MEMBER_8f, TRUNK_MEMBER_9f, TRUNK_MEMBER_10f, TRUNK_MEMBER_11f,
    121     TRUNK_MEMBER_12f, TRUNK_MEMBER_13f, TRUNK_MEMBER_14f, TRUNK_MEMBER_15f,
    122     TRUNK_MEMBER_16f, TRUNK_MEMBER_17f, TRUNK_MEMBER_18f, TRUNK_MEMBER_19f,
    123     TRUNK_MEMBER_20f, TRUNK_MEMBER_21f, TRUNK_MEMBER_22f, TRUNK_MEMBER_23f,
    124     TRUNK_MEMBER_24f, TRUNK_MEMBER_25f, TRUNK_MEMBER_26f, TRUNK_MEMBER_27f,
    125     TRUNK_MEMBER_28f, TRUNK_MEMBER_29f, TRUNK_MEMBER_30f, TRUNK_MEMBER_31f,
    126     TRUNK_MEMBER_32f, TRUNK_MEMBER_33f, TRUNK_MEMBER_34f, TRUNK_MEMBER_35f,
    127     TRUNK_MEMBER_36f, TRUNK_MEMBER_37f, TRUNK_MEMBER_38f, TRUNK_MEMBER_39f,
    128     TRUNK_MEMBER_40f, TRUNK_MEMBER_41f, TRUNK_MEMBER_42f, TRUNK_MEMBER_43f,
    129     TRUNK_MEMBER_44f, TRUNK_MEMBER_45f, TRUNK_MEMBER_46f, TRUNK_MEMBER_47f,
    130     TRUNK_MEMBER_48f, TRUNK_MEMBER_49f, TRUNK_MEMBER_50f, TRUNK_MEMBER_51f,
    131     TRUNK_MEMBER_52f, TRUNK_MEMBER_53f, TRUNK_MEMBER_54f, TRUNK_MEMBER_55f,
    132     TRUNK_MEMBER_56f, TRUNK_MEMBER_57f, TRUNK_MEMBER_58f, TRUNK_MEMBER_59f,
    133     TRUNK_MEMBER_60f, TRUNK_MEMBER_61f, TRUNK_MEMBER_62f, TRUNK_MEMBER_63f
    134 };
    135 #endif
    136 #if 1
    137 
    138 /*
    139  * Function:
    140  *      _bcm_th3_trunk_member_info_deinit
    141  * Purpose:
    142  *      De-allocate trunk membership info.
    143  * Parameters:
    144  *      unit - (IN)SOC unit number. 
    145  * Returns:
    146  *      None
    147  */
    148 STATIC void
    149 _bcm_th3_trunk_member_info_deinit(int unit)
    150 {
    151     int trunk_num_groups;
    152     int i;
    153 
    154     if (_th3_trunk_member_info[unit]) {
    155         if (_th3_trunk_member_info[unit]->member_info) {
    156             trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    157             for (i = 0; i < trunk_num_groups; i++) {
    158                 if (MEMBER_INFO(unit, i).port) {
    159                     sal_free(MEMBER_INFO(unit, i).port);
    160                     MEMBER_INFO(unit, i).port = NULL;
    161                 }
    162                 if (MEMBER_INFO(unit, i).member_flags) {
    163                     sal_free(MEMBER_INFO(unit, i).member_flags);
    164                     MEMBER_INFO(unit, i).member_flags = NULL;
    165                 }
    166             }
    167             sal_free(_th3_trunk_member_info[unit]->member_info);
    168             _th3_trunk_member_info[unit]->member_info = NULL;
    169         }
    170         sal_free(_th3_trunk_member_info[unit]);
    171         _th3_trunk_member_info[unit] = NULL;
    172     }
    173 }
    174 
    175 /*
    176  * Function:
    177  *      _bcm_th3_trunk_member_info_init
    178  * Purpose:
    179  *      Allocate and Initialize trunk member info
    180  * Parameters:
    181  *      unit - (IN) SOC unit number
    182  * Returns:
    183  *      BCM_X_XXX
    184  */
    185 STATIC int
    186 _bcm_th3_trunk_member_info_init(int unit)
    187 {
    188     int trunk_num_groups;
    189 
    190     if (_th3_trunk_member_info[unit] == NULL) {
    191         _th3_trunk_member_info[unit] = 
    192             sal_alloc(sizeof(_th3_trunk_member_info_t),
    193                       "_th3_trunk_member_info");
    194         if (_th3_trunk_member_info[unit] == NULL) {
    195             return BCM_E_MEMORY;
    196         }
    197     }
    198     sal_memset(_th3_trunk_member_info[unit], 0,
    199             sizeof(_th3_trunk_member_info_t));
    200 
    201     /* Allocate the array of trunk groups */
    202 
    203     /* Only need to count FAST_TRUNK_PORTS_1m because
    204      * FAST_TRUNK_PORTS_2m is extension of the same LAG */
    205     trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    206 
    207     if (_th3_trunk_member_info[unit]->member_info == NULL) {
    208         _th3_trunk_member_info[unit]->member_info = 
    209             sal_alloc(sizeof(_th3_member_info_t) * trunk_num_groups,
    210                     "member_info");
    211         if (_th3_trunk_member_info[unit]->member_info == NULL) {
    212             _bcm_th3_trunk_member_info_deinit(unit);
    213             return BCM_E_MEMORY;
    214         }
    215     }
    216     sal_memset(_th3_trunk_member_info[unit]->member_info, 0,
    217             sizeof(_th3_member_info_t) * trunk_num_groups);
    218 
    219     /* Note: The maximum number of member ports in a trunk group is 64 in TH3.
    220      *       But it would be quite wasteful to allocate 64 entries to each 
    221      *       _th3_trunk_member_info[unit]->member_info[x].port/member_flags
    222      *       arrays.
    223      *       These arrays will be allocated as member ports are added to
    224      *       trunk group.
    225      */
    226 
    227 
    228     return BCM_E_NONE;
    229 }
    230 
    231 
    232 
    233 /*
    234  * Function:
    235  *      _bcm_th3_trunk_hwfailover_deinit
    236  * Purpose:
    237  *      Deallocate _th3_trunk_hwfail
    238  * Parameters:
    239  *      unit - (IN)SOC unit number. 
    240  * Returns:
    241  *      None
    242  */
    243 STATIC void
    244 _bcm_th3_trunk_hwfailover_deinit(int unit)
    245 {
    246     int trunk_num_groups;
    247     int i;
    248 
    249     if (_th3_trunk_hwfail[unit]) {
    250         if (_th3_trunk_hwfail[unit]->hw_tinfo) {
    251             /* Only need to count FAST_TRUNK_PORTS_1m because
    252              * FAST_TRUNK_PORTS_2m is extension of the same LAG */
    253             trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    254             for (i = 0; i < trunk_num_groups; i++) {
    255                 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].port) {
    256                     sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].port);
    257                     _th3_trunk_hwfail[unit]->hw_tinfo[i].port = NULL;
    258                 }
    259                 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].psc) {
    260                     sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].psc);
    261                     _th3_trunk_hwfail[unit]->hw_tinfo[i].psc = NULL;
    262                 }
    263                 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].flags) {
    264                     sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].flags);
    265                     _th3_trunk_hwfail[unit]->hw_tinfo[i].flags = NULL;
    266                 }
    267             }
    268             sal_free(_th3_trunk_hwfail[unit]->hw_tinfo);
    269             _th3_trunk_hwfail[unit]->hw_tinfo = NULL;
    270         }
    271         sal_free(_th3_trunk_hwfail[unit]);
    272         _th3_trunk_hwfail[unit] = NULL;
    273     }
    274 }
    275 
    276 /*
    277  * Function:
    278  *      _bcm_th3_trunk_hwfailover_init
    279  * Purpose:
    280  *      Allocate and initialize _th3_trunk_hwfail
    281  * Parameters:
    282  *      unit - (IN)SOC unit number. 
    283  * Returns:
    284  *      BCM_X_XXX
    285  */
    286 STATIC int
    287 _bcm_th3_trunk_hwfailover_init(int unit)
    288 {
    289     int trunk_num_groups;
    290 
    291     if (_th3_trunk_hwfail[unit] == NULL) {
    292         _th3_trunk_hwfail[unit] = sal_alloc(sizeof(_th3_trunk_hwfail_t), 
    293                 "_th3_trunk_hwfail");
    294         if (_th3_trunk_hwfail[unit] == NULL) {
    295             return BCM_E_MEMORY;
    296         }
    297     }
    298     sal_memset(_th3_trunk_hwfail[unit], 0, sizeof(_th3_trunk_hwfail_t));
    299 
    300     /* Only need to count FAST_TRUNK_PORTS_1m because
    301      * FAST_TRUNK_PORTS_2m is extension of the same LAG */
    302     trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    303     if (_th3_trunk_hwfail[unit]->hw_tinfo == NULL) {
    304         _th3_trunk_hwfail[unit]->hw_tinfo =
    305             sal_alloc(sizeof(_th3_hw_tinfo_t) * trunk_num_groups,
    306                     "_th3_trunk_hwfail_hw_tinfo");
    307         if (_th3_trunk_hwfail[unit]->hw_tinfo == NULL) {
    308             _bcm_th3_trunk_hwfailover_deinit(unit);
    309             return BCM_E_MEMORY;
    310         }
    311     }
    312     sal_memset(_th3_trunk_hwfail[unit]->hw_tinfo, 0, 
    313                sizeof(_th3_hw_tinfo_t) * trunk_num_groups);
    314                                                                                 
    315     /* Note: The maximum number of member ports in a trunk group is 64 in TH3.
    316      *       But it would be quite wasteful to allocate 64 entries to each 
    317      *       _th3_trunk_hwfail[unit]->hw_tinfo[x].port/psc/flags arrays.
    318      *       These arrays will be allocated as member ports are added to trunk group.
    319      */
    320 
    321     return BCM_E_NONE;
    322 }
    323 /*
    324  * Function:
    325  *      _bcm_th3_trunk_port_map_init
    326  * Purpose:
    327  *      Initialize a software cache for the SOURCE_TRUNK_MAP_TABLE.
    328  * Parameters:
    329  *      unit     -  (IN)SOC unit number. 
    330  * Returns:
    331  *      BCM_X_XXX
    332  */
    333 int
    334 _bcm_th3_trunk_port_map_init(int unit)
    335 {
    336     int mem_size;
    337     uint8 *ptr;
    338 
    339     if (NULL != _th3_port_to_tid_map[unit]) {
    340         _bcm_th3_trunk_port_map_deinit(unit);
    341     }
    342 
    343     /* Allocated mapping array */
    344     
    345     mem_size = SOC_MAX_NUM_PORTS * sizeof(uint8);
    346     ptr = sal_alloc(mem_size, "TH3_Port_Trunk");
    347     if (NULL == ptr) {
    348         return BCM_E_MEMORY;
    349     }
    350 
    351     /* Reset buffer */
    352     sal_memset(ptr, 0, mem_size);
    353 
    354     _th3_port_to_tid_map[unit] = ptr;
    355 
    356     return BCM_E_NONE;
    357 }
    358 
    359 /*
    360  * Function:
    361  *      _bcm_th3_trunk_port_map_deinit
    362  * Purpose:
    363  *      Deinitialize a software cache for the SOURCE_TRUNK_MAP_TABLE.
    364  * Parameters:
    365  *      unit     -  (IN)SOC unit number. 
    366  * Returns:
    367  *      BCM_X_XXX
    368  */
    369 int 
    370 _bcm_th3_trunk_port_map_deinit(int unit) 
    371 {
    372     void *ptr;
    373 
    374     ptr = (void *)_th3_port_to_tid_map[unit];
    375 	
    376     _th3_port_to_tid_map[unit] = NULL;
    377 
    378     if (NULL != ptr) {
    379        	sal_free(ptr);
    380     }
    381     return (BCM_E_NONE);
    382 }
    383 
    384 /*
    385  * Function:
    386  *      _bcm_th3_trunk_port_map_set
    387  * Purpose:
    388  *      Set  (port) to  trunk id map.
    389  *      Map implements a software cache for the SOURCE_TRUNK_MAP_TABLE.
    390  * Parameters:
    391  *      unit     -  (IN) BCM device number.
    392  *      modid    -  (IN) Member port module id (not used, but from api call)
    393  *      port     -  (IN) Member port number.  
    394  *      trunk_id -  (IN) Trunk number or negative value for reset.  
    395  * Returns:
    396  *      BCM_X_XXX
    397  */
    398 STATIC int
    399 _bcm_th3_trunk_port_map_set(int unit, bcm_module_t modid,
    400                             bcm_port_t port, bcm_trunk_t trunk_id)
    401 {
    402     if (NULL == _th3_port_to_tid_map[unit]) {
    403         return BCM_E_INIT;
    404     }
    405 
    406     /* Trunk id range check. */
    407     if (trunk_id >= _BCM_TH3_TRUNK_NUM_MAX) {
    408         return BCM_E_INTERNAL;
    409     }
    410 
    411     if (port >= SOC_MAX_NUM_PORTS) {
    412         return BCM_E_PARAM;
    413     }
    414 
    415     _th3_port_to_tid_map[unit][port] = (trunk_id < 0) ? 0 : (++trunk_id);
    416 
    417     return BCM_E_NONE;
    418 }
    419 
    420 /*
    421  * Function:
    422  *      _bcm_th3_trunk_port_map_get
    423  * Purpose:
    424  *      Read mapping (port) to trunk id from software cache 
    425  *      for the SOURCE_TRUNK_MAP_TABLE.
    426  * Parameters:
    427  *      unit     -  (IN) BCM device number. 
    428  *      port     -  (IN) Member port number.  
    429  *      trunk_id -  (OUT) Trunk number or negative value for reset.  
    430  * Returns:
    431  *      BCM_X_XXX
    432  */
    433 STATIC int 
    434 _bcm_th3_trunk_port_map_get(int unit,
    435                             bcm_port_t port, bcm_trunk_t *trunk_id) 
    436 {
    437 
    438     int              idx;      /* Map array index.         */
    439 
    440     if (NULL == _th3_port_to_tid_map[unit]) {
    441         return BCM_E_INIT;
    442     }
    443 
    444     idx = port;
    445     if (idx >= SOC_MAX_NUM_PORTS) { 
    446         return (BCM_E_PARAM);
    447     }
    448 
    449     *trunk_id = _th3_port_to_tid_map[unit][idx] - 1;
    450 
    451     return (_th3_port_to_tid_map[unit][idx]) ? BCM_E_NONE : BCM_E_NOT_FOUND;
    452 }
    453 
    454 /*
    455  * Function:
    456  *      _bcm_th3_trunk_get_port_property
    457  * Purpose:
    458  *      Get trunk group ID for a port
    459  * Parameters:
    460  *      unit - (IN) SOC unit number
    461  *      port - (IN) Port number
    462  *      tid  - (OUT) Trunk group ID
    463  * Returns:
    464  *      BCM_E_xxx
    465  */
    466 int
    467 _bcm_th3_trunk_get_port_property(int unit, bcm_port_t port, int *tid)
    468 {
    469     return _bcm_th3_trunk_port_map_get(unit, port, tid);
    470 }
    471 /*
    472  * Function:
    473  *      _bcm_th3_trunk_swfailover_deinit
    474  * Purpose:
    475  *      Deallocate _th3_trunk_swfail
    476  * Parameters:
    477  *      unit - (IN)SOC unit number. 
    478  * Returns:
    479  *      None
    480  */
    481 STATIC void
    482 _bcm_th3_trunk_swfailover_deinit(int unit)
    483 {
    484     int trunk_num_groups;
    485     int i;
    486 
    487     if (_th3_trunk_swfail[unit]) {
    488         if (_th3_trunk_swfail[unit]->tinfo) {
    489             /* Only need to count FAST_TRUNK_PORTS_1m because
    490              * FAST_TRUNK_PORTS_2m is extension of the same LAG */
    491             trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    492             for (i = 0; i < trunk_num_groups; i++) {
    493                 if (_th3_trunk_swfail[unit]->tinfo[i].port) {
    494                     sal_free(_th3_trunk_swfail[unit]->tinfo[i].port);
    495                     _th3_trunk_swfail[unit]->tinfo[i].port = NULL;
    496                 }
    497             }
    498             sal_free(_th3_trunk_swfail[unit]->tinfo);
    499             _th3_trunk_swfail[unit]->tinfo = NULL;
    500         }
    501         sal_free(_th3_trunk_swfail[unit]);
    502         _th3_trunk_swfail[unit] = NULL;
    503     }
    504 }
    505 
    506 /*
    507  * Function:
    508  *      _th3_trunk_add_info_member_free
    509  * Purpose:
    510  *      Free member_flags, tp, and tm of _esw_trunk_add_info_t.
    511  * Parameters:
    512  *      add_info  - (IN) Pointer to trunk add info structure.
    513  * Returns:
    514  *      BCM_E_xxx
    515  */
    516 STATIC void 
    517 _th3_trunk_add_info_member_free(_esw_trunk_add_info_t *add_info)
    518 {
    519     if (NULL != add_info->member_flags) {
    520         sal_free(add_info->member_flags);
    521     }
    522 
    523     if (NULL != add_info->tp) {
    524         sal_free(add_info->tp);
    525     }
    526 
    527     if (NULL != add_info->tm) {
    528         sal_free(add_info->tm);
    529     }
    530 
    531     if (NULL != add_info->dynamic_scaling_factor) {
    532         sal_free(add_info->dynamic_scaling_factor);
    533     }
    534     if (NULL != add_info->dynamic_load_weight) {
    535         sal_free(add_info->dynamic_load_weight);
    536     }
    537     if (NULL != add_info->dynamic_queue_size_weight) {
    538         sal_free(add_info->dynamic_queue_size_weight);
    539     }
    540 }
    541 
    542 
    543 /*
    544  * Function:
    545  *      _th3_trunk_add_info_member_alloc
    546  * Purpose:
    547  *      Allocate member_flags, tp, and tm of _esw_trunk_add_info_t.
    548  * Parameters:
    549  *      add_info  - (IN/OUT) Pointer to trunk add info structure.
    550  *      num_ports - (IN) Number of member ports.
    551  * Returns:
    552  *      BCM_E_xxx
    553  */
    554 STATIC int
    555 _th3_trunk_add_info_member_alloc(_esw_trunk_add_info_t *add_info,
    556         int num_ports)
    557 {
    558     int rv = BCM_E_NONE;
    559 
    560     add_info->member_flags = sal_alloc(sizeof(uint32) * num_ports,
    561             "_th3_trunk_add_info_member_flags");
    562     if (add_info->member_flags == NULL) {
    563         rv = BCM_E_MEMORY;
    564         goto error;
    565     }
    566     sal_memset(add_info->member_flags, 0, sizeof(uint32) * num_ports);
    567 
    568     add_info->tp = sal_alloc(sizeof(bcm_port_t) * num_ports,
    569             "_th3_trunk_add_info_tp");
    570     if(add_info->tp == NULL) {
    571         rv = BCM_E_MEMORY;
    572         goto error;
    573     }
    574     sal_memset(add_info->tp, 0, sizeof(bcm_port_t) * num_ports);
    575 
    576     /* Following fields are not used by TH3, but add memory for
    577      * instances where we will fill it with 0 */
    578     add_info->tm = sal_alloc(sizeof(bcm_module_t) * num_ports,
    579             "_th3_trunk_add_info_tm");
    580     if (add_info->tm == NULL) {
    581         rv = BCM_E_MEMORY;
    582         goto error;
    583     }
    584     sal_memset(add_info->tm, 0, sizeof(bcm_module_t) * num_ports);
    585 
    586     add_info->dynamic_scaling_factor = sal_alloc(sizeof(int) * num_ports,
    587             "_trident_trunk_add_info_dynamic_scaling_factor");
    588     if (add_info->dynamic_scaling_factor == NULL) {
    589         rv = BCM_E_MEMORY;
    590         goto error;
    591     }
    592     sal_memset(add_info->dynamic_scaling_factor, 0, sizeof(int) * num_ports);
    593 
    594     add_info->dynamic_load_weight = sal_alloc(sizeof(int) * num_ports,
    595             "_trident_trunk_add_info_dynamic_load_weight");
    596     if (add_info->dynamic_load_weight == NULL) {
    597         rv = BCM_E_MEMORY;
    598         goto error;
    599     }
    600     sal_memset(add_info->dynamic_load_weight, 0, sizeof(int) * num_ports);
    601 
    602     add_info->dynamic_queue_size_weight = sal_alloc(sizeof(int) * num_ports,
    603             "_trident_trunk_add_info_dynamic_queue_size_weight");
    604     if (add_info->dynamic_queue_size_weight == NULL) {
    605         rv = BCM_E_MEMORY;
    606         goto error;
    607     }
    608     sal_memset(add_info->dynamic_queue_size_weight, 0, sizeof(int) * num_ports);
    609 
    610     return rv;
    611 
    612 error:
    613     if (NULL != add_info->member_flags) {
    614         sal_free(add_info->member_flags);
    615         add_info->member_flags = NULL;
    616     }
    617     if (NULL != add_info->tp) {
    618         sal_free(add_info->tp);
    619         add_info->tp = NULL;
    620     }
    621     if (NULL != add_info->tm) {
    622         sal_free(add_info->tm);
    623         add_info->tm = NULL;
    624     }
    625     if (NULL != add_info->dynamic_scaling_factor) {
    626         sal_free(add_info->dynamic_scaling_factor);
    627         add_info->dynamic_scaling_factor = NULL;
    628     }
    629     if (NULL != add_info->dynamic_load_weight) {
    630         sal_free(add_info->dynamic_load_weight);
    631         add_info->dynamic_load_weight = NULL;
    632     }
    633     if (NULL != add_info->dynamic_queue_size_weight) {
    634         sal_free(add_info->dynamic_queue_size_weight);
    635         add_info->dynamic_queue_size_weight = NULL;
    636     }
    637 
    638     return rv;
    639 }
    640 
    641 /*
    642  * Function:
    643  *	_bcm_th3_trunk_get
    644  * Purpose:
    645  *      Return a trunk information of given trunk ID.
    646  * Parameters:
    647  *      unit   - (IN) StrataSwitch PCI device unit number (driver internal).
    648  *      tid    - (IN) Trunk ID.
    649  *      t_data - (OUT) Place to store returned trunk add info.
    650  *      t_info - (IN) Trunk info.
    651  * Returns:
    652  *      BCM_E_NONE              Success.
    653  *      BCM_E_XXX
    654  */
    655 STATIC int
    656 _bcm_th3_trunk_get(int unit,
    657         bcm_trunk_t tid,
    658         _esw_trunk_add_info_t *t_data,
    659         trunk_private_t *t_info)
    660 {
    661     int i;
    662     bcm_module_t mod;
    663     bcm_port_t port;
    664 
    665     t_data->flags = t_info->flags;
    666     t_data->psc = t_info->psc;
    667     t_data->ipmc_psc = t_info->ipmc_psc;
    668     t_data->dlf_index = t_info->dlf_index_used;
    669     t_data->mc_index = t_info->mc_index_used;
    670     t_data->ipmc_index = t_info->ipmc_index_used;
    671     t_data->dynamic_size = t_info->dynamic_size;
    672     t_data->dynamic_age = t_info->dynamic_age;
    673     t_data->dynamic_load_exponent =
    674         t_info->dynamic_load_exponent;
    675     t_data->dynamic_expected_load_exponent =
    676         t_info->dynamic_expected_load_exponent;
    677 
    678     if (!t_info->in_use) {
    679         t_data->num_ports = 0;
    680         return BCM_E_NONE;
    681     }
    682 
    683     if (t_data->num_ports == 0) {
    684         t_data->num_ports = MEMBER_INFO(unit, tid).num_ports;
    685     } else {
    686         if (MEMBER_INFO(unit, tid).num_ports <= t_data->num_ports) {
    687             t_data->num_ports = MEMBER_INFO(unit, tid).num_ports;
    688         } 
    689 
    690         /* Fill in data for each port in the trunk */
    691         for (i = 0; i < t_data->num_ports; i++) {
    692             mod = 0; /* True for TH3 */
    693             port = MEMBER_INFO(unit, tid).port[i] & 0xff;
    694             t_data->tm[i] = mod;
    695             t_data->tp[i] = port;
    696             t_data->member_flags[i] = MEMBER_INFO(unit, tid).member_flags[i];
    697 
    698             t_data->dynamic_scaling_factor[i] = 0;
    699             t_data->dynamic_load_weight[i] = 0;
    700             t_data->dynamic_queue_size_weight[i] = 0;
    701         }
    702     }
    703 
    704     return BCM_E_NONE;
    705 }
    706 
    707 /*
    708  * Function:
    709  *	bcm_th3_trunk_get
    710  * Purpose:
    711  *      Return a trunk information of given trunk ID.
    712  * Parameters:
    713  *      unit   - (IN) StrataSwitch PCI device unit number (driver internal).
    714  *      tid    - (IN) Trunk ID.
    715  *      trunk_info   - (OUT) Place to store returned trunk info.
    716  *      member_max   - (IN) Size of member_array.
    717  *      member_array - (OUT) Array of trunk member structures.
    718  *      member_count - (OUT) Number of trunk members returned.
    719  *      t_info       - (IN) Internal trunk info.
    720  * Returns:
    721  *      BCM_E_NONE              Success.
    722  *      BCM_E_XXX
    723  */
    724 int
    725 bcm_th3_trunk_get(int unit,
    726         bcm_trunk_t tid,
    727         bcm_trunk_info_t *trunk_info,
    728         int member_max, 
    729         bcm_trunk_member_t *member_array,
    730         int *member_count,
    731         trunk_private_t *t_info)
    732 {
    733     _esw_trunk_add_info_t add_info;
    734     int i;
    735     int rv = BCM_E_NONE;
    736     bcm_trunk_chip_info_t chip_info;
    737     int higig_trunk;
    738 
    739     sal_memset(&add_info, 0, sizeof(_esw_trunk_add_info_t));
    740     add_info.num_ports = member_max;
    741     if (member_max > 0) {
    742         BCM_IF_ERROR_RETURN
    743             (_th3_trunk_add_info_member_alloc(&add_info, member_max));
    744     }
    745 
    746     rv = _bcm_th3_trunk_get(unit, tid, &add_info, t_info);
    747     if (BCM_FAILURE(rv)) {
    748         if (member_max > 0) {
    749             _th3_trunk_add_info_member_free(&add_info);
    750         }
    751         return rv;
    752     }
    753 
    754     trunk_info->flags = add_info.flags;
    755     trunk_info->psc = add_info.psc;
    756     trunk_info->ipmc_psc = add_info.ipmc_psc;
    757     trunk_info->dlf_index = add_info.dlf_index;
    758     trunk_info->mc_index = add_info.mc_index;
    759     trunk_info->ipmc_index = add_info.ipmc_index;
    760     trunk_info->dynamic_size = add_info.dynamic_size;
    761     trunk_info->dynamic_age = add_info.dynamic_age;
    762     trunk_info->dynamic_load_exponent =
    763         add_info.dynamic_load_exponent;
    764     trunk_info->dynamic_expected_load_exponent =
    765         add_info.dynamic_expected_load_exponent;
    766 
    767     *member_count = add_info.num_ports;
    768 
    769     if (member_max > 0) {
    770         if (member_max < *member_count) {
    771             *member_count = member_max;
    772         }
    773 
    774         /* Construct member gport */
    775         rv = bcm_esw_trunk_chip_info_get(unit, &chip_info);
    776         if (BCM_FAILURE(rv)) {
    777             _th3_trunk_add_info_member_free(&add_info);
    778             return rv;
    779         }
    780         /* No HiGig in TH3 */
    781         higig_trunk = 0;
    782         rv = _bcm_esw_trunk_gport_construct(unit, higig_trunk,
    783                 *member_count,
    784                 add_info.tp, add_info.tm,
    785                 add_info.tp);
    786         if (BCM_FAILURE(rv)) {
    787             _th3_trunk_add_info_member_free(&add_info);
    788             return rv;
    789         }
    790 
    791         for (i = 0; i < *member_count; i++) {
    792             bcm_trunk_member_t_init(&member_array[i]);
    793             member_array[i].flags = add_info.member_flags[i];
    794             member_array[i].gport = add_info.tp[i];
    795             member_array[i].dynamic_scaling_factor =
    796                 add_info.dynamic_scaling_factor[i];
    797             member_array[i].dynamic_load_weight =
    798                 add_info.dynamic_load_weight[i];
    799             member_array[i].dynamic_queue_size_weight=
    800                 add_info.dynamic_queue_size_weight[i];
    801         }
    802 
    803         _th3_trunk_add_info_member_free(&add_info);
    804     }
    805 
    806     return rv;
    807 }
    808 
    809 /* Function:
    810  *      bcm_th3_trunk_mcast_join
    811  * Purpose:
    812  *
    813  * Returns:
    814  */
    815 int
    816 bcm_th3_trunk_mcast_join(int unit, bcm_trunk_t tid,
    817         bcm_vlan_t vid, sal_mac_addr_t mac, trunk_private_t *t_info)
    818 {
    819     trunk_bitmap_entry_t        trunk_bitmap_entry;
    820     bcm_mcast_addr_t            mc_addr;
    821     bcm_trunk_chip_info_t chip_info;
    822   
    823     /* Initialising and setting the mc_addr by bcm_mcast_addr_t_init() */
    824     bcm_mcast_addr_t_init(&mc_addr, mac, vid);
    825 
    826     BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &chip_info));
    827     if ((tid >= chip_info.trunk_id_min) && (tid <= chip_info.trunk_id_max)) {
    828         /* get the ports in the trunk group */
    829         SOC_IF_ERROR_RETURN
    830             (READ_TRUNK_BITMAPm(unit, MEM_BLOCK_ANY, tid, &trunk_bitmap_entry));
    831         soc_mem_pbmp_field_get(unit, TRUNK_BITMAPm, &trunk_bitmap_entry,
    832                                TRUNK_BITMAPf, &mc_addr.pbmp);
    833     } else {
    834         return BCM_E_PARAM;
    835     }
    836 
    837     /* Add the trunk group's ports to the multicast group. */
    838     return bcm_esw_mcast_port_add(unit, &mc_addr);
    839 }
    840 
    841 /*
    842  * Function:
    843  *      _bcm_th3_trunk_swfailover_init
    844  * Purpose:
    845  *      Allocate and initialize _th3_trunk_swfail
    846  * Parameters:
    847  *      unit - (IN)SOC unit number. 
    848  * Returns:
    849  *      BCM_X_XXX
    850  */
    851 STATIC int
    852 _bcm_th3_trunk_swfailover_init(int unit)
    853 {
    854     int trunk_num_groups;
    855 
    856     if (_th3_trunk_swfail[unit] == NULL) {
    857         _th3_trunk_swfail[unit] = sal_alloc(sizeof(_th3_trunk_swfail_t), 
    858                 "_th3_trunk_swfail");
    859         if (_th3_trunk_swfail[unit] == NULL) {
    860             return BCM_E_MEMORY;
    861         }
    862     }
    863     sal_memset(_th3_trunk_swfail[unit], 0, sizeof(_th3_trunk_swfail_t));
    864     /* Only need to count FAST_TRUNK_PORTS_1m because
    865      * FAST_TRUNK_PORTS_2m is extension of the same LAG */
    866     trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m);
    867     if (_th3_trunk_swfail[unit]->tinfo == NULL) {
    868         _th3_trunk_swfail[unit]->tinfo =
    869             sal_alloc(sizeof(_th3_tinfo_t) * trunk_num_groups,
    870                     "_th3_trunk_swfail_tinfo");
    871         if (_th3_trunk_swfail[unit]->tinfo == NULL) {
    872             _bcm_th3_trunk_swfailover_deinit(unit);
    873             return BCM_E_MEMORY;
    874         }
    875     }
    876     sal_memset(_th3_trunk_swfail[unit]->tinfo, 0, 
    877                sizeof(_th3_tinfo_t) * trunk_num_groups);
    878                                                                                 
    879     /* Note: The maximum number of member ports in a trunk group is 64 in TH3.
    880      *       But it would be quite wasteful to allocate 64 entries to each 
    881      *       _th3_trunk_swfail[unit]->tinfo[x].port array. The port
    882      *       array will be allocated as member ports are added to trunk group.
    883      */
    884 
    885     return BCM_E_NONE;
    886 }
    887 
    888 /*
    889  * Function:
    890  *      _bcm_th3_trunk_deinit
    891  * Purpose:
    892  *      Deallocate global data structures
    893  * Parameters:
    894  *      unit - (IN)SOC unit number.
    895  * Returns:
    896  *      BCM_E_xxx
    897  */
    898 void
    899 _bcm_th3_trunk_deinit(int unit)
    900 {
    901     _bcm_th3_trunk_member_info_deinit(unit);
    902 
    903     _bcm_th3_trunk_port_map_deinit(unit);
    904 
    905 
    906     _bcm_th3_trunk_hwfailover_deinit(unit);
    907 
    908     _bcm_th3_trunk_swfailover_deinit(unit);
    909 }
    910 /*
    911  * Function:
    912  *      _bcm_th3_trunk_init
    913  * Purpose:
    914  *      Initialize global data structures
    915  * Parameters:
    916  *      unit - (IN)SOC unit number.
    917  * Returns:
    918  *      BCM_E_xxx
    919  */
    920 int
    921 _bcm_th3_trunk_init(int unit)
    922 {
    923     int rv;
    924 
    925     _bcm_th3_trunk_deinit(unit);
    926 
    927     rv = _bcm_th3_trunk_member_info_init(unit);
    928     if (BCM_FAILURE(rv)) {
    929         _bcm_th3_trunk_member_info_deinit(unit);
    930         return rv;
    931     }
    932 
    933     rv = _bcm_th3_trunk_port_map_init(unit);
    934     if (BCM_FAILURE(rv)) {
    935         _bcm_th3_trunk_deinit(unit);
    936         return rv;
    937     }
    938 
    939     rv = _bcm_th3_trunk_hwfailover_init(unit);
    940     if (BCM_FAILURE(rv)) {
    941         _bcm_th3_trunk_deinit(unit);
    942         return rv;
    943     }
    944 
    945     rv = _bcm_th3_trunk_swfailover_init(unit);
    946     if (BCM_FAILURE(rv)) {
    947         _bcm_th3_trunk_deinit(unit);
    948         return rv;
    949     }
    950 
    951     return BCM_E_NONE;
    952 }
    953 /* Function:
    954  *      _bcm_th3_trunk_psc_to_rtag
    955  * Purpose:
    956  *      Convert PSC to RTAG
    957  * Parameters:
    958  *      unit - (IN) unit number
    959  *      psc  - (IN) Port selection criteria
    960  *      rtag - (OUT) Pointer to RTAG
    961  * Returns:
    962  *      BCM_E_XXX
    963  */
    964 STATIC int
    965 _bcm_th3_trunk_psc_to_rtag(int unit, int psc, int *rtag)
    966 {
    967     switch (psc) {
    968     case BCM_TRUNK_PSC_SRCMAC:
    969     case BCM_TRUNK_PSC_DSTMAC:
    970     case BCM_TRUNK_PSC_SRCDSTMAC:
    971     case BCM_TRUNK_PSC_SRCIP:
    972     case BCM_TRUNK_PSC_DSTIP:
    973     case BCM_TRUNK_PSC_SRCDSTIP:
    974         /* These BCM_TRUNK_PSC_ values match the hardware RTAG values */
    975         *rtag = psc;
    976         break;
    977     case BCM_TRUNK_PSC_PORTINDEX:
    978         if (!soc_feature(unit, soc_feature_port_trunk_index)) {
    979             return BCM_E_PARAM;
    980         }
    981         *rtag = 7;
    982         break;
    983     case BCM_TRUNK_PSC_RANDOMIZED:
    984         *rtag = 0;
    985         break;
    986     case BCM_TRUNK_PSC_PORTFLOW:
    987         if (!soc_feature(unit, soc_feature_port_flow_hash)) {
    988             return BCM_E_PARAM;
    989         }
    990         *rtag = 7;
    991         break;
    992     case BCM_TRUNK_PSC_DYNAMIC:
    993     case BCM_TRUNK_PSC_DYNAMIC_ASSIGNED:
    994     case BCM_TRUNK_PSC_DYNAMIC_OPTIMAL:
    995         *rtag = 7;
    996 #ifdef BCM_TOMAHAWK3_SUPPORT
    997         if (SOC_IS_TOMAHAWK3(unit)) {
    998                return BCM_E_UNAVAIL;
    999         } else 
   1000 #endif
   1001         if (SOC_IS_ENDURO(unit)) {
   1002            if (!soc_feature(unit, soc_feature_lag_dlb)) {
   1003                return BCM_E_UNAVAIL;
   1004            }
   1005         }
   1006        break;
   1007     default:
   1008         return BCM_E_PARAM;
   1009     }
   1010 
   1011     if ((*rtag == 7) && 
   1012         (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) {
   1013         /* Hurricanex/Greyhound don't support enhanced hashing */
   1014         return BCM_E_PARAM;
   1015     }
   1016 
   1017     return BCM_E_NONE;
   1018 }
   1019 
   1020 /*
   1021  * Function:
   1022  *      _bcm_th3_nuc_tpbm_get
   1023  * Purpose:
   1024  *      Get non-unicast panel trunk members.
   1025  * Parameters:
   1026  *      unit      - (IN) SOC unit number. 
   1027  *      num_ports - (IN) Number of ports in trunk group.
   1028  *      tm        - (IN) Pointer to array of module IDs.
   1029  *      nuc_tpbm  - (OUT) Bitmap of ports eligible for non-unicast.
   1030  * Returns:
   1031  *      BCM_E_xxx
   1032  */
   1033 STATIC
   1034 int _bcm_th3_nuc_tpbm_get(int unit,
   1035                       int num_ports,
   1036                       bcm_module_t *tm,
   1037                       SHR_BITDCL *nuc_tpbm)
   1038 {
   1039     int    rv = BCM_E_NONE;
   1040     int    i, mod = -1;
   1041     uint32 mod_type;
   1042     int    all_equal = 1;
   1043 
   1044     SHR_BITDCL *xgs12_tpbm = NULL;
   1045     SHR_BITDCL *xgs3_tpbm = NULL;
   1046     SHR_BITDCL *unknown_tpbm = NULL;
   1047 
   1048     SHR_BITDCL xgs12_tpbm_result;
   1049     SHR_BITDCL xgs3_tpbm_result;
   1050     SHR_BITDCL unknown_tpbm_result;
   1051 
   1052     xgs12_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "xgs12_tpbm");
   1053     if (xgs12_tpbm == NULL) {
   1054         return BCM_E_MEMORY;
   1055     }
   1056     sal_memset(xgs12_tpbm, 0, SHR_BITALLOCSIZE(num_ports));
   1057 
   1058     xgs3_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "xgs3_tpbm");
   1059     if (xgs3_tpbm == NULL) {
   1060         sal_free(xgs12_tpbm);
   1061         return BCM_E_MEMORY;
   1062     }
   1063     sal_memset(xgs3_tpbm, 0, SHR_BITALLOCSIZE(num_ports));
   1064 
   1065     unknown_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "unknown_tpbm");
   1066     if (unknown_tpbm == NULL) {
   1067         sal_free(xgs12_tpbm);
   1068         sal_free(xgs3_tpbm);
   1069         return BCM_E_MEMORY;
   1070     }
   1071     sal_memset(unknown_tpbm, 0, SHR_BITALLOCSIZE(num_ports));
   1072 
   1073     SHR_BITSET(nuc_tpbm, 0);
   1074     for (i = 0; i < num_ports; i++) {
   1075         if (i == 0) {
   1076             mod = tm[i];
   1077         } else if (mod != tm[i]) {
   1078             all_equal = 0;
   1079         }
   1080         rv = _bcm_switch_module_type_get(unit, tm[i], &mod_type);
   1081         if (BCM_FAILURE(rv)) {
   1082             sal_free(xgs12_tpbm);
   1083             sal_free(xgs3_tpbm);
   1084             sal_free(unknown_tpbm);
   1085             return rv;
   1086         }
   1087         switch(mod_type) {
   1088             case BCM_SWITCH_MODULE_XGS1:
   1089                 /* passthru */
   1090             case BCM_SWITCH_MODULE_XGS2:
   1091                 SHR_BITSET(xgs12_tpbm, i);
   1092                 break;
   1093             case BCM_SWITCH_MODULE_XGS3:
   1094                 SHR_BITSET(xgs3_tpbm, i);
   1095                 break;
   1096             case BCM_SWITCH_MODULE_UNKNOWN:
   1097                 /* passthru */
   1098             default:
   1099                 SHR_BITSET(unknown_tpbm, i);
   1100                 break;
   1101         }
   1102     }
   1103 
   1104     /* tpbm_result will be 0 if all bits in the range are 0 */
   1105     SHR_BITTEST_RANGE(xgs12_tpbm, 0, num_ports, xgs12_tpbm_result);
   1106     SHR_BITTEST_RANGE(xgs3_tpbm, 0, num_ports, xgs3_tpbm_result);
   1107     SHR_BITTEST_RANGE(unknown_tpbm, 0, num_ports, unknown_tpbm_result);
   1108 
   1109     if (all_equal) {
   1110         SHR_BITSET_RANGE(nuc_tpbm, 0, num_ports);
   1111     } else if (xgs12_tpbm_result || unknown_tpbm_result) {
   1112         SHR_BITSET(nuc_tpbm, 0);
   1113     } else if (xgs3_tpbm_result) {
   1114         SHR_BITCOPY_RANGE(nuc_tpbm, 0, xgs3_tpbm, 0, num_ports);
   1115     }
   1116 
   1117     sal_free(xgs12_tpbm);
   1118     sal_free(xgs3_tpbm);
   1119     sal_free(unknown_tpbm);
   1120 
   1121     return rv;
   1122 }
   1123 
   1124 /*
   1125  * Function:
   1126  *      _bcm_th3_trunk_set_port_property
   1127  * Purpose:
   1128  *      Mark a mod/port pair as being in a particular trunk (or not)
   1129  *      A negative tid sets the mod/port back to non-trunk status.
   1130  */
   1131 STATIC int
   1132 _bcm_th3_trunk_set_port_property(int unit,
   1133                                   bcm_module_t mod,
   1134                                   bcm_port_t port,
   1135                                   int tid)
   1136 {
   1137     source_trunk_map_table_entry_t  stm;
   1138     soc_mem_t        mem;
   1139     int              idx, rv, ptype_get, ptype_set, tid_get, tid_set;
   1140 
   1141     if (tid < 0) {
   1142         ptype_set = 0;                /* normal port */
   1143         tid_set = 0;
   1144     } else {
   1145         ptype_set = 1;                /* trunk port */
   1146         tid_set = tid;
   1147     }
   1148 /*
   1149     BCM_IF_ERROR_RETURN
   1150         (_bcm_esw_src_mod_port_table_index_get(unit, mod, port, &idx));
   1151         */
   1152     idx = port;
   1153 
   1154     mem = SOURCE_TRUNK_MAP_TABLEm;
   1155     soc_mem_lock(unit, mem);
   1156     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, &stm);
   1157     if (BCM_SUCCESS(rv)) {
   1158         ptype_get = soc_mem_field32_get(unit, mem, (uint32 *)&stm, PORT_TYPEf);
   1159         tid_get = soc_mem_field32_get(unit, mem, (uint32 *)&stm, TGIDf);
   1160         if ((ptype_get != ptype_set) || (tid_get != tid_set)) {
   1161             soc_mem_field32_set(unit, mem, (uint32 *)&stm,
   1162                                 PORT_TYPEf, ptype_set);
   1163             soc_mem_field32_set(unit, mem, (uint32 *)&stm,
   1164                                 TGIDf, tid_set);
   1165             rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, &stm);
   1166         }
   1167     }
   1168     soc_mem_unlock(unit, mem);
   1169 
   1170     /* Update SW module, port to tid mapping. */
   1171     if (BCM_SUCCESS(rv)) {
   1172         rv = _bcm_th3_trunk_port_map_set(unit, mod, port, tid);  
   1173     }
   1174 
   1175     return rv;
   1176 }
   1177 
   1178 /*
   1179  * Function:
   1180  *      _bcm_th3_trunk_block_mask
   1181  * Purpose:
   1182  *      Update the trunk block mask table.
   1183  *      Old ports are cleared and new ports are added to each entry.
   1184  *      Each hash index location entry is owned by a specific unit/modid
   1185  *      across all units in a stack. Hash index location entry owned by
   1186  *      local unit/modid is provided by my_modid_bmap. member_count is
   1187  *      the number of NUC forwarding eligible ports in the trunk group.
   1188  *      Each eligible entry also has a rolling port that is not masked
   1189  *      from among the new NUC forwarding eligible ports (nuc_ports).
   1190  *      This is what spreads non-unicast traffic across multiple ports.
   1191  */
   1192 STATIC int
   1193 _bcm_th3_trunk_block_mask(int unit,
   1194                            int nuc_type,
   1195                            pbmp_t old_ports,
   1196                            pbmp_t new_ports,
   1197                            int *localport_array,
   1198                            int localport_count,
   1199                            SHR_BITDCL *my_modid_bmap,
   1200                            uint32 member_count,
   1201                            uint32 flags)
   1202 {
   1203     int                   i, imin, imax;
   1204     int                   rv, index_count, region_size;
   1205     soc_mem_t             mem;
   1206     nonucast_trunk_block_mask_entry_t *mask_entry;
   1207     nonucast_trunk_block_mask_entry_t *mask_table;
   1208     bcm_pbmp_t            pbmp, old_pbmp;
   1209 
   1210     rv = BCM_E_NONE;
   1211 
   1212     /* On TH3 everything should be local port because there is no stacking
   1213      * or HiGig
   1214     if (!((localport_count > 0) && (localport_count == member_count))) {
   1215         return BCM_E_PARAM;
   1216     }*/
   1217 
   1218     /* The NONUCAST_TRUNK_BLOCK_MASK table is divided into 4 regions:
   1219      * IPMC, L2MC, broadcast, and unknown unicast/multicast.
   1220      */
   1221     mem = NONUCAST_TRUNK_BLOCK_MASKm;
   1222     region_size = soc_mem_index_count(unit, mem) / 4;
   1223     if (nuc_type == TRUNK_BLOCK_MASK_TYPE_IPMC) {
   1224         imin = 0;
   1225     } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_L2MC) {
   1226         imin = region_size;
   1227     } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_BCAST) {
   1228         imin = region_size * 2;
   1229     } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_DLF) {
   1230         imin = region_size * 3;
   1231     } else {
   1232         return BCM_E_PARAM;
   1233     }
   1234 
   1235     imax = imin + region_size - 1;
   1236 
   1237     mask_table = soc_cm_salloc(unit,
   1238                             sizeof(nonucast_trunk_block_mask_entry_t) *
   1239                             region_size,
   1240                             "TH3 Block of NONUCAST_TRUNK_BLOCK_MASK entries");
   1241 
   1242     if (NULL == mask_table) {
   1243         return BCM_E_MEMORY;
   1244     }
   1245 
   1246     soc_mem_lock(unit, mem);
   1247 
   1248     if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   1249                             imin, imax, mask_table)) < 0) {
   1250         soc_mem_unlock(unit, mem);
   1251         soc_cm_sfree(unit, mask_table);
   1252         return rv;
   1253     }
   1254 
   1255     index_count = 0;
   1256     for (i = imin; i <= imax; i++) {
   1257         mask_entry = soc_mem_table_idx_to_pointer(unit, mem,
   1258                                                 nonucast_trunk_block_mask_entry_t *,
   1259                                                 mask_table, i - imin);
   1260         soc_mem_pbmp_field_get(unit, mem, mask_entry, BLOCK_MASKf, &pbmp);
   1261         SOC_PBMP_ASSIGN(old_pbmp, pbmp);
   1262         SOC_PBMP_REMOVE(pbmp, old_ports);
   1263 
   1264         if (nuc_type == TRUNK_BLOCK_MASK_TYPE_IPMC &&
   1265                 (flags & BCM_TRUNK_FLAG_IPMC_CLEAVE)) {
   1266             /* If the flag BCM_TRUNK_FLAG_IPMC_CLEAVE is set,
   1267              * IPMC trunk resolution is disabled, and the bits in
   1268              * pbmp corresponding to new_ports are not set.
   1269              */
   1270         } else {
   1271             SOC_PBMP_OR(pbmp, new_ports);
   1272             if (localport_count > 0) {
   1273                 /* All ports in TH3 are going to be local.
   1274                  * Assuming onlhy one region for now, but may need to change to
   1275                  * reflect: TRUNK_BLOCK_MASK_TYPE_IPMC, TRUNK_BLOCK_MASK_TYPE_L2MC,
   1276                  * etc. Compare with _bcm_trident_trunk_block_mask
   1277                  */
   1278                 if (SHR_BITGET(my_modid_bmap,
   1279                             ((i % region_size) % member_count))) {
   1280                     SOC_PBMP_PORT_REMOVE(
   1281                             pbmp, localport_array[index_count % localport_count]);
   1282                     index_count++;
   1283                 }
   1284             }
   1285         }
   1286         if (SOC_PBMP_EQ(pbmp, old_pbmp)) {
   1287             continue;
   1288         }
   1289         soc_mem_pbmp_field_set(unit, mem, mask_entry, BLOCK_MASKf, &pbmp);
   1290     }
   1291     rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, imin, imax, mask_table);
   1292     soc_mem_unlock(unit, mem);
   1293     soc_cm_sfree(unit, mask_table);
   1294 
   1295     return rv;
   1296 }
   1297 
   1298 /* Function:
   1299  *      _bcm_th3_trunk_failover_set
   1300  * Purpose:
   1301  *      Disable hardware failover for old trunk ports, and configure
   1302  *      hardware failover for new trunk ports.
   1303  *
   1304  *      This function first deletes any existing trunk failover setting.
   1305  *      It then frees that SDK memory up and reallocates it for
   1306  *      the passed in new failover settings (add_info).
   1307  *
   1308  *      Any existing failover settings on the passed in trunk id will
   1309  *      be deleted.
   1310  * Parameters:
   1311  *      unit        - (IN) SOC unit number
   1312  *      tid         - (IN) Trunk group ID
   1313  *      hg_trunk    - (IN) Indicates if HiGig Trunk, (NO FOR TH3)
   1314  *      add_info    - (IN) Pointer to trunk add info structure
   1315  *  Returns:
   1316  *      BCM_E_xxx
   1317  */
   1318 STATIC int
   1319 _bcm_th3_trunk_failover_set(int unit,
   1320                             bcm_trunk_t tid,
   1321                             int hg_trunk,
   1322                             _esw_trunk_add_info_t *add_info)
   1323 {
   1324     int trunk_index, failover_flags, num_hw_fail_ports, rv;
   1325     _th3_hw_tinfo_t *hw_fail_trunk;
   1326     bcm_port_t trunk_port;
   1327     bcm_port_t *port_array = NULL;
   1328 
   1329     failover_flags = 0;
   1330     if (add_info != NULL) {
   1331         if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_NEXT) {
   1332             failover_flags = BCM_TRUNK_FLAG_FAILOVER_NEXT;
   1333         } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL) {
   1334             failover_flags = BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL;
   1335         } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_ALL) {
   1336             failover_flags = BCM_TRUNK_FLAG_FAILOVER_ALL;
   1337         } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL) {
   1338             failover_flags = BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL;
   1339         }
   1340     } 
   1341     
   1342     /* No stacking, so no need to calculate trunk info index with
   1343      * HG.  Just use trunk id passed in */
   1344     hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   1345 
   1346     /* Delete the existing hardware failover configuration */
   1347     if ((NULL == add_info) || (0 != failover_flags)) {
   1348         /*Disable hardware failover for old trunk ports */
   1349         for (trunk_index = 0;
   1350              trunk_index < hw_fail_trunk->num_ports;
   1351              trunk_index++) {
   1352             /* in previous implementations, the lower 8 bits
   1353              * were the port and the upper 8 bits were modid.
   1354              * No modid since no stacking
   1355              */
   1356             trunk_port = hw_fail_trunk->port[trunk_index] & 0xff;
   1357 
   1358             BCM_IF_ERROR_RETURN
   1359                 (_bcm_th3_trunk_hwfailover_set(unit, tid, trunk_port,
   1360                                                hw_fail_trunk->psc[trunk_index],
   1361                                                0, 0, NULL));
   1362         }
   1363     }
   1364 
   1365     /* Clean up the hardware trunk failover structure */
   1366     if (hw_fail_trunk->port) {
   1367         sal_free(hw_fail_trunk->port);
   1368         hw_fail_trunk->port = NULL;
   1369     }
   1370     if (hw_fail_trunk->psc) {
   1371         sal_free(hw_fail_trunk->psc);
   1372         hw_fail_trunk->psc = NULL;
   1373     }
   1374     if (hw_fail_trunk->flags) {
   1375         sal_free(hw_fail_trunk->flags);
   1376         hw_fail_trunk->flags = NULL;
   1377     }
   1378     hw_fail_trunk->num_ports = 0;
   1379 
   1380     /* Done if we're just deleting the trunk */
   1381     if (NULL == add_info) {
   1382         return BCM_E_NONE;
   1383     }
   1384 
   1385 
   1386     /* Add new trunk data */
   1387 
   1388     /* Allocate space for the ports */
   1389     if (hw_fail_trunk->port == NULL) {
   1390         hw_fail_trunk->port = sal_alloc(sizeof(uint16) * add_info->num_ports,
   1391                         "hw_tinfo_port");
   1392         if (hw_fail_trunk->port == NULL) {
   1393             return BCM_E_MEMORY;
   1394         }
   1395     }
   1396     sal_memset(hw_fail_trunk->port, 0, sizeof(uint16) * add_info->num_ports);
   1397 
   1398     /* Allocate space for the port selection criteria */
   1399     if (hw_fail_trunk->psc == NULL) {
   1400         hw_fail_trunk->psc = sal_alloc(sizeof(uint8) * add_info->num_ports,
   1401                         "hw_tinfo_psc");
   1402         if (hw_fail_trunk->psc == NULL) {
   1403             sal_free(hw_fail_trunk->port);
   1404             hw_fail_trunk->port = NULL;
   1405             return BCM_E_MEMORY;
   1406         }
   1407     }
   1408     sal_memset(hw_fail_trunk->psc, 0, sizeof(uint8) * add_info->num_ports);
   1409 
   1410     /* Allocate space for flags */
   1411     if (hw_fail_trunk->flags == NULL) {
   1412         hw_fail_trunk->flags = sal_alloc(sizeof(uint32) * add_info->num_ports,
   1413                         "hw_tinfo_flags");
   1414         if (hw_fail_trunk->flags == NULL) {
   1415             sal_free(hw_fail_trunk->port);
   1416             hw_fail_trunk->port = NULL;
   1417             sal_free(hw_fail_trunk->psc);
   1418             hw_fail_trunk->psc = NULL;
   1419             return BCM_E_MEMORY;
   1420         }
   1421     }
   1422     sal_memset(hw_fail_trunk->flags, 0, sizeof(uint32) * add_info->num_ports);
   1423 
   1424     /* Allocate space for local port array, to be freed at end of function */
   1425     if (port_array == NULL) {
   1426         port_array = sal_alloc(sizeof(bcm_port_t) * add_info->num_ports,
   1427                         "port_array");
   1428         if (port_array == NULL) {
   1429             sal_free(hw_fail_trunk->port);
   1430             hw_fail_trunk->port = NULL;
   1431             sal_free(hw_fail_trunk->psc);
   1432             hw_fail_trunk->psc = NULL;
   1433             sal_free(hw_fail_trunk->flags);
   1434             hw_fail_trunk->flags = NULL;
   1435             return BCM_E_MEMORY;
   1436         }
   1437     }
   1438     sal_memset(port_array, 0, sizeof(bcm_port_t) * add_info->num_ports);
   1439 
   1440     /* Copy info from the add_info into the local hardware failover
   1441      * structure */
   1442     num_hw_fail_ports = 0;
   1443     for(trunk_index = 0; trunk_index < add_info->num_ports; trunk_index++) {
   1444         if (add_info->member_flags[trunk_index] &
   1445                 BCM_TRUNK_MEMBER_EGRESS_DISABLE) {
   1446             continue;
   1447         }
   1448 
   1449         hw_fail_trunk->flags[num_hw_fail_ports] = failover_flags;
   1450         hw_fail_trunk->psc[num_hw_fail_ports] = add_info->psc;
   1451         hw_fail_trunk->port[num_hw_fail_ports] = add_info->tp[trunk_index];
   1452 
   1453         /* Add all the passed in ports to this array. If there are any
   1454          * flags set for a port, it is updated, else a port from
   1455          * this array is added. */
   1456         port_array[num_hw_fail_ports] = add_info->tp[trunk_index];
   1457 
   1458         num_hw_fail_ports++;
   1459     }
   1460 
   1461     hw_fail_trunk->num_ports = num_hw_fail_ports;
   1462 
   1463     /* No flags in trunk_set means no failover changes */
   1464     if (0 != failover_flags) {
   1465         /* Configure hardware failover for new trunk ports */
   1466         for (trunk_index = 0; trunk_index < hw_fail_trunk->num_ports; 
   1467                 trunk_index++) {
   1468 
   1469             /* modport is always 0 and there is no HiGig, and no
   1470              * cascaded physical ports, so just calling to set
   1471              * hwfailover
   1472              */
   1473             rv = _bcm_th3_trunk_hwfailover_set(unit, tid,
   1474                     hw_fail_trunk->port[trunk_index],
   1475                     hw_fail_trunk->psc[trunk_index],
   1476                     hw_fail_trunk->flags[trunk_index],
   1477                     hw_fail_trunk->num_ports,
   1478                     port_array);
   1479             if (BCM_FAILURE(rv)) {
   1480                 sal_free(port_array);
   1481                 return rv;
   1482             }
   1483         }
   1484     }
   1485 
   1486     sal_free(port_array);
   1487     
   1488     return BCM_E_NONE;
   1489 }
   1490 #ifdef BCM_WARM_BOOT_SUPPORT
   1491 /*
   1492  * Function:
   1493  *      _bcm_th3_trunk_member_info_set
   1494  * Purpose:
   1495  *      Set trunk member info - used by trunk_reinit
   1496  * Parameters:
   1497  *      unit   - (IN) SOC unit number. 
   1498  *      tid    - (IN) Trunk ID.
   1499  *      num_ports - (IN) Number of trunk members. 
   1500  *      member_port  - (IN) Trunk member port ID array.
   1501  *      member_flags - (IN) Trunk member flags array.
   1502  * Returns:
   1503  *      BCM_E_xxx
   1504  */
   1505 int
   1506 _bcm_th3_trunk_member_info_set(int unit, bcm_trunk_t tid,
   1507               uint16 num_ports, uint8  *member_port, uint32 *member_flags)
   1508 {
   1509     int i, rv;
   1510     bcm_module_t mod = 0;
   1511     /* Save new trunk member info. Free up the old memory and allocate new space
   1512      * since there may be a different number of entries. */
   1513 
   1514     if (MEMBER_INFO(unit, tid).port) {
   1515         sal_free(MEMBER_INFO(unit, tid).port);
   1516         MEMBER_INFO(unit, tid).port = NULL;
   1517     }
   1518     if (MEMBER_INFO(unit, tid).member_flags) {
   1519         sal_free(MEMBER_INFO(unit, tid).member_flags);
   1520         MEMBER_INFO(unit, tid).member_flags = NULL;
   1521     }
   1522 
   1523     MEMBER_INFO(unit, tid).port = sal_alloc(
   1524             sizeof(uint16) * num_ports, "member info port");
   1525     if (NULL == MEMBER_INFO(unit, tid).port) {
   1526         return BCM_E_MEMORY ;
   1527     }
   1528 
   1529     MEMBER_INFO(unit, tid).member_flags = sal_alloc(
   1530             sizeof(uint32) * num_ports, "member info flags");
   1531     if (NULL == MEMBER_INFO(unit, tid).member_flags) {
   1532         sal_free(MEMBER_INFO(unit, tid).port);
   1533         MEMBER_INFO(unit, tid).port = NULL;
   1534         return BCM_E_MEMORY ;
   1535     }
   1536     MEMBER_INFO(unit, tid).num_ports = num_ports;
   1537 
   1538     for (i = 0; i < num_ports; i++) {
   1539         MEMBER_INFO(unit, tid).port[i] = member_port[i];
   1540         MEMBER_INFO(unit, tid).member_flags[i] = member_flags[i];
   1541         /* restore inverted relationship also */
   1542         if ((rv = _bcm_th3_trunk_port_map_set(unit, mod,
   1543                  member_port[i], tid)) != BCM_E_NONE) {
   1544             return rv;
   1545         }
   1546     }
   1547     return BCM_E_NONE;
   1548 }
   1549 
   1550 /*
   1551  * Function:
   1552  *      _bcm_th3_trunk_member_info_get
   1553  * Purpose:
   1554  *      Return tunk and member info - used by trunk_sync
   1555  * Parameters:
   1556  *      unit   - (IN) SOC unit number. 
   1557  *      tid    - (IN) Trunk ID.
   1558  *      t_data - (OUT) carries trunk and member data filled out
   1559  *      t_info - (IN) Internal trunk info.
   1560  * Returns:
   1561  *      BCM_E_xxx
   1562  */
   1563 int
   1564  _bcm_th3_trunk_member_info_get(int unit, bcm_trunk_t tid,
   1565                                 _esw_trunk_add_info_t *t_data, trunk_private_t *t_info)
   1566 {
   1567     int rv = BCM_E_NONE;
   1568     if (t_data->num_ports != 0) {
   1569         rv = _th3_trunk_add_info_member_alloc(t_data, t_data->num_ports);
   1570         if (BCM_FAILURE(rv)) {
   1571             return rv;
   1572         }
   1573     }
   1574     rv = _bcm_th3_trunk_get(unit, tid, t_data, t_info);
   1575     if (BCM_FAILURE(rv)) {
   1576         _th3_trunk_add_info_member_free(t_data);
   1577     }
   1578     return rv;
   1579 }
   1580 /*
   1581  * Function:
   1582  *      _bcm_th3_trunk_hwfailover_num_ports_get
   1583  * Purpose:
   1584  *      Get hwfailover fail to ports
   1585  * Parameters:
   1586  *      unit   - (IN) SOC unit number. 
   1587  *      tid    - (IN) Trunk ID.
   1588  * Returns:
   1589  *      hwfailover fail to ports
   1590  */
   1591 uint16
   1592 _bcm_th3_trunk_hwfailover_num_ports_get(int unit, bcm_trunk_t tid)
   1593 {
   1594     uint16 num_ports;
   1595 
   1596     num_ports = _th3_trunk_hwfail[unit]->hw_tinfo[tid].num_ports;
   1597 
   1598     return num_ports;
   1599 }
   1600 /*
   1601  * Function:
   1602  *      _bcm_th3_trunk_hwfailover_num_ports_set
   1603  * Purpose:
   1604  *      Set hwfailover fail to ports
   1605  * Parameters:
   1606  *      unit   - (IN) SOC unit number. 
   1607  *      tid    - (IN) Trunk ID.
   1608  *      num_ports - (IN) hwfailover fail to ports
   1609  * Returns:
   1610  *      hwfailover num ports
   1611  */
   1612 void
   1613 _bcm_th3_trunk_hwfailover_num_ports_set(int unit, bcm_trunk_t tid, uint16 num_ports)
   1614 {
   1615     _th3_trunk_hwfail[unit]->hw_tinfo[tid].num_ports = num_ports;
   1616 }
   1617 /*
   1618  * Function:
   1619  *      _bcm_th3_trunk_hwfailover_flags_get
   1620  * Purpose:
   1621  *      Get hwfailover per port flags
   1622  * Parameters:
   1623  *      unit   - (IN) SOC unit number. 
   1624  *      tid    - (IN) Trunk ID.
   1625  *      port    - (IN) port.
   1626  * Returns:
   1627  *      hwfailover per port flags
   1628  */
   1629 uint8
   1630  _bcm_th3_trunk_hwfailover_flags_get(int unit, bcm_trunk_t tid, int port)
   1631 {
   1632     uint8 flags;
   1633     _th3_hw_tinfo_t *hw_fail_trunk;
   1634 
   1635     hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   1636 
   1637     if (NULL != hw_fail_trunk->flags) {
   1638         flags = hw_fail_trunk->flags[port];
   1639     } else {
   1640         flags = 0;
   1641     }
   1642 
   1643     return flags;
   1644 }
   1645 /*
   1646  * Function:
   1647  *      _bcm_th3_trunk_hwfailover_flags_set
   1648  * Purpose:
   1649  *      Set hwfailover per port flags
   1650  * Parameters:
   1651  *      unit   - (IN) SOC unit number. 
   1652  *      tid    - (IN) Trunk ID.
   1653  *      port   - (IN) port.
   1654  *      flags  - (IN) hwfailover per port flags.
   1655  * Returns:
   1656  *      None
   1657  */
   1658 void
   1659  _bcm_th3_trunk_hwfailover_flags_set(int unit, bcm_trunk_t tid, int port, uint8 flags)
   1660 {
   1661     _th3_hw_tinfo_t *hw_fail_trunk;
   1662 
   1663     hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   1664 
   1665     if (NULL != hw_fail_trunk->flags) {
   1666         hw_fail_trunk->flags[port] = flags;
   1667     }
   1668 }
   1669 #endif
   1670 /*
   1671  * Function:
   1672  *      _bcm_th3_trunk_swfailover_set
   1673  * Purpose:
   1674  *      Set front panel trunk software failover config.
   1675  * Parameters:
   1676  *      unit   - (IN) SOC unit number. 
   1677  *      tid    - (IN) Trunk ID.
   1678  *      rtag   - (IN) Port selection criteria. 
   1679  *      nports - (IN) Number of trunk members. 
   1680  *      mods   - (IN) Trunk member module ID array.
   1681  *      ports  - (IN) Trunk member port ID array.
   1682  *      member_flags - (IN) Trunk member flags array.
   1683  *      flags  - (IN) Trunk group flags.
   1684  * Returns:
   1685  *      BCM_E_xxx
   1686  */
   1687 STATIC int
   1688 _bcm_th3_trunk_swfailover_set(int unit,
   1689         bcm_trunk_t tid,
   1690         int rtag,
   1691         int nports,
   1692         int *mods,
   1693         int *ports,
   1694         uint32 *member_flags,
   1695         uint32 flags)
   1696 {
   1697     _th3_trunk_swfail_t *swf;
   1698     _th3_tinfo_t        *swft;
   1699     bcm_pbmp_t          localports;
   1700     bcm_port_t          port;
   1701     int                 i;
   1702     bcm_pbmp_t          all_pbmp;
   1703 
   1704     if (_th3_trunk_swfail[unit] == NULL) {
   1705         return BCM_E_INIT;
   1706     }
   1707 
   1708     swf = _th3_trunk_swfail[unit];
   1709     swft = &swf->tinfo[tid];
   1710 
   1711     swf->mymodid = 0;
   1712     swft->rtag = rtag;
   1713     swft->num_ports = nports;
   1714     swft->flags = flags;
   1715 
   1716     if (swft->port) {
   1717         sal_free(swft->port);
   1718         swft->port = NULL;
   1719     }
   1720     if (swft->member_flags) {
   1721         sal_free(swft->member_flags);
   1722         swft->member_flags = NULL;
   1723     }
   1724 
   1725     BCM_PBMP_CLEAR(localports);
   1726     if (swft->num_ports > 0) {
   1727         swft->port = sal_alloc(sizeof(uint16) * swft->num_ports,
   1728                 "swfail_tinfo_port");
   1729         if (swft->port == NULL) {
   1730             return BCM_E_MEMORY;
   1731         }
   1732         swft->member_flags = sal_alloc(sizeof(uint32) * swft->num_ports,
   1733                 "swfail_tinfo_member_flags");
   1734         if (swft->member_flags == NULL) {
   1735             sal_free(swft->port);
   1736             swft->port = NULL;
   1737             return BCM_E_MEMORY;
   1738         }
   1739 
   1740         for (i = 0; i < nports; i++) {
   1741             swft->port[i] = (mods[i] << 8) | ports[i];
   1742             if (mods[i] == 0) {
   1743                 BCM_PBMP_PORT_ADD(localports, ports[i]);
   1744             }
   1745 
   1746             swft->member_flags[i] = member_flags[i];
   1747         }
   1748     }
   1749 
   1750     BCM_PBMP_CLEAR(all_pbmp);
   1751     BCM_PBMP_ASSIGN(all_pbmp, PBMP_ALL(unit));
   1752 
   1753     PBMP_ITER(all_pbmp, port) {
   1754         if (BCM_PBMP_MEMBER(localports, port)) {
   1755             /* coverity[overrun-local : FALSE] */
   1756             swf->trunk[port] = tid + 1;
   1757         } else if (swf->trunk[port] == tid + 1) {
   1758             swf->trunk[port] = 0;       /* remove stale pointers to tid */
   1759         }
   1760     }
   1761     return BCM_E_NONE;
   1762 }
   1763 
   1764 /*
   1765  * Function:
   1766  *      _bcm_th3_trunk_lag_reinit
   1767  * Purpose:
   1768  *      Initialize global data structures
   1769  * Parameters:
   1770  *      unit - (IN)SOC unit number.
   1771  * Returns:
   1772  *      BCM_E_xxx
   1773  */
   1774 int
   1775 _bcm_th3_trunk_lag_reinit(int unit, int ngroups_fp, trunk_private_t *trunk_info)
   1776 {
   1777     _th3_hw_tinfo_t *hw_fail_trunk;
   1778     int tid;
   1779     int rv = BCM_E_NONE;
   1780     int i;
   1781     int num_ports, rtag;
   1782     bcm_module_t *egr_hw_mods;
   1783     bcm_port_t *egr_hw_ports;
   1784 
   1785     for (tid = 0; tid < ngroups_fp; tid++, trunk_info++) {
   1786         num_ports = MEMBER_INFO(unit, tid).num_ports;
   1787         egr_hw_mods = sal_alloc(sizeof(bcm_module_t) * num_ports,
   1788                 "egr_hw_mods");
   1789         if (egr_hw_mods == NULL) {
   1790             return BCM_E_MEMORY;
   1791         }
   1792     
   1793         egr_hw_ports = sal_alloc(sizeof(bcm_port_t) * num_ports,
   1794                 "egr_hw_ports");
   1795         if (egr_hw_ports == NULL) {
   1796             sal_free(egr_hw_mods);
   1797             return BCM_E_MEMORY;
   1798         }
   1799         sal_memset(egr_hw_mods, 0, sizeof(bcm_module_t) * num_ports);
   1800         for (i = 0; i < num_ports; i++) {
   1801 	    egr_hw_ports[i] = MEMBER_INFO(unit, tid).port[i];
   1802         }
   1803 	rv = _bcm_th3_trunk_psc_to_rtag(unit, trunk_info->psc, &rtag);
   1804         if (BCM_FAILURE(rv)) {
   1805             sal_free(egr_hw_mods);
   1806             sal_free(egr_hw_ports);
   1807             return rv;
   1808         }
   1809         rv = _bcm_th3_trunk_swfailover_set( unit, tid, 
   1810                                   rtag,
   1811                                   num_ports, 
   1812                                   egr_hw_mods,
   1813                                   egr_hw_ports,
   1814                                   MEMBER_INFO(unit, tid).member_flags,
   1815                                   trunk_info->flags);
   1816         sal_free(egr_hw_mods);
   1817         sal_free(egr_hw_ports);
   1818         if (BCM_FAILURE(rv)) {
   1819             return rv;
   1820         }
   1821         
   1822         hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   1823         hw_fail_trunk->port = sal_alloc(sizeof(uint16) * hw_fail_trunk->num_ports,
   1824                         "hw_tinfo_port");
   1825         if (hw_fail_trunk->port == NULL) { 
   1826                 return BCM_E_MEMORY;
   1827         }
   1828         sal_memset(hw_fail_trunk->port, 0, sizeof(uint16) * hw_fail_trunk->num_ports);
   1829 
   1830         /* Allocate space for the port selection criteria */
   1831         hw_fail_trunk->psc = sal_alloc(sizeof(uint8) * hw_fail_trunk->num_ports,
   1832                         "hw_tinfo_psc");
   1833         if (hw_fail_trunk->psc == NULL) {
   1834             sal_free(hw_fail_trunk->port);
   1835             hw_fail_trunk->port = NULL;
   1836             return BCM_E_MEMORY;
   1837         }
   1838         sal_memset(hw_fail_trunk->psc, 0, sizeof(uint8) * hw_fail_trunk->num_ports);
   1839 
   1840         /* Allocate space for flags */
   1841         hw_fail_trunk->flags = sal_alloc(sizeof(uint32) * hw_fail_trunk->num_ports,
   1842                         "hw_tinfo_flags");
   1843         if (hw_fail_trunk->flags == NULL) {
   1844             sal_free(hw_fail_trunk->port);
   1845             hw_fail_trunk->port = NULL;
   1846             sal_free(hw_fail_trunk->psc);
   1847             hw_fail_trunk->psc = NULL;
   1848             return BCM_E_MEMORY;
   1849         }
   1850         sal_memset(hw_fail_trunk->flags, 0, sizeof(uint32) * hw_fail_trunk->num_ports);
   1851         for (i = 0; i < hw_fail_trunk->num_ports; i++) {
   1852             hw_fail_trunk->psc[i] = trunk_info->psc;
   1853             hw_fail_trunk->port[i] = MEMBER_INFO(unit, tid).port[i]; 
   1854             hw_fail_trunk->flags[i] = MEMBER_INFO(unit, tid).member_flags[i]; 
   1855         }
   1856 
   1857 
   1858     } /*  for tid */
   1859 
   1860     return rv;
   1861 }
   1862 
   1863 #if 0
   1864 /*
   1865  * Function:
   1866  *      _bcm_th3_lag_slb_free_resource
   1867  * Purpose:
   1868  *      Free resources for a LAG static load balancing group.
   1869  * Parameters:
   1870  *      unit  - (IN) SOC unit number. 
   1871  *      tid - (IN) Trunk group ID.
   1872  * Returns:
   1873  *      BCM_E_xxx
   1874  */
   1875 STATIC int
   1876 _bcm_th3_lag_slb_free_resource(int unit, int tid)
   1877 {
   1878     trunk_group_entry_t tg_entry;
   1879     int base_ptr;
   1880     int tg_size;
   1881     int rtag;
   1882     int num_entries;
   1883  
   1884     SOC_IF_ERROR_RETURN
   1885         (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry));
   1886     base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry,
   1887             BASE_PTRf);
   1888     tg_size = 1 + soc_TRUNK_GROUPm_field32_get(unit, &tg_entry,
   1889             TG_SIZEf);
   1890     rtag = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry,
   1891             RTAGf);
   1892 
   1893     if (rtag != 0) {
   1894         num_entries = tg_size;
   1895         if (rtag >= 1 && rtag <= 6) {
   1896 #ifdef BCM_KATANA_SUPPORT
   1897             if (SOC_IS_KATANAX(unit)) {
   1898                 num_entries = _BCM_KATANA_FP_TRUNK_RTAG1_6_MAX_PORTCNT;
   1899             } else
   1900 #endif
   1901             if (soc_feature(unit,
   1902                         soc_feature_rtag1_6_max_portcnt_less_than_rtag7)) { 
   1903                 num_entries = _BCM_TD_FP_TRUNK_RTAG1_6_MAX_PORTCNT;
   1904             }
   1905         } 
   1906 
   1907         _BCM_FP_TRUNK_MEMBER_USED_CLR_RANGE(unit, base_ptr, num_entries);
   1908     }
   1909     return BCM_E_NONE;
   1910 }
   1911 #endif
   1912 
   1913 /*
   1914  * Function:
   1915  *      _bcm_th3_lag_slb_set
   1916  * Purpose:
   1917  *      Configure a LAG static load balancing group.
   1918  *      Memories modified: 
   1919  *          FAST_TRUNK_PORTS_1
   1920  *          FAST_TRUNK_PORTS_2
   1921  *          FAST_TRUNK_SIZE
   1922  * Parameters:
   1923  *      unit  - (IN) SOC unit number. 
   1924  *      tid   - (IN) Trunk group ID.
   1925  *      num_uc_egr_ports - (IN) Number of trunk member ports eligible for
   1926  *                              unicast egress
   1927  *      uc_egr_hwmod  - (IN) Array of module IDs
   1928  *      uc_egr_hwport - (IN) Array of port IDs
   1929  *      t_info        - (IN) Pointer to trunk info.
   1930  * Returns:
   1931  *      BCM_E_xxx
   1932  */
   1933 STATIC int
   1934 _bcm_th3_lag_slb_set(int unit, int tid, int num_uc_egr_ports,
   1935         int *uc_egr_hwmod, int *uc_egr_hwport, trunk_private_t *t_info)
   1936 {
   1937     int i, pipe;
   1938     uint32 rval;
   1939     uint16 seed = 0;
   1940     soc_reg_t reg;
   1941     fast_trunk_ports_1_entry_t  fast_1;
   1942     fast_trunk_ports_2_entry_t  fast_2;
   1943     fast_trunk_size_entry_t     fast_trunk_size;
   1944 
   1945     memset(&fast_1, 0, sizeof(fast_trunk_ports_1_entry_t));
   1946     memset(&fast_2, 0, sizeof(fast_trunk_ports_2_entry_t));
   1947     memset(&fast_trunk_size, 0, sizeof(fast_trunk_size_entry_t));
   1948 
   1949     /* No enabled ports in the trunk. Clear it all out */
   1950     if (num_uc_egr_ports == 0) {
   1951 
   1952         /* Clear out all 64 ports in this trunk */
   1953         for (i = 0; i < _BCM_TH3_PORTS_PER_TRUNK_MAX; i++) {
   1954             /* Clear the first 32 Fast LAG Ports */
   1955             if (i < _BCM_TH3_PORTS_PER_TRUNK_MAX / 2) {
   1956                 soc_FAST_TRUNK_PORTS_1m_field32_set(unit, &fast_1,
   1957                         _th3_fast_portf[i], 0);
   1958             } else {
   1959                 /* Clear the last 32 Fast LAG Ports */
   1960                 soc_FAST_TRUNK_PORTS_2m_field32_set(unit, &fast_2,
   1961                         _th3_fast_portf[i], 0);
   1962             }
   1963         }
   1964 
   1965         /* Set the size of the Fast LAG to 0 and reset the trunk mode */
   1966         soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size,
   1967                                         TRUNK_MODEf, 0);
   1968         soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size,
   1969                                         TG_SIZEf, 0);
   1970 
   1971     } else {
   1972         /* Fill in the Fast LAG Ports */
   1973         for (i = 0; i < num_uc_egr_ports; i++) {
   1974             /* Set the first 32 Fast LAG Ports */
   1975             if (i < _BCM_TH3_PORTS_PER_TRUNK_MAX / 2) {
   1976                 soc_FAST_TRUNK_PORTS_1m_field32_set(unit, &fast_1,
   1977                         _th3_fast_portf[i], uc_egr_hwport[i]);
   1978             } else {
   1979                 /* Set the last 32 Fast LAG Ports */
   1980                 soc_FAST_TRUNK_PORTS_2m_field32_set(unit, &fast_2,
   1981                         _th3_fast_portf[i], uc_egr_hwport[i]);
   1982             }
   1983         }
   1984 
   1985         
   1986         soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, TG_SIZEf,
   1987                 num_uc_egr_ports - 1);
   1988 
   1989         /* Set the Trunk Mode */
   1990         if (t_info->psc == BCM_TRUNK_PSC_RANDOMIZED) {
   1991             /* Random */
   1992             soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size,
   1993                                             TRUNK_MODEf, 0x1);
   1994            /* Configure Rand LB Seed */
   1995             seed = (sal_rand()) % 0xFFFF;
   1996             rval = 0;
   1997             for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   1998                 reg = SOC_REG_UNIQUE_ACC(unit, TRUNK_RAND_LB_SEEDr)[pipe];
   1999                 soc_reg_field_set(unit, reg, &rval, SEEDf, seed);
   2000                 SOC_IF_ERROR_RETURN
   2001                     (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
   2002             }
   2003 
   2004         } else {
   2005             /* Hash */
   2006             soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size,
   2007                                             TRUNK_MODEf, 0x0);
   2008         }
   2009     }
   2010 
   2011     SOC_IF_ERROR_RETURN
   2012         (WRITE_FAST_TRUNK_PORTS_1m(unit, MEM_BLOCK_ALL, tid, &fast_1));
   2013     SOC_IF_ERROR_RETURN
   2014         (WRITE_FAST_TRUNK_PORTS_2m(unit, MEM_BLOCK_ALL, tid, &fast_2));
   2015     SOC_IF_ERROR_RETURN
   2016         (WRITE_FAST_TRUNK_SIZEm(unit, MEM_BLOCK_ALL, tid, &fast_trunk_size));
   2017 
   2018 #if 0
   2019 
   2020 
   2021 
   2022     int i;
   2023     int num_entries;
   2024     int max_base_ptr;
   2025     int base_ptr;
   2026     SHR_BITDCL occupied;
   2027     trunk_member_entry_t trunk_member_entry;
   2028     trunk_group_entry_t  tg_entry;
   2029 #ifdef BCM_TOMAHAWK_SUPPORT
   2030     trunk_rr_cnt_entry_t rrlb_cnt_entry;
   2031     uint16 seed=0;
   2032     soc_reg_t reg;
   2033     uint32 rval;
   2034     int pipe;
   2035 #endif
   2036 
   2037     if (num_uc_egr_ports == 0) {
   2038         SOC_IF_ERROR_RETURN
   2039             (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry));
   2040         soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, BASE_PTRf, 0);
   2041         soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TG_SIZEf, 0);
   2042         soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RTAGf, 0);
   2043         SOC_IF_ERROR_RETURN
   2044             (WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, &tg_entry));
   2045         return BCM_E_NONE;
   2046     }
   2047 
   2048     /* Find a contiguous region of TRUNK_MEMBERm table that's large
   2049      * enough to hold all of the trunk group's egress member ports.
   2050      */
   2051 
   2052     num_entries = num_uc_egr_ports;
   2053 
   2054     /* If RTAG is 1-6, Trident A0 and Katana ignore the TG_SIZE field and 
   2055      * assume the trunk group occupies FP_TRUNK_RTAG1_6_MAX_PORTCNT
   2056      * contiguous entries in TRUNK_MEMBER table.
   2057      */
   2058     if (t_info->rtag >= 1 && t_info->rtag <= 6) {
   2059 #ifdef BCM_KATANA_SUPPORT
   2060         if (SOC_IS_KATANAX(unit)) {
   2061             num_entries = _BCM_KATANA_FP_TRUNK_RTAG1_6_MAX_PORTCNT;
   2062         } else
   2063 #endif
   2064         if (soc_feature(unit,
   2065                     soc_feature_rtag1_6_max_portcnt_less_than_rtag7)) { 
   2066             num_entries = _BCM_TD_FP_TRUNK_RTAG1_6_MAX_PORTCNT;
   2067         }
   2068     } 
   2069 
   2070     max_base_ptr = soc_mem_index_count(unit, TRUNK_MEMBERm) - num_entries;
   2071     for (base_ptr = 0; base_ptr <= max_base_ptr; base_ptr++) {
   2072         /* Check if the contiguous region of TRUNK_MEMBERm table from
   2073          * index base_ptr to (base_ptr + num_entries - 1) is free. 
   2074          */
   2075         _BCM_FP_TRUNK_MEMBER_TEST_RANGE(unit, base_ptr, num_entries, occupied); 
   2076         if (!occupied) {
   2077             break;
   2078         }
   2079     }
   2080 
   2081     if (base_ptr > max_base_ptr) {
   2082         /* A contiguous region of the desired size could not be found in
   2083          * TRUNK_MEMBERm table.
   2084          */
   2085         return BCM_E_RESOURCE;
   2086     }
   2087 
   2088     for (i = 0; i < num_entries; i++) {
   2089         sal_memset(&trunk_member_entry, 0, sizeof(trunk_member_entry_t));
   2090         soc_TRUNK_MEMBERm_field32_set
   2091             (unit, &trunk_member_entry, MODULE_IDf,
   2092              uc_egr_hwmod[i % num_uc_egr_ports]);
   2093         soc_TRUNK_MEMBERm_field32_set
   2094             (unit, &trunk_member_entry, PORT_NUMf,
   2095              uc_egr_hwport[i % num_uc_egr_ports]);
   2096         SOC_IF_ERROR_RETURN(WRITE_TRUNK_MEMBERm(unit, MEM_BLOCK_ALL,
   2097                     base_ptr + i, &trunk_member_entry)); 
   2098     }
   2099 
   2100     /* Set fp_trunk_member_bitmap */
   2101     _BCM_FP_TRUNK_MEMBER_USED_SET_RANGE(unit, base_ptr, num_entries);
   2102 
   2103     /* Update TRUNK_GROUP table */
   2104 
   2105     SOC_IF_ERROR_RETURN
   2106         (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry));
   2107     soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, BASE_PTRf, base_ptr);
   2108     soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TG_SIZEf,
   2109             num_uc_egr_ports-1);
   2110     soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RTAGf, t_info->rtag);
   2111 
   2112 #ifdef BCM_APACHE_SUPPORT
   2113     if (t_info->psc == BCM_TRUNK_PSC_ROUND_ROBIN) {
   2114         if (soc_feature(unit, soc_feature_apache_round_robin_fp_lag)) {
   2115            soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RR_LB_ENABLEf, 0x1);
   2116            soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RR_LB_COUNTER_SELECTf, t_info->rr_lag_select);
   2117         }
   2118     }
   2119 #endif /* BCM_APACHE_SUPPORT  */
   2120 
   2121 #ifdef BCM_TOMAHAWK_SUPPORT
   2122     if (t_info->psc == BCM_TRUNK_PSC_ROUND_ROBIN) {
   2123         if (soc_feature(unit, soc_feature_round_robin_load_balance)) {
   2124            soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TRUNK_MODEf, 0x2);
   2125 
   2126             BCM_IF_ERROR_RETURN(READ_TRUNK_RR_CNTm(unit, MEM_BLOCK_ANY,
   2127                     tid, &rrlb_cnt_entry));
   2128             soc_TRUNK_RR_CNTm_field32_set(unit, &rrlb_cnt_entry,
   2129                             RRLB_CNTf, 0);
   2130             BCM_IF_ERROR_RETURN(WRITE_TRUNK_RR_CNTm(unit, MEM_BLOCK_ALL,
   2131                             tid, &rrlb_cnt_entry));
   2132         }
   2133     } else if (t_info->psc == BCM_TRUNK_PSC_RANDOMIZED) {
   2134         if (soc_feature(unit, soc_feature_randomized_load_balance)) {
   2135            soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TRUNK_MODEf, 0x1);
   2136            /* Configure Rand LB Seed */
   2137             seed = (sal_rand()) % 0xFFFF;
   2138             rval = 0;
   2139             for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   2140                 reg = SOC_REG_UNIQUE_ACC(unit, TRUNK_RAND_LB_SEEDr)[pipe];
   2141                 soc_reg_field_set(unit, reg, &rval, SEEDf, seed);
   2142                 SOC_IF_ERROR_RETURN
   2143                     (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval));
   2144             }
   2145         }
   2146     }
   2147 #endif
   2148 
   2149     SOC_IF_ERROR_RETURN
   2150         (WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, &tg_entry));
   2151 #endif
   2152     return BCM_E_NONE;
   2153 }
   2154 
   2155 
   2156 /* Macro to free memory and return code */
   2157 
   2158 #define _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(_r_) \
   2159     if (nuc_tpbm) {                                    \
   2160         sal_free(nuc_tpbm);                            \
   2161     }                                                  \
   2162     if (ipmc_tpbm) {                                   \
   2163         sal_free(ipmc_tpbm);                           \
   2164     }                                                  \
   2165     if (l2mc_tpbm) {                                   \
   2166         sal_free(l2mc_tpbm);                           \
   2167     }                                                  \
   2168     if (bcast_tpbm) {                                  \
   2169         sal_free(bcast_tpbm);                          \
   2170     }                                                  \
   2171     if (dlf_tpbm) {                                    \
   2172         sal_free(dlf_tpbm);                            \
   2173     }                                                  \
   2174     if (ipmc_my_modid_bmap) {                          \
   2175         sal_free(ipmc_my_modid_bmap);                  \
   2176     }                                                  \
   2177     if (l2mc_my_modid_bmap) {                          \
   2178         sal_free(l2mc_my_modid_bmap);                  \
   2179     }                                                  \
   2180     if (bcast_my_modid_bmap) {                         \
   2181         sal_free(bcast_my_modid_bmap);                 \
   2182     }                                                  \
   2183     if (dlf_my_modid_bmap) {                           \
   2184         sal_free(dlf_my_modid_bmap);                   \
   2185     }                                                  \
   2186     if (hwmod) {                                       \
   2187         sal_free(hwmod);                               \
   2188     }                                                  \
   2189     if (hwport) {                                      \
   2190         sal_free(hwport);                              \
   2191     }                                                  \
   2192     if (egr_hwmod) {                                   \
   2193         sal_free(egr_hwmod);                           \
   2194     }                                                  \
   2195     if (egr_hwport) {                                  \
   2196         sal_free(egr_hwport);                          \
   2197     }                                                  \
   2198     if (egr_member_flags) {                            \
   2199         sal_free(egr_member_flags);                    \
   2200     }                                                  \
   2201     if (egr_scaling_factor) {                          \
   2202         sal_free(egr_scaling_factor);                  \
   2203     }                                                  \
   2204     if (egr_load_weight) {                             \
   2205         sal_free(egr_load_weight);                     \
   2206     }                                                  \
   2207     if (egr_qsize_weight) {                            \
   2208         sal_free(egr_qsize_weight);                    \
   2209     }                                                  \
   2210     if (uc_egr_hwmod) {                                \
   2211         sal_free(uc_egr_hwmod);                        \
   2212     }                                                  \
   2213     if (uc_egr_hwport) {                               \
   2214         sal_free(uc_egr_hwport);                       \
   2215     }                                                  \
   2216     if (uc_egr_scaling_factor) {                       \
   2217         sal_free(uc_egr_scaling_factor);               \
   2218     }                                                  \
   2219     if (uc_egr_load_weight) {                          \
   2220         sal_free(uc_egr_load_weight);                  \
   2221     }                                                  \
   2222     if (uc_egr_qsize_weight) {                         \
   2223         sal_free(uc_egr_qsize_weight);                 \
   2224     }                                                  \
   2225     if (leaving_members) {                             \
   2226         sal_free(leaving_members);                     \
   2227     }                                                  \
   2228     if (staying_members) {                             \
   2229         sal_free(staying_members);                     \
   2230     }                                                  \
   2231     if (joining_members) {                             \
   2232         sal_free(joining_members);                     \
   2233     }                                                  \
   2234     if (ipmc_localport_array) {                        \
   2235         sal_free(ipmc_localport_array);                \
   2236     }                                                  \
   2237     if (l2mc_localport_array) {                        \
   2238         sal_free(l2mc_localport_array);                \
   2239     }                                                  \
   2240     if (bcast_localport_array) {                       \
   2241         sal_free(bcast_localport_array);               \
   2242     }                                                  \
   2243     if (dlf_localport_array) {                         \
   2244         sal_free(dlf_localport_array);                 \
   2245     }                                                  \
   2246     return _r_;                             
   2247 
   2248 /*
   2249  * Function:
   2250  *      _bcm_th3_trunk_set
   2251  * Purpose:
   2252  *      Set trunk members.
   2253  * Parameters:
   2254  *      unit     - (IN) SOC unit number. 
   2255  *      tid      - (IN) Trunk group ID.
   2256  *      add_info - (IN) Pointer to trunk add info structure.
   2257  *      t_info   - (IN) Pointer to trunk info.
   2258  * Returns:
   2259  *      BCM_E_xxx
   2260  */
   2261 STATIC int
   2262 _bcm_th3_trunk_set(int unit,
   2263         bcm_trunk_t tid,
   2264         _esw_trunk_add_info_t *add_info,
   2265         trunk_private_t *t_info)
   2266 {
   2267 #if 1
   2268     int                 rv = BCM_E_NONE;
   2269     SHR_BITDCL          *nuc_tpbm = NULL;
   2270     SHR_BITDCL          *ipmc_tpbm = NULL;
   2271     SHR_BITDCL          *l2mc_tpbm = NULL;
   2272     SHR_BITDCL          *bcast_tpbm = NULL;
   2273     SHR_BITDCL          *dlf_tpbm = NULL;
   2274     SHR_BITDCL           *ipmc_my_modid_bmap = NULL;
   2275     SHR_BITDCL           *l2mc_my_modid_bmap = NULL;
   2276     SHR_BITDCL           *bcast_my_modid_bmap = NULL;
   2277     SHR_BITDCL           *dlf_my_modid_bmap = NULL;
   2278     int                  *hwmod = NULL;
   2279     int                  *hwport = NULL;
   2280     int                  num_egr_ports = 0;
   2281     int                  *egr_hwmod = NULL;
   2282     int                  *egr_hwport = NULL;
   2283     uint32               *egr_member_flags = NULL;
   2284     int                  *egr_scaling_factor = NULL;
   2285     int                  *egr_load_weight = NULL;
   2286     int                  *egr_qsize_weight = NULL;
   2287     int                  num_uc_egr_ports = 0;
   2288     int                  *uc_egr_hwmod = NULL;
   2289     int                  *uc_egr_hwport = NULL;
   2290     int                  *uc_egr_scaling_factor = NULL;
   2291     int                  *uc_egr_load_weight = NULL;
   2292     int                  *uc_egr_qsize_weight = NULL;
   2293     int                  negr_disable_port = 0;
   2294     int                  num_uc_egr_disable_port = 0;
   2295     pbmp_t               new_trunk_pbmp;
   2296     uint32               ipmc_member_count;
   2297     uint32               l2mc_member_count;
   2298     uint32               bcast_member_count;
   2299     uint32               dlf_member_count;
   2300     int                  mod, port, mod_out, port_out;
   2301     bcm_gport_t          gport;
   2302     bcm_port_t           loc_port = BCM_GPORT_INVALID;
   2303     int                  i;
   2304     trunk_bitmap_entry_t trunk_bitmap_entry;
   2305     pbmp_t               old_trunk_pbmp;
   2306     int                  j, k, remove_trunk_port;
   2307     int                  num_leaving_members = 0;
   2308     bcm_gport_t          *leaving_members = NULL;
   2309     int                  match_leaving_members;
   2310     int                  num_staying_members = 0;
   2311     bcm_gport_t          *staying_members = NULL;
   2312     int                  match_staying_members;
   2313     int                  num_joining_members = 0;
   2314     bcm_gport_t          *joining_members = NULL;
   2315     int                  match_joining_members;
   2316     int                  is_local;
   2317     int                  is_local_subport = 0;
   2318     int                  *ipmc_localport_array = NULL;
   2319     int                  *l2mc_localport_array = NULL;
   2320     int                  *bcast_localport_array = NULL;
   2321     int                  *dlf_localport_array = NULL;
   2322     int                  ipmc_localport_count;
   2323     int                  l2mc_localport_count;
   2324     int                  bcast_localport_count;
   2325     int                  dlf_localport_count;
   2326 
   2327     if (add_info->num_ports > _BCM_TH3_PORTS_PER_TRUNK_MAX) {
   2328         return BCM_E_PARAM;
   2329     }
   2330 
   2331     /* Audit unsupported flag combination */
   2332     for (i = 0; i < add_info->num_ports; i++) {
   2333         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) {
   2334             if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_INGRESS_DISABLE) {
   2335                 return BCM_E_PARAM;
   2336             }
   2337             if (add_info->member_flags[i] &
   2338                     BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) {
   2339                 return BCM_E_PARAM;
   2340             }
   2341             if (add_info->member_flags[i] &
   2342                     BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) {
   2343                 return BCM_E_PARAM;
   2344             }
   2345             if (add_info->member_flags[i] &
   2346                     BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) {
   2347                 return BCM_E_PARAM;
   2348             }
   2349             if (add_info->member_flags[i] &
   2350                     BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) {
   2351                 return BCM_E_PARAM;
   2352             }
   2353             if (add_info->member_flags[i] &
   2354                     BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) {
   2355                 return BCM_E_PARAM;
   2356             }
   2357         }
   2358         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) {
   2359             if (add_info->ipmc_index != BCM_TRUNK_UNSPEC_INDEX) {
   2360                 return BCM_E_PARAM;
   2361             }
   2362         }
   2363         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) {
   2364             if (add_info->mc_index != BCM_TRUNK_UNSPEC_INDEX) {
   2365                 return BCM_E_PARAM;
   2366             }
   2367         }
   2368         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) {
   2369             if (add_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) {
   2370                 return BCM_E_PARAM;
   2371             }
   2372         }
   2373         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) {
   2374             if (add_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) {
   2375                 return BCM_E_PARAM;
   2376             }
   2377         }
   2378     }
   2379 
   2380     if (add_info->dlf_index >= add_info->num_ports) {
   2381         return BCM_E_PARAM;
   2382     }
   2383 
   2384 #if 1
   2385     /* Derive a member bitmap of non-unicast eligible members */
   2386     nuc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "nuc_tpbm");
   2387     if (nuc_tpbm == NULL) {
   2388         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2389     }
   2390     sal_memset(nuc_tpbm, 0, SHR_BITALLOCSIZE(add_info->num_ports));
   2391     if (add_info->dlf_index == -1) {
   2392         rv = _bcm_th3_nuc_tpbm_get(unit, add_info->num_ports, 
   2393                 add_info->tm, nuc_tpbm);
   2394         if (BCM_FAILURE(rv)) {
   2395         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2396         }
   2397     } else {
   2398         SHR_BITSET(nuc_tpbm, add_info->dlf_index);
   2399     }
   2400 
   2401     /* Copy the non-unicast eligible member bitmap to IPMC, L2MC, broadcast,
   2402      * and DLF eligible member bitmaps.
   2403      */
   2404     ipmc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "ipmc_tpbm");
   2405     if (ipmc_tpbm == NULL) {
   2406         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2407     }
   2408     sal_memcpy(ipmc_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports));
   2409 
   2410     l2mc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "l2mc_tpbm");
   2411     if (l2mc_tpbm == NULL) {
   2412         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2413     }
   2414     sal_memcpy(l2mc_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports));
   2415 
   2416     bcast_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "bcast_tpbm");
   2417     if (bcast_tpbm == NULL) {
   2418         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2419     }
   2420     sal_memcpy(bcast_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports));
   2421 
   2422     dlf_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "dlf_tpbm");
   2423     if (dlf_tpbm == NULL) {
   2424         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2425     }
   2426     sal_memcpy(dlf_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports));
   2427 
   2428     /* Iterate through the trunk member list to get module ID (SHOULD BE 0)
   2429      * and port number of each member, a port bitmap of local members, and
   2430      * port bitmaps of IPMC/L2MC/BCAST/DLF eligible local members.
   2431      */
   2432     hwmod = sal_alloc(sizeof(int) * (add_info->num_ports), "hwmod");
   2433     if (hwmod == NULL) {
   2434         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2435     }
   2436     sal_memset(hwmod, 0, sizeof(int) * (add_info->num_ports));
   2437 
   2438     hwport = sal_alloc(sizeof(int) * (add_info->num_ports), "hwport");
   2439     if (hwport == NULL) {
   2440         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2441     }
   2442     sal_memset(hwport, 0, sizeof(int) * (add_info->num_ports));
   2443 
   2444     ipmc_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports),
   2445             "ipmc_my_modid_bmap");
   2446     if (ipmc_my_modid_bmap == NULL) {
   2447         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2448     }
   2449     sal_memset(ipmc_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports));
   2450 
   2451     l2mc_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports),
   2452             "l2mc_my_modid_bmap");
   2453     if (l2mc_my_modid_bmap == NULL) {
   2454         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2455     }
   2456     sal_memset(l2mc_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports));
   2457 
   2458     bcast_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports),
   2459             "bcast_my_modid_bmap");
   2460     if (bcast_my_modid_bmap == NULL) {
   2461         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2462     }
   2463     sal_memset(bcast_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports));
   2464 
   2465     dlf_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports),
   2466             "dlf_my_modid_bmap");
   2467     if (dlf_my_modid_bmap == NULL) {
   2468         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2469     }
   2470     sal_memset(dlf_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports));
   2471     ipmc_localport_array = sal_alloc(add_info->num_ports * sizeof(int),
   2472                                      "ipmc_localport_array");
   2473     if (ipmc_localport_array == NULL) {
   2474         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2475     }
   2476     sal_memset(ipmc_localport_array, 0, add_info->num_ports * sizeof(int));
   2477     l2mc_localport_array = sal_alloc(add_info->num_ports * sizeof(int),
   2478                                      "l2mc_localport_array");
   2479     if (l2mc_localport_array == NULL) {
   2480         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2481     }
   2482     sal_memset(l2mc_localport_array, 0, add_info->num_ports * sizeof(int));
   2483     bcast_localport_array = sal_alloc(add_info->num_ports * sizeof(int),
   2484                                       "bcast_localport_array");
   2485     if (bcast_localport_array == NULL) {
   2486         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2487     }
   2488     sal_memset(bcast_localport_array, 0, add_info->num_ports * sizeof(int));
   2489     dlf_localport_array = sal_alloc(add_info->num_ports * sizeof(int),
   2490                                     "dlf_localport_array");
   2491     if (dlf_localport_array == NULL) {
   2492         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2493     }
   2494     sal_memset(dlf_localport_array, 0, add_info->num_ports * sizeof(int));
   2495 
   2496     SOC_PBMP_CLEAR(new_trunk_pbmp);
   2497     ipmc_member_count = 0;
   2498     l2mc_member_count = 0;
   2499     bcast_member_count = 0;
   2500     dlf_member_count = 0;
   2501     negr_disable_port = 0;
   2502     num_uc_egr_disable_port = 0;
   2503     ipmc_localport_count = 0;
   2504     l2mc_localport_count = 0;
   2505     bcast_localport_count = 0;
   2506     dlf_localport_count = 0;
   2507 
   2508     for (i = 0; i < add_info->num_ports; i++) {
   2509         mod = 0; /* Set modid to 0 */
   2510         port = add_info->tp[i];
   2511         /*In case of feature not supported on chip return E_PARAM*/
   2512         /*if (!soc_feature(unit, soc_feature_shared_trunk_member_table)) {
   2513              _BCM_TRIDENT_TRUNK_FP_SET_FREE_MEM_RETURN(BCM_E_PARAM);
   2514         }*/
   2515 
   2516         mod_out = mod;
   2517         port_out = port;
   2518 
   2519         if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   2520             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_BADID);
   2521         }
   2522         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   2523             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_PORT);
   2524         }
   2525         hwmod[i] = mod_out; /* SHOULD BE 0! */
   2526         hwport[i] = port_out;
   2527 
   2528         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) {
   2529             SHR_BITCLR(ipmc_tpbm, i);
   2530             SHR_BITCLR(l2mc_tpbm, i);
   2531             SHR_BITCLR(bcast_tpbm, i);
   2532             SHR_BITCLR(dlf_tpbm, i);
   2533             negr_disable_port++;
   2534         } else {
   2535             if (add_info->member_flags[i] &
   2536                     BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) {
   2537                 num_uc_egr_disable_port++;
   2538             }
   2539             if (add_info->member_flags[i] &
   2540                     BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) {
   2541                 SHR_BITCLR(ipmc_tpbm, i);
   2542             }
   2543             if (add_info->member_flags[i] &
   2544                     BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) {
   2545                 SHR_BITCLR(l2mc_tpbm, i);
   2546             }
   2547             if (add_info->member_flags[i] &
   2548                     BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) {
   2549                 SHR_BITCLR(bcast_tpbm, i);
   2550             }
   2551             if (add_info->member_flags[i] &
   2552                     BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) {
   2553                 SHR_BITCLR(dlf_tpbm, i);
   2554             }
   2555         }
   2556 
   2557         BCM_GPORT_MODPORT_SET(gport, mod_out, port_out);
   2558         loc_port = BCM_GPORT_INVALID;
   2559         if (BCM_SUCCESS(bcm_esw_port_local_get(unit, gport, &loc_port))) {
   2560 #if 0
   2561             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe)) {
   2562 #if defined(BCM_HGPROXY_COE_SUPPORT)
   2563                 if(_bcm_xgs5_subport_coe_mod_port_local(unit, mod_out,
   2564                                                         port_out)) {
   2565 
   2566                     is_local_subport = 1;
   2567                 }
   2568 #endif
   2569             } else
   2570 
   2571             if (soc_feature(unit, soc_feature_linkphy_coe) ||
   2572                 soc_feature(unit, soc_feature_subtag_coe)) {
   2573 #if defined(BCM_KATANA2_SUPPORT)
   2574                 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_is_local_coe_subport(unit,
   2575                     mod_out, port_out, &is_local_subport));
   2576 #endif
   2577             }
   2578             if (!is_local_subport) {
   2579                 if (!(IS_E_PORT(unit, loc_port) || IS_HG_PORT(unit, loc_port)) ||
   2580                     /* Cascaded physical ports are not considered as front-panel port */
   2581                     (soc_feature(unit, soc_feature_linkphy_coe) &&
   2582                         IS_LP_PORT(unit, loc_port)) ||
   2583                     (soc_feature(unit, soc_feature_subtag_coe) &&
   2584                         IS_SUBTAG_PORT(unit, loc_port)) || 
   2585                     (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   2586                      IS_SUBTAG_PORT (unit, loc_port))) {
   2587                     _BCM_TRIDENT_TRUNK_FP_SET_FREE_MEM_RETURN(BCM_E_PARAM);
   2588                 }
   2589             }
   2590 #endif
   2591             SOC_PBMP_PORT_ADD(new_trunk_pbmp, loc_port);
   2592             if (SHR_BITGET(ipmc_tpbm, i)) {
   2593                 ipmc_localport_array[ipmc_localport_count++] = loc_port;
   2594                 SHR_BITSET(ipmc_my_modid_bmap, ipmc_member_count);
   2595             }
   2596             if (SHR_BITGET(l2mc_tpbm, i)) {
   2597                 l2mc_localport_array[l2mc_localport_count++] = loc_port;
   2598                 SHR_BITSET(l2mc_my_modid_bmap, l2mc_member_count);
   2599             }
   2600             if (SHR_BITGET(bcast_tpbm, i)) {
   2601                 bcast_localport_array[bcast_localport_count++] = loc_port;
   2602                 SHR_BITSET(bcast_my_modid_bmap, bcast_member_count);
   2603             }
   2604             if (SHR_BITGET(dlf_tpbm, i)) {
   2605                 dlf_localport_array[dlf_localport_count++] = loc_port;
   2606                 SHR_BITSET(dlf_my_modid_bmap, dlf_member_count);
   2607             }
   2608         }
   2609 
   2610         
   2611         if (SHR_BITGET(ipmc_tpbm, i)) {
   2612             /* Eligible for IPMC forwarding */
   2613             ipmc_member_count++;
   2614         }
   2615         if (SHR_BITGET(l2mc_tpbm, i)) {
   2616             /* Eligible for L2MC forwarding */
   2617             l2mc_member_count++;
   2618         }
   2619         if (SHR_BITGET(bcast_tpbm, i)) {
   2620             /* Eligible for broadcast forwarding */
   2621             bcast_member_count++;
   2622         }
   2623         if (SHR_BITGET(dlf_tpbm, i)) {
   2624             /* Eligible for DLF forwarding */
   2625             dlf_member_count++;
   2626         }
   2627     }
   2628 
   2629     /* Figure out which trunk ports are eligible for egress and
   2630      * unicast egress
   2631      */
   2632     num_egr_ports = add_info->num_ports - negr_disable_port;
   2633     if (num_egr_ports > 0) {
   2634         egr_hwmod = sal_alloc(sizeof(bcm_module_t) * num_egr_ports,
   2635                 "egr_hwmod");
   2636         if (egr_hwmod == NULL) {
   2637             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2638         }
   2639         egr_hwport = sal_alloc(sizeof(bcm_port_t) * num_egr_ports,
   2640                 "egr_hwport");
   2641         if (egr_hwport == NULL) {
   2642             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2643         }
   2644         egr_member_flags = sal_alloc(sizeof(uint32) * num_egr_ports,
   2645                 "egr_member_flags");
   2646         if (egr_member_flags == NULL) {
   2647             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2648         }
   2649         egr_scaling_factor = sal_alloc(sizeof(int) * num_egr_ports,
   2650                 "egr_scaling_factor");
   2651         if (egr_scaling_factor == NULL) {
   2652             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2653         }
   2654         egr_load_weight = sal_alloc(sizeof(int) * num_egr_ports,
   2655                 "egr_load_weight");
   2656         if (egr_load_weight == NULL) {
   2657             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2658         }
   2659         egr_qsize_weight = sal_alloc(sizeof(int) * num_egr_ports,
   2660                 "egr_qsize_weight");
   2661         if (egr_qsize_weight == NULL) {
   2662             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2663         }
   2664         for (i = 0, j = 0; i < add_info->num_ports; i++) {
   2665             if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) {
   2666                 continue;
   2667             }
   2668             egr_hwmod[j] = hwmod[i];
   2669             egr_hwport[j] = hwport[i];
   2670             egr_member_flags[j] = add_info->member_flags[i];
   2671             egr_scaling_factor[j] = add_info->dynamic_scaling_factor[i];
   2672             egr_load_weight[j] = add_info->dynamic_load_weight[i];
   2673             egr_qsize_weight[j] = add_info->dynamic_queue_size_weight[i];
   2674             j++;
   2675         }
   2676 
   2677         /* Figure out which of these egress ports are unicast */
   2678         num_uc_egr_ports = num_egr_ports - num_uc_egr_disable_port;
   2679         if (num_uc_egr_ports > 0 ) {
   2680             uc_egr_hwmod = sal_alloc(sizeof(bcm_module_t) * num_uc_egr_ports,
   2681                     "uc_egr_hwmod");
   2682             if (uc_egr_hwmod == NULL) {
   2683                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2684             }
   2685             uc_egr_hwport = sal_alloc(sizeof(bcm_port_t) * num_uc_egr_ports,
   2686                     "uc_egr_hwport");
   2687             if (uc_egr_hwport == NULL) {
   2688                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2689             }
   2690             uc_egr_scaling_factor = sal_alloc(sizeof(int) * num_uc_egr_ports,
   2691                     "uc_egr_scaling_factor");
   2692             if (uc_egr_scaling_factor == NULL) {
   2693                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2694             }
   2695             uc_egr_load_weight = sal_alloc(sizeof(int) * num_uc_egr_ports,
   2696                     "uc_egr_load_weight");
   2697             if (uc_egr_load_weight == NULL) {
   2698                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2699             }
   2700             uc_egr_qsize_weight = sal_alloc(sizeof(int) * num_uc_egr_ports,
   2701                     "uc_egr_qsize_weight");
   2702             if (uc_egr_qsize_weight == NULL) {
   2703                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2704             }
   2705             for (i = 0, k = 0; i < j; i++) {
   2706                 if (egr_member_flags[i] &
   2707                         BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) {
   2708                     continue;
   2709                 }
   2710                 uc_egr_hwmod[k] = egr_hwmod[i];
   2711                 uc_egr_hwport[k] = egr_hwport[i];
   2712                 uc_egr_scaling_factor[k] = egr_scaling_factor[i];
   2713                 uc_egr_load_weight[k] = egr_load_weight[i];
   2714                 uc_egr_qsize_weight[k] = egr_qsize_weight[i];
   2715                 k++;
   2716             }
   2717         }
   2718     } else {
   2719         
   2720 #if 0
   2721         /* Time to use entry 0 reserved for this purpose.
   2722          * Set mod and port to inavlid values in entry */
   2723         if (trunk_mbr_entry_zero_rsvd == TRUE) {
   2724             trunk_member_entry_t trunk_member_entry;
   2725             sal_memset(&trunk_member_entry, 0, sizeof(trunk_member_entry_t));
   2726             soc_TRUNK_MEMBERm_field32_set(unit,&trunk_member_entry,
   2727                                           MODULE_IDf,0xff);
   2728             soc_TRUNK_MEMBERm_field32_set(unit,&trunk_member_entry,
   2729                                           PORT_NUMf, 0x7f);
   2730             SOC_IF_ERROR_RETURN
   2731                 (WRITE_TRUNK_MEMBERm(unit, MEM_BLOCK_ALL,
   2732                                      0,&trunk_member_entry));
   2733             trunk_mbr_entry_zero_rsvd = FALSE;
   2734         }
   2735 #endif
   2736     }
   2737     
   2738 #if 0
   2739     if (t_info->in_use) {
   2740         rv = _bcm_th3_lag_slb_free_resource(unit, tid);
   2741         if (BCM_FAILURE(rv)) {
   2742             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2743         }
   2744     }
   2745 #endif
   2746 
   2747     /* Write TH3 memory for Fast LAG settings. Static load
   2748      * balancing.  There is no dynamic load balancing in TH3. */
   2749     rv = _bcm_th3_lag_slb_set(unit, tid, num_uc_egr_ports,
   2750             uc_egr_hwmod, uc_egr_hwport, t_info);
   2751     if (BCM_FAILURE(rv)) {
   2752         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2753     }
   2754 
   2755     /* Update TRUNK_BITMAP table */
   2756     rv = READ_TRUNK_BITMAPm(unit, MEM_BLOCK_ANY, tid, &trunk_bitmap_entry);
   2757     if (BCM_FAILURE(rv)) {
   2758         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2759     }
   2760     SOC_PBMP_CLEAR(old_trunk_pbmp);
   2761     soc_mem_pbmp_field_get(unit, TRUNK_BITMAPm, &trunk_bitmap_entry,
   2762             TRUNK_BITMAPf, &old_trunk_pbmp);
   2763     soc_mem_pbmp_field_set(unit, TRUNK_BITMAPm, &trunk_bitmap_entry,
   2764             TRUNK_BITMAPf, &new_trunk_pbmp);
   2765     rv = WRITE_TRUNK_BITMAPm(unit, MEM_BLOCK_ALL, tid, &trunk_bitmap_entry);
   2766     if (BCM_FAILURE(rv)) {
   2767         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2768     }
   2769 
   2770     /* Update source trunk map configuration */
   2771     for (i = 0; i < add_info->num_ports; i++) {
   2772         mod = hwmod[i%add_info->num_ports]; /* SHOULD ALL BE 0 */
   2773         port = hwport[i%add_info->num_ports];
   2774 
   2775         if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_INGRESS_DISABLE) {
   2776             rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1);
   2777         } else {
   2778             rv = _bcm_th3_trunk_set_port_property(unit, mod, port, tid);
   2779         }
   2780         if (BCM_FAILURE(rv)) {
   2781             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2782         }
   2783     }    
   2784 
   2785     /* Update the trunk block mask */
   2786     if (SOC_PBMP_NOT_NULL(new_trunk_pbmp) ||
   2787             SOC_PBMP_NOT_NULL(old_trunk_pbmp)) {
   2788         rv = _bcm_th3_trunk_block_mask(unit,
   2789                 TRUNK_BLOCK_MASK_TYPE_IPMC,
   2790                 old_trunk_pbmp,
   2791                 new_trunk_pbmp,
   2792                 ipmc_localport_array,
   2793                 ipmc_localport_count,
   2794                 ipmc_my_modid_bmap,
   2795                 ipmc_member_count,
   2796                 add_info->flags);
   2797         if (BCM_FAILURE(rv)) {
   2798             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2799         }
   2800         rv = _bcm_th3_trunk_block_mask(unit,
   2801                 TRUNK_BLOCK_MASK_TYPE_L2MC,
   2802                 old_trunk_pbmp,
   2803                 new_trunk_pbmp,
   2804                 l2mc_localport_array,
   2805                 l2mc_localport_count,
   2806                 l2mc_my_modid_bmap,
   2807                 l2mc_member_count,
   2808                 add_info->flags);
   2809         if (BCM_FAILURE(rv)) {
   2810             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2811         }
   2812         rv = _bcm_th3_trunk_block_mask(unit,
   2813                 TRUNK_BLOCK_MASK_TYPE_BCAST,
   2814                 old_trunk_pbmp,
   2815                 new_trunk_pbmp,
   2816                 bcast_localport_array,
   2817                 bcast_localport_count,
   2818                 bcast_my_modid_bmap,
   2819                 bcast_member_count,
   2820                 add_info->flags);
   2821         if (BCM_FAILURE(rv)) {
   2822             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2823         }
   2824         rv = _bcm_th3_trunk_block_mask(unit,
   2825                 TRUNK_BLOCK_MASK_TYPE_DLF,
   2826                 old_trunk_pbmp,
   2827                 new_trunk_pbmp,
   2828                 dlf_localport_array,
   2829                 dlf_localport_count,
   2830                 dlf_my_modid_bmap,
   2831                 dlf_member_count,
   2832                 add_info->flags);
   2833         if (BCM_FAILURE(rv)) {
   2834             _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2835         }
   2836     }
   2837 
   2838     /* Hardware trunk failover */
   2839     rv = _bcm_th3_trunk_failover_set(unit, tid, FALSE, add_info);
   2840     if (BCM_FAILURE(rv)) {
   2841         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2842     }
   2843 
   2844     /* Software failover; called from linkscan */
   2845     rv = _bcm_th3_trunk_swfailover_set(unit, tid, t_info->rtag,
   2846                                 num_egr_ports, egr_hwmod, egr_hwport,
   2847                                 egr_member_flags, add_info->flags);
   2848 
   2849 
   2850     /* Figure out which members are leaving, staying or joining
   2851      * the trunk group
   2852      */
   2853     if (t_info->in_use) {
   2854         if (MEMBER_INFO(unit, tid).num_ports > 0) {
   2855             leaving_members = sal_alloc(sizeof(bcm_gport_t) *
   2856                     MEMBER_INFO(unit, tid).num_ports, "leaving members");
   2857             if (leaving_members == NULL) {
   2858                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2859             }
   2860             sal_memset(leaving_members, 0,
   2861                     sizeof(bcm_gport_t) * MEMBER_INFO(unit, tid).num_ports);
   2862 
   2863             staying_members = sal_alloc(sizeof(bcm_gport_t) *
   2864                     MEMBER_INFO(unit, tid).num_ports, "staying members");
   2865             if (staying_members == NULL) {
   2866                 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2867             }
   2868             sal_memset(staying_members, 0,
   2869                     sizeof(bcm_gport_t) * MEMBER_INFO(unit, tid).num_ports);
   2870 
   2871             for (i = 0; i < MEMBER_INFO(unit, tid).num_ports; i++) {
   2872                 mod = 0; /*MEMBER_INFO(unit, tid).modport[i] >> 8; */
   2873                 port = MEMBER_INFO(unit, tid).port[i] & 0xff;
   2874                 BCM_GPORT_MODPORT_SET(gport, mod, port);
   2875 
   2876                 /* Invalidate port only if it is not a part from new trunk group */
   2877                 remove_trunk_port = TRUE;
   2878                 for (j = 0; j < add_info->num_ports; j++) {
   2879                     if (mod == add_info->tm[j] && port == add_info->tp[j]) {
   2880                         remove_trunk_port = FALSE;
   2881                     }
   2882                 }
   2883                 if (remove_trunk_port) {
   2884                     /* Add port to array containing members leaving the trunk
   2885                      * group if it is different from previous leaving members
   2886                      */
   2887                     match_leaving_members = FALSE;
   2888                     for (k = 0; k < num_leaving_members; k++) {
   2889                         if (gport == leaving_members[k]) {
   2890                             match_leaving_members = TRUE;
   2891                             break;
   2892                         }
   2893                     }
   2894                     if (!match_leaving_members) {
   2895                         leaving_members[num_leaving_members++] = gport;
   2896                     }
   2897 
   2898                     rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1);
   2899                     if (BCM_FAILURE(rv)) {
   2900                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2901                     }
   2902 
   2903                     is_local = is_local_subport = 0;
   2904                     /* If deleted port is local, clear HW failover info */
   2905                     rv = _bcm_esw_modid_is_local(unit, mod, &is_local);
   2906                     if (BCM_FAILURE(rv)) {
   2907                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2908                     }
   2909 
   2910                     if (!is_local && !is_local_subport) {
   2911                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2912                         /* continue; */
   2913                     }
   2914 
   2915                     BCM_GPORT_MODPORT_SET(gport, mod, port);
   2916                     rv = bcm_esw_port_local_get(unit, gport, &loc_port);
   2917                     if (BCM_FAILURE(rv)) {
   2918                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2919                     }
   2920                     if (IS_HG_PORT(unit, loc_port)) {
   2921                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2922                         /* continue; */
   2923                     }
   2924                     /* ERROR on Cascaded Physical Ports. No Support */
   2925                     if ((soc_feature(unit, soc_feature_linkphy_coe) &&
   2926                         IS_LP_PORT(unit, loc_port)) ||
   2927                         (soc_feature(unit, soc_feature_subtag_coe) &&
   2928                         IS_SUBTAG_PORT(unit, loc_port)) ||
   2929                         (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   2930                         IS_SUBTAG_PORT (unit, loc_port))) {
   2931                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2932                         /* continue; */
   2933                     }
   2934                     rv = _bcm_th3_trunk_hwfailover_set(unit, tid,
   2935                             port, add_info->psc,
   2936                             0, 0, NULL);
   2937                     if (BCM_FAILURE(rv)) {
   2938                         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2939                     }
   2940                 } else {
   2941                     /* Add port to array containing members staying in the trunk
   2942                      * group if it is different from previous staying members
   2943                      */
   2944                     match_staying_members = FALSE;
   2945                     for (k = 0; k < num_staying_members; k++) {
   2946                         if (gport == staying_members[k]) {
   2947                             match_staying_members = TRUE;
   2948                             break;
   2949                         }
   2950                     }
   2951                     if (!match_staying_members) {
   2952                         staying_members[num_staying_members++] = gport;
   2953                     }
   2954 
   2955                 }
   2956             }
   2957         }
   2958     }
   2959 
   2960     /* allocate space and set joining members for comparison. If a joining
   2961      * member matches a staying member, don't need to add it again. */
   2962     joining_members = sal_alloc(sizeof(bcm_gport_t) * add_info->num_ports,
   2963             "joining members");
   2964     if (joining_members == NULL) {
   2965         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   2966     }
   2967     sal_memset(joining_members, 0, sizeof(bcm_gport_t) * add_info->num_ports);
   2968     for (i = 0; i < add_info->num_ports; i++) {
   2969         BCM_GPORT_MODPORT_SET(gport, hwmod[i], hwport[i]); 
   2970         match_staying_members = FALSE;
   2971         for (j = 0; j < num_staying_members; j++) {
   2972             if (gport == staying_members[j]) {
   2973                 match_staying_members = TRUE;
   2974                 break;
   2975             }
   2976         }
   2977         if (!match_staying_members) {
   2978             match_joining_members = FALSE;
   2979             for (j = 0; j < num_joining_members; j++) {
   2980                 if (gport == joining_members[j]) {
   2981                     match_joining_members = TRUE;
   2982                     break;
   2983                 }
   2984             }
   2985             if (!match_joining_members) {
   2986                 joining_members[num_joining_members++] = gport;
   2987             }
   2988         }
   2989     }
   2990 
   2991     
   2992 
   2993     rv = _bcm_xgs3_trunk_property_migrate(unit,
   2994                 num_leaving_members, leaving_members,
   2995                 num_staying_members, staying_members,
   2996                 num_joining_members, joining_members);
   2997     if (BCM_FAILURE(rv)) {
   2998         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   2999     }
   3000 
   3001     /* Save new trunk member info. Free up the old memory and allocate new space
   3002      * since there may be a different number of entries. */
   3003     if (MEMBER_INFO(unit, tid).port) {
   3004         sal_free(MEMBER_INFO(unit, tid).port);
   3005         MEMBER_INFO(unit, tid).port = NULL;
   3006     }
   3007     if (MEMBER_INFO(unit, tid).member_flags) {
   3008         sal_free(MEMBER_INFO(unit, tid).member_flags);
   3009         MEMBER_INFO(unit, tid).member_flags = NULL;
   3010     }
   3011 
   3012     MEMBER_INFO(unit, tid).port = sal_alloc(
   3013             sizeof(uint16) * add_info->num_ports, "member info port");
   3014     if (NULL == MEMBER_INFO(unit, tid).port) {
   3015         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   3016     }
   3017 
   3018     MEMBER_INFO(unit, tid).member_flags = sal_alloc(
   3019             sizeof(uint32) * add_info->num_ports, "member info flags");
   3020     if (NULL == MEMBER_INFO(unit, tid).member_flags) {
   3021         sal_free(MEMBER_INFO(unit, tid).port);
   3022         MEMBER_INFO(unit, tid).port = NULL;
   3023         _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY);
   3024     }
   3025 
   3026     /* Save the information to our memory */
   3027     for (i = 0; i < add_info->num_ports; i++) {
   3028         MEMBER_INFO(unit, tid).port[i] = ((hwmod[i] & 0xff) << 8) |
   3029                                             (hwport[i] & 0xff);
   3030         MEMBER_INFO(unit, tid).member_flags[i] = add_info->member_flags[i];
   3031     }
   3032     MEMBER_INFO(unit, tid).num_ports = add_info->num_ports;
   3033 
   3034 #endif
   3035 #endif
   3036 
   3037     /* Free all dynamically allocated memory used in this function */
   3038     _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv);
   3039 }
   3040 
   3041 
   3042 /*
   3043  * Function:
   3044  *      bcm_th3_trunk_modify
   3045  * Purpose:
   3046  *      Set trunk members.
   3047  * Parameters:
   3048  *      unit       - (IN) SOC unit number. 
   3049  *      tid        - (IN) Trunk group ID.
   3050  *      trunk_info - (IN) Pointer to user provided trunk info.
   3051  *      member_count - (IN) Number of trunk members.
   3052  *      member_array - (IN) Array of trunk members.
   3053  *      t_info       - (IN) Pointer to internal trunk info.
   3054  *      op           - (IN) Not used by this procedure.
   3055  *      member       - (IN) Not used by this procedure.
   3056  * Returns:
   3057  *      BCM_E_xxx
   3058  */
   3059 int
   3060 bcm_th3_trunk_modify(int unit,
   3061         bcm_trunk_t tid,
   3062         bcm_trunk_info_t *trunk_info,
   3063         int member_count,
   3064         bcm_trunk_member_t *member_array,
   3065         trunk_private_t *t_info,
   3066         int op,
   3067         bcm_trunk_member_t *member)
   3068 {
   3069     int rv = BCM_E_NONE;
   3070     int rtag;
   3071 #if 1
   3072 /*    bcm_trunk_chip_info_t chip_info; */
   3073     _esw_trunk_add_info_t add_info;
   3074     int i;
   3075     int higig_trunk;
   3076 
   3077     if (trunk_info->psc <= 0) {
   3078         trunk_info->psc = BCM_TRUNK_PSC_PORTFLOW;
   3079     }
   3080     BCM_IF_ERROR_RETURN
   3081         (_bcm_th3_trunk_psc_to_rtag(unit, trunk_info->psc, &rtag));
   3082     t_info->rtag = rtag;
   3083     t_info->flags = trunk_info->flags;
   3084 
   3085     if ((trunk_info->dlf_index != trunk_info->mc_index) ||
   3086         (trunk_info->dlf_index != trunk_info->ipmc_index)) {
   3087         return BCM_E_PARAM;
   3088     }
   3089 
   3090     t_info->dlf_index_spec =
   3091         t_info->dlf_index_used =
   3092         t_info->mc_index_spec = 
   3093         t_info->mc_index_used =
   3094         t_info->ipmc_index_spec =
   3095         t_info->ipmc_index_used = trunk_info->dlf_index;
   3096 
   3097     if (member_count < 1) {
   3098         if (t_info->in_use) {
   3099             /* Delete existing trunk member ports */
   3100             BCM_IF_ERROR_RETURN
   3101                 (bcm_th3_trunk_destroy(unit, tid, t_info));
   3102         }
   3103     } else {
   3104         sal_memset(&add_info, 0, sizeof(_esw_trunk_add_info_t));
   3105 
   3106         /* Fill in fields.  Don't need to fill in DLB fields because
   3107          * TH3 does not support DLB and already initialized mem to 0 */
   3108         add_info.flags = trunk_info->flags;
   3109         add_info.num_ports = member_count;
   3110         add_info.psc = trunk_info->psc;
   3111         add_info.ipmc_psc = trunk_info->ipmc_psc;
   3112         add_info.dlf_index = trunk_info->dlf_index;
   3113         add_info.mc_index = trunk_info->mc_index;
   3114         add_info.ipmc_index = trunk_info->ipmc_index;
   3115 
   3116         BCM_IF_ERROR_RETURN
   3117             (_th3_trunk_add_info_member_alloc(&add_info, member_count));
   3118 
   3119         for (i = 0; i < member_count; i++) {
   3120             add_info.member_flags[i] = member_array[i].flags;
   3121             add_info.tp[i] = member_array[i].gport;
   3122             add_info.tm[i] = -1;
   3123         }
   3124 
   3125         /* Convert member gport to module and port */
   3126         
   3127         higig_trunk = 0;
   3128         rv = _bcm_esw_trunk_gport_array_resolve(unit,
   3129                 higig_trunk,
   3130                 member_count,
   3131                 add_info.tp,
   3132                 add_info.tp,
   3133                 add_info.tm);
   3134 
   3135 
   3136         if (BCM_FAILURE(rv)) {
   3137             _th3_trunk_add_info_member_free(&add_info);
   3138             return rv;
   3139         }
   3140 
   3141         /* Check modids of passed in gports in member_array.  Return error
   3142          * if nonzero
   3143          */
   3144         for (i = 0; i < member_count; i++) {
   3145             if (!SOC_MODID_ADDRESSABLE(unit, add_info.tm[i])) {
   3146                 rv = BCM_E_BADID;
   3147                 _th3_trunk_add_info_member_free(&add_info);
   3148                 break;
   3149             }
   3150         }
   3151         if (BCM_SUCCESS(rv)) {
   3152             /* The new psc in trunk_info is the one to be programmed */
   3153             t_info->psc = trunk_info->psc;
   3154             rv = _bcm_th3_trunk_set(unit, tid, &add_info, t_info);
   3155             _th3_trunk_add_info_member_free(&add_info);
   3156         }
   3157     }
   3158 #endif
   3159     return rv;
   3160 }
   3161 
   3162 
   3163 
   3164 /*
   3165  * Function:
   3166  *      bcm_th3_trunk_destroy
   3167  * Purpose:
   3168  *      Deletes the trunk specified
   3169  */
   3170 int
   3171 bcm_th3_trunk_destroy(int unit,
   3172                        bcm_trunk_t tid,
   3173                        trunk_private_t *t_info)
   3174 {
   3175     
   3176     bcm_module_t                mod;
   3177     bcm_port_t                  port, loc_port;
   3178     bcm_gport_t                 gport;
   3179     pbmp_t                      old_ports, new_ports;
   3180     int                         i, rv;
   3181     int                         num_leaving_members = 0;
   3182     bcm_gport_t                 *leaving_members = NULL;
   3183 
   3184     SOC_PBMP_CLEAR(new_ports);
   3185 
   3186     /* front panel trunks */
   3187 
   3188     SOC_PBMP_CLEAR(old_ports);
   3189 
   3190     /* Dynamically allocate this because 64 * 4 bytes
   3191      * is a lot to put on the stack */
   3192     leaving_members = sal_alloc(MEMBER_INFO(unit, tid).num_ports * sizeof(int),
   3193                                 "bcm_th3_drunk_destroy leaving_members");
   3194     if (NULL == leaving_members) {
   3195         return BCM_E_MEMORY;
   3196     }
   3197     sal_memset(leaving_members, 0, MEMBER_INFO(unit, tid).num_ports * sizeof(int));
   3198 
   3199     for (i = 0; i < MEMBER_INFO(unit, tid).num_ports; i++) {
   3200         mod = 0; /* MEMBER_INFO(tid).port[i] >> 8; */
   3201         port = MEMBER_INFO(unit, tid).port[i] & 0xff;
   3202         BCM_GPORT_MODPORT_SET(gport, mod, port);
   3203         if (BCM_SUCCESS(bcm_esw_port_local_get(unit, gport, &loc_port))) { 
   3204             SOC_PBMP_PORT_ADD(old_ports, loc_port);
   3205         }
   3206         leaving_members[num_leaving_members++] = gport;
   3207         rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1);
   3208         if (BCM_FAILURE(rv)) {
   3209             goto cleanup;
   3210         }
   3211     }
   3212 
   3213     /*
   3214      * Remove ports from the block mask table
   3215      */
   3216     if (SOC_PBMP_NOT_NULL(old_ports)) {
   3217         SOC_PBMP_CLEAR(new_ports);
   3218         /* coverity[divide_by_zero] */
   3219         rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_IPMC,
   3220                 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags);
   3221         if (BCM_FAILURE(rv)) {
   3222             goto cleanup;
   3223         }
   3224         rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_L2MC,
   3225                 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags);
   3226         if (BCM_FAILURE(rv)) {
   3227             goto cleanup;
   3228         }
   3229         rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_BCAST,
   3230                 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags);
   3231         if (BCM_FAILURE(rv)) {
   3232             goto cleanup;
   3233         }
   3234         rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_DLF,
   3235                 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags);
   3236         if (BCM_FAILURE(rv)) {
   3237             goto cleanup;
   3238         }
   3239     }
   3240 
   3241     /*
   3242      * Reset table entries to empty state
   3243      */
   3244     rv = soc_mem_write(unit, TRUNK_BITMAPm, MEM_BLOCK_ALL, tid,
   3245                       soc_mem_entry_null(unit, TRUNK_BITMAPm));
   3246     if (BCM_FAILURE(rv)) {
   3247         goto cleanup;
   3248     }
   3249     rv = soc_mem_write(unit, FAST_TRUNK_PORTS_1m, MEM_BLOCK_ALL, tid,
   3250                       soc_mem_entry_null(unit, FAST_TRUNK_PORTS_1m));
   3251     if (BCM_FAILURE(rv)) {
   3252         goto cleanup;
   3253     }
   3254     rv = soc_mem_write(unit, FAST_TRUNK_PORTS_2m, MEM_BLOCK_ALL, tid,
   3255                       soc_mem_entry_null(unit, FAST_TRUNK_PORTS_2m));
   3256     if (BCM_FAILURE(rv)) {
   3257         goto cleanup;
   3258     }
   3259     rv = soc_mem_write(unit, FAST_TRUNK_SIZEm, MEM_BLOCK_ALL, tid,
   3260                       soc_mem_entry_null(unit, FAST_TRUNK_SIZEm));
   3261     if (BCM_FAILURE(rv)) {
   3262         goto cleanup;
   3263     }
   3264 
   3265     /*
   3266      * Remove ports from failover
   3267      */
   3268     rv = _bcm_th3_trunk_failover_set(unit, tid, FALSE, NULL);
   3269     if (BCM_FAILURE(rv)) {
   3270         goto cleanup;
   3271     }
   3272 
   3273     rv =  _bcm_th3_trunk_swfailover_set(unit,
   3274                                         tid,
   3275                                         0,
   3276                                         0,
   3277                                         NULL,
   3278                                         NULL,
   3279                                         NULL,
   3280                                         0);
   3281     if (BCM_FAILURE(rv)) {
   3282         goto cleanup;
   3283     }
   3284 
   3285     
   3286     rv = _bcm_xgs3_trunk_property_migrate(unit,
   3287                 num_leaving_members, leaving_members,
   3288                 0, NULL, 0, NULL);
   3289     if (BCM_FAILURE(rv)) {
   3290         goto cleanup;
   3291     }
   3292 
   3293     
   3294 
   3295     /* Free memory allocated for ports and member flags in the trunk_set
   3296      * function */
   3297     if (MEMBER_INFO(unit, tid).port) {
   3298         sal_free(MEMBER_INFO(unit, tid).port);
   3299         MEMBER_INFO(unit, tid).port = NULL;
   3300     }
   3301     if (MEMBER_INFO(unit, tid).member_flags) {
   3302         sal_free(MEMBER_INFO(unit, tid).member_flags);
   3303         MEMBER_INFO(unit, tid).member_flags = NULL;
   3304     }
   3305     MEMBER_INFO(unit, tid).num_ports = 0;
   3306 
   3307     t_info->in_use = FALSE;
   3308 
   3309 cleanup:
   3310     sal_free(leaving_members);
   3311 
   3312     return rv;
   3313 }
   3314 
   3315 static soc_field_t _th3_trunk_failover_portf[8] = {
   3316     PORT0f, PORT1f, PORT2f, PORT3f,
   3317     PORT4f, PORT5f, PORT6f, PORT7f
   3318 };
   3319 
   3320 /*
   3321  * Function:
   3322  *      _bcm_th3_trunk_hwfailover_write
   3323  * Purpose:
   3324  *      Set front panel trunk hardware failover config
   3325  * Parameters:
   3326  *      unit        - (IN) SOC unit number.
   3327  *      failport    - (IN) Fail port
   3328  *      rtag        - (IN) Port selection criteria for failover port list
   3329  *      hw_count    - (IN) Number of ports in failover port list
   3330  *      ftp         - (IN) Pointer to failover port list port ID
   3331  * Returns:
   3332  *      BCM_E_xxx
   3333  */
   3334 STATIC int
   3335 _bcm_th3_trunk_hwfailover_write(int unit,
   3336         bcm_port_t failport, int rtag,
   3337         int hw_count, bcm_port_t *ftp)
   3338 {
   3339     int failover_status, failover_max_portcnt, mirror_enable, i;
   3340     port_lag_failover_set_entry_t fail_entry;
   3341 
   3342 
   3343     if (SOC_USE_PORTCTRL(unit)) {
   3344         BCM_IF_ERROR_RETURN
   3345             (bcmi_esw_portctrl_hwfailover_status_get(unit, failport,
   3346                                                      &failover_status));
   3347     } else {
   3348         /* TH3 uses portmod and portctrl */
   3349         return BCM_E_INIT;
   3350     }
   3351 
   3352     if (failover_status) {
   3353         /*
   3354          * Already in failover mode.  Do not change HW settings!
   3355          * This should be dealt with as part of the port link processing.
   3356          */
   3357         if (hw_count == 0) {
   3358             /* Notify linkscan of port removal from trunk */
   3359             BCM_IF_ERROR_RETURN
   3360                 (_bcm_esw_link_failover_set(unit, failport, FALSE));
   3361             return BCM_E_NONE;
   3362         } else {
   3363             /* Failed port has not yet been removed from the trunk
   3364              * -- do not change the failover configuration
   3365              */
   3366             return BCM_E_NONE;
   3367         }
   3368     }
   3369 
   3370     /* Enabling trunk failover */
   3371     if (hw_count) {
   3372         /* Must be in directed mirroring mode to use this feature */
   3373         BCM_IF_ERROR_RETURN
   3374             (bcm_esw_switch_control_get(unit, bcmSwitchDirectedMirroring,
   3375                                         &mirror_enable));
   3376         if (!mirror_enable) {
   3377             return BCM_E_CONFIG;
   3378         }
   3379 
   3380         sal_memset(&fail_entry, 0, sizeof(fail_entry));
   3381         soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm,
   3382                 (uint32 *)&fail_entry,
   3383                 FAILOVER_SET_SIZEf, hw_count - 1);
   3384         soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm,
   3385                 (uint32 *)&fail_entry, RTAGf, rtag);
   3386 
   3387         failover_max_portcnt = 1 << soc_mem_field_length(unit,
   3388                 PORT_LAG_FAILOVER_SETm, FAILOVER_SET_SIZEf);
   3389 
   3390         /* Set each port to failover to for failport */
   3391         for(i = 0; i < failover_max_portcnt; i++) {
   3392             soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm,
   3393                     (uint32 *)&fail_entry,
   3394                     _th3_trunk_failover_portf[i],
   3395                     ftp[i % hw_count]);
   3396         }
   3397 
   3398         SOC_IF_ERROR_RETURN
   3399             (WRITE_PORT_LAG_FAILOVER_SETm(unit, MEM_BLOCK_ALL, failport,
   3400                                           &fail_entry));
   3401     }
   3402 
   3403     if (SOC_USE_PORTCTRL(unit)) {
   3404         BCM_IF_ERROR_RETURN
   3405             (bcmi_esw_portctrl_hwfailover_enable_set(unit, failport,
   3406                                                      (hw_count != 0) ? 1 : 0));
   3407     } else {
   3408         /* TH3 uses portmod and portctrl */
   3409         return BCM_E_INIT;
   3410     }
   3411 
   3412     /* Notify linkscan of failover status */
   3413     BCM_IF_ERROR_RETURN
   3414         (_bcm_esw_link_failover_set(unit, failport, (hw_count != 0)));
   3415 
   3416     return BCM_E_NONE;
   3417 }
   3418 
   3419 /*
   3420  * Function:
   3421  *      _bcm_th3_trunk_hwfailover_read
   3422  * Purpose:
   3423  *      Set front panel trunk hardware failover config
   3424  * Parameters:
   3425  *      unit        - (IN) SOC unit number.
   3426  *      failport    - (IN) Fail port
   3427  *      max_ports   - (IN) max ports to copy out
   3428  *      ftp         - (OUT) Pointer to port IDs in failover port list
   3429  *      hw_count    - (OUT) Number of failover ports copied out.
   3430  *      rtag        - (OUT) pointer to failover ports rtag
   3431  * Returns:
   3432  *      BCM_E_xxx
   3433  */
   3434 STATIC int
   3435 _bcm_th3_trunk_hwfailover_read(int unit, bcm_port_t failport, int max_ports,
   3436                            bcm_port_t *ftp, int *hw_count, int *rtag)
   3437 {
   3438     int enable = FALSE, mirror_enable, i;
   3439     port_lag_failover_set_entry_t fail_entry;
   3440     uint32 failover_set_size;
   3441 
   3442     *hw_count = 0;
   3443 
   3444     if (SOC_USE_PORTCTRL(unit)) {
   3445         BCM_IF_ERROR_RETURN
   3446             (bcmi_esw_portctrl_hwfailover_enable_get(unit, failport,
   3447                                                      &enable));
   3448     } else {
   3449         /* TH3 uses portmod and portctrl */
   3450         return BCM_E_INIT;
   3451     }
   3452 
   3453     if (!enable) {
   3454         return BCM_E_NONE;
   3455     }
   3456 
   3457     /* Must be in directed mirroring mode to use this feature */
   3458     BCM_IF_ERROR_RETURN
   3459         (bcm_esw_switch_control_get(unit, bcmSwitchDirectedMirroring,
   3460                                     &mirror_enable));
   3461     if (!mirror_enable) {
   3462         return BCM_E_NONE;
   3463     }
   3464 
   3465     sal_memset(&fail_entry, 0, sizeof(fail_entry));
   3466     SOC_IF_ERROR_RETURN
   3467         (READ_PORT_LAG_FAILOVER_SETm(unit, MEM_BLOCK_ALL, failport,
   3468                                       &fail_entry));
   3469 
   3470     failover_set_size = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm,
   3471             (uint32 *)&fail_entry, FAILOVER_SET_SIZEf) + 1;
   3472     *rtag = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm,
   3473             (uint32 *)&fail_entry, RTAGf);
   3474     *hw_count = failover_set_size > max_ports? max_ports: failover_set_size;
   3475 
   3476     /* Set each port to failover to for failport */
   3477     for(i = 0; i < *hw_count; i++) {
   3478         ftp[i] = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm,
   3479                 (uint32 *)&fail_entry,
   3480                 _th3_trunk_failover_portf[i]);
   3481     }
   3482 
   3483     return BCM_E_NONE;
   3484 }
   3485 
   3486 /*
   3487  * Function:
   3488  *      _bcm_th3_trunk_hwfailover_set
   3489  * Purpose:
   3490  *      Derive hardware failover port list and set hardware
   3491  *      failover config.
   3492  * Parameters:
   3493  *      unit        - (IN) unit number
   3494  *      tid         - (IN) Trunk Group ID
   3495  *      port        - (IN) Port ID of the fail port
   3496  *      psc         - (IN) Port selection criteria for the failover port list
   3497  *      flags       - (IN) BCM_TRUNK_FLAG_FAILOVER_xxx
   3498  *      count       - (IN) Number of ports in failover port list
   3499  *      ftp         - (IN) Pointer to port IDs in failover port list
   3500  * Returns:
   3501  *      BCM_E_xxx
   3502  */
   3503 int
   3504 _bcm_th3_trunk_hwfailover_set(int unit, bcm_trunk_t tid,
   3505                         bcm_port_t port, int psc, uint32 flags,
   3506                         int count, bcm_port_t *ftp)
   3507 {
   3508     int rtag, trunk_ports, trunk_index, failover_max_portcnt;
   3509     int hw_count, i, rv, next;
   3510     uint16 fail_port;
   3511     bcm_port_t *port_list = NULL;
   3512     _th3_hw_tinfo_t *hw_fail_trunk;
   3513 
   3514     /* Passed in port is the fail port. No HG/stacking calc */
   3515     fail_port = port;
   3516 
   3517     BCM_IF_ERROR_RETURN(_bcm_th3_trunk_psc_to_rtag(unit, psc, &rtag));
   3518 
   3519     hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   3520     trunk_ports = hw_fail_trunk->num_ports;
   3521 
   3522     for(trunk_index = 0; trunk_index < trunk_ports; trunk_index++) {
   3523         if (fail_port == hw_fail_trunk->port[trunk_index]) {
   3524             break;
   3525         }
   3526     }
   3527 
   3528     if ((0 != count) && (trunk_index == trunk_ports)) {
   3529         /* Port not in trunk! */
   3530         return BCM_E_NOT_FOUND;
   3531     }
   3532 
   3533     /* TH3 allows a max of 8 failover ports */
   3534     failover_max_portcnt = 1 << soc_mem_field_length(unit,
   3535             PORT_LAG_FAILOVER_SETm, FAILOVER_SET_SIZEf);
   3536 
   3537     port_list = sal_alloc(sizeof(bcm_port_t) * failover_max_portcnt,
   3538                     "failover port list");
   3539 
   3540     if (port_list == NULL) {
   3541         return BCM_E_MEMORY;
   3542     }
   3543 
   3544     sal_memset(port_list, 0, sizeof(bcm_port_t) * failover_max_portcnt);
   3545 
   3546     if (flags) {
   3547         switch (flags) {
   3548             case BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL:
   3549                 next = TRUE;
   3550                 break;
   3551             case BCM_TRUNK_FLAG_FAILOVER_NEXT:
   3552                 next = TRUE;
   3553                 break;
   3554             case BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL:
   3555                 next = FALSE;
   3556                 break;
   3557             case BCM_TRUNK_FLAG_FAILOVER_ALL:
   3558                 next = FALSE;
   3559                 break;
   3560             default:
   3561                 /* Illegal flags setting */
   3562                 sal_free(port_list);
   3563                 return BCM_E_PARAM;
   3564         }
   3565         
   3566         hw_count = 0;
   3567 
   3568         for (i = ((trunk_index + 1) % trunk_ports); /* Start after fail port */
   3569             i != trunk_index;                   /* Stop after cycling around */
   3570             i = ((i + 1) % trunk_ports)) { /* Cycle through trunk port list */
   3571 
   3572             /* All ports are local; modid is 0, so only add port */
   3573             port_list[hw_count] = hw_fail_trunk->port[i];
   3574             hw_count++;
   3575             if (hw_count == failover_max_portcnt) {
   3576                 break;
   3577             }
   3578             if (next) {
   3579                 break;
   3580             }
   3581         }
   3582     } else {
   3583         hw_count = 0;
   3584 
   3585         if (count) {
   3586             for (i = 0; i < count && i < failover_max_portcnt; i++) {
   3587                 port_list[i] = BCM_GPORT_MODPORT_PORT_GET(ftp[i]);
   3588 
   3589             }
   3590             hw_count = i;
   3591         }
   3592     }
   3593 
   3594     rv = _bcm_th3_trunk_hwfailover_write(unit, port, rtag,
   3595             hw_count, port_list);
   3596 
   3597     sal_free(port_list);
   3598     if (BCM_FAILURE(rv)) {
   3599         return rv;
   3600     }
   3601 
   3602     /* Set the port selection criteria and the flags in the
   3603      * port that hardware failover was just configured for
   3604      */
   3605     if (trunk_index < hw_fail_trunk->num_ports) {
   3606         hw_fail_trunk->flags[trunk_index] = flags;
   3607         hw_fail_trunk->psc[trunk_index] = psc;
   3608     }
   3609 
   3610     return rv;
   3611 }
   3612 /*
   3613  * Function:
   3614  *      _bcm_th3_trunk_hwfailover_get
   3615  * Purpose:
   3616  *      Derive hardware failover port list and set hardware
   3617  *      failover config.
   3618  * Parameters:
   3619  *      unit        - (IN) unit number
   3620  *      tid         - (IN) Trunk Group ID
   3621  *      port        - (IN) Port ID of the fail port
   3622  *      array_size  - (IN) numbers of max failovers ports to copy out
   3623  *      psc         - (OUT) Port selection criteria for the failover port list
   3624  *      flags       - (OUT) BCM_TRUNK_FLAG_FAILOVER_xxx
   3625  *      array_count - (OUT) Number of failover ports copied out
   3626  *      ftp         - (OUT) Pointer to port IDs in failover port list
   3627  * Returns:
   3628  *      BCM_E_xxx
   3629  */
   3630 int
   3631 _bcm_th3_trunk_hwfailover_get(int unit, bcm_trunk_t tid,
   3632                          bcm_port_t port, int *psc, uint32 *flags,
   3633                          int array_size, bcm_port_t *ftp, int *array_count)
   3634 {
   3635     int trunk_ports, trunk_index;
   3636     int rv = BCM_E_NONE;
   3637     uint16 fail_port;
   3638     _th3_hw_tinfo_t *hw_fail_trunk;
   3639     int rtag;
   3640 
   3641     /* Passed in port is the fail port. No HG/stacking calc */
   3642     fail_port = port;
   3643 
   3644     if (array_size != 0 && ftp == NULL) {
   3645         return BCM_E_PARAM;
   3646     }
   3647     hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]);
   3648     trunk_ports = hw_fail_trunk->num_ports;
   3649 
   3650     for(trunk_index = 0; trunk_index < trunk_ports; trunk_index++) {
   3651         if (fail_port == hw_fail_trunk->port[trunk_index]) {
   3652             break;
   3653         }
   3654     }
   3655 
   3656     if (trunk_index == trunk_ports) {
   3657         /* Port not in trunk! */
   3658         return BCM_E_NOT_FOUND;
   3659     }
   3660     *psc = hw_fail_trunk->psc[trunk_index];
   3661     *flags = hw_fail_trunk->flags[trunk_index];
   3662 
   3663     if (array_size > 0) {
   3664         sal_memset(ftp, 0, sizeof(bcm_port_t) * array_size);
   3665         rv = _bcm_th3_trunk_hwfailover_read(unit, port, array_size, ftp, array_count, &rtag);
   3666     }
   3667 
   3668     return rv;
   3669 }
   3670 
   3671 #endif
   3672 #endif /* BCM_TOMAHAWK3_SUPPORT */