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

mpls.c (50242B)


      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:    mpls.c
      8  * Purpose: Handle trident3 specific MPLS APIs
      9  */
     10 
     11 
     12 #include <shared/bsl.h>
     13 
     14 #include <soc/defs.h>
     15 #include <sal/core/libc.h>
     16 #include <bcm/error.h>
     17 
     18 #ifdef INCLUDE_L3
     19 #ifdef BCM_MPLS_SUPPORT
     20 #ifdef BCM_SPECIAL_LABEL_SUPPORT
     21 
     22 #include <soc/drv.h>
     23 #include <soc/mem.h>
     24 #include <soc/util.h>
     25 #include <soc/debug.h>
     26 
     27 #include <bcm/types.h>
     28 #include <bcm/error.h>
     29 
     30 #include <include/bcm_int/esw/mpls.h>
     31 #include <bcm_int/esw/firebolt.h>
     32 #include <bcm_int/esw/triumph.h>
     33 #include <bcm_int/esw/trident3.h>
     34 
     35 /*
     36  * External Linkages.
     37  */
     38 #define MPLS_INFO(_unit_)   (&_bcm_tr_mpls_bk_info[_unit_])
     39 
     40 /*
     41  * Global Defines.
     42  */
     43 bcmi_mpls_special_label_control_t *bcmi_special_label_precedence_state[BCM_MAX_NUM_UNITS];
     44 
     45 /*
     46  * Structure to store REF counts for egress special labels.
     47  */
     48 bcmi_mpls_special_label_egress_t bcmi_special_label_egress_state[BCM_MAX_NUM_UNITS] = {{ 0 }};
     49 
     50 /************************************
     51  ********  Enf Of Headers ***********
     52  */
     53 /*
     54  * Function:
     55  *      bcmi_mpls_special_label_identifier_sw_state_init
     56  * Purpose:
     57  *      Initialize software state for special label routines.
     58  *
     59  * Parameters:
     60  *      unit       - (IN) Device Number
     61  * Returns:
     62  *      BCM_E_XXX
     63  */
     64 int
     65 bcmi_mpls_special_label_identifier_sw_state_init(int unit)
     66 {
     67 
     68     soc_mem_t mem;
     69     int index_min = 0;
     70     int index_max = 0;
     71     uint32 *spl_label_buf = NULL;
     72     int buf_size = 0;
     73     bcmi_mpls_special_label_control_t *ptr;
     74     int rv = BCM_E_NONE;
     75     int i = 0;
     76     special_label_control_entry_t *label_entry;
     77 
     78     mem = SPECIAL_LABEL_CONTROLm;
     79     index_min = soc_mem_index_min(unit, mem);
     80     index_max = soc_mem_index_max(unit, mem);
     81 
     82     buf_size = SOC_MEM_TABLE_BYTES(unit, mem) * ((index_max - index_min ) + 1);
     83     ptr = bcmi_special_label_precedence_state[unit];
     84 
     85     spl_label_buf = soc_cm_salloc(unit, buf_size,
     86                       "SPECIAL_LABEL_CONTROL buffer");
     87     if (NULL == spl_label_buf) {
     88         return BCM_E_MEMORY;
     89     }
     90     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, spl_label_buf);
     91     if (rv < 0) {
     92         soc_cm_sfree(unit, spl_label_buf);
     93         return rv;
     94     }
     95 
     96     for (i = index_min; i <= index_max; i++) {
     97 
     98         label_entry = soc_mem_table_idx_to_pointer(unit,
     99             mem, special_label_control_entry_t *, spl_label_buf, i);
    100 
    101         if (soc_mem_field32_get(unit, mem, label_entry, VALIDf) != 0x1) {
    102             continue;
    103         }
    104 
    105         ptr[i].valid = 1;
    106         ptr[i].label_value =
    107             soc_mem_field32_get(unit, mem, label_entry, LABEL_VALUEf);
    108         ptr[i].label_mask =
    109             soc_mem_field32_get(unit, mem, label_entry, LABEL_VALUE_MASKf);
    110         ptr[i].label_type =
    111             soc_mem_field32_get(unit, mem, label_entry, CURRENT_LABEL_TYPEf);
    112 
    113         if (!SOC_WARM_BOOT(unit)) {
    114             ptr[i].ref_count++;
    115             ptr[i].cancun_added = 1;
    116         }
    117     }
    118 
    119     bcmi_special_label_egress_state[unit].special_label_ref_count = 0;
    120     bcmi_special_label_egress_state[unit].entropy_label_ref_count = 0;
    121     soc_cm_sfree(unit, spl_label_buf);
    122     return BCM_E_NONE;
    123 }
    124 
    125 /*
    126  * Function:
    127  *      bcmi_mpls_special_label_deinit
    128  * Purpose:
    129  *      Cleans software state for special label routines.
    130  *
    131  * Parameters:
    132  *      unit       - (IN) Device Number
    133  * Returns:
    134  *      None
    135  */
    136 void
    137 bcmi_mpls_special_label_deinit(int unit)
    138 {
    139     if (bcmi_special_label_precedence_state[unit]) {
    140         soc_cm_sfree(unit, bcmi_special_label_precedence_state[unit]);
    141         bcmi_special_label_precedence_state[unit] = NULL;
    142     }
    143 
    144 }
    145 
    146 /*
    147  * Function:
    148  *      bcmi_mpls_special_label_init
    149  * Purpose:
    150  *      Initializes software state for special label routines.
    151  *
    152  * Parameters:
    153  *      unit       - (IN) Device Number
    154  * Returns:
    155  *      BCM_E_XXX
    156  */
    157 int
    158 bcmi_mpls_special_label_init(int unit)
    159 {
    160     int num_entry;
    161 
    162     num_entry = soc_mem_index_count(unit, SPECIAL_LABEL_CONTROLm);
    163 
    164     /* First clean if some old state is still not freed */
    165     bcmi_mpls_special_label_deinit(unit);
    166 
    167     bcmi_special_label_precedence_state[unit] = soc_cm_salloc(unit, 
    168             (num_entry * sizeof(bcmi_mpls_special_label_control_t)),
    169             "software state to set precedence of special labels");
    170 
    171     if (bcmi_special_label_precedence_state[unit] == NULL) {
    172         return BCM_E_MEMORY;
    173     }
    174     sal_memset(bcmi_special_label_precedence_state[unit], 0,
    175         (num_entry * sizeof(bcmi_mpls_special_label_control_t)));
    176     
    177     /* 
    178      * Sync the state with h/w.
    179      * Currently, CanCun is writing some default entries at start.
    180      * it will be difficult to maintain refcount if user also adds 
    181      * similar entries and then deletes them.
    182      * therefore SDK will read those entries first and then keep
    183      * track of them so there is no affect if user deletes their entry.
    184      * this will also be helpful during warmboot recovery.
    185      */
    186     bcmi_mpls_special_label_identifier_sw_state_init(unit);
    187 
    188     return BCM_E_NONE;
    189 }
    190 
    191 int
    192 bcmi_mpls_special_label_egress_match(int unit,
    193             bcm_mpls_special_label_type_t label_type,
    194             void * read_value,
    195             void * new_value)
    196 {
    197     uint64 val64;
    198     uint64 val64_r;
    199     uint32 val = 0;
    200     uint32 val_r = 0;
    201 
    202     if (label_type == bcmMplsSpecialLabelTypeSpecial) {
    203         COMPILER_64_ZERO(val64);
    204         COMPILER_64_ZERO(val64_r);
    205 
    206         val64 = *((uint64 *)(new_value));
    207         val64_r = *((uint64 *)(read_value));
    208 
    209         if (COMPILER_64_EQ(val64_r, val64)) {
    210             return TRUE;
    211         }
    212 
    213     } else {
    214         val  =  *((uint32 *)(new_value));
    215         val_r  =  *((uint32 *)(read_value));
    216 
    217         if (val == val_r) {
    218             return TRUE;
    219         }
    220     }
    221 
    222     return FALSE;
    223 }
    224 
    225 
    226 
    227 /*
    228  * Function:
    229  *      bcmi_mpls_special_label_egress_add 
    230  * Purpose:
    231  *      Add an MPLS entropy/special label in
    232  *      MPLS stack for egress tunnel encap.
    233  * Parameters:
    234  *      unit       - (IN) Device Number
    235  *      label_type - (IN) type of label
    236  *      label_info - (IN) Info about special label.
    237  * Returns:
    238  *      BCM_E_XXX
    239  */
    240 int
    241 bcmi_mpls_special_label_egress_add(int unit,
    242             bcm_mpls_special_label_type_t label_type,
    243             bcm_mpls_special_label_t label_info)
    244 {
    245     int rv = BCM_E_NONE;
    246     uint64 val64;
    247     uint64 val64_r;
    248     uint32 val = 0;
    249     uint32 val_r = 0;
    250     bcmi_mpls_special_label_egress_t *ptr;
    251 
    252     ptr = (&(bcmi_special_label_egress_state[unit]));
    253 
    254 
    255     if (!BCMI_MPLS_LABEL_ID_VALID(label_info.label_value)) {
    256         return BCM_E_PARAM;
    257     }
    258 
    259     if (!BCMI_MPLS_EXP_VALID(label_info.exp)) {
    260         return BCM_E_PARAM;
    261     }
    262 
    263     if (!BCMI_MPLS_TTL_VALID(label_info.ttl)) {
    264         return BCM_E_PARAM;
    265     }
    266 
    267 
    268     /* Only Special and entropy labels can be added here*/
    269     if ((label_type != bcmMplsSpecialLabelTypeSpecial) &&
    270         (label_type != bcmMplsSpecialLabelTypeEntropy)) {
    271 
    272         return BCM_E_PARAM;
    273     }
    274 
    275     if (label_type == bcmMplsSpecialLabelTypeSpecial) {
    276 
    277         COMPILER_64_ZERO(val64);
    278         COMPILER_64_ZERO(val64_r);
    279         BCM_IF_ERROR_RETURN(READ_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, &(val64_r)));
    280 
    281         soc_reg64_field32_set(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, &val64,
    282             EXPf, label_info.exp);
    283         soc_reg64_field32_set(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, &val64,
    284             TTLf, label_info.ttl);
    285 
    286          soc_reg64_field32_set(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, &val64,
    287             LABEL_VALUEf, label_info.label_value);
    288 
    289         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP) {
    290             soc_reg64_field32_set(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, &val64,
    291                 EXP_SOURCEf, 1);
    292         }
    293         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL) {
    294             soc_reg64_field32_set(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, &val64,
    295                 TTL_SOURCEf, 1);
    296         }
    297 
    298         if (bcmi_mpls_special_label_egress_match
    299             (unit, label_type, (void *)(&val64_r), (void *)(&val64))) {
    300             /* Similar entry exists. Add an refcount */
    301             ptr->special_label_ref_count++;
    302             return BCM_E_NONE;
    303         } else if (ptr->special_label_ref_count) {
    304             return BCM_E_RESOURCE;
    305         }
    306 
    307         rv = WRITE_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, val64);   
    308         if (BCM_SUCCESS(rv)) {
    309             ptr->special_label_ref_count++;
    310         }
    311 
    312     } else if (label_type == bcmMplsSpecialLabelTypeEntropy) {
    313 
    314         /* Only reserved labels are allowed here */
    315         if (label_info.label_value > 0xf) {
    316             return BCM_E_PARAM;
    317         }
    318 
    319         BCM_IF_ERROR_RETURN(READ_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, &val_r));
    320 
    321         soc_reg_field_set(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, &val,
    322             EXPf, label_info.exp);
    323         soc_reg_field_set(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, &val,
    324             TTLf, label_info.ttl);
    325 
    326          soc_reg_field_set(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, &val,
    327             LABEL_OFFSETf, label_info.label_value);
    328 
    329         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP) {
    330             soc_reg_field_set(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, &val,
    331                 EXP_SOURCEf, 1);
    332         }
    333         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL) {
    334             soc_reg_field_set(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, &val,
    335                 TTL_SOURCEf, 1);
    336         }
    337         if (bcmi_mpls_special_label_egress_match
    338             (unit, label_type, (void *) (&(val_r)), (void *)(&val))) {
    339             /* Similar entry exists. Add an refcount */
    340             ptr->entropy_label_ref_count++;
    341             return BCM_E_NONE;
    342         } else if (ptr->entropy_label_ref_count) {
    343             return BCM_E_RESOURCE;
    344         }
    345 
    346         rv = WRITE_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, val);
    347         if (BCM_SUCCESS(rv)) {
    348             ptr->entropy_label_ref_count++;
    349         }
    350     }
    351 
    352     return rv;
    353 }
    354 
    355 /*
    356  * Function:
    357  *      bcmi_mpls_special_label_egress_get
    358  * Purpose:
    359  *      Get an MPLS entropy/special label in
    360  *      MPLS stack for egress tunnel encap.
    361  * Parameters:
    362  *      unit       - (IN) Device Number
    363  *      label_type - (IN) type of label
    364  *      label_info - (OUT) Info about special label.
    365  * Returns:
    366  *      BCM_E_XXX
    367  */
    368 int
    369 bcmi_mpls_special_label_egress_get(int unit,
    370             bcm_mpls_special_label_type_t label_type,
    371             bcm_mpls_special_label_t *label_info)
    372 {
    373     int rv = BCM_E_NONE;
    374     uint64 val64;
    375     uint32 val = 0;
    376     bcmi_mpls_special_label_egress_t *ptr;
    377 
    378     COMPILER_64_ZERO(val64);
    379 
    380     ptr = (&(bcmi_special_label_egress_state[unit]));
    381 
    382     if (label_info == NULL) {
    383         return BCM_E_PARAM;
    384     }
    385 
    386     /* Only Special and entropy labels can be added here*/
    387     if ((label_type != bcmMplsSpecialLabelTypeSpecial) &&
    388         (label_type != bcmMplsSpecialLabelTypeEntropy)) {
    389 
    390         return BCM_E_PARAM;
    391     }
    392 
    393     if (label_type == bcmMplsSpecialLabelTypeSpecial) {
    394          if (!(ptr->special_label_ref_count)) {
    395             return BCM_E_NOT_FOUND;
    396         }
    397 
    398         COMPILER_64_ZERO(val64);
    399         BCM_IF_ERROR_RETURN(READ_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, &val64));
    400 
    401         label_info->exp = soc_reg64_field32_get(unit,
    402             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, EXPf);
    403 
    404         label_info->ttl = soc_reg64_field32_get(unit,
    405             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, TTLf);
    406 
    407         label_info->label_value = soc_reg64_field32_get(unit,
    408             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, LABEL_VALUEf);
    409 
    410         if (soc_reg64_field32_get(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64,
    411                 EXP_SOURCEf)) {
    412 
    413             label_info->flags |= BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP;
    414         }
    415 
    416         if (soc_reg64_field32_get(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64,
    417                 TTL_SOURCEf)) {
    418 
    419             label_info->flags |= BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL;
    420         }
    421 
    422     } else if (label_type == bcmMplsSpecialLabelTypeEntropy) {
    423          if (!(ptr->entropy_label_ref_count)) {
    424             return BCM_E_NOT_FOUND;
    425         }
    426 
    427         BCM_IF_ERROR_RETURN(READ_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, &val));
    428 
    429         label_info->exp = soc_reg_field_get(unit,
    430             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, EXPf);
    431 
    432         label_info->ttl = soc_reg_field_get(unit,
    433             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, TTLf);
    434 
    435         label_info->label_value = soc_reg_field_get(unit,
    436             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, LABEL_OFFSETf);
    437 
    438         if (soc_reg_field_get(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, val,
    439                 EXP_SOURCEf)) {
    440 
    441             label_info->flags |= BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP;
    442         }
    443 
    444         if (soc_reg_field_get(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, val,
    445                 TTL_SOURCEf)) {
    446 
    447             label_info->flags |= BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL;
    448         }
    449     }
    450 
    451     return rv;
    452 }
    453 
    454 /*
    455  * Function:
    456  *      bcmi_mpls_special_label_egress_delete
    457  * Purpose:
    458  *      Delete an MPLS entropy/special label in
    459  *      MPLS stack for egress tunnel encap.
    460  * Parameters:
    461  *      unit       - (IN) Device Number
    462  *      label_type - (IN) type of label
    463  *      label_info - (IN) Info about special label.
    464  * Returns:
    465  *      BCM_E_XXX
    466  */
    467 
    468 int
    469 bcmi_mpls_special_label_egress_delete(int unit,
    470             bcm_mpls_special_label_type_t label_type,
    471             bcm_mpls_special_label_t label_info)
    472 {
    473     int rv = BCM_E_NONE;
    474     uint64 val64;
    475     uint32 val = 0;
    476     bcmi_mpls_special_label_egress_t *ptr;
    477 
    478     COMPILER_64_ZERO(val64);
    479 
    480     ptr = (&(bcmi_special_label_egress_state[unit]));
    481 
    482     /* Only Special and entropy labels can be added here*/
    483     if ((label_type != bcmMplsSpecialLabelTypeSpecial) &&
    484         (label_type != bcmMplsSpecialLabelTypeEntropy)) {
    485 
    486         return BCM_E_PARAM;
    487     }
    488 
    489     if (label_type == bcmMplsSpecialLabelTypeSpecial) {
    490 
    491         /* If there is no entry to delete then reutrn not found. */
    492         if (!(ptr->special_label_ref_count)) {
    493             return BCM_E_NOT_FOUND;
    494         }
    495 
    496 
    497         COMPILER_64_ZERO(val64);
    498         BCM_IF_ERROR_RETURN(READ_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, &val64));
    499 
    500         if (label_info.exp != soc_reg64_field32_get(unit,
    501             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, EXPf)) {
    502             return BCM_E_NOT_FOUND;
    503         }
    504 
    505         if (label_info.ttl != soc_reg64_field32_get(unit,
    506             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, TTLf)) {
    507             return BCM_E_NOT_FOUND;
    508         }
    509 
    510         if (label_info.label_value != soc_reg64_field32_get(unit,
    511             EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64, LABEL_VALUEf)) {
    512             return BCM_E_NOT_FOUND;
    513         }
    514 
    515         if (soc_reg64_field32_get(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64,
    516                 EXP_SOURCEf)) {
    517 
    518             if (!(label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP)) {
    519                 return BCM_E_NOT_FOUND;
    520             }
    521         } else if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP) {
    522             return BCM_E_NOT_FOUND;
    523         }
    524 
    525 
    526         if (soc_reg64_field32_get(unit, EGR_MPLS_SPECIAL_LABEL_CONTROLr, val64,
    527                 TTL_SOURCEf)) {
    528 
    529             if (!(label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL)) {
    530                 return BCM_E_NOT_FOUND;
    531             }
    532         } else if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL) {
    533             return BCM_E_NOT_FOUND;
    534         }
    535 
    536         ptr->special_label_ref_count--;
    537         if (ptr->special_label_ref_count > 0) {
    538             return BCM_E_NONE;
    539         }
    540 
    541         COMPILER_64_ZERO(val64);
    542         rv = WRITE_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, val64);
    543 
    544     } else {
    545         /* If there is no entry to delete then reutrn not found. */
    546         if (!(ptr->entropy_label_ref_count)) {
    547             return BCM_E_NOT_FOUND;
    548         }
    549 
    550        BCM_IF_ERROR_RETURN(READ_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, &val));
    551 
    552         if (label_info.exp != soc_reg_field_get(unit,
    553             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, EXPf)) {
    554             return BCM_E_NOT_FOUND;
    555         }
    556 
    557         if (label_info.ttl != soc_reg_field_get(unit,
    558             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, TTLf)) {
    559             return BCM_E_NOT_FOUND;
    560         }
    561 
    562         if (label_info.label_value != soc_reg_field_get(unit,
    563             EGR_MPLS_ENTROPY_LABEL_CONTROLr, val, LABEL_OFFSETf)) {
    564             return BCM_E_NOT_FOUND;
    565         }
    566 
    567         if (soc_reg_field_get(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, val,
    568                 EXP_SOURCEf)) {
    569 
    570             if (!(label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP)) {
    571                 return BCM_E_NOT_FOUND;
    572             }
    573         } else if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_EXP) {
    574             return BCM_E_NOT_FOUND;
    575         }
    576 
    577 
    578         if (soc_reg_field_get(unit, EGR_MPLS_ENTROPY_LABEL_CONTROLr, val,
    579                 TTL_SOURCEf)) {
    580 
    581             if (!(label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL)) {
    582                 return BCM_E_NOT_FOUND;
    583             }
    584         } else if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_USE_TABLE_TTL) {
    585             return BCM_E_NOT_FOUND;
    586         }
    587 
    588 
    589         ptr->entropy_label_ref_count--;
    590         if (ptr->entropy_label_ref_count > 0) {
    591             return BCM_E_NONE;
    592         }
    593         val = 0;
    594         rv = WRITE_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, val);
    595     }
    596 
    597     return rv;
    598 }
    599 /*
    600  * Function:
    601  *      bcmi_mpls_special_label_egress_delete_all
    602  * Purpose:
    603  *      Delete MPLS entropy/special labels in
    604  *      MPLS stack for egress tunnel encap.
    605  * Parameters:
    606  *      unit       - (IN) Device Number
    607  *      label_type - (IN) type of label
    608  *      label_info - (IN) Info about special label.
    609  * Returns:
    610  *      BCM_E_XXX
    611  */
    612 int
    613 bcmi_mpls_special_label_egress_delete_all(int unit)
    614 
    615 {
    616 
    617     uint64 val64;
    618     uint32 val = 0;
    619     bcmi_mpls_special_label_egress_t *ptr;
    620 
    621     /* pick up the local state. */
    622     ptr = (&(bcmi_special_label_egress_state[unit]));
    623 
    624     /* First delete the special label.*/
    625     COMPILER_64_ZERO(val64);
    626     BCM_IF_ERROR_RETURN(WRITE_EGR_MPLS_SPECIAL_LABEL_CONTROLr(unit, val64));
    627     ptr->special_label_ref_count = 0;
    628 
    629     /* Now delete the Entropy label.*/
    630     BCM_IF_ERROR_RETURN(WRITE_EGR_MPLS_ENTROPY_LABEL_CONTROLr(unit, val));
    631     ptr->entropy_label_ref_count = 0;
    632 
    633     return BCM_E_NONE;
    634 }
    635 /*
    636  * Function:
    637  *      bcmi_mpls_special_label_egress_traverse
    638  * Purpose:
    639  *      Traverse MPLS entropy/special labels in
    640  *      MPLS stack for egress tunnel encap.
    641  * Parameters:
    642  *      unit       - (IN) Device Number
    643  *      label_type - (IN) type of label
    644  *      cb        - (IN) callback from user.
    645  *      user_data  - (INOUT) user provided data
    646  * Returns:
    647  *      BCM_E_XXX
    648  */
    649 
    650 int 
    651 bcmi_mpls_special_label_egress_traverse(
    652     int unit, 
    653     bcm_mpls_special_label_egress_traverse_cb cb, 
    654     void *user_data)
    655 {
    656     int rv = BCM_E_NONE;
    657     bcm_mpls_special_label_t label_info;
    658     int i = 0;
    659     bcmi_mpls_special_label_egress_t *ptr;
    660     bcm_mpls_special_label_type_t label_type[2] = 
    661                         {bcmMplsSpecialLabelTypeSpecial,
    662                          bcmMplsSpecialLabelTypeEntropy};
    663 
    664     ptr = (&(bcmi_special_label_egress_state[unit]));
    665 
    666 
    667     if (cb == NULL) {
    668         return BCM_E_PARAM;
    669     }
    670 
    671     /* run loop for both label types to get info */
    672     for (; i<2; i++) {
    673 
    674     if (label_type[i] == bcmMplsSpecialLabelTypeSpecial) {
    675         if (ptr->special_label_ref_count == 0) {
    676             continue;
    677         }
    678     } else {
    679         if (ptr->entropy_label_ref_count == 0) {
    680             continue;
    681         }
    682     }
    683     sal_memset(&label_info, 0, sizeof(label_info));
    684 
    685     BCM_IF_ERROR_RETURN(
    686         bcmi_mpls_special_label_egress_get(unit,
    687             label_type[i], &label_info));
    688 
    689     rv = cb(unit, &(label_type[i]), &label_info, user_data);
    690 #ifdef BCM_CB_ABORT_ON_ERR
    691     if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
    692         return rv;
    693     }
    694 #endif
    695     }
    696 
    697     return rv;
    698 }
    699 
    700 /*
    701  * Function:
    702  *      bcmi_mpls_special_label_push_action_set
    703  * Description:
    704  *      Set mpls push action in MPLS objects.
    705  *      going into MPLS tunnel.
    706  *
    707  * Parameters:
    708  *      unit                - (IN) unit number
    709  *      element             - (IN) MPLS object
    710  *      push_type           - (OUT) push action
    711  * Return Value:
    712  *      BCM_E_XXX
    713  * Notes:
    714  */
    715 int
    716 bcmi_mpls_special_label_push_action_set(int unit,
    717             bcm_mpls_special_label_push_element_t *element,
    718             bcm_mpls_special_label_push_type_t push_type)
    719 {
    720     int vp=0xFFFF;
    721     ing_dvp_table_entry_t dvp;
    722     bcm_if_t nh_index;
    723     egr_mpls_vc_and_swap_label_table_entry_t vc_entry;
    724     egr_l3_next_hop_entry_t egr_nh;
    725     int rv = BCM_E_NONE;
    726     int vc_swap_idx = 0, new_vc_swap_index = -1;
    727     _bcm_tr_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
    728     int action = 0;
    729 
    730     if (element == NULL) {
    731         return BCM_E_PARAM;
    732     }
    733 
    734     if (push_type > bcmMplsSpecialLabelPushSpecialPlusEntropy) {
    735         return BCM_E_PARAM;
    736     }
    737 
    738     if (element->gport != BCM_GPORT_INVALID) {
    739 
    740         if (!BCM_GPORT_IS_MPLS_PORT(element->gport)) {
    741             return BCM_E_PARAM;
    742         }
    743 
    744         vp = BCM_GPORT_MPLS_PORT_ID_GET(element->gport);
    745 
    746         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
    747             return BCM_E_PARAM;
    748         }
    749 
    750         BCM_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
    751 
    752         /* Get nh index from the DVP table */
    753         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    754     } else {
    755 
    756         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, element->egr_obj_id) ||
    757             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, element->egr_obj_id)) {
    758 
    759             /* Extract next hop index from unipath egress object. */
    760             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, element->egr_obj_id)) {
    761                 nh_index = element->egr_obj_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
    762             } else {
    763                 nh_index = element->egr_obj_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
    764             }
    765         } else {
    766             return BCM_E_PARAM;
    767         }
    768     }
    769 
    770     BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    771                           nh_index, &egr_nh));
    772 
    773     /* First check if this is the correct MPLS next hop */
    774     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, DATA_TYPEf) != 1) {
    775         return BCM_E_PARAM;
    776     }
    777 
    778     vc_swap_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    779                           MPLS__VC_AND_SWAP_INDEXf);
    780  
    781     BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    782                           MEM_BLOCK_ANY, vc_swap_idx, &vc_entry));
    783 
    784 
    785     soc_mem_field32_set(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    786                           &vc_entry, SPECIAL_LABEL_PUSH_TYPEf, push_type);
    787 
    788     /* Action for sw state management */
    789     action = mpls_info->egr_vc_swap_lbl_action[vc_swap_idx];
    790 
    791     /* Now we need to look if someone has similar entry like this */
    792     if ( mpls_info->vc_swap_ref_count[vc_swap_idx] > 1) {
    793 
    794         /* we have more objects pointing to it. so we can not update it just like that.
    795          * Look for some similar entry.
    796          * The new index is ref counted inside the below method only.
    797          * just remove the ref-count from old index once everything is set.
    798          */
    799         BCM_IF_ERROR_RETURN(_bcm_tr_mpls_get_vc_and_swap_table_index (unit, 0,
    800                            NULL, NULL, NULL, &vc_entry,
    801                            action,
    802                            &new_vc_swap_index));
    803 
    804         if ((new_vc_swap_index != -1) && (new_vc_swap_index != vc_swap_idx)) {
    805             /* write vc_entry into the new index */
    806             rv = soc_mem_write(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    807                           MEM_BLOCK_ALL, new_vc_swap_index, &vc_entry);
    808 
    809             if (BCM_FAILURE(rv)) {
    810                 goto cleanup;
    811             }
    812 
    813             /* Got new index. Point NH to it.*/
    814             soc_EGR_L3_NEXT_HOPm_field32_set(unit, &egr_nh,
    815                           MPLS__VC_AND_SWAP_INDEXf, new_vc_swap_index);
    816 
    817             /* Lock the memory before writing. */
    818             soc_mem_lock(unit, EGR_L3_NEXT_HOPm);
    819 
    820             /* Write new index in NH */
    821             rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ALL,
    822                            nh_index, &egr_nh);
    823 
    824             soc_mem_unlock(unit, EGR_L3_NEXT_HOPm);
    825             if (BCM_FAILURE(rv)) {
    826                 goto cleanup;
    827             }
    828         }
    829         if (new_vc_swap_index != -1) {
    830             /* Remove the reference from old index */
    831             (void)_bcm_tr_mpls_vc_and_swap_ref_count_adjust(unit,
    832                 vc_swap_idx, -1);
    833 
    834             mpls_info->egr_vc_swap_lbl_action[new_vc_swap_index] = action;
    835         }
    836     } else {
    837 
    838         BCM_IF_ERROR_RETURN(soc_mem_write(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    839                           MEM_BLOCK_ALL, vc_swap_idx, &vc_entry));
    840     }
    841 
    842     return rv;
    843 
    844 cleanup:
    845 
    846     if (new_vc_swap_index != -1) {
    847         (void)_bcm_tr_mpls_vc_and_swap_ref_count_adjust (unit,
    848                              new_vc_swap_index, -1);
    849         (void) _bcm_tr_mpls_vc_and_swap_table_index_reset (unit,
    850                              new_vc_swap_index);
    851     }
    852 
    853 
    854     return rv;
    855 }
    856 
    857 /*
    858  * Function:
    859  *      bcmi_mpls_special_label_push_action_get
    860  * Description:
    861  *      Get mpls push action in MPLS objects.
    862  *      going into MPLS tunnel.
    863  *
    864  * Parameters:
    865  *      unit                - (IN) unit number
    866  *      element             - (IN) MPLS object
    867  *      push_type           - (OUT) push action
    868  * Return Value:
    869  *      BCM_E_XXX
    870  * Notes:
    871  */
    872 int
    873 bcmi_mpls_special_label_push_action_get(int unit,
    874             bcm_mpls_special_label_push_element_t *element,
    875             bcm_mpls_special_label_push_type_t *push_type)
    876 {
    877     int vp=0xFFFF;
    878     ing_dvp_table_entry_t dvp;
    879     bcm_if_t nh_index;
    880     egr_mpls_vc_and_swap_label_table_entry_t vc_entry;
    881     egr_l3_next_hop_entry_t egr_nh;
    882     int vc_swap_idx = 0;
    883 
    884     if (element == NULL) {
    885         return BCM_E_PARAM;
    886     }
    887 
    888     if (push_type == NULL) {
    889         return BCM_E_PARAM;
    890     }
    891 
    892     if (element->gport != BCM_GPORT_INVALID) {
    893 
    894         if (!BCM_GPORT_IS_MPLS_PORT(element->gport)) {
    895             return BCM_E_PARAM;
    896         }
    897 
    898         vp = BCM_GPORT_MPLS_PORT_ID_GET(element->gport);
    899 
    900         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
    901             return BCM_E_PARAM;
    902         }
    903 
    904         BCM_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
    905 
    906         /* Get nh index from the DVP table */
    907         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    908     } else {
    909         nh_index = element->egr_obj_id;
    910 
    911         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, element->egr_obj_id) ||
    912             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, element->egr_obj_id)) {
    913 
    914             /* Extract next hop index from unipath egress object. */
    915             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, element->egr_obj_id)) {
    916                 nh_index = element->egr_obj_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
    917             } else {
    918                 nh_index = element->egr_obj_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
    919             }
    920         } else {
    921             return BCM_E_PARAM;
    922         }
    923     }
    924 
    925     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    926     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    927                                       nh_index, &egr_nh));
    928 
    929     /* First check if this is the correct MPLS next hop */
    930     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, DATA_TYPEf) != 1) {
    931         return BCM_E_PARAM;
    932     }
    933 
    934     vc_swap_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    935                                       MPLS__VC_AND_SWAP_INDEXf);
    936       
    937     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    938                                       MEM_BLOCK_ANY, vc_swap_idx, &vc_entry));
    939 
    940     *push_type = soc_mem_field32_get(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    941                                         &vc_entry, SPECIAL_LABEL_PUSH_TYPEf);
    942 
    943     return BCM_E_NONE;
    944 }
    945 
    946 /*
    947  * Function:
    948  *      bcmi_mpls_special_label_move_entries
    949  * Description:
    950  *      In order to keep precedence of labels, we
    951  *      need to move entries.
    952  *
    953  * Parameters:
    954  *      unit          - (IN) unit number
    955  *      from          - (IN) Move from
    956  *      to            - (OUT) Move to
    957  * Return Value:
    958  *      BCM_E_XXX
    959  * Notes:
    960  */
    961 int
    962 bcmi_mpls_special_label_move_entries(int unit, int from, int to)
    963 {
    964 
    965     special_label_control_entry_t spl_label_entry;
    966     soc_mem_t mem = SPECIAL_LABEL_CONTROLm;
    967     int i = 0;
    968     uint32 total_moves = 0;
    969     int num_entry;
    970     bcmi_mpls_special_label_control_t *ptr;
    971 
    972     ptr = bcmi_special_label_precedence_state[unit];
    973 
    974     total_moves = ((to>from) ? (to - from) : (from - to));
    975     num_entry = soc_mem_index_count(unit, SPECIAL_LABEL_CONTROLm);
    976     if (total_moves > num_entry) {
    977         return BCM_E_PARAM;
    978     }
    979 
    980 if (from != -1) {
    981     if (to < from) {
    982         /* move entries up first*/
    983         while (total_moves) {
    984 
    985             BCM_IF_ERROR_RETURN(
    986                 soc_mem_read(unit, mem, MEM_BLOCK_ALL, (to + i + 1), 
    987                     &spl_label_entry));
    988 
    989             BCM_IF_ERROR_RETURN(
    990                 soc_mem_write(unit, mem, MEM_BLOCK_ALL, (to + i), &spl_label_entry));
    991 
    992             sal_memcpy((&(ptr[to + i])), (&(ptr[to + i + 1])), 
    993                 sizeof(bcmi_mpls_special_label_control_t));
    994 
    995             total_moves--;
    996             i++;
    997        }
    998     } else {
    999         while (total_moves) {
   1000 
   1001             BCM_IF_ERROR_RETURN(
   1002                 soc_mem_read(unit, mem, MEM_BLOCK_ALL, 
   1003                     (to - i - 1), &spl_label_entry));
   1004 
   1005             BCM_IF_ERROR_RETURN(
   1006                 soc_mem_write(unit, mem, MEM_BLOCK_ALL, 
   1007                     (to - i), &spl_label_entry));
   1008 
   1009             sal_memcpy((&(ptr[to - i])), (&(ptr[to - i - 1])),
   1010                 sizeof(bcmi_mpls_special_label_control_t));
   1011 
   1012             total_moves--;
   1013             i++;
   1014         }
   1015     }
   1016     sal_memset((&(ptr[from])), 0,
   1017         sizeof(bcmi_mpls_special_label_control_t));
   1018 } 
   1019    
   1020     return BCM_E_NONE;
   1021 }
   1022 
   1023 /*
   1024  * Function:
   1025  *      bcmi_mpls_special_label_make_slot
   1026  * Description:
   1027  *      Make slot for label identifiers in order of precedence.
   1028  *
   1029  * Parameters:
   1030  *      unit             - (IN) unit number
   1031  *      mpls_label       - (IN) label value
   1032  *      mpls_label_mask  - (IN) Mask of label
   1033  *      slot             - (OUT) slot to add entry
   1034  * Return Value:
   1035  *      BCM_E_XXX
   1036  * Notes:
   1037  */
   1038 int
   1039 bcmi_mpls_special_label_make_slot(int unit, uint32 mpls_label,
   1040                     uint32 mpls_label_mask, int *slot)
   1041 {
   1042 
   1043     soc_mem_t mem;
   1044     bcmi_mpls_special_label_control_t *ptr;
   1045     int num_entry = 0, i;
   1046     int free_slot = -1, move_start = -1;
   1047 
   1048     mem = SPECIAL_LABEL_CONTROLm;
   1049     ptr = bcmi_special_label_precedence_state[unit];
   1050 
   1051     num_entry = soc_mem_index_count(unit, mem);
   1052 
   1053     /* First get the slot where it should go */
   1054     for (i = 0; i < num_entry; i++) {
   1055 
   1056         if (!(ptr[i].valid)) {
   1057             if (free_slot == -1) {
   1058                 free_slot = i;
   1059             }
   1060             continue;
   1061         }
   1062 
   1063         if ((mpls_label & mpls_label_mask) <
   1064             (ptr[i].label_value &  ptr[i].label_mask)) {
   1065             continue;
   1066         }
   1067 
   1068         if ((mpls_label & mpls_label_mask) ==
   1069             (ptr[i].label_value & ptr[i].label_mask)) {
   1070             if (mpls_label < ptr[i].label_value) {
   1071                 continue;
   1072             }
   1073         }
   1074 
   1075         if (free_slot != -1) {
   1076             break;
   1077         }
   1078 
   1079         /* if we are here then we have got the slot where we can put values*/
   1080         if (move_start == -1) {
   1081             move_start = i;
   1082         }
   1083 
   1084     }
   1085 
   1086     if (free_slot == -1) {
   1087         /* we do not have any free slot left */
   1088         return BCM_E_RESOURCE;
   1089     }
   1090 
   1091     /* If there is nothing to move then just return free index */
   1092     *slot = ((move_start == -1) ? free_slot : move_start);
   1093 
   1094     /* When free index is before move index, then we need to move
   1095      * one less entry as logic will give index to smaller entry.
   1096      * In case free index is after move index, we will have to manage
   1097      * entries from move index so we are okay.
   1098      */
   1099     move_start = ((free_slot < move_start) ? (move_start - 1) : move_start);
   1100     bcmi_mpls_special_label_move_entries(unit, move_start, free_slot);
   1101 
   1102     return BCM_E_NONE;
   1103 }
   1104 
   1105 
   1106 /*
   1107  * Function:
   1108  *      bcmi_mpls_special_label_match_entry
   1109  * Description:
   1110  *      Match incoming entry with label identifiers in h/w.
   1111  *
   1112  * Parameters:
   1113  *      unit             - (IN) unit number
   1114  *      label type       - (IN) Type of label to match
   1115  *      mpls_label       - (IN) label value
   1116  *      mpls_label_mask  - (IN) Mask of label
   1117  *      slot             - (OUT) matched slot
   1118  * Return Value:
   1119  *      BCM_E_XXX
   1120  * Notes:
   1121  */
   1122 
   1123 int
   1124 bcmi_mpls_special_label_match_entry(int unit, int label_type, uint32 mpls_label,
   1125                     uint32 mpls_label_mask, int *slot)
   1126 { 
   1127 
   1128     soc_mem_t mem;
   1129     int index_min = 0;
   1130     int index_max = 0;
   1131     bcmi_mpls_special_label_control_t *ptr;
   1132     int i = 0;
   1133 
   1134     mem = SPECIAL_LABEL_CONTROLm;
   1135     index_min = soc_mem_index_min(unit, mem);
   1136     index_max = soc_mem_index_max(unit, mem);
   1137 
   1138     ptr = bcmi_special_label_precedence_state[unit];
   1139 
   1140     for (i = index_min; i <= index_max; i++) {
   1141 
   1142         if (!(ptr[i].valid)) {
   1143             continue;
   1144         }
   1145 
   1146         if (ptr[i].label_type != label_type) {
   1147             continue;
   1148         }
   1149 
   1150         if ((mpls_label == ptr[i].label_value) &&
   1151             (mpls_label_mask == ptr[i].label_mask)) {
   1152             *slot = i;
   1153             return BCM_E_NONE;
   1154         }
   1155 
   1156     }
   1157 
   1158     return BCM_E_NOT_FOUND;
   1159 }
   1160 /*
   1161  * Function:
   1162  *      bcmi_mpls_special_label_get_slot 
   1163  * Description:
   1164  *      Get slot to add identifier entry of special label.
   1165  *
   1166  * Parameters:
   1167  *      unit                - (IN) unit number
   1168  *      label_value         - (IN) MPLS Label
   1169  *      label_mask          - (IN) MPLS mask
   1170  *      slot                - (OUT) slot number
   1171  * Return Value:
   1172  *      BCM_E_XXX
   1173  * Notes:
   1174  */
   1175 int
   1176 bcmi_mpls_special_label_get_slot(int unit, int label_type,
   1177                     bcm_mpls_special_label_t label_info,  uint32 mpls_label,
   1178                     uint32 mpls_label_mask, int *slot, int *new_slot)
   1179 {
   1180     int rv = BCM_E_NONE;
   1181     special_label_control_entry_t entry;
   1182 
   1183     /* first match the entry and check if matching entry is there */
   1184     rv = bcmi_mpls_special_label_match_entry(unit, label_type, 
   1185                 mpls_label, mpls_label_mask, slot);
   1186     if (BCM_SUCCESS(rv)) {
   1187         /* Match the complete entry */
   1188         BCM_IF_ERROR_RETURN(READ_SPECIAL_LABEL_CONTROLm(unit, MEM_BLOCK_ALL,
   1189             *slot, &entry));
   1190 
   1191         if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1192             CURRENT_LABEL_HASH_ACTIONf)) {
   1193 
   1194             if (!(label_info.flags & 
   1195                 BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_HASH)) {
   1196                 return BCM_E_EXISTS;
   1197             }
   1198         } else if (label_info.flags &
   1199                 BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_HASH) {
   1200 
   1201                 return BCM_E_EXISTS;
   1202         }
   1203 
   1204 
   1205         if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1206             NEXT_LABEL_HASH_ACTIONf)) {
   1207 
   1208             if (!(label_info.flags &
   1209                 BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_HASH)) {
   1210                 return BCM_E_EXISTS;
   1211             }
   1212         } else if (label_info.flags &
   1213                 BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_HASH) {
   1214                 return BCM_E_EXISTS;
   1215         }
   1216 
   1217         if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1218            CURRENT_LABEL_LOOKUP_ACTIONf)) {
   1219 
   1220             if (!(label_info.flags &
   1221                 BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_LKUP)) {
   1222                 return BCM_E_EXISTS;
   1223             }
   1224         } else if (label_info.flags &
   1225                 BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_LKUP) {
   1226                 return BCM_E_EXISTS;
   1227         }
   1228 
   1229 
   1230         if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1231             NEXT_LABEL_LOOKUP_ACTIONf)) {
   1232 
   1233             if (!(label_info.flags &
   1234                 BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_LKUP)) {
   1235                 return BCM_E_EXISTS;
   1236             }
   1237         } else if (label_info.flags &
   1238                 BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_LKUP) {
   1239                 return BCM_E_EXISTS;
   1240         }
   1241 
   1242 
   1243         if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1244             LABEL_INHERIT_ENf)) {
   1245 
   1246             if (!(label_info.flags &
   1247                 BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE)) {
   1248                 return BCM_E_EXISTS;
   1249             }
   1250        } else if (label_info.flags &
   1251                 BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE) {
   1252                 return BCM_E_EXISTS;
   1253         }
   1254 
   1255     }
   1256 
   1257     if (rv != BCM_E_NOT_FOUND) {
   1258         *new_slot = 0;
   1259         return rv;
   1260     }
   1261 
   1262     /*
   1263      * We have not got matching entry.
   1264      * we need to check if we can fit it somewhere.
   1265      */
   1266     rv = bcmi_mpls_special_label_make_slot(unit, mpls_label, mpls_label_mask,
   1267                 slot);
   1268     *new_slot = 1;
   1269     return rv;
   1270 }
   1271 
   1272 /*
   1273  * Function:
   1274  *      bcmi_mpls_special_label_identifier_add
   1275  * Description:
   1276  *      Add identifier entry of special label.
   1277  *
   1278  * Parameters:
   1279  *      unit                - (IN) unit number
   1280  *      label_type          - (IN) MPLS Label
   1281  *      label_info          - (IN) MPLS Gport
   1282  * Return Value:
   1283  *      BCM_E_XXX
   1284  * Notes:
   1285  */
   1286 int
   1287 bcmi_mpls_special_label_identifier_add(int unit,
   1288             bcm_mpls_special_label_type_t label_type,
   1289             bcm_mpls_special_label_t label_info)
   1290 {
   1291 
   1292     uint32 mpls_label = 0, mpls_label_mask = 0;
   1293     int rv = BCM_E_NONE;
   1294     special_label_control_entry_t entry;
   1295     int slot = -1, new_slot = -1;
   1296     bcmi_mpls_special_label_control_t *ptr;
   1297     int bos_value = 0;
   1298     int bos_mask = 0;
   1299 
   1300     if (!BCMI_MPLS_LABEL_ID_VALID(label_info.label_value)) {
   1301         return BCM_E_PARAM;
   1302     }
   1303 
   1304     if (!BCMI_MPLS_EXP_VALID(label_info.exp)) {
   1305         return BCM_E_PARAM;
   1306     }
   1307 
   1308     if (!BCMI_MPLS_TTL_VALID(label_info.ttl)) {
   1309         return BCM_E_PARAM;
   1310     }
   1311 
   1312     /* Check for range of mask also. */
   1313     if (label_info.label_mask > BCMI_MPLS_LABEL_MASK_MAX) {
   1314         return BCM_E_PARAM;
   1315     }
   1316 
   1317     if (label_info.exp_mask > BCMI_MPLS_EXP_MASK_MAX) {
   1318         return BCM_E_PARAM;
   1319     }
   1320 
   1321     if (label_info.ttl_mask > BCMI_MPLS_TTL_MASK_MAX) {
   1322         return BCM_E_PARAM;
   1323     }
   1324 
   1325     if (label_type > bcmMplsSpecialLabelTypeEntropy) {
   1326         return BCM_E_PARAM;
   1327     }
   1328 
   1329     ptr = bcmi_special_label_precedence_state[unit];
   1330 
   1331     bos_value = ((label_info.flags & BCM_MPLS_SPECIAL_LABEL_BOS_PRESENT) ? 1:0);
   1332     bos_mask  = ((label_info.flags & BCM_MPLS_SPECIAL_LABEL_BOS_MASKED) ? 1:0);
   1333 
   1334     mpls_label = BCMI_MPLS_CONSTRUCT_LABEL(
   1335                  label_info.label_value,label_info.exp,label_info.ttl,
   1336                  bos_value);
   1337 
   1338     mpls_label_mask = BCMI_MPLS_CONSTRUCT_LABEL(
   1339                       label_info.label_mask, label_info.exp_mask,
   1340                       label_info.ttl_mask,
   1341                       bos_mask);
   1342 
   1343     /* get matching entry or new slot for adding new entry */
   1344     BCM_IF_ERROR_RETURN(bcmi_mpls_special_label_get_slot(unit, label_type, label_info,
   1345                     mpls_label, mpls_label_mask, &slot, &new_slot));
   1346 
   1347     /* Check if we found some old slot */
   1348     if (!new_slot) {
   1349         ptr[slot].ref_count++;
   1350         return BCM_E_NONE;
   1351     }
   1352     /* For new slots, start writing the entry */
   1353     sal_memset(&entry, 0, sizeof(special_label_control_entry_t));
   1354     soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry, LABEL_VALUEf, 
   1355                     mpls_label);
   1356     soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry, LABEL_VALUE_MASKf,
   1357                     mpls_label_mask);
   1358 
   1359     soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry, CURRENT_LABEL_TYPEf,
   1360                     label_type);
   1361 
   1362     if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_HASH) {
   1363         soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1364                     CURRENT_LABEL_HASH_ACTIONf, 1);
   1365     }
   1366 
   1367     if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_HASH) {
   1368         soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1369                     NEXT_LABEL_HASH_ACTIONf, 1);
   1370     }
   1371 
   1372     if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_LKUP) {
   1373         soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1374                     CURRENT_LABEL_LOOKUP_ACTIONf, 1);
   1375     }
   1376 
   1377     if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_LKUP) {
   1378         soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1379                     NEXT_LABEL_LOOKUP_ACTIONf, 1);
   1380     }
   1381     if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE) {
   1382         soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1383             LABEL_INHERIT_ENf, 1);
   1384     }
   1385 
   1386     if (label_type == bcmMplsSpecialLabelTypeNone) {
   1387         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE) {
   1388             soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1389                     INHERITANCE_TYPEf, 0);
   1390         }
   1391     } else {
   1392         if (label_info.flags & BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE) {
   1393             soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry,
   1394                     INHERITANCE_TYPEf, 1);
   1395         }
   1396     }
   1397 
   1398     soc_SPECIAL_LABEL_CONTROLm_field32_set(unit, &entry, VALIDf, 1);
   1399 
   1400     rv = WRITE_SPECIAL_LABEL_CONTROLm(unit, MEM_BLOCK_ALL, slot, &entry);
   1401     if (BCM_SUCCESS(rv)) {
   1402         /* Clear the s/w state first */
   1403         sal_memset((&(ptr[slot])), 0, sizeof(bcmi_mpls_special_label_control_t));
   1404 
   1405         if (rv == BCM_E_NONE) {
   1406             ptr[slot].label_value = mpls_label;
   1407             ptr[slot].label_mask  = mpls_label_mask;
   1408             ptr[slot].label_type  = label_type;
   1409             ptr[slot].valid = 1;
   1410             ptr[slot].ref_count = 1;
   1411         }
   1412     }
   1413 
   1414     return rv;
   1415 }
   1416 
   1417 /*
   1418  * Function:
   1419  *      bcmi_mpls_special_label_identifier_get
   1420  * Description:
   1421  *      Get identifier entry of special label.
   1422  *
   1423  * Parameters:
   1424  *      unit                - (IN) unit number
   1425  *      label_type          - (IN) MPLS Label
   1426  *      label_info          - (IN) MPLS Gport
   1427  * Return Value:
   1428  *      BCM_E_XXX
   1429  * Notes:
   1430  */
   1431 int
   1432 bcmi_mpls_special_label_identifier_get(int unit,
   1433             bcm_mpls_special_label_type_t label_type,
   1434             bcm_mpls_special_label_t *label_info)
   1435 {
   1436     int slot = -1;
   1437     special_label_control_entry_t entry;
   1438     uint32 mpls_label = 0;
   1439     uint32 mpls_label_mask = 0;
   1440     int bos_value = 0;
   1441     int bos_mask = 0;
   1442 
   1443     if (label_info == NULL) {
   1444         return BCM_E_PARAM;
   1445     }
   1446 
   1447     if (label_type > bcmMplsSpecialLabelTypeEntropy) {
   1448         return BCM_E_PARAM;
   1449     }
   1450 
   1451     bos_value = 
   1452         ((label_info->flags & BCM_MPLS_SPECIAL_LABEL_BOS_PRESENT) ? 1:0);
   1453     bos_mask  = 
   1454         ((label_info->flags & BCM_MPLS_SPECIAL_LABEL_BOS_MASKED) ? 1:0);
   1455 
   1456     mpls_label = BCMI_MPLS_CONSTRUCT_LABEL(
   1457                  label_info->label_value, label_info->exp, label_info->ttl,
   1458                  bos_value);
   1459 
   1460     mpls_label_mask = BCMI_MPLS_CONSTRUCT_LABEL(
   1461                       label_info->label_mask, label_info->exp_mask,
   1462                       label_info->ttl_mask,
   1463                       bos_mask);
   1464 
   1465     /* get matching entry or new slot for adding new entry */
   1466     BCM_IF_ERROR_RETURN(bcmi_mpls_special_label_match_entry(unit, label_type,
   1467         mpls_label, mpls_label_mask, &slot));
   1468 
   1469     sal_memset(&entry, 0, sizeof(special_label_control_entry_t));
   1470     BCM_IF_ERROR_RETURN(READ_SPECIAL_LABEL_CONTROLm(unit, MEM_BLOCK_ALL, 
   1471         slot, &entry)); 
   1472 
   1473     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry, 
   1474         CURRENT_LABEL_HASH_ACTIONf)) {
   1475 
   1476         label_info->flags |= BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_HASH;
   1477     }
   1478 
   1479     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1480         NEXT_LABEL_HASH_ACTIONf)) {
   1481         label_info->flags |= BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_HASH;
   1482     }
   1483 
   1484     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry, 
   1485         CURRENT_LABEL_LOOKUP_ACTIONf)) {
   1486 
   1487         label_info->flags |= BCM_MPLS_SPECIAL_LABEL_CURR_LABEL_EXCLUDE_LKUP;
   1488     }
   1489 
   1490     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1491         NEXT_LABEL_LOOKUP_ACTIONf)) {
   1492         label_info->flags |= BCM_MPLS_SPECIAL_LABEL_NEXT_LABEL_EXCLUDE_LKUP;
   1493     }
   1494 
   1495     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1496         LABEL_INHERIT_ENf)) {
   1497         label_info->flags |=  BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE;
   1498     }
   1499 
   1500     if (soc_SPECIAL_LABEL_CONTROLm_field32_get(unit, &entry,
   1501                 INHERITANCE_TYPEf)) {
   1502 
   1503         label_info->flags |= BCM_MPLS_SPECIAL_LABEL_INHERITANCE_ENABLE;
   1504     }
   1505 
   1506     return BCM_E_NONE;
   1507 }
   1508 
   1509 /*
   1510  * Function:
   1511  *      bcmi_mpls_special_label_identifier_delete
   1512  * Description:
   1513  *      Delete identifiers of special label.
   1514  *
   1515  * Parameters:
   1516  *      unit                - (IN) unit number
   1517  *      label_type          - (IN) MPLS Label
   1518  *      label_info          - (IN) MPLS Gport
   1519  * Return Value:
   1520  *      BCM_E_XXX
   1521  * Notes:
   1522  */
   1523 int
   1524 bcmi_mpls_special_label_identifier_delete(int unit,
   1525             bcm_mpls_special_label_type_t label_type,
   1526             bcm_mpls_special_label_t label_info)
   1527 {
   1528     int slot = -1;
   1529     int rv = BCM_E_NONE;
   1530     special_label_control_entry_t entry;
   1531     bcmi_mpls_special_label_control_t *ptr;
   1532     uint32 mpls_label = 0;
   1533     uint32 mpls_label_mask = 0;
   1534     int bos_value = 0;
   1535     int bos_mask = 0;
   1536 
   1537     ptr = bcmi_special_label_precedence_state[unit];
   1538 
   1539     if (label_type > bcmMplsSpecialLabelTypeEntropy) {
   1540         return BCM_E_PARAM;
   1541     }
   1542 
   1543     bos_value = ((label_info.flags & BCM_MPLS_SPECIAL_LABEL_BOS_PRESENT) ? 1:0);
   1544     bos_mask  = ((label_info.flags & BCM_MPLS_SPECIAL_LABEL_BOS_MASKED) ? 1:0);
   1545 
   1546     mpls_label = BCMI_MPLS_CONSTRUCT_LABEL(
   1547                  label_info.label_value,label_info.exp,label_info.ttl,
   1548                  bos_value);
   1549 
   1550     mpls_label_mask = BCMI_MPLS_CONSTRUCT_LABEL(
   1551                     label_info.label_mask, label_info.exp_mask,
   1552                     label_info.ttl_mask,
   1553                     bos_mask);
   1554 
   1555     /* get matching entry or new slot for adding new entry */
   1556     BCM_IF_ERROR_RETURN(bcmi_mpls_special_label_match_entry(unit, label_type,
   1557                     mpls_label, mpls_label_mask, &slot));
   1558 
   1559     ptr[slot].ref_count--;
   1560     if (ptr[slot].ref_count > 0) {
   1561         /* more applications are still using this. Do not remove*/
   1562         return BCM_E_NONE;
   1563     }
   1564     /* If we are here then nobody else has programmed this*/
   1565     sal_memset(&(ptr[slot]), 0, sizeof(bcmi_mpls_special_label_control_t));
   1566     /* Make the s/w entry as 0 */
   1567     sal_memset(&entry, 0, sizeof(special_label_control_entry_t));
   1568     /* Write the cleared entry into h/w */
   1569     rv = WRITE_SPECIAL_LABEL_CONTROLm(unit, MEM_BLOCK_ALL, slot, &entry);
   1570 
   1571     return rv;
   1572 }
   1573 
   1574 /*
   1575  * Function:
   1576  *      bcmi_mpls_special_label_identifier_delete_all
   1577  * Description:
   1578  *      Delete all identifiers ofs pecial labels.
   1579  *
   1580  * Parameters:
   1581  *      unit                - (IN) unit number
   1582  *      label_type          - (IN) MPLS Label
   1583  *      label_info          - (IN) MPLS Gport
   1584  * Return Value:
   1585  *      BCM_E_XXX
   1586  * Notes:
   1587  */
   1588 int
   1589 bcmi_mpls_special_label_identifier_delete_all(int unit)
   1590 {
   1591     int i=0;
   1592     special_label_control_entry_t entry;
   1593     bcmi_mpls_special_label_control_t *ptr;
   1594     int num_entry;
   1595 
   1596     num_entry = soc_mem_index_count(unit, SPECIAL_LABEL_CONTROLm);
   1597 
   1598     ptr = bcmi_special_label_precedence_state[unit];
   1599 
   1600     for (; i<num_entry; i++) {
   1601         if (ptr[i].cancun_added) {
   1602             /* if this is added by cancun then
   1603                make ref_count to 1 and do not do much. */
   1604             ptr[i].ref_count = 1;
   1605             continue;
   1606         }
   1607 
   1608         /* If we are here then nobody else has programmed this*/
   1609         sal_memset(&(ptr[i]), 0, sizeof(bcmi_mpls_special_label_control_t));
   1610         /* Make the s/w entry as 0 */
   1611         sal_memset(&entry, 0, sizeof(special_label_control_entry_t));
   1612         /* Write the cleared entry into h/w */
   1613         BCM_IF_ERROR_RETURN(
   1614             WRITE_SPECIAL_LABEL_CONTROLm(unit, MEM_BLOCK_ALL, i, &entry));
   1615     }
   1616     return BCM_E_NONE;
   1617 }
   1618 
   1619 /*
   1620  * Function:
   1621  *      bcmi_mpls_special_label_identifier_traverse
   1622  * Description:
   1623  *      Traverse and call user call back for all special labels identifiers.
   1624  *
   1625  * Parameters:
   1626  *      unit                - (IN) unit number
   1627  *      cb                  - (IN) user callback
   1628  *      user data           - (IN) option user data
   1629  * Return Value:
   1630  *      BCM_E_XXX
   1631  * Notes:
   1632  */
   1633 int
   1634 bcmi_mpls_special_label_identifier_traverse(int unit,
   1635             bcm_mpls_special_label_identifier_traverse_cb cb, void *user_data)
   1636 {
   1637     int i=0;
   1638     bcmi_mpls_special_label_control_t *ptr;
   1639     int num_entry;
   1640     bcm_mpls_special_label_t label_info;
   1641     int rv = BCM_E_NONE;
   1642     bcm_mpls_special_label_type_t label_type;
   1643 
   1644     num_entry = soc_mem_index_count(unit, SPECIAL_LABEL_CONTROLm);
   1645 
   1646     ptr = bcmi_special_label_precedence_state[unit];
   1647 
   1648     for (; i<num_entry; i++) {
   1649        sal_memset(&label_info, 0, sizeof(bcm_mpls_special_label_t));
   1650         if (!(ptr[i].valid)) {
   1651             continue;
   1652         }
   1653         label_info.label_value = BCMI_MPLS_LABEL_VAL_FROM_LABEL_GET(ptr[i].label_value);
   1654         label_info.label_mask  = BCMI_MPLS_LABEL_VAL_FROM_LABEL_GET(ptr[i].label_mask);
   1655 
   1656         label_info.exp = BCMI_MPLS_EXP_FROM_LABEL_GET(ptr[i].label_value);
   1657         label_info.exp_mask = BCMI_MPLS_EXP_FROM_LABEL_GET(ptr[i].label_mask);
   1658 
   1659         label_info.ttl = BCMI_MPLS_TTL_FROM_LABEL_GET(ptr[i].label_value);
   1660         label_info.ttl_mask = BCMI_MPLS_TTL_FROM_LABEL_GET(ptr[i].label_mask);
   1661         label_type = ptr[i].label_type;
   1662 
   1663         if (BCMI_MPLS_EXP_FROM_LABEL_GET(ptr[i].label_value)) {
   1664             label_info.flags |= BCM_MPLS_SPECIAL_LABEL_BOS_PRESENT;
   1665         }        
   1666 
   1667         if (BCMI_MPLS_EXP_FROM_LABEL_GET(ptr[i].label_mask)) {
   1668             label_info.flags |= BCM_MPLS_SPECIAL_LABEL_BOS_MASKED;
   1669         }        
   1670 
   1671         bcmi_mpls_special_label_identifier_get(unit, label_type, &label_info);
   1672  
   1673         rv = cb(unit, &label_type, &label_info, user_data);
   1674 #ifdef BCM_CB_ABORT_ON_ERR
   1675         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   1676             return rv;
   1677         }
   1678 #endif
   1679     }
   1680     return rv;
   1681 }
   1682 
   1683 #endif /* BCM_SPECIAL_LABEL_SUPPORT */
   1684 #endif /* BCM_MPLS_SUPPORT */
   1685 #endif /* INCLUDE_L3 */