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

multicast.c (23240B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        multicast.c
      8  * Purpose:     Trident2Plus multicast functions
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 #include <shared/bsl.h>
     14 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(INCLUDE_L3)
     15 #include <soc/drv.h>
     16 #include <soc/scache_dictionary.h>
     17 #include <bcm/error.h>
     18 #include <bcm/types.h>
     19 #include <bcm_int/esw/trident2plus.h>
     20 #define _TD2P_NUM_TRUNKS 1024
     21 
     22 
     23 #define _TD2P_NUM_AGGID_PER_PIPE(unit)  \
     24         (soc_mem_field_length(unit, MMU_REPL_GROUP_INFO0m, PIPE_MEMBER_BMPf))
     25 
     26 typedef struct _bcm_td2p_aggid_used_bmp_per_pipe_s {
     27     SHR_BITDCL* pipe_aggid_bmp;
     28 } _bcm_td2p_aggid_used_bmp_per_pipe_t;
     29 
     30 STATIC _bcm_td2p_aggid_used_bmp_per_pipe_t *td2p_aggid_used_bmp[BCM_MAX_NUM_UNITS];
     31 
     32 typedef struct _bcm_td2p_trunk_aggid_info_s {
     33     int agg_id;
     34     int ref_cnt;
     35 } _bcm_td2p_trunk_aggid_info_t;
     36 
     37 typedef struct _bcm_td2p_trunk_aggid_per_pipe_info_s {
     38     _bcm_td2p_trunk_aggid_info_t trunk_aggid_info[_TD2P_NUM_TRUNKS];
     39 } _bcm_td2p_trunk_aggid_per_pipe_info_t;
     40 
     41 typedef struct _bcm_td2p_port_aggid_info_s {
     42     int agg_id;
     43     int ref_cnt;   /* The number of the pair <mc group, nexthop> pointing to it. */
     44     int trunk_id;
     45 } _bcm_td2p_port_aggid_info_t;
     46 
     47 STATIC _bcm_td2p_trunk_aggid_per_pipe_info_t *td2p_trunk_aggid[BCM_MAX_NUM_UNITS];
     48 
     49 STATIC _bcm_td2p_port_aggid_info_t *td2p_port_aggid[BCM_MAX_NUM_UNITS];
     50 
     51 /*
     52  * Function:
     53  *      bcm_td2p_aggid_info_detach
     54  * Purpose:
     55  *      Free aggregation ID list.
     56  * Parameters:
     57  *      unit  - (IN) Unit number.
     58  * Returns:
     59  *      BCM_E_XXX
     60  */
     61 int
     62 bcm_td2p_aggid_info_detach(int unit)
     63 {
     64     int num_pipes;
     65     int i;
     66     SHR_BITDCL *pipe_aggid_bmp;
     67 
     68     num_pipes = NUM_PIPE(unit);
     69 
     70     if (td2p_aggid_used_bmp[unit] != NULL) {
     71         for (i = 0; i < num_pipes; i++) {
     72             pipe_aggid_bmp = td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp;
     73             if (pipe_aggid_bmp != NULL) {
     74                 sal_free(pipe_aggid_bmp);
     75                 pipe_aggid_bmp = NULL;
     76             }
     77         }
     78         sal_free(td2p_aggid_used_bmp[unit]);
     79         td2p_aggid_used_bmp[unit] = NULL;
     80     }
     81 
     82     if (td2p_trunk_aggid[unit] != NULL) {
     83         sal_free(td2p_trunk_aggid[unit]);
     84         td2p_trunk_aggid[unit] = NULL;
     85     }
     86 
     87     if (td2p_port_aggid[unit] != NULL) {
     88         sal_free(td2p_port_aggid[unit]);
     89         td2p_port_aggid[unit] = NULL;
     90     }
     91 
     92     return BCM_E_NONE;
     93 }
     94 
     95 /*
     96  * Function:
     97  *      bcm_td2p_aggid_info_init
     98  * Purpose:
     99  *      Initialize aggregation ID to trunk map array.
    100  * Parameters:
    101  *      unit  - (IN) Unit number.
    102  * Returns:
    103  *      BCM_E_XXX
    104  */
    105 int
    106 bcm_td2p_aggid_info_init(int unit)
    107 {
    108     int   num_pipes;
    109     int   i, j;
    110     _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info;
    111     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    112 
    113 
    114     if (!SOC_UNIT_VALID(unit)) {
    115         return BCM_E_UNIT;
    116     }
    117 
    118     num_pipes = NUM_PIPE(unit);
    119 
    120     bcm_td2p_aggid_info_detach(unit);
    121 
    122 
    123     td2p_aggid_used_bmp[unit] =
    124         sal_alloc((num_pipes * sizeof(_bcm_td2p_aggid_used_bmp_per_pipe_t)),
    125                   "aggid_used_bmp_info");
    126     if (td2p_aggid_used_bmp[unit] == NULL) {
    127         return BCM_E_MEMORY;
    128     }
    129     for (i = 0; i < num_pipes; i++) {
    130         td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp =
    131             sal_alloc(SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)),
    132                       "aggid_used_bmp_per_piep_info");
    133         if (td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp == NULL) {
    134             bcm_td2p_aggid_info_detach(unit);
    135             return BCM_E_MEMORY;
    136         }
    137         sal_memset(td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp, 0,
    138                    SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit)));
    139     }
    140 
    141     /* Init trunk aggid info. */
    142     td2p_trunk_aggid[unit] =
    143         sal_alloc((num_pipes * sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t)),
    144                   "trunk_aggid_info");
    145     if (td2p_trunk_aggid[unit] == NULL) {
    146         bcm_td2p_aggid_info_detach(unit);
    147         return BCM_E_MEMORY;
    148     }
    149     for (i = 0; i < num_pipes; i++) {
    150         for (j = 0; j < _TD2P_NUM_TRUNKS; j++) {
    151             trunk_aggid_info = &(td2p_trunk_aggid[unit][i].trunk_aggid_info[j]);
    152             trunk_aggid_info->agg_id = TD2P_AGG_ID_INVALID;
    153             trunk_aggid_info->ref_cnt = 0;
    154         }
    155     }
    156 
    157     /* Init port aggid info. */
    158     td2p_port_aggid[unit] =
    159         sal_alloc((SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t)),
    160                    "port_aggid_info");
    161     if (td2p_port_aggid[unit] == NULL) {
    162         bcm_td2p_aggid_info_detach(unit);
    163         return BCM_E_MEMORY;
    164     }
    165     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
    166         port_aggid_info = &td2p_port_aggid[unit][i];
    167         port_aggid_info->agg_id = TD2P_AGG_ID_INVALID;
    168         port_aggid_info->ref_cnt = 0;
    169         port_aggid_info->trunk_id = BCM_TRUNK_INVALID;
    170     }
    171 
    172     return BCM_E_NONE;
    173 }
    174 
    175 /*
    176  * Function:
    177  *      bcm_td2p_get_free_aggid
    178  * Purpose:
    179  *      Get a free aggid for given pipe.
    180  * Parameters:
    181  *      unit  - (IN)  Unit number.
    182  *      pipe  - (IN)  Pipe id.
    183  *      aggid - (OUT) Returned aggid.
    184  * Returns:
    185  *      BCM_E_XXX
    186  */
    187 STATIC int
    188 bcm_td2p_get_free_aggid(int unit, int pipe, int *aggid)
    189 {
    190     SHR_BITDCL *aggid_bmp;
    191     int i;
    192 
    193     aggid_bmp = td2p_aggid_used_bmp[unit][pipe].pipe_aggid_bmp;
    194     for (i = 0; i < _TD2P_NUM_AGGID_PER_PIPE(unit); i++) {
    195         if (!SHR_BITGET(aggid_bmp, i)) {
    196             *aggid = i;
    197             SHR_BITSET(aggid_bmp, i);
    198             return BCM_E_NONE;
    199         }
    200     }
    201 
    202     if (i == _TD2P_NUM_AGGID_PER_PIPE(unit)) {
    203         return BCM_E_FULL;
    204     }
    205 
    206     return BCM_E_NONE;
    207 
    208 }
    209 
    210 /*
    211  * Function:
    212  *      bcm_td2p_set_free_aggid
    213  * Purpose:
    214  *      Free aggid for given pipe.
    215  * Parameters:
    216  *      unit  - (IN)  Unit number.
    217  *      pipe  - (IN)  Pipe id.
    218  *      aggid - (IN)  Aggregation ID.
    219  * Returns:
    220  *      BCM_E_XXX
    221  */
    222 STATIC int
    223 bcm_td2p_set_free_aggid(int unit, int pipe, int aggid)
    224 {
    225     SHR_BITDCL *aggid_bmp;
    226 
    227     aggid_bmp = td2p_aggid_used_bmp[unit][pipe].pipe_aggid_bmp;
    228     if (aggid >= _TD2P_NUM_AGGID_PER_PIPE(unit)) {
    229         return BCM_E_PARAM;
    230     }
    231     SHR_BITCLR(aggid_bmp, aggid);
    232 
    233     return BCM_E_NONE;
    234 }
    235 
    236 /*
    237  * Function:
    238  *      bcm_td2p_set_port_hw_agg_map
    239  * Purpose:
    240  *      Set HW aggid map register for a port.
    241  *      Since L3MC-Port-Agg-ID is used per egress pipe, the maximum L3MC-Port-Agg-IDs
    242  *      needs to match the maximum number of ports per pipe, which is 53.
    243  *      Therefore, only the lower six bits are needed for L3MC-Port-Agg-ID by the hardware.
    244  *      But for the ENQ stage regregiter used in cut-through mode,
    245  *      PIPE_NUM field must be programmed because L3MC-Port-Agg-ID is used per chip.
    246  * Parameters:
    247  *      unit  - (IN) Unit number.
    248  *      port  - (IN) Logical Port.
    249  *      aggid - (IN) Aggregation ID.
    250  * Returns:
    251  *      BCM_E_XXX
    252  */
    253 int
    254 bcm_td2p_set_port_hw_agg_map(int unit, bcm_port_t port, int aggid)
    255 {
    256     uint32 regval;
    257     int pipe_num = SOC_INFO(unit).port_pipe[port];
    258 
    259     BCM_IF_ERROR_RETURN(READ_MMU_TOQ_REPL_PORT_AGG_MAPr(unit, port, &regval));
    260     soc_reg_field_set(unit, MMU_TOQ_REPL_PORT_AGG_MAPr, &regval,
    261                       L3MC_PORT_AGG_IDf, aggid);
    262     SOC_IF_ERROR_RETURN(
    263         soc_reg32_set(unit, MMU_TOQ_REPL_PORT_AGG_MAPr, port, 0, regval));
    264 
    265     soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, &regval,
    266                       L3MC_PORT_AGG_IDf, aggid);
    267     soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, &regval,
    268                       PIPE_NUMf, pipe_num);
    269     SOC_IF_ERROR_RETURN(
    270         soc_reg32_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, port, 0, regval));
    271 
    272     soc_reg_field_set(unit, MMU_ENQ_LOGICAL_PORT_TO_PORT_AGG_MAPr, &regval,
    273                       L3MC_PORT_AGG_IDf, aggid);
    274     soc_reg_field_set(unit, MMU_ENQ_REPL_PORT_AGG_MAPr, &regval,
    275                       PIPE_NUMf, pipe_num);
    276     SOC_IF_ERROR_RETURN(WRITE_MMU_ENQ_LOGICAL_PORT_TO_PORT_AGG_MAPr(unit,
    277                         port, regval));
    278 
    279     return BCM_E_NONE;
    280 }
    281 
    282 /*
    283  * Function:
    284  *      bcm_td2p_aggid_add
    285  * Purpose:
    286  *      Increase aggid refcnt of a independ port or trunk.
    287  * Parameters:
    288  *      unit  - (IN)  Unit number.
    289  *      port  - (IN)  Logical Port.
    290  *      tgid  - (IN)  Trunk id.
    291  *      aggid - (OUT) Returned aggid.
    292  * Returns:
    293  *      BCM_E_XXX
    294  */
    295 STATIC int
    296 bcm_td2p_aggid_add(int unit, bcm_port_t port, bcm_trunk_t tgid, int *aggid)
    297 {
    298     int rv = BCM_E_NONE;
    299     int pipe;
    300     _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info;
    301     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    302 
    303     if (((tgid != BCM_TRUNK_INVALID) && (tgid < 0 || tgid >= _TD2P_NUM_TRUNKS)) ||
    304         (port < 0 || port >= SOC_MAX_NUM_PORTS) ||
    305         (aggid == NULL)) {
    306         return BCM_E_PARAM;
    307     }
    308 
    309     pipe = SOC_INFO(unit).port_pipe[port];
    310     if (tgid != BCM_TRUNK_INVALID) {
    311         trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]);
    312         if (trunk_aggid_info->agg_id == TD2P_AGG_ID_INVALID) {
    313             BCM_IF_ERROR_RETURN(bcm_td2p_get_free_aggid(unit, pipe, aggid));
    314             trunk_aggid_info->agg_id = *aggid;
    315             trunk_aggid_info->ref_cnt = 1;
    316         } else {
    317             *aggid = trunk_aggid_info->agg_id;
    318             trunk_aggid_info->ref_cnt++;
    319         }
    320     } else {
    321         port_aggid_info = &(td2p_port_aggid[unit][port]);
    322         if (port_aggid_info->agg_id == TD2P_AGG_ID_INVALID) {
    323             BCM_IF_ERROR_RETURN(bcm_td2p_get_free_aggid(unit, pipe, aggid));
    324             rv = bcm_td2p_set_port_hw_agg_map(unit, port, *aggid);
    325             if (BCM_FAILURE(rv)) {
    326                 bcm_td2p_set_free_aggid(unit, pipe, *aggid);
    327                 return rv;
    328             }
    329             port_aggid_info->agg_id = *aggid;
    330             port_aggid_info->ref_cnt = 1;
    331             port_aggid_info->trunk_id = BCM_TRUNK_INVALID;
    332         } else {
    333             *aggid = port_aggid_info->agg_id;
    334             port_aggid_info->ref_cnt++;
    335         }
    336     }
    337 
    338     return BCM_E_NONE;
    339 }
    340 
    341 /*
    342  * Function:
    343  *      bcm_td2p_aggid_del
    344  * Purpose:
    345  *      Decrease aggid refcnt of a independ port or trunk.
    346  * Parameters:
    347  *      unit  - (IN)  Unit number.
    348  *      port  - (IN)  Logical Port.
    349  * Returns:
    350  *      BCM_E_XXX
    351  */
    352 STATIC int
    353 bcm_td2p_aggid_del(int unit, bcm_port_t port)
    354 {
    355     int pipe;
    356     bcm_trunk_t tgid;
    357     int rv;
    358     _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info;
    359     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    360 
    361     if ((port < 0) || (port >= SOC_MAX_NUM_PORTS)) {
    362         return BCM_E_PARAM;
    363     }
    364     port_aggid_info = &(td2p_port_aggid[unit][port]);
    365     tgid = port_aggid_info->trunk_id;
    366     pipe = SOC_INFO(unit).port_pipe[port];
    367     if (tgid != BCM_TRUNK_INVALID) {
    368         trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]);
    369         if (trunk_aggid_info->ref_cnt <= 0) {
    370             return BCM_E_PARAM;
    371         }
    372         trunk_aggid_info->ref_cnt--;
    373         if (trunk_aggid_info->ref_cnt == 0) {
    374             bcm_td2p_set_free_aggid(unit, pipe, trunk_aggid_info->agg_id);
    375             trunk_aggid_info->agg_id = TD2P_AGG_ID_INVALID;
    376         }
    377         if (port_aggid_info->ref_cnt == 0) {
    378             port_aggid_info->trunk_id = BCM_TRUNK_INVALID;
    379         }
    380     } else {
    381         if (port_aggid_info->ref_cnt <= 0) {
    382             return BCM_E_PARAM;
    383         }
    384         port_aggid_info->ref_cnt--;
    385         if (port_aggid_info->ref_cnt == 0) {
    386             rv = bcm_td2p_set_port_hw_agg_map(unit, port, TD2P_AGG_ID_HW_INVALID);
    387             if (BCM_FAILURE(rv)) {
    388                 port_aggid_info->ref_cnt++;
    389                 return rv;
    390             }
    391             bcm_td2p_set_free_aggid(unit, pipe, port_aggid_info->agg_id);
    392             port_aggid_info->agg_id = TD2P_AGG_ID_INVALID;
    393         }
    394     }
    395 
    396     return BCM_E_NONE;
    397 }
    398 
    399 
    400 /*
    401  * Function:
    402  *      bcm_td2p_aggid_ref_inc_for_member
    403  * Purpose:
    404  *      Increase aggid refcount for a trunk member port.
    405  * Parameters:
    406  *      unit  - (IN)  Unit number.
    407  *      port  - (IN)  Logical Port.
    408  *      tgid  - (IN)  Trunk id.
    409  * Returns:
    410  *      BCM_E_XXX
    411  */
    412 STATIC int
    413 bcm_td2p_aggid_ref_inc_for_member(int unit, bcm_port_t port, bcm_trunk_t tgid)
    414 {
    415     int aggid, pipe;
    416     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    417 
    418     if (port < 0 || port >= SOC_MAX_NUM_PORTS) {
    419         return BCM_E_PARAM;
    420     }
    421 
    422     port_aggid_info = &(td2p_port_aggid[unit][port]);
    423     if (port_aggid_info->agg_id != TD2P_AGG_ID_INVALID) {
    424         return BCM_E_PARAM;
    425     }
    426 
    427     if (port_aggid_info->trunk_id == BCM_TRUNK_INVALID) {
    428         /* This is the first time that member port joined trunk tgid.
    429          * For member port, it just uses trunk's agg_id not itself.
    430          */
    431         if (port_aggid_info->ref_cnt != 0) {
    432             return BCM_E_PARAM;
    433         }
    434         port_aggid_info->trunk_id = tgid;
    435         port_aggid_info->ref_cnt = 1;
    436         pipe = SOC_INFO(unit).port_pipe[port];
    437         aggid = td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid].agg_id;
    438         BCM_IF_ERROR_RETURN(bcm_td2p_set_port_hw_agg_map(unit, port, aggid));
    439     } else {
    440         /* member port has joined one trunk. */
    441         if (port_aggid_info->trunk_id != tgid) {
    442             return BCM_E_PARAM;
    443         }
    444         port_aggid_info->ref_cnt++;
    445     }
    446 
    447     return BCM_E_NONE;
    448 }
    449 
    450 /*
    451  * Function:
    452  *      bcm_td2p_aggid_ref_dec_for_member
    453  * Purpose:
    454  *      Decrease aggid refcount for a trunk member port.
    455  * Parameters:
    456  *      unit  - (IN) Unit number.
    457  *      port  - (IN)  Logical Port.
    458  * Returns:
    459  *      BCM_E_XXX
    460  */
    461 STATIC int
    462 bcm_td2p_aggid_ref_dec_for_member(int unit, bcm_port_t port)
    463 {
    464     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    465     int rv;
    466 
    467     if (port < 0 || port >= SOC_MAX_NUM_PORTS) {
    468         return BCM_E_PARAM;
    469     }
    470 
    471     port_aggid_info = &(td2p_port_aggid[unit][port]);
    472     if (port_aggid_info->trunk_id == BCM_TRUNK_INVALID) {
    473         return BCM_E_PARAM;
    474     }
    475 
    476     if (port_aggid_info->ref_cnt <= 0) {
    477         return BCM_E_PARAM;
    478     }
    479 
    480     port_aggid_info->ref_cnt--;
    481     if (port_aggid_info->ref_cnt == 0) {
    482         /* All (port, mc group) has can leave the trunk.
    483          * Do not set port_aggid_info->trunk_id to BCM_TRUNK_INVALID here.
    484          */
    485         rv = bcm_td2p_set_port_hw_agg_map(unit, port, TD2P_AGG_ID_HW_INVALID);
    486         if (BCM_FAILURE(rv)) {
    487             port_aggid_info->ref_cnt++;
    488             return rv;
    489         }
    490     }
    491 
    492     return BCM_E_NONE;
    493 }
    494 
    495 /*
    496  * Function:
    497  *      bcm_td2p_port_aggid_add
    498  * Purpose:
    499  *      Add a aggid for a logical port.
    500  *      If there is no aggid allocated for the logical port, a new aggid
    501  *      will be allocated for it. Otherwise, the reference count will be
    502  *      incremented.
    503  * Parameters:
    504  *      unit  - (IN)  Unit number.
    505  *      port  - (IN)  Logical Port.
    506  *      tgid  - (IN)  Trunk id.
    507  *      aggid - (OUT) Aggid returned.
    508  * Returns:
    509  *      BCM_E_XXX
    510  */
    511 int
    512 bcm_td2p_port_aggid_add(int unit, bcm_port_t port, bcm_trunk_t tgid, int *aggid)
    513 {
    514     int rv;
    515 
    516     if (tgid != BCM_TRUNK_INVALID) {
    517         rv = bcm_td2p_aggid_add(unit, port, tgid, aggid);
    518         if (BCM_FAILURE(rv)) {
    519             return rv;
    520         }
    521         rv = bcm_td2p_aggid_ref_inc_for_member(unit, port, tgid);
    522         if (BCM_FAILURE(rv)) {
    523             bcm_td2p_aggid_del(unit, port);
    524             return rv;
    525         }
    526     } else {
    527         rv = bcm_td2p_aggid_add(unit, port, tgid, aggid);
    528         if (BCM_FAILURE(rv)) {
    529             return rv;
    530         }
    531     }
    532 
    533     return BCM_E_NONE;
    534 }
    535 
    536 /*
    537  * Function:
    538  *      bcm_td2p_port_aggid_del
    539  * Purpose:
    540  *      Del aggid of a logical port.
    541  *      If there is the reference count is greater than 1, the reference count
    542  *      will be decreased. Otherwise, the aggid will be freed.
    543  * Parameters:
    544  *      unit  - (IN)  Unit number.
    545  *      port  - (IN)  Logical Port.
    546  * Returns:
    547  *      BCM_E_XXX
    548  */
    549 int
    550 bcm_td2p_port_aggid_del(int unit, bcm_port_t port)
    551 {
    552     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    553     bcm_trunk_t tgid;
    554     int rv;
    555 
    556     if (port < 0 || port >= SOC_MAX_NUM_PORTS) {
    557         return BCM_E_PARAM;
    558     }
    559 
    560     port_aggid_info = &(td2p_port_aggid[unit][port]);
    561     tgid = port_aggid_info->trunk_id;
    562 
    563     if (tgid != BCM_TRUNK_INVALID) {
    564         rv = bcm_td2p_aggid_ref_dec_for_member(unit, port);
    565         if (BCM_FAILURE(rv)) {
    566             return rv;
    567         }
    568         rv = bcm_td2p_aggid_del(unit, port);
    569         if (BCM_FAILURE(rv)) {
    570             bcm_td2p_aggid_ref_inc_for_member(unit, port, tgid);
    571             return rv;
    572         }
    573     } else {
    574         rv = bcm_td2p_aggid_del(unit, port);
    575         if (BCM_FAILURE(rv)) {
    576             return rv;
    577         }
    578     }
    579 
    580     return BCM_E_NONE;
    581 }
    582 
    583 /*
    584  * Function:
    585  *      bcm_td2p_port_trunkid_get
    586  * Purpose:
    587  *      When port has been removed from trunk in trunk module,
    588  *      we could only get trunkid of port from previous saved DB.
    589  * Parameters:
    590  *      unit  - (IN) Unit number.
    591  *      port  - (IN) Logical Port
    592  *      tgid  - (OUT) returned Trunk id.
    593  * Returns:
    594  *      BCM_E_XXX
    595  * Note: This function only can be used when deleting port from trunk.
    596  */
    597 int
    598 bcm_td2p_port_trunkid_get(int unit, bcm_port_t port, int *tgid)
    599 {
    600     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    601 
    602     if ((port < 0 || port >= SOC_MAX_NUM_PORTS) ||
    603         (tgid == NULL)) {
    604         return BCM_E_PARAM;
    605     }
    606 
    607     port_aggid_info = &(td2p_port_aggid[unit][port]);
    608     *tgid = port_aggid_info->trunk_id;
    609 
    610     return BCM_E_NONE;
    611 }
    612 
    613 /*
    614  * Function:
    615  *      bcm_td2p_port_last_member_check
    616  * Purpose:
    617  *      Check whether a member port is the last member of its trunk.
    618  * Parameters:
    619  *      unit  - (IN)  Unit number.
    620  *      port  - (IN)  Logical Port
    621  *      val   - (OUT) returned val.
    622  * Returns:
    623  *      BCM_E_XXX
    624  */
    625 int
    626 bcm_td2p_port_last_member_check(int unit, bcm_port_t port, int *val)
    627 {
    628     int pipe;
    629     bcm_trunk_t tgid;
    630     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    631     int i;
    632     int member_cnt = 0;
    633 
    634     if (port < 0 || port >= SOC_MAX_NUM_PORTS) {
    635         return BCM_E_PARAM;
    636     }
    637 
    638     pipe = SOC_INFO(unit).port_pipe[port];
    639     port_aggid_info = &(td2p_port_aggid[unit][port]);
    640     tgid = port_aggid_info->trunk_id;
    641     if (tgid == BCM_TRUNK_INVALID) {
    642         return BCM_E_PARAM;
    643     }
    644 
    645     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
    646         if (member_cnt > 1) {
    647             *val = FALSE;
    648             return BCM_E_NONE;
    649         }
    650         port_aggid_info = &(td2p_port_aggid[unit][i]);
    651         if ((port_aggid_info->trunk_id == tgid) &&
    652             (SOC_INFO(unit).port_pipe[i] == pipe)) {
    653             member_cnt++;
    654         }
    655     }
    656 
    657     if (member_cnt > 1) {
    658         *val = FALSE;
    659     } else {
    660         *val = TRUE;
    661     }
    662 
    663     return BCM_E_NONE;
    664 }
    665 
    666 /*
    667  * Function:
    668  *      bcm_td2p_port_to_aggid
    669  * Purpose:
    670  *      Get aggid value for a logical port.
    671  * Parameters:
    672  *      unit  - (IN)  Unit number.
    673  *      aggid - (OUT) Returned aggid.
    674  * Returns:
    675  *      BCM_E_XXX
    676  */
    677 int
    678 bcm_td2p_port_to_aggid(int unit, bcm_port_t port, int *aggid)
    679 {
    680     int pipe;
    681     bcm_trunk_t tgid;
    682     _bcm_td2p_port_aggid_info_t *port_aggid_info;
    683     _bcm_td2p_trunk_aggid_info_t *trunk_aggid_info;
    684 
    685     if (port < 0 || port >= SOC_MAX_NUM_PORTS) {
    686         return BCM_E_PARAM;
    687     }
    688 
    689     pipe = SOC_INFO(unit).port_pipe[port];
    690     port_aggid_info = &(td2p_port_aggid[unit][port]);
    691     tgid = port_aggid_info->trunk_id;
    692     if (tgid == BCM_TRUNK_INVALID) {
    693         *aggid = port_aggid_info->agg_id;
    694     } else {
    695         trunk_aggid_info = &(td2p_trunk_aggid[unit][pipe].trunk_aggid_info[tgid]);
    696         *aggid = trunk_aggid_info->agg_id;
    697     }
    698     if (*aggid == TD2P_AGG_ID_INVALID) {
    699         return BCM_E_INTERNAL;
    700     }
    701 
    702     return BCM_E_NONE;
    703 }
    704 
    705 
    706 #ifdef BCM_WARM_BOOT_SUPPORT
    707 /*
    708  * Function:
    709  *      bcm_td2p_ipmc_aggid_info_scache_size_get
    710  * Purpose:
    711  *      Get the required scache size for storing aggid info.
    712  * Parameters:
    713  *      unit - (IN)  StrataSwitch unit #
    714  *      size - (OUT) Number of bytes
    715  * Returns:
    716  *      BCM_E_xxx
    717  */
    718 int
    719 bcm_td2p_ipmc_aggid_info_scache_size_get(
    720     int unit, uint32 *size)
    721 {
    722     int   num_pipes;
    723     int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size;
    724 
    725     *size = 0;
    726 
    727     num_pipes = NUM_PIPE(unit);
    728 
    729     aggid_used_bmp_size =
    730         num_pipes * SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit));
    731     *size += aggid_used_bmp_size;
    732 
    733     trunk_aggid_size =
    734         num_pipes * sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t);
    735     *size += trunk_aggid_size;
    736 
    737     port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t);
    738     *size += port_aggid_size;
    739 
    740     return BCM_E_NONE;
    741 }
    742 
    743 /*
    744  * Function:
    745  *      bcm_td2p_ipmc_aggid_info_sync
    746  * Purpose:
    747  *      Sync aggid info to scache.
    748  * Parameters:
    749  *      unit       - (IN)     StrataSwitch unit #
    750  *      scache_ptr - (IN/OUT) Scache pointer
    751  * Returns:
    752  *      BCM_E_xxx
    753  */
    754 int bcm_td2p_ipmc_aggid_info_sync(int unit, uint8 **scache_ptr)
    755 {
    756     int num_pipes;
    757     int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size;
    758     int i;
    759 
    760     num_pipes = NUM_PIPE(unit);
    761 
    762     aggid_used_bmp_size = SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit));
    763     for (i = 0; i < num_pipes; i++) {
    764         sal_memcpy((*scache_ptr), td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp,
    765                    aggid_used_bmp_size);
    766         (*scache_ptr) += aggid_used_bmp_size;
    767     }
    768 
    769     trunk_aggid_size = sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t);
    770     for (i = 0; i < num_pipes; i++) {
    771         sal_memcpy((*scache_ptr), td2p_trunk_aggid[unit] + i, trunk_aggid_size);
    772         (*scache_ptr) += trunk_aggid_size;
    773     }
    774 
    775     port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t);
    776     sal_memcpy((*scache_ptr), td2p_port_aggid[unit], port_aggid_size);
    777     (*scache_ptr) += port_aggid_size;
    778 
    779     return BCM_E_NONE;
    780 }
    781 
    782 
    783 /*
    784  * Function:
    785  *      bcm_td2p_ipmc_aggid_info_recover
    786  * Purpose:
    787  *      Recover aggid info from scache.
    788  * Parameters:
    789  *      unit       - (IN)     StrataSwitch unit #
    790  *      scache_ptr - (IN/OUT) Scache pointer
    791  * Returns:
    792  *      BCM_E_xxx
    793  */
    794 int
    795 bcm_td2p_ipmc_aggid_info_recover(int unit, uint8 **scache_ptr)
    796 {
    797     int   num_pipes;
    798     int aggid_used_bmp_size, trunk_aggid_size, port_aggid_size;
    799     int i;
    800     int max_num_ports, scache_sz;
    801 
    802     max_num_ports = soc_scache_dictionary_entry_get(unit, 
    803                                  ssden_SOC_MAX_NUM_PORTS,
    804                                  SOC_MAX_NUM_PORTS);
    805     num_pipes = NUM_PIPE(unit);
    806 
    807     aggid_used_bmp_size = SHR_BITALLOCSIZE(_TD2P_NUM_AGGID_PER_PIPE(unit));
    808     for (i = 0; i < num_pipes; i++) {
    809         sal_memcpy(td2p_aggid_used_bmp[unit][i].pipe_aggid_bmp,
    810                    (*scache_ptr), aggid_used_bmp_size);
    811         (*scache_ptr) += aggid_used_bmp_size;
    812     }
    813 
    814     trunk_aggid_size = sizeof(_bcm_td2p_trunk_aggid_per_pipe_info_t);
    815     for (i = 0; i < num_pipes; i++) {
    816         sal_memcpy(td2p_trunk_aggid[unit] + i, (*scache_ptr), trunk_aggid_size);
    817         (*scache_ptr) += trunk_aggid_size;
    818     }
    819 
    820     port_aggid_size = SOC_MAX_NUM_PORTS * sizeof(_bcm_td2p_port_aggid_info_t);
    821     scache_sz = max_num_ports * sizeof(_bcm_td2p_port_aggid_info_t);
    822 
    823     SOC_SCACHE_SIZE_MIN_RECOVER(*scache_ptr, td2p_port_aggid[unit], 
    824                                 scache_sz, port_aggid_size);
    825 
    826     return BCM_E_NONE;
    827 }
    828 
    829 #endif /* BCM_WARM_BOOT_SUPPORT */
    830 
    831 #endif
    832