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

ecmp.c (58980B)


      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:        ecmp.c
      8  * Purpose:     Ecmp SOC functions.
      9  */
     10 
     11 
     12 #include <soc/defs.h>
     13 
     14 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
     15 
     16 #include <shared/bsl.h>
     17 #include <soc/error.h>
     18 #include <soc/esw/ecmp.h>
     19 
     20 #ifdef BCM_WARM_BOOT_SUPPORT
     21 #include <soc/scache.h>
     22 
     23 #define SOC_ESW_ECMP_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
     24 
     25 /* Default warmboot version */
     26 #define SOC_ESW_ECMP_WB_DEFAULT_VERSION            SOC_ESW_ECMP_WB_VERSION_1_1
     27 
     28 
     29 #define SOC_ESW_ECMP_WB_SIZE(_data_)  sizeof(*(_data_))
     30 
     31 
     32 #define SOC_ESW_ECMP_WB_SYNC(_scache_, _data_)                \
     33     do {                                                      \
     34         sal_memcpy((_scache_), (_data_), sizeof(*(_data_)));  \
     35         (_scache_) +=  sizeof(*(_data_));                     \
     36     } while (0)
     37 
     38 #define SOC_ESW_ECMP_WB_RECOVER(_scache_, _data_)             \
     39     do {                                                      \
     40         sal_memcpy((_data_), (_scache_), sizeof(*(_data_)));  \
     41         (_scache_) +=  sizeof(*(_data_));                     \
     42     } while (0)
     43 
     44 #endif /* BCM_WARM_BOOT_SUPPORT */
     45 
     46 
     47 /* SOC ESW ECMP State */
     48 soc_esw_ecmp_state_t *soc_esw_ecmp_state[SOC_MAX_NUM_DEVICES];
     49 
     50 static const soc_mem_t ecmp_member_mems[] = {
     51         INITIAL_L3_ECMPm,
     52         L3_ECMPm
     53     };
     54 
     55 static const soc_mem_t ecmp_group_mems[] = {
     56         INITIAL_L3_ECMP_GROUPm,
     57         L3_ECMP_COUNTm
     58     };
     59 
     60 
     61 
     62 STATIC void
     63 soc_esw_nh_if_ecmp_grp_decode(int unit, uint32 *nh_idx, int *ecmpf)
     64 {
     65     int ecmp_if_offset;
     66 
     67     ecmp_if_offset = SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset;
     68 
     69     if (*nh_idx >= ecmp_if_offset) {
     70         *ecmpf = 1;
     71         *nh_idx -= ecmp_if_offset;
     72     }
     73 
     74     return;
     75 }
     76 
     77 STATIC void
     78 soc_esw_nh_if_ecmp_grp_encode(int unit, uint32 *nh_idx, int ecmpf)
     79 {
     80     int ecmp_if_offset;
     81 
     82     ecmp_if_offset = SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset;
     83 
     84     if (ecmpf) {
     85         *nh_idx += ecmp_if_offset;
     86     }
     87 
     88     return;
     89 }
     90 
     91 
     92 
     93 /*
     94  * Function:
     95  *      soc_esw_mem_dma_read
     96  * Purpose:
     97  *
     98  * Parameters:
     99  *      unit         -(IN)SOC unit number.
    100  *      tbl_mem      -(IN)Table memory.
    101  *      tbl_entry_sz -(IN)Table entry size.
    102  *      descr        -(IN)Table descriptor.
    103  *      start        -(IN) Start index
    104  *      count        -(IN) Number of entries
    105  *      res_ptr      -(OUT) Allocated pointer filled with table info
    106  * Returns:
    107  *      SOC_E_XXX
    108  */
    109 int
    110 soc_esw_mem_dma_read(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz,
    111                      const char *descr, int start, int end, uint8 **res_ptr)
    112 {
    113     int alloc_size;             /* Allocation size.          */
    114     uint8 *buffer;               /* Buffer to read the table. */
    115     int tbl_size;               /* HW table size.            */
    116 
    117     /* Input parameters sanity check. */
    118     if ((NULL == res_ptr) || (NULL == descr)) {
    119         return (SOC_E_PARAM);
    120     }
    121 
    122     /* If entry size is not deterministic. reject. */
    123     if (tbl_entry_sz <= 0) {
    124         return (SOC_E_PARAM);
    125     }
    126 
    127     if (INVALIDm == tbl_mem) {
    128         return (SOC_E_NOT_FOUND);
    129     }
    130 
    131     if (start < soc_mem_index_min(unit, tbl_mem) ||
    132         end > soc_mem_index_max(unit, tbl_mem)) {
    133         return SOC_E_PARAM;
    134     }
    135 
    136     /* Calculate table size. */
    137     tbl_size = (end - start) + 1;
    138     alloc_size = tbl_entry_sz * tbl_size;
    139 
    140     /* Allocate memory buffer. */
    141     buffer = soc_cm_salloc(unit, alloc_size, descr);
    142     if (buffer == NULL) {
    143         return (SOC_E_MEMORY);
    144     }
    145 
    146     /* Reset allocated buffer. */
    147     memset(buffer, 0, alloc_size);
    148 
    149     /* Read table to the buffer. */
    150     if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY,
    151                            start,
    152                            end, buffer) < 0) {
    153         soc_cm_sfree(unit, buffer);
    154         return (SOC_E_INTERNAL);
    155     }
    156 
    157     *res_ptr = buffer;
    158     return (SOC_E_NONE);
    159 }
    160 
    161 
    162 STATIC int
    163 soc_esw_ecmp_protected_idx_alloc(int unit, int bix, int ecmp_idx, int count)
    164 {
    165     int offset;
    166     int start;
    167     soc_esw_ecmp_bank_state_t *bank_info;
    168 
    169     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
    170     offset = bank_info->tbl_offset;
    171 
    172     start = (ecmp_idx - offset);
    173     SHR_BITSET_RANGE(bank_info->idx_used, start, count);
    174 
    175     return SOC_E_NONE;
    176 }
    177 
    178 STATIC int
    179 soc_esw_ecmp_protected_idx_free(int unit, int bix, int ecmp_idx, int count)
    180 {
    181     int start;
    182     int offset;
    183     soc_esw_ecmp_bank_state_t *bank_info;
    184 
    185     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
    186     offset = bank_info->tbl_offset;
    187 
    188     start = (ecmp_idx - offset);
    189     SHR_BITCLR_RANGE(bank_info->idx_used, start, count);
    190 
    191     return SOC_E_NONE;
    192 }
    193 
    194 STATIC int
    195 soc_esw_ecmp_protected_idx_move(int unit,
    196                                 int src_bix, int to_bix,
    197                                 int ecmp_idx, int count)
    198 {
    199     int rv;
    200     int start;
    201 
    202     start = (SOC_ESW_ECMP_BANK_INFO(unit, src_bix))->tbl_offset + ecmp_idx;
    203     rv = soc_esw_ecmp_protected_idx_free(unit, src_bix, start, count);
    204     SOC_IF_ERROR_RETURN(rv);
    205 
    206     start = (SOC_ESW_ECMP_BANK_INFO(unit, to_bix))->tbl_offset + ecmp_idx;
    207     rv = soc_esw_ecmp_protected_idx_alloc(unit, to_bix, start, count);
    208     SOC_IF_ERROR_RETURN(rv);
    209 
    210     return SOC_E_NONE;
    211 }
    212 
    213 
    214 
    215 
    216 STATIC int
    217 soc_esw_ecmp_idx_bank_get(int unit, int idx, int *bank_idx)
    218 {
    219     int bix;
    220     soc_esw_ecmp_bank_state_t *bank_info;
    221 
    222     for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) {
    223         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
    224         if ((idx >= bank_info->tbl_offset) &&
    225             (idx < (bank_info->tbl_offset + bank_info->bank_size))) {
    226             *bank_idx = bix;
    227             return SOC_E_NONE;
    228         }
    229     }
    230 
    231     return SOC_E_NOT_FOUND;
    232 }
    233 
    234 
    235 STATIC int
    236 soc_esw_ecmp_idx_bank_offset_get(int unit, int *if_id)
    237 {
    238     int rv;
    239     int bank_idx;
    240 
    241     rv = soc_esw_ecmp_idx_bank_get(unit, *if_id, &bank_idx);
    242     SOC_IF_ERROR_RETURN(rv);
    243 
    244     *if_id -= (SOC_ESW_ECMP_BANK_INFO(unit, bank_idx))->tbl_offset;
    245 
    246     return SOC_E_NONE;
    247 }
    248 
    249 
    250 
    251 STATIC int
    252 soc_esw_ecmp_protected_state_set(int unit, int grp_idx,
    253                                  int bank_idx, int base, int count)
    254 {
    255     soc_esw_ecmp_group_state_t *grp_state;
    256 
    257     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    258 
    259     grp_state->bank = bank_idx;
    260     grp_state->base = base;
    261     grp_state->count = count;
    262 
    263     return SOC_E_NONE;
    264 }
    265 
    266 STATIC int
    267 soc_esw_ecmp_protected_state_get(int unit, int grp_idx,
    268                                  int *bank_idx, int *base, int *count)
    269 {
    270     soc_esw_ecmp_group_state_t *grp_state;
    271 
    272     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    273 
    274     if (bank_idx) {
    275         *bank_idx = grp_state->bank;
    276     }
    277     if (base) {
    278         *base = grp_state->base;
    279     }
    280     if (count) {
    281         *count = grp_state->count;
    282     }
    283 
    284     return SOC_E_NONE;
    285 }
    286 
    287 STATIC int
    288 soc_esw_ecmp_bank_used_count_get(int unit, int bank_idx, int *count)
    289 {
    290     int ix;
    291     int use_count = 0;
    292     soc_esw_ecmp_bank_state_t *bank_info;
    293 
    294     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx);
    295 
    296     for (ix = 0; ix < _SHR_BITDCLSIZE(bank_info->bank_size); ix++) {
    297         use_count += _shr_popcount(bank_info->idx_used[ix]);
    298     }
    299 
    300     *count = use_count;
    301 
    302     return SOC_E_NONE;
    303 }
    304 
    305 STATIC int
    306 soc_esw_ecmp_bank_active_set(int unit, int bank_idx)
    307 {
    308     int rv;
    309     int rsvd_bank;
    310     uint32 regval = 0;
    311     uint32 banksel[1] = {0};
    312 
    313     rsvd_bank = SOC_ESW_ECMP_BANK_RSVD_GET(unit);
    314 
    315     /* Update BANK_SEL config. */
    316     rv = soc_reg32_get(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, &regval);
    317     SOC_IF_ERROR_RETURN(rv);
    318 
    319     banksel[0] = soc_reg_field_get(unit, ING_L3_ECMP_BANK_SELr, regval, BANK_SELf);
    320     if (SHR_BITGET(banksel, bank_idx)) {
    321         SHR_BITSET(banksel, rsvd_bank);
    322     } else {
    323         SHR_BITCLR(banksel, rsvd_bank);
    324     }
    325     soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, &regval, BANK_SELf, banksel[0]);
    326 
    327     rv = soc_reg32_set(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval);
    328     SOC_IF_ERROR_RETURN(rv);
    329     rv = soc_reg32_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval);
    330     SOC_IF_ERROR_RETURN(rv);
    331 
    332     return SOC_E_NONE;
    333 }
    334 
    335 STATIC int
    336 soc_esw_ecmp_bank_reserved_set(int unit, int bank_idx)
    337 {
    338     int rv;
    339     int rsvd_bank;
    340     int tmp_level;
    341     int tmp_prot_disabled;
    342     uint32 regval = 0;
    343     uint32 banksel[1] = {0};
    344     soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info;
    345 
    346     rsvd_bank = SOC_ESW_ECMP_BANK_RSVD_GET(unit);
    347 
    348     src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx);
    349     dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, rsvd_bank);
    350 
    351     tmp_level = dst_bank_info->level;
    352     tmp_prot_disabled = dst_bank_info->protected_write_disabled;
    353 
    354     dst_bank_info->level = src_bank_info->level;
    355     dst_bank_info->protected_write_disabled = src_bank_info->protected_write_disabled;
    356 
    357     src_bank_info->level = tmp_level;
    358     src_bank_info->protected_write_disabled = tmp_prot_disabled;
    359 
    360     /* Update BANK_SEL config. */
    361     rv = soc_reg32_get(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, &regval);
    362     SOC_IF_ERROR_RETURN(rv);
    363 
    364     banksel[0] = soc_reg_field_get(unit, ING_L3_ECMP_BANK_SELr, regval, BANK_SELf);
    365     SHR_BITCLR(banksel, bank_idx);
    366     soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, &regval, BANK_SELf, banksel[0]);
    367 
    368     rv = soc_reg32_set(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval);
    369     SOC_IF_ERROR_RETURN(rv);
    370     rv = soc_reg32_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval);
    371     SOC_IF_ERROR_RETURN(rv);
    372 
    373     /* Mark bank_idx as reserved */
    374     SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx = bank_idx;
    375 
    376     return SOC_E_NONE;
    377 }
    378 
    379 STATIC int
    380 soc_esw_ecmp_protected_idx_range_get(int unit, int bank_idx, int rsvd_bank,
    381                                      int ecmp_idx, int max_grp_size,
    382                                      int *rd_start, int *rd_end,
    383                                      int *wr_start, int *wr_end)
    384 {
    385     int use_count;
    386     soc_esw_ecmp_bank_state_t *bank_info;
    387 
    388     SOC_IF_ERROR_RETURN(soc_esw_ecmp_bank_used_count_get(unit, bank_idx, &use_count));
    389 
    390     if ((!SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bank_idx)) || (use_count == 0)) {
    391         *rd_start = *wr_start = (ecmp_idx);
    392         *rd_end   = *wr_end   = (ecmp_idx + max_grp_size);
    393 
    394         return SOC_E_NONE;
    395     }
    396 
    397     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx);
    398     *rd_start = (bank_info->tbl_offset);
    399     *rd_end   = (*rd_start + bank_info->bank_size - 1);
    400 
    401     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, rsvd_bank);
    402     *wr_start = (bank_info->tbl_offset);
    403     *wr_end   = (*wr_start + bank_info->bank_size - 1);
    404 
    405     return SOC_E_NONE;
    406 }
    407 
    408 
    409 STATIC int
    410 soc_esw_ecmp_protected_bank_update(int unit, int src_bank, int dst_bank)
    411 {
    412     int rv;
    413     int grp_idx;
    414     int ecmp_base_offset;
    415     int idx_min, idx_max;
    416     soc_mem_t ecmp_grp_mem1, ecmp_grp_mem2;
    417     soc_esw_ecmp_group_state_t *grp_state;
    418 
    419     uint8 *ecmp1_tbl_p = NULL;    /* L3_ECMP_GROUP table pointer. */
    420     uint8 *ecmp2_tbl_p = NULL;    /* INITIAL_L3_ECMP_GROUP table pointer. */
    421 
    422     uint32 *ecmp_grp_ptr = NULL;  /* ECMP group pointer.*/
    423     uint32 *ecmp2_grp_ptr = NULL; /* INITIAL_ECMP group pointer.*/
    424 
    425     ecmp_grp_mem1 = L3_ECMP_COUNTm;
    426     ecmp_grp_mem2 = INITIAL_L3_ECMP_GROUPm;
    427     idx_min = soc_mem_index_min(unit, ecmp_grp_mem1);
    428     idx_max = soc_mem_index_max(unit, ecmp_grp_mem1);
    429 
    430     /* Read ecmp group tables */
    431     rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem1,
    432                               sizeof(ecmp_count_entry_t),
    433                               "ecmp_grp_tbl",
    434                               idx_min, idx_max,
    435                               &ecmp1_tbl_p);
    436     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    437 
    438     rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem2,
    439                               sizeof(initial_l3_ecmp_group_entry_t),
    440                               "ecmp2_grp_tbl",
    441                               idx_min, idx_max,
    442                               &ecmp2_tbl_p);
    443     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    444 
    445 
    446     for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) {
    447         grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    448 
    449         /* Group is not installed yet */
    450         if (grp_state->count == 0) {
    451             continue;
    452         }
    453         /* Group does not have members in the src_bank */
    454         if (grp_state->bank != src_bank) {
    455             continue;
    456         }
    457 
    458         ecmp_base_offset =  grp_state->base;
    459         rv = soc_esw_ecmp_idx_bank_offset_get(unit, &ecmp_base_offset);
    460         SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    461 
    462         /* Update ecmp base and bank_idx for the group */
    463         grp_state->base = ((SOC_ESW_ECMP_BANK_INFO(unit, dst_bank))->tbl_offset + ecmp_base_offset);
    464         grp_state->bank = dst_bank;
    465 
    466 
    467         /* Move ecmp idx range from src_bank to dst_bank. */
    468         rv = soc_esw_ecmp_protected_idx_move(unit, src_bank, dst_bank,
    469                                              ecmp_base_offset, grp_state->count);
    470         SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    471 
    472         ecmp_grp_ptr =
    473             soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem1, uint32 *,
    474                                          ecmp1_tbl_p, grp_idx);
    475         ecmp2_grp_ptr =
    476             soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem2, uint32 *,
    477                                          ecmp2_tbl_p, grp_idx);
    478 
    479         soc_mem_field32_set(unit, ecmp_grp_mem1, ecmp_grp_ptr,
    480                             BASE_PTRf, grp_state->base);
    481         soc_mem_field32_set(unit, ecmp_grp_mem2, ecmp2_grp_ptr,
    482                             BASE_PTRf, grp_state->base);
    483     }
    484 
    485     rv = soc_esw_ecmp_bank_active_set(unit, src_bank);
    486     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    487 
    488     /* Write updated member tables  */
    489     rv = soc_mem_write_range(unit, ecmp_grp_mem1, MEM_BLOCK_ALL,
    490                              idx_min, idx_max, ecmp1_tbl_p);
    491     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    492 
    493     rv = soc_mem_write_range(unit, ecmp_grp_mem2, MEM_BLOCK_ALL,
    494                              idx_min, idx_max, ecmp2_tbl_p);
    495     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    496 
    497     rv = soc_esw_ecmp_bank_reserved_set(unit, src_bank);
    498     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    499 
    500 err_exit:
    501     if (ecmp2_tbl_p) {
    502         soc_cm_sfree(unit, ecmp2_tbl_p);
    503     }
    504     if (ecmp1_tbl_p) {
    505         soc_cm_sfree(unit, ecmp1_tbl_p);
    506     }
    507 
    508     return rv;
    509 }
    510 
    511 
    512 STATIC int
    513 soc_esw_ecmp_protected_base_ptr_update(int unit)
    514 {
    515     int rv;
    516     int grp_idx;
    517     int idx_min, idx_max;
    518     soc_mem_t ecmp_grp_mem1, ecmp_grp_mem2;
    519 
    520     soc_esw_ecmp_group_state_t *grp_state;
    521 
    522     uint8 *ecmp1_tbl_p = NULL;    /* L3_ECMP_GROUP table pointer. */
    523     uint8 *ecmp2_tbl_p = NULL;    /* INITIAL_L3_ECMP_GROUP table pointer. */
    524 
    525     uint32 *ecmp_grp_ptr = NULL;  /* ECMP group pointer.*/
    526     uint32 *ecmp2_grp_ptr = NULL; /* INITIAL_ECMP group pointer.*/
    527 
    528     ecmp_grp_mem1 = L3_ECMP_COUNTm;
    529     ecmp_grp_mem2 = INITIAL_L3_ECMP_GROUPm;
    530     idx_min = soc_mem_index_min(unit, ecmp_grp_mem1);
    531     idx_max = soc_mem_index_max(unit, ecmp_grp_mem1);
    532 
    533     /* Read ecmp group tables */
    534     rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem1,
    535                               sizeof(ecmp_count_entry_t),
    536                               "ecmp_grp_tbl",
    537                               idx_min, idx_max,
    538                               &ecmp1_tbl_p);
    539     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    540 
    541     rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem2,
    542                               sizeof(initial_l3_ecmp_group_entry_t),
    543                               "ecmp2_grp_tbl",
    544                               idx_min, idx_max,
    545                               &ecmp2_tbl_p);
    546     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    547 
    548 
    549     for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) {
    550         grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    551 
    552         /* Group not in use. */
    553         if (!grp_state->count && !grp_state->base) {
    554             continue;
    555         }
    556 
    557         ecmp_grp_ptr =
    558             soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem1, uint32 *,
    559                                          ecmp1_tbl_p, grp_idx);
    560         ecmp2_grp_ptr =
    561             soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem2, uint32 *,
    562                                          ecmp2_tbl_p, grp_idx);
    563 
    564         soc_mem_field32_set(unit, ecmp_grp_mem1, ecmp_grp_ptr,
    565                             BASE_PTRf, grp_state->base);
    566         soc_mem_field32_set(unit, ecmp_grp_mem2, ecmp2_grp_ptr,
    567                             BASE_PTRf, grp_state->base);
    568     }
    569 
    570     /* Write updated member tables  */
    571     rv = soc_mem_write_range(unit, ecmp_grp_mem1, MEM_BLOCK_ALL,
    572                              idx_min, idx_max, ecmp1_tbl_p);
    573     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    574 
    575     rv = soc_mem_write_range(unit, ecmp_grp_mem2, MEM_BLOCK_ALL,
    576                              idx_min, idx_max, ecmp2_tbl_p);
    577     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
    578 
    579 err_exit:
    580     if (ecmp2_tbl_p) {
    581         soc_cm_sfree(unit, ecmp2_tbl_p);
    582     }
    583     if (ecmp1_tbl_p) {
    584         soc_cm_sfree(unit, ecmp1_tbl_p);
    585     }
    586 
    587     return rv;
    588 }
    589 
    590 
    591 STATIC int
    592 soc_esw_ecmp_protected_member_move(int unit,
    593                                    int grp_idx,
    594                                    int src_bank_idx,
    595                                    int dst_bank_idx,
    596                                    uint8 *src_ecmp_tbl1_p,
    597                                    uint8 *src_ecmp_tbl2_p,
    598                                    uint8 *dst_ecmp_tbl1_p,
    599                                    uint8 *dst_ecmp_tbl2_p,
    600                                    int new_base_idx
    601                                    )
    602 {
    603     int rv;
    604     int idx;
    605     int ecmp_base_offset;
    606     soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info;
    607     soc_esw_ecmp_group_state_t *grp_state;
    608 
    609     uint32 *src_ecmp1_p = NULL;
    610     uint32 *src_ecmp2_p = NULL;
    611     uint32 *dst_ecmp1_p = NULL;
    612     uint32 *dst_ecmp2_p = NULL;
    613 
    614     src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, src_bank_idx);
    615     dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, dst_bank_idx);
    616 
    617     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    618     ecmp_base_offset = (grp_state->base - src_bank_info->tbl_offset);
    619 
    620     for (idx = ecmp_base_offset;
    621          idx < (ecmp_base_offset + grp_state->count);
    622          idx++) {
    623         src_ecmp1_p =
    624             soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *,
    625                                           src_ecmp_tbl1_p, idx);
    626         src_ecmp2_p =
    627             soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *,
    628                                          src_ecmp_tbl2_p, idx);
    629 
    630         dst_ecmp1_p =
    631             soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *,
    632                                           dst_ecmp_tbl1_p, new_base_idx);
    633         dst_ecmp2_p =
    634             soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *,
    635                                          dst_ecmp_tbl2_p, new_base_idx);
    636 
    637         sal_memcpy(dst_ecmp1_p, src_ecmp1_p, sizeof(ecmp_entry_t));
    638         sal_memcpy(dst_ecmp2_p, src_ecmp2_p,
    639                    sizeof(initial_l3_ecmp_entry_t));
    640 
    641         new_base_idx++;
    642     }
    643 
    644     /* Free idx from src_bank. */
    645     rv = soc_esw_ecmp_protected_idx_free(unit,
    646                                          src_bank_idx,
    647                                          grp_state->base,
    648                                          grp_state->count);
    649     SOC_IF_ERROR_RETURN(rv);
    650 
    651     grp_state->base = (dst_bank_info->tbl_offset + new_base_idx - grp_state->count);
    652 
    653     /* Alloc idx in dst_bank. */
    654     rv = soc_esw_ecmp_protected_idx_alloc(unit,
    655                                           dst_bank_idx,
    656                                           grp_state->base,
    657                                           grp_state->count);
    658     SOC_IF_ERROR_RETURN(rv);
    659 
    660     /* Update ECMP group bank */
    661     grp_state->bank = dst_bank_idx;
    662 
    663     return SOC_E_NONE;
    664 }
    665 
    666 /*
    667  * Function:
    668  *      soc_esw_ecmp_protected_grp_size_update
    669  * Purpose:
    670  *      Update the max group size of an ECMP group.
    671  * Parameters:
    672  *      unit       - (IN)SOC unit number.
    673  *      grp_info   - (IN)ecmp group id to write.
    674  *      base_ptr   - (IN)ecmp member base pointer.
    675  * Returns:
    676  *      SOC_E_XXX
    677  */
    678 STATIC int
    679 soc_esw_ecmp_protected_grp_size_update(int unit,
    680                                        soc_esw_ecmp_group_info_t *grp_info,
    681                                        int *base_ptr)
    682 {
    683     int rv = SOC_E_NONE;
    684     int bix;
    685     int bank;
    686     int grp_idx;
    687     int old_max_grp_sz;
    688     int new_max_grp_size;
    689     int free_count = 0;
    690     int free_idx;
    691     int level;
    692     uint32 bank_bmp = 0;
    693     soc_esw_ecmp_group_state_t *grp_state;
    694     soc_esw_ecmp_bank_state_t *bank_info;
    695 
    696     grp_idx = grp_info->ecmp_grp;
    697     new_max_grp_size = grp_info->max_paths;
    698 
    699     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
    700     bank = grp_state->bank;
    701     old_max_grp_sz = grp_state->count;
    702 
    703     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank);
    704     level = bank_info->level;
    705 
    706     /* Get the number of free entries in this bank. */
    707     rv = soc_esw_ecmp_bank_free_count_get(unit,
    708                                           bank,
    709                                           &free_count);
    710     SOC_IF_ERROR_RETURN(rv);
    711 
    712     if (new_max_grp_size <= (free_count + old_max_grp_sz)) {
    713         rv = soc_esw_ecmp_protected_bank_defragment(unit,
    714                                                     bank,
    715                                                     grp_idx,
    716                                                     &free_count);
    717         SOC_IF_ERROR_RETURN(rv);
    718 
    719         /* Check if the current bank can accommodate the new max path */
    720         *base_ptr = grp_state->base;
    721     } else {
    722         rv = soc_esw_ecmp_protected_banks_get(unit,
    723                                               level,
    724                                               &bank_bmp);
    725         SOC_IF_ERROR_RETURN(rv);
    726 
    727         free_count = 0;
    728         /* Compress other banks of the same level to make room for new group */
    729         for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) {
    730             if (SHR_BITGET(&bank_bmp, bix) && bix != grp_state->bank) {
    731                 rv = soc_esw_ecmp_bank_free_count_get(unit,
    732                                                       bix,
    733                                                       &free_count);
    734                 SOC_IF_ERROR_RETURN(rv);
    735 
    736                 /* Not enough space in this bank, continue. */
    737                 if (free_count < new_max_grp_size) {
    738                     continue;
    739                 }
    740 
    741                 rv = soc_esw_ecmp_protected_bank_defragment(unit,
    742                                                             bix,
    743                                                             -1,
    744                                                             &free_count);
    745                 SOC_IF_ERROR_RETURN(rv);
    746 
    747                 /* If the defragmented bank can fit the new group, break */
    748                 if (free_count >= new_max_grp_size) {
    749                     break;
    750                 }
    751             }
    752         }
    753 
    754         if (free_count < new_max_grp_size) {
    755             return SOC_E_FULL;
    756         }
    757 
    758         /* Check if a free idx can be found now */
    759         free_idx = -1;
    760         bank_bmp = 0;
    761         rv = soc_esw_ecmp_protected_banks_get(unit,
    762                                               level,
    763                                               &bank_bmp);
    764         SOC_IF_ERROR_RETURN(rv);
    765 
    766 
    767         for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) {
    768             if (SHR_BITGET(&bank_bmp, bix) && bix != grp_state->bank) {
    769                 rv = soc_esw_ecmp_protected_idx_free_get(unit,
    770                                                          bix,
    771                                                          new_max_grp_size,
    772                                                          &free_idx);
    773                 if (rv == SOC_E_NONE) {
    774                     *base_ptr = free_idx;
    775                     break;
    776                 }
    777             }
    778         }
    779     }
    780 
    781     return rv;
    782 }
    783 
    784 /* | *************************************************** |
    785  * | *************************************************** |
    786  * | *           Start - Public Functions              * |
    787  * | *************************************************** |
    788  * | *************************************************** |
    789  */
    790 
    791 /* Function to initialize ecmp_init_info struct */
    792 void
    793 soc_esw_ecmp_init_info_t_init(soc_esw_ecmp_init_info_t *info)
    794 {
    795     sal_memset(info, 0, sizeof(soc_esw_ecmp_init_info_t));
    796 
    797     return;
    798 }
    799 
    800 /* Function to initialize ecmp_group_info struct */
    801 void
    802 soc_esw_ecmp_group_info_t_init(soc_esw_ecmp_group_info_t *info)
    803 {
    804     sal_memset(info, 0, sizeof(soc_esw_ecmp_group_info_t));
    805 
    806     return;
    807 }
    808 
    809 /*
    810  * Function:
    811  *      soc_esw_ecmp_state_lock
    812  * Purpose:
    813  *      Mutext Take (lock) ecmp state
    814  * Parameters:
    815  *      unit       - (IN)SOC unit number.
    816  * Returns:
    817  *      SOC_E_XXX
    818  */
    819 int
    820 soc_esw_ecmp_state_lock(int unit)
    821 {
    822     if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) {
    823         return SOC_E_INIT;
    824     }
    825 
    826     sal_mutex_take(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock,
    827                    sal_mutex_FOREVER);
    828 
    829     return SOC_E_NONE;
    830 }
    831 
    832 /*
    833  * Function:
    834  *      soc_esw_ecmp_state_unlock
    835  * Purpose:
    836  *      Mutext Give (unlock) ecmp state
    837  * Parameters:
    838  *      unit       - (IN)SOC unit number.
    839  * Returns:
    840  *      SOC_E_XXX
    841  */
    842 int
    843 soc_esw_ecmp_state_unlock(int unit)
    844 {
    845     if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) {
    846         return SOC_E_INIT;
    847     }
    848 
    849     if (sal_mutex_give(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock) != 0) {
    850         return SOC_E_INTERNAL;
    851     }
    852 
    853     return SOC_E_NONE;
    854 }
    855 
    856 #ifdef BCM_WARM_BOOT_SUPPORT
    857 
    858 STATIC void
    859 soc_esw_ecmp_protected_state_wb_alloc_size(int unit, uint32 *size)
    860 {
    861     int ix;
    862     int alloc_size;
    863     soc_esw_ecmp_group_state_t *group_info;
    864     soc_esw_ecmp_bank_state_t *bank_info;
    865 
    866     alloc_size = 0;
    867 
    868     /* spare bank idx */
    869     alloc_size += SOC_ESW_ECMP_WB_SIZE(&(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx));
    870 
    871     /* Sync group_info structs. */
    872     for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) {
    873         group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix);
    874 
    875         alloc_size += SOC_ESW_ECMP_WB_SIZE(group_info);
    876     }
    877 
    878     /* Sync bank_info structs. */
    879     for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) {
    880         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix);
    881 
    882         alloc_size += SOC_ESW_ECMP_WB_SIZE(bank_info);
    883     }
    884 
    885     /* Return the calculated size. */
    886     *size = alloc_size;
    887 
    888     return;
    889 }
    890 
    891 /*
    892  * Function:
    893  *      soc_esw_ecmp_protected_state_wb_alloc_size
    894  * Purpose:
    895  *      Allocate persistent info memory for soc esw ecmp module
    896  * Parameters:
    897  *     unit - (IN) SOC device id
    898  * Returns:
    899  *      SOC_E_XXX
    900  */
    901 int
    902 soc_esw_ecmp_protected_state_warmboot_alloc(int unit)
    903 {
    904 
    905     uint8 *ecmp_scache_ptr;
    906     uint32 size = 0;
    907     int rv = SOC_E_NONE;
    908     soc_scache_handle_t scache_handle;
    909 
    910     scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle;
    911 
    912 
    913     soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size);
    914 
    915     rv = soc_versioned_scache_ptr_get(unit, scache_handle, TRUE,
    916                                  &size, &ecmp_scache_ptr,
    917                                  SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL);
    918 
    919     if (SOC_E_NOT_FOUND == rv) {
    920         /* Proceed with Level 1 Warm Boot */
    921         rv = SOC_E_NONE;
    922     }
    923 
    924     return rv;
    925 }
    926 
    927 /*
    928  * Function:
    929  *     soc_esw_ecmp_protected_state_warmboot_sync
    930  * Purpose:
    931  *     Sync soc esw ecmp state.
    932  * Parameters:
    933  *     unit - (IN) SOC device id
    934  *
    935  * Returns:
    936  *     SOC_E_XXX
    937  */
    938 int
    939 soc_esw_ecmp_protected_state_warmboot_sync(int unit)
    940 {
    941     int ix;
    942     uint32 size;
    943     soc_esw_ecmp_group_state_t *group_info;
    944     soc_esw_ecmp_bank_state_t *bank_info;
    945     uint8 *ecmp_scache_ptr;
    946     soc_scache_handle_t scache_handle;
    947 
    948     scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle;
    949 
    950 
    951     /* Get the size to save ecmp protected warmboot state. */
    952     soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size);
    953 
    954     SOC_IF_ERROR_RETURN
    955         (soc_versioned_scache_ptr_get(unit, scache_handle, FALSE,
    956                                  &size, &ecmp_scache_ptr,
    957                                  SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL));
    958 
    959 
    960     /* spare bank idx */
    961     SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, &(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx));
    962 
    963     /* Sync group_info structs. */
    964     for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) {
    965         group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix);
    966 
    967         SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, group_info);
    968     }
    969 
    970     /* Sync bank_info structs. */
    971     for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) {
    972         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix);
    973 
    974         SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, bank_info);
    975     }
    976 
    977     return SOC_E_NONE;
    978 }
    979 
    980 /*
    981  * Function:
    982  *     soc_esw_ecmp_protected_state_warmboot_recover
    983  * Purpose:
    984  *     Recover soc esw ecmp state.
    985  * Parameters:
    986  *     unit - (IN) SOC device id
    987  *
    988  * Returns:
    989  *     SOC_E_XXX
    990  */
    991 
    992 int
    993 soc_esw_ecmp_protected_state_warmboot_recover(int unit)
    994 {
    995     int ix;
    996     uint32 size;
    997     soc_esw_ecmp_group_state_t *group_info;
    998     soc_esw_ecmp_bank_state_t *bank_info;
    999     uint8 *ecmp_scache_ptr;
   1000     soc_scache_handle_t scache_handle;
   1001 
   1002     scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle;
   1003 
   1004     /* Get the size to save ecmp protected warmboot state. */
   1005     soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size);
   1006 
   1007 
   1008     SOC_IF_ERROR_RETURN
   1009         (soc_versioned_scache_ptr_get(unit, scache_handle, FALSE,
   1010                                  &size, &ecmp_scache_ptr,
   1011                                  SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL));
   1012 
   1013     /* spare bank idx */
   1014     SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, &(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx));
   1015 
   1016     /* Sync group_info structs. */
   1017     for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) {
   1018         group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix);
   1019 
   1020         SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, group_info);
   1021     }
   1022 
   1023     /* Sync bank_info structs. */
   1024     for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) {
   1025         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix);
   1026 
   1027         SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, bank_info);
   1028     }
   1029 
   1030     return SOC_E_NONE;
   1031 }
   1032 
   1033 #endif /* BCM_WARM_BOOT_SUPPORT */
   1034 
   1035 /*
   1036  * Function:
   1037  *      soc_esw_ecmp_protected_init
   1038  * Purpose:
   1039  *      Initialize state for ecmp protected accesses
   1040  * Parameters:
   1041  *      unit            - (IN)SOC unit number.
   1042  *      first_lkup_sz   - (IN)ECMP table first lookup size.
   1043  *      ecmp_table_sz   - (IN)ECMP table total size.
   1044  *      ecmp_nh_offset  - (IN)ECMP next hop offset.
   1045  * Returns:
   1046  *      SOC_E_XXX
   1047  */
   1048 int
   1049 soc_esw_ecmp_protected_init(int unit,
   1050                             soc_esw_ecmp_init_info_t *init_info)
   1051 {
   1052     int ix;
   1053     int bix, bix_r;
   1054     int tbl_offset;
   1055     int bank_size;
   1056     int lkup1_banks, lkup2_banks;
   1057     soc_mem_t mem;
   1058     soc_esw_ecmp_bank_state_t *bank_info;
   1059 
   1060     if ((init_info == NULL) ||
   1061         (init_info->bank_size > SOC_ESW_ECMP_BANK_SIZE)) {
   1062         return SOC_E_INIT;
   1063     }
   1064 
   1065     /* Make sure the ECMP member and group tables are always enabled for memcache */
   1066     for (ix = 0; ix < COUNTOF(ecmp_member_mems); ix++) {
   1067         mem = ecmp_member_mems[0];
   1068         if (SOC_MEM_STATE(unit, mem).cache[SOC_MEM_BLOCK_ANY(unit, mem)] == NULL) {
   1069             return SOC_E_INIT;
   1070         }
   1071     }
   1072     for (ix = 0; ix < COUNTOF(ecmp_group_mems); ix++) {
   1073         mem = ecmp_group_mems[0];
   1074         if (SOC_MEM_STATE(unit, mem).cache[SOC_MEM_BLOCK_ANY(unit, mem)] == NULL) {
   1075             return SOC_E_INIT;
   1076         }
   1077     }
   1078 
   1079 
   1080     /* Allocate export software state. */
   1081     if (SOC_ESW_ECMP_STATE(unit) == NULL) {
   1082         SOC_ESW_ECMP_STATE(unit) =
   1083             sal_alloc(sizeof(soc_esw_ecmp_state_t),
   1084                       "SOC esw ecmp sw state");
   1085     }
   1086 
   1087     if (SOC_ESW_ECMP_STATE(unit) == NULL) {
   1088         return SOC_E_MEMORY;
   1089     }
   1090     sal_memset(SOC_ESW_ECMP_STATE(unit), 0, sizeof(soc_esw_ecmp_state_t));
   1091 
   1092     /* Create ECMP State lock */
   1093     if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) {
   1094         SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock =
   1095             sal_mutex_create("soc.esw.ecmp.state.mutex");
   1096 
   1097         if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) {
   1098             sal_free(SOC_ESW_ECMP_STATE(unit));
   1099             SOC_ESW_ECMP_STATE(unit) = NULL;
   1100             return SOC_E_MEMORY;
   1101         }
   1102     }
   1103 
   1104     SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks = init_info->num_banks;
   1105     SOC_ESW_ECMP_STATE(unit)->ecmp_members_per_banks = init_info->bank_size;
   1106     SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset = init_info->ecmp_if_offset;
   1107 #ifdef BCM_WARM_BOOT_SUPPORT
   1108     SOC_ESW_ECMP_STATE(unit)->scache_handle = init_info->scache_handle;
   1109 #endif /* BCM_WARM_BOOT_SUPPORT */
   1110 
   1111     tbl_offset = 0;
   1112     bank_size = init_info->bank_size;
   1113     lkup1_banks = ((init_info->lkup1_size + (bank_size - 1)) / bank_size);
   1114     lkup2_banks = ((init_info->lkup2_size + (bank_size - 1)) / bank_size);
   1115 
   1116     bix_r = -1;
   1117     for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) {
   1118         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
   1119 
   1120         if (init_info->num_levels < 2) {
   1121             bank_info->protected_write_disabled = 1;
   1122             bank_info->level = socEswEcmpBankLkupLevelInvalid;
   1123             continue;
   1124         }
   1125 
   1126         
   1127         if (bix < lkup1_banks) {
   1128             bank_info->level = socEswEcmpBankLkupLevelOverlay;
   1129             bank_info->protected_write_disabled = 0;
   1130         } else if (bix < (lkup1_banks + lkup2_banks)) {
   1131             bank_info->level = socEswEcmpBankLkupLevelUnderlay;
   1132             bank_info->protected_write_disabled = 0;
   1133         } else {
   1134             if (bix_r == -1) {
   1135                 bix_r = bix;
   1136                 bank_info->level = socEswEcmpBankLkupLevelReserved;
   1137 
   1138                 SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx = bix;
   1139             } else {
   1140                 bank_info->level = socEswEcmpBankLkupLevelInvalid;
   1141             }
   1142             bank_info->protected_write_disabled = 1;
   1143         }
   1144 
   1145         
   1146         bank_info->idx_min = 0;
   1147         bank_info->idx_max = bank_size;
   1148         bank_info->bank_size = bank_size;
   1149 
   1150         bank_info->tbl_offset = tbl_offset;
   1151         tbl_offset += bank_size;
   1152     }
   1153 
   1154 
   1155 #ifdef BCM_WARM_BOOT_SUPPORT
   1156     if (!SOC_WARM_BOOT(unit)) {
   1157         SOC_IF_ERROR_RETURN(soc_esw_ecmp_protected_state_warmboot_alloc(unit));
   1158     } else {
   1159         SOC_IF_ERROR_RETURN(soc_esw_ecmp_protected_state_warmboot_recover(unit));
   1160     }
   1161 #endif /* BCM_WARM_BOOT_SUPPORT */
   1162 
   1163     return SOC_E_NONE;
   1164 }
   1165 
   1166 /*
   1167  * Function:
   1168  *      soc_esw_ecmp_protected_detach
   1169  * Purpose:
   1170  *      De-Initialize state for ecmp protected accesses
   1171  * Parameters:
   1172  *      unit       - (IN)SOC unit number.
   1173  * Returns:
   1174  *      SOC_E_XXX
   1175  */
   1176 int
   1177 soc_esw_ecmp_protected_detach(int unit)
   1178 {
   1179 
   1180     /* Destroy ECMP State lock */
   1181     if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock != NULL) {
   1182         sal_mutex_destroy(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock);
   1183         SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock = NULL;
   1184     }
   1185 
   1186     /* Free export software state. */
   1187     if (SOC_ESW_ECMP_STATE(unit)) {
   1188         sal_free(SOC_ESW_ECMP_STATE(unit));
   1189         SOC_ESW_ECMP_STATE(unit) = NULL;
   1190     }
   1191 
   1192     return SOC_E_NONE;
   1193 }
   1194 
   1195 
   1196 /*
   1197  * Function:
   1198  *      soc_esw_ecmp_protected_enabled
   1199  * Purpose:
   1200  *      Checks whether protected ecmp is required or not.
   1201  * Parameters:
   1202  *      unit       - (IN)SOC unit number.
   1203  * Returns:
   1204  *      TRUE:  Protected ECMP access routines should be used
   1205  *      FALSE: Protected ECMP access routines are not required
   1206  */
   1207 int
   1208 soc_esw_ecmp_protected_enabled(int unit)
   1209 {
   1210     int bix;
   1211 
   1212     /* SOC featue is not set. Return FALSE. */
   1213     if (!soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
   1214         return FALSE;
   1215     }
   1216 
   1217     /* Ecmp state is not initialized yet. Return FALSE. */
   1218     if (SOC_ESW_ECMP_STATE(unit) == NULL) {
   1219         return FALSE;
   1220     }
   1221 
   1222     /* TRUE if at least one bank requires protected writing. */
   1223     for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) {
   1224         if (SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bix)) {
   1225             return TRUE;
   1226         }
   1227     }
   1228 
   1229     return FALSE;
   1230 }
   1231 
   1232 int
   1233 soc_esw_ecmp_protected_idx_free_get(int unit,
   1234                                     int bix,
   1235                                     int count,
   1236                                     int *free_idx)
   1237 {
   1238     int idx, lkup_idx;
   1239     soc_esw_ecmp_bank_state_t *bank_info;
   1240 
   1241     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
   1242 
   1243     *free_idx = -1;
   1244     for (lkup_idx = 0;
   1245          lkup_idx <= bank_info->bank_size; lkup_idx++) {
   1246 
   1247         if (!SHR_BITGET(bank_info->idx_used, lkup_idx)) {
   1248             idx = count;
   1249             /* Check if the group crosses the bank boundary. */
   1250             if ((lkup_idx + idx) > bank_info->bank_size) {
   1251                 break;
   1252             }
   1253             while (--idx) {
   1254                 /* Check if free slots can accomodate wide entry. */
   1255                 if (SHR_BITGET(bank_info->idx_used, lkup_idx + idx)) {
   1256                     break;
   1257                 }
   1258             }
   1259             if (idx) {
   1260                 /* There is no room to accomodate wide entry. */
   1261                 continue;
   1262             }
   1263             *free_idx = (lkup_idx + bank_info->tbl_offset);
   1264             return (SOC_E_NONE);
   1265         }
   1266     }
   1267 
   1268     return SOC_E_FULL;
   1269 }
   1270 
   1271 
   1272 int
   1273 soc_esw_ecmp_protected_banks_get(int unit,
   1274                                  soc_esw_ecmp_bank_lkup_level_t lvl,
   1275                                  uint32 *bank_bitmap)
   1276 {
   1277     int bix;
   1278     soc_esw_ecmp_bank_state_t *bank_info;
   1279 
   1280     for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) {
   1281         bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix);
   1282         if (bank_info->level == lvl) {
   1283             SHR_BITSET(bank_bitmap, bix);
   1284         }
   1285     }
   1286 
   1287     return SOC_E_NONE;
   1288 }
   1289 
   1290 /*
   1291  * Function:
   1292  *      soc_esw_ecmp_protected_bank_defragment
   1293  * Purpose:
   1294  *      Defragment an ecmp bank to fill up holes in
   1295  *      the middle of the ecmp member table and compress.
   1296  * Parameters:
   1297  *      unit            - (IN)  SOC unit number.
   1298  *      bank_idx        - (IN)  bank idx to compress.
   1299  *      grp_idx_move    - (IN)  ecmp group id to write.
   1300  *      free_count      - (OUT) Free count in bank after compression.
   1301  * Returns:
   1302  *      SOC_E_XXX
   1303  */
   1304 int
   1305 soc_esw_ecmp_protected_bank_defragment(int unit,
   1306                                        int bank_idx,
   1307                                        int grp_idx_move,
   1308                                        int *free_count)
   1309 {
   1310     int rv;
   1311     int grp_idx;
   1312     int new_base_idx;
   1313     int rd_start, rd_end, wr_start, wr_end;
   1314 
   1315     soc_esw_ecmp_group_state_t *grp_state;
   1316     soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info;
   1317 
   1318     uint8 *ecmp1_tbl_p = NULL;     /* L3_ECMP table pointer. */
   1319     uint8 *ecmp2_tbl_p = NULL;     /* INITIAL_L3_ECMP table pointer. */
   1320     uint8 *dst_ecmp1_tbl_p = NULL; /* L3_ECMP table pointer. */
   1321     uint8 *dst_ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP table pointer. */
   1322 
   1323     src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx);
   1324     dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, SOC_ESW_ECMP_BANK_RSVD_GET(unit));
   1325 
   1326 
   1327     rd_start = src_bank_info->tbl_offset;
   1328     rd_end = (src_bank_info->tbl_offset + src_bank_info->bank_size - 1);
   1329 
   1330     wr_start = dst_bank_info->tbl_offset;
   1331     wr_end = (dst_bank_info->tbl_offset + dst_bank_info->bank_size - 1);
   1332 
   1333     /* Copy all member table entries into buffer */
   1334     rv = soc_esw_mem_dma_read(unit, L3_ECMPm,
   1335                               sizeof(ecmp_entry_t),
   1336                               "ecmp_tbl",
   1337                               rd_start, rd_end,
   1338                               &ecmp1_tbl_p);
   1339     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1340 
   1341     rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm,
   1342                               sizeof(initial_l3_ecmp_entry_t),
   1343                               "ecmp2_tbl",
   1344                               rd_start, rd_end,
   1345                               &ecmp2_tbl_p);
   1346     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1347 
   1348     /* Read ecmp member tables */
   1349     rv = soc_esw_mem_dma_read(unit, L3_ECMPm,
   1350                               sizeof(ecmp_entry_t),
   1351                               "ecmp_tbl",
   1352                               wr_start, wr_end,
   1353                               &dst_ecmp1_tbl_p);
   1354     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1355 
   1356     rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm,
   1357                               sizeof(initial_l3_ecmp_entry_t),
   1358                               "ecmp2_tbl",
   1359                               wr_start, wr_end,
   1360                               &dst_ecmp2_tbl_p);
   1361     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1362 
   1363 
   1364     new_base_idx = 0;
   1365 
   1366     for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) {
   1367         grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx);
   1368 
   1369         if (grp_state->bank != bank_idx) {
   1370             continue;
   1371         }
   1372 
   1373         /* Group not in use. */
   1374         if (!grp_state->bank && !grp_state->base && !grp_state->count) {
   1375             continue;
   1376         }
   1377 
   1378         /* Do it at the end */
   1379         if (grp_idx == grp_idx_move) {
   1380             continue;
   1381         }
   1382 
   1383         rv = soc_esw_ecmp_protected_member_move(unit,
   1384                                                 grp_idx,
   1385                                                 bank_idx,
   1386                                                 SOC_ESW_ECMP_BANK_RSVD_GET(unit),
   1387                                                 ecmp1_tbl_p,
   1388                                                 ecmp2_tbl_p,
   1389                                                 dst_ecmp1_tbl_p,
   1390                                                 dst_ecmp2_tbl_p,
   1391                                                 new_base_idx);
   1392         SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1393 
   1394         new_base_idx += grp_state->count;
   1395     }
   1396 
   1397     if (grp_idx_move != -1) {
   1398         grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx_move);
   1399 
   1400         rv = soc_esw_ecmp_protected_member_move(unit,
   1401                                                 grp_idx_move,
   1402                                                 bank_idx,
   1403                                                 SOC_ESW_ECMP_BANK_RSVD_GET(unit),
   1404                                                 ecmp1_tbl_p,
   1405                                                 ecmp2_tbl_p,
   1406                                                 dst_ecmp1_tbl_p,
   1407                                                 dst_ecmp2_tbl_p,
   1408                                                 new_base_idx);
   1409         SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1410 
   1411         new_base_idx += grp_state->count;
   1412     }
   1413 
   1414     /* Write updated member tables  */
   1415     rv = soc_mem_write_range(unit, L3_ECMPm, MEM_BLOCK_ALL,
   1416                              wr_start, wr_end, dst_ecmp1_tbl_p);
   1417     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1418 
   1419     rv = soc_mem_write_range(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL,
   1420                              wr_start, wr_end, dst_ecmp2_tbl_p);
   1421     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1422 
   1423     rv = soc_esw_ecmp_bank_active_set(unit, bank_idx);
   1424     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1425 
   1426     /* traverse group tables and update base pointers. */
   1427     rv = soc_esw_ecmp_protected_base_ptr_update(unit);
   1428     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1429 
   1430     rv = soc_esw_ecmp_bank_reserved_set(unit, bank_idx);
   1431     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1432 
   1433     if (free_count) {
   1434         *free_count = (dst_bank_info->bank_size - new_base_idx);
   1435     }
   1436 
   1437 err_exit:
   1438     if (ecmp2_tbl_p) {
   1439         soc_cm_sfree(unit, ecmp2_tbl_p);
   1440     }
   1441     if (ecmp1_tbl_p) {
   1442         soc_cm_sfree(unit, ecmp1_tbl_p);
   1443     }
   1444 
   1445     if (dst_ecmp1_tbl_p) {
   1446         soc_cm_sfree(unit, dst_ecmp1_tbl_p);
   1447     }
   1448 
   1449     if (dst_ecmp2_tbl_p) {
   1450         soc_cm_sfree(unit, dst_ecmp2_tbl_p);
   1451     }
   1452     return rv;
   1453 }
   1454 
   1455 /*
   1456  * Function:
   1457  *      soc_esw_ecmp_protected_ser_update
   1458  * Purpose:
   1459  *      Free the bank corresponding to index of errored ECMP memory.
   1460  * Parameters:
   1461  *      unit            - (IN)  SOC unit number.
   1462  *      mem             - (IN)  SOC memory.
   1463  *      ecmp_idx        - (IN)  ECMP memory index.
   1464  * Returns:
   1465  *      SOC_E_XXX
   1466  */
   1467 int
   1468 soc_esw_ecmp_protected_ser_update(int unit,
   1469                                   soc_mem_t mem,
   1470                                   int ecmp_idx)
   1471 {
   1472     int rv;
   1473     int bank_idx;
   1474 
   1475     /* Bank update required only for INITIAL_L3_ECMP memory. */
   1476     if (mem != INITIAL_L3_ECMPm) {
   1477         return SOC_E_NONE;
   1478     }
   1479 
   1480     /* get ECMP member bank idx */
   1481     rv = soc_esw_ecmp_idx_bank_get(unit, ecmp_idx, &bank_idx);
   1482     SOC_IF_ERROR_RETURN(rv);
   1483 
   1484     if (!SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bank_idx)) {
   1485         return SOC_E_NONE;
   1486     }
   1487 
   1488     /* Call defragment function for the bank_idx. This does necessary shuffling. */
   1489     rv = soc_esw_ecmp_protected_bank_defragment(unit, bank_idx, -1, NULL);
   1490 
   1491     return rv;
   1492 }
   1493 
   1494 /*
   1495  * Function:
   1496  *      soc_esw_ecmp_bank_free_count_get
   1497  * Purpose:
   1498  *      Get the number of free entries in this bank.
   1499  * Parameters:
   1500  *      unit            - (IN)  SOC unit number.
   1501  *      bank_idx        - (IN)  Bank index.
   1502  *      count           - (OUT) Free entry count.
   1503  * Returns:
   1504  *      SOC_E_XXX
   1505  */
   1506 int
   1507 soc_esw_ecmp_bank_free_count_get(int unit, int bank_idx, int *count)
   1508 {
   1509     int use_count = 0;
   1510     soc_esw_ecmp_bank_state_t *bank_info;
   1511 
   1512     bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx);
   1513 
   1514     SOC_IF_ERROR_RETURN(
   1515         soc_esw_ecmp_bank_used_count_get(unit, bank_idx, &use_count));
   1516 
   1517     *count = (bank_info->bank_size - use_count);
   1518 
   1519     return SOC_E_NONE;
   1520 }
   1521 
   1522 /*
   1523  * Function:
   1524  *      soc_esw_ecmp_protected_grp_add
   1525  * Purpose:
   1526  *      Add ecmp group next hop members, or reset ecmp group entry.
   1527  *      NOTE: Function only updates the INITIAL_L3_ECMP and L3_ECMP tables only.
   1528  *            Group tables and other associated tables are updated by the callee.
   1529  *            Function may update group tables of other groups as part of this API though.
   1530  * Parameters:
   1531  *      unit        - (IN)SOC unit number.
   1532  *      grp_info    - (IN)ecmp group id to write.
   1533  *      member_list - (IN)Next hop indexes or NULL for entry reset.
   1534  * Returns:
   1535  *      SOC_E_XXX
   1536  */
   1537 int
   1538 soc_esw_ecmp_protected_grp_add(int unit,
   1539                                soc_esw_ecmp_group_info_t *grp_info,
   1540                                void *member_list)
   1541 {
   1542     int idx;                /* Iteration index.  */
   1543     int rv;                 /* Operation return value. */
   1544     int ecmpf;              /* Ecmp group vs NextHop Id indicator. */
   1545     int nh_idx;             /* NextHop Idx or Ecmp Group. */
   1546     int bank_idx;           /* Ecmp Member Table Bank. */
   1547     int bank_idx_r;         /* Reserved ecmp member bank. */
   1548     int ecmp_idx;           /* Ecmp table entry index. */
   1549     int ecmp_base_offset;   /* Ecmp table entry index. */
   1550     int max_grp_size;       /* Maximum ecmp group size. */
   1551     int rd_start, rd_end;   /* Read idx range. */
   1552     int wr_start, wr_end;   /* Write idx range. */
   1553     int bank_swap_reqd;     /* Bank Swap needed  */
   1554 
   1555     uint8 *ecmp1_tbl_p = NULL;         /* L3_ECMP table pointer. */
   1556     uint8 *ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP table pointer. */
   1557     uint32 *ecmp1_entry_ptr = NULL;         /* ECMP entry pointer.*/
   1558     uint32 *ecmp2_entry_ptr = NULL; /* INITIAL ECMP entry pointer.*/
   1559     soc_esw_ecmp_member_info_t *ecmp_members;  /* Ecmp group member info.  */
   1560     soc_esw_ecmp_group_state_t *grp_state; /* ECMP group info. */
   1561     void *ecmp1_null_entry = NULL, *ecmp2_null_entry = NULL;
   1562 
   1563     /* Cast input buffer. */
   1564     ecmp_members = member_list;
   1565 
   1566     bank_idx_r = SOC_ESW_ECMP_BANK_RSVD_GET(unit);
   1567 
   1568     max_grp_size = grp_info->max_paths;
   1569     ecmp_idx = grp_info->ecmp_member_base;
   1570     ecmp_base_offset = ecmp_idx;
   1571     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_info->ecmp_grp);
   1572 
   1573     if (grp_state->count != 0) {
   1574         if (max_grp_size > grp_state->count) {
   1575             rv = soc_esw_ecmp_protected_grp_size_update(unit,
   1576                                                         grp_info,
   1577                                                         &ecmp_idx);
   1578             SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1579             ecmp_base_offset = ecmp_idx;
   1580         }
   1581     }
   1582 
   1583     /* get ECMP member bank idx */
   1584     rv = soc_esw_ecmp_idx_bank_get(unit, ecmp_idx, &bank_idx);
   1585     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1586 
   1587     rv = soc_esw_ecmp_protected_idx_range_get(unit, bank_idx, bank_idx_r,
   1588                                               ecmp_idx, max_grp_size,
   1589                                               &rd_start, &rd_end,
   1590                                               &wr_start, &wr_end);
   1591     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1592 
   1593     /* Bank swap required if read and write ranges different */
   1594     bank_swap_reqd = ((wr_start != rd_start) ? 1 : 0);
   1595 
   1596     rv = soc_esw_ecmp_idx_bank_offset_get(unit, &ecmp_base_offset);
   1597     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1598 
   1599     /* Read ecmp member tables */
   1600     rv = soc_esw_mem_dma_read(unit, L3_ECMPm,
   1601                               sizeof(ecmp_entry_t),
   1602                               "ecmp_tbl",
   1603                               rd_start, rd_end,
   1604                               &ecmp1_tbl_p);
   1605     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1606 
   1607     rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm,
   1608                               sizeof(initial_l3_ecmp_entry_t),
   1609                               "ecmp2_tbl",
   1610                               rd_start, rd_end,
   1611                               &ecmp2_tbl_p);
   1612     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1613 
   1614     ecmp1_null_entry = soc_mem_entry_null(unit, L3_ECMPm);
   1615     ecmp2_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm);
   1616 
   1617     /* Populate new nexthop indices in the member tables. */
   1618     for (idx = ecmp_base_offset, nh_idx = 0;
   1619          idx < (ecmp_base_offset + max_grp_size);
   1620          idx++, nh_idx++) {
   1621 
   1622          /* Set next hop index. */
   1623          ecmp1_entry_ptr =
   1624              soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *,
   1625                                           ecmp1_tbl_p, idx);
   1626          ecmp2_entry_ptr =
   1627              soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *,
   1628                                           ecmp2_tbl_p, idx);
   1629 
   1630          sal_memcpy(ecmp1_entry_ptr, ecmp1_null_entry,
   1631                     sizeof(ecmp_entry_t));
   1632          sal_memcpy(ecmp2_entry_ptr, ecmp2_null_entry,
   1633                     sizeof(initial_l3_ecmp_entry_t));
   1634 
   1635         ecmpf = 0;
   1636         soc_esw_nh_if_ecmp_grp_decode(unit, &(ecmp_members[nh_idx].nh), &ecmpf);
   1637 
   1638         /* Set ecmp flag if member is an ecmp group */
   1639         if (ecmpf == 1) {
   1640             soc_mem_field32_set(unit, L3_ECMPm,
   1641                                 ecmp1_entry_ptr, ECMP_FLAGf, 1);
   1642             soc_mem_field32_set(unit, INITIAL_L3_ECMPm,
   1643                                 ecmp2_entry_ptr, ECMPf, 1);
   1644 
   1645             soc_mem_field32_dest_set(unit, L3_ECMPm,
   1646                                      ecmp1_entry_ptr,
   1647                                      DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, 
   1648                                      ecmp_members[nh_idx].nh);
   1649             soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm,
   1650                                      ecmp2_entry_ptr,
   1651                                      DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, 
   1652                                      ecmp_members[nh_idx].nh);
   1653         } else {
   1654             soc_mem_field32_dest_set(unit, L3_ECMPm,
   1655                                      ecmp1_entry_ptr,
   1656                                      DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, 
   1657                                      ecmp_members[nh_idx].nh);
   1658             soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm,
   1659                                      ecmp2_entry_ptr,
   1660                                      DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, 
   1661                                      ecmp_members[nh_idx].nh);
   1662         }
   1663 
   1664         if (grp_info->vp_lag == 1) {
   1665             soc_mem_field32_set(unit, L3_ECMPm,
   1666                                 ecmp1_entry_ptr, DVPf,
   1667                                 ecmp_members[nh_idx].dvp);
   1668         }
   1669 
   1670         soc_mem_field32_set(unit, INITIAL_L3_ECMPm,
   1671                             ecmp2_entry_ptr,
   1672                             PROT_NEXT_HOP_INDEXf,
   1673                             ecmp_members[nh_idx].prot_nh);
   1674 
   1675         soc_mem_field32_set(unit, INITIAL_L3_ECMPm,
   1676                             ecmp2_entry_ptr,
   1677                             PROT_GROUPf,
   1678                             ecmp_members[nh_idx].prot_grp);
   1679     }
   1680 
   1681     /* Write updated member tables  */
   1682     rv = soc_mem_write_range(unit, L3_ECMPm, MEM_BLOCK_ALL,
   1683                              wr_start, wr_end, ecmp1_tbl_p);
   1684     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1685 
   1686     rv = soc_mem_write_range(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL,
   1687                              wr_start, wr_end, ecmp2_tbl_p);
   1688     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1689 
   1690     /* If the group is being updated and index has moved, free old index. */
   1691     rv = soc_esw_ecmp_protected_idx_free(unit,
   1692                                          grp_state->bank,
   1693                                          grp_state->base,
   1694                                          grp_state->count);
   1695     SOC_IF_ERROR_RETURN(rv);
   1696 
   1697     /* Update ECMP group's base ptr */
   1698     grp_info->ecmp_member_base = (ecmp_idx + (wr_start - rd_start));
   1699 
   1700     /* Update ECMP member state */
   1701     rv = soc_esw_ecmp_protected_idx_alloc(unit,
   1702                                           (bank_swap_reqd ? bank_idx_r : bank_idx),
   1703                                           grp_info->ecmp_member_base,
   1704                                           grp_info->max_paths);
   1705     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1706 
   1707     /* Update ECMP group state */
   1708     rv = soc_esw_ecmp_protected_state_set(unit,
   1709                                           grp_info->ecmp_grp,
   1710                                           (bank_swap_reqd ? bank_idx_r : bank_idx),
   1711                                           grp_info->ecmp_member_base,
   1712                                           grp_info->max_paths);
   1713     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1714 
   1715     if (bank_swap_reqd) {
   1716         /* Update other groups with members in this bank */
   1717         rv = soc_esw_ecmp_protected_bank_update(unit, bank_idx, bank_idx_r);
   1718         SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1719     }
   1720 
   1721 err_exit:
   1722     if (ecmp2_tbl_p) {
   1723         soc_cm_sfree(unit, ecmp2_tbl_p);
   1724     }
   1725     if (ecmp1_tbl_p) {
   1726         soc_cm_sfree(unit, ecmp1_tbl_p);
   1727     }
   1728 
   1729 
   1730     return rv;
   1731 }
   1732 
   1733 /*
   1734  * Function:
   1735  *      soc_esw_ecmp_protected_grp_delete
   1736  * Purpose:
   1737  *      Delete ECMP members
   1738  *      NOTE: Function does not update the INITIAL_L3_ECMP and L3_ECMP tables.
   1739  *            Group tables need to be updated to reflect group delete.
   1740  * Parameters:
   1741  *      unit       - (IN)SOC unit number.
   1742  *      grp_info   - (IN)ecmp group id to write.
   1743  * Returns:
   1744  *      SOC_E_XXX
   1745  */
   1746 int
   1747 soc_esw_ecmp_protected_grp_delete(int unit,
   1748                                   soc_esw_ecmp_group_info_t *grp_info)
   1749 {
   1750     int rv;
   1751     soc_esw_ecmp_group_state_t *grp_state;
   1752 
   1753     grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_info->ecmp_grp);
   1754 
   1755     /* Update ECMP member state */
   1756     rv = soc_esw_ecmp_protected_idx_free(unit,
   1757                                          grp_state->bank,
   1758                                          grp_state->base,
   1759                                          grp_state->count);
   1760     SOC_IF_ERROR_RETURN(rv);
   1761 
   1762     /* Update ECMP group state */
   1763     rv = soc_esw_ecmp_protected_state_set(unit,
   1764                                           grp_info->ecmp_grp,
   1765                                           0,
   1766                                           0,
   1767                                           0);
   1768     SOC_IF_ERROR_RETURN(rv);
   1769 
   1770     return SOC_E_NONE;
   1771 }
   1772 
   1773 /*
   1774  * Function:
   1775  *      soc_esw_ecmp_protected_grp_get
   1776  * Purpose:
   1777  *      Fetch ecmp members info for a given group
   1778  * Parameters:
   1779  *      unit       - (IN)SOC unit number.
   1780  *      grp_info   - (IN)ecmp group id to write.
   1781  *      mem_list   - (OUT)Next hop indexes or NULL for entry reset.
   1782  * Returns:
   1783  *      SOC_E_XXX
   1784  */
   1785 int
   1786 soc_esw_ecmp_protected_grp_get(int unit,
   1787                                soc_esw_ecmp_group_info_t *grp_info,
   1788                                void *mem_list)
   1789 {
   1790     int max_grp_size;  /* Maximum ecmp group size.*/
   1791     int ecmp_idx;      /* Ecmp table entry index. */
   1792     int nh_idx;        /* NextHop Idx or Ecmp Group */
   1793     int bank_idx;      /* Ecmp Member Table Bank */
   1794     int idx;           /* Iteration index.  */
   1795     int rv;            /* Operation return value. */
   1796 
   1797     uint8 *ecmp1_tbl_p = NULL;         /* Dma L3 ECMP table pointer. */
   1798     uint8 *ecmp2_tbl_p = NULL;         /* Dma L3 ECMP table pointer. */
   1799     uint32 *ecmp1_entry_ptr = NULL;    /* ECMP entry pointer.*/
   1800     uint32 *ecmp2_entry_ptr = NULL;    /* ECMP entry pointer.*/
   1801     uint32 dest_val;
   1802     uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   1803     soc_esw_ecmp_member_info_t *ecmp_members;/* Ecmp group nh indexes.  */
   1804 
   1805     /* Get ECMP group state */
   1806     rv = soc_esw_ecmp_protected_state_get(unit,
   1807                                           grp_info->ecmp_grp,
   1808                                           &bank_idx,
   1809                                           &ecmp_idx,
   1810                                           &max_grp_size);
   1811     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1812 
   1813     /* Cast input buffer. */
   1814     ecmp_members = mem_list;
   1815 
   1816     /* Read ecmp member tables */
   1817     rv = soc_esw_mem_dma_read(unit, L3_ECMPm,
   1818                               sizeof(ecmp_entry_t),
   1819                               "ecmp_tbl",
   1820                               ecmp_idx,
   1821                               (ecmp_idx + max_grp_size - 1),
   1822                               &ecmp1_tbl_p);
   1823     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1824 
   1825     /* Read ecmp member tables */
   1826     rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm,
   1827                               sizeof(ecmp_entry_t),
   1828                               "initial_ecmp_tbl",
   1829                               ecmp_idx,
   1830                               (ecmp_idx + max_grp_size - 1),
   1831                               &ecmp2_tbl_p);
   1832     SOC_ESW_ECMP_IF_ERR_EXIT(rv);
   1833 
   1834     /* Populate new nexthop indices from the member tables. */
   1835     for (idx = 0, nh_idx = 0; idx < max_grp_size; idx++, nh_idx++) {
   1836         /* Set next hop index. */
   1837         ecmp1_entry_ptr =
   1838             soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *,
   1839                                          ecmp1_tbl_p, idx);
   1840         ecmp2_entry_ptr =
   1841             soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *,
   1842                                          ecmp2_tbl_p, idx);
   1843 
   1844         dest_val = soc_mem_field32_dest_get(unit, L3_ECMPm, ecmp1_entry_ptr,
   1845                                             DESTINATIONf, &dest_type);
   1846         soc_esw_nh_if_ecmp_grp_encode(unit, &(dest_val),
   1847                                       (dest_type == SOC_MEM_FIF_DEST_ECMP));
   1848         ecmp_members[nh_idx].nh = dest_val;
   1849 
   1850         if (grp_info->vp_lag == 1) {
   1851             ecmp_members[nh_idx].dvp = soc_mem_field32_get(unit, L3_ECMPm,
   1852                                                            ecmp1_entry_ptr, DVPf);
   1853         }
   1854 
   1855         ecmp_members[nh_idx].prot_nh = soc_mem_field32_get(unit, INITIAL_L3_ECMPm,
   1856                                                            ecmp2_entry_ptr,
   1857                                                            PROT_NEXT_HOP_INDEXf);
   1858         ecmp_members[nh_idx].prot_grp = soc_mem_field32_get(unit, INITIAL_L3_ECMPm,
   1859                                                            ecmp2_entry_ptr,
   1860                                                            PROT_GROUPf);
   1861     }
   1862 
   1863 err_exit:
   1864     if (ecmp1_tbl_p) {
   1865         soc_cm_sfree(unit, ecmp1_tbl_p);
   1866     }
   1867 
   1868     if (ecmp2_tbl_p) {
   1869         soc_cm_sfree(unit, ecmp2_tbl_p);
   1870     }
   1871     return rv;
   1872 }
   1873 
   1874 #else
   1875 int _include_soc_ecmp_not_empty;
   1876 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   1877