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

switch.c (67744B)


      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 
      8 #include <shared/bsl.h>
      9 #include <soc/debug.h>
     10 #include <soc/drv.h>
     11 #include <soc/scache.h>
     12 #include <soc/mem.h>
     13 #include <bcm/switch.h>
     14 #include <bcm/error.h>
     15 #include <bcm_int/esw/trx.h>
     16 #include <bcm_int/esw/switch.h>
     17 #include <bcm_int/esw/hurricane3.h>
     18 #include <bcm_int/esw/triumph2.h>
     19 #include <bcm_int/esw/xgs3.h>
     20 #include <bcm_int/esw/stack.h>
     21 
     22 #ifdef BCM_HURRICANE3_SUPPORT
     23 
     24 /*
     25  * Software book keeping for Switch Encap related information
     26  */
     27 typedef struct _bcm_hr3_switch_encap_bookkeeping_s {
     28 #ifdef INCLUDE_L3
     29     SHR_BITDCL  *intf_bitmap;                           /* L3 interfaces used */
     30     uint32  *miml_encap;                                  /* MiML encap id */
     31 #endif /* INCLUDE_L3 */
     32     uint32  *custom_header_encap;                  /* Custom Header encap id */
     33 } _bcm_hr3_switch_encap_bookkeeping_t;
     34 
     35 _bcm_hr3_switch_encap_bookkeeping_t
     36     _bcm_hr3_switch_encap_bk_info[BCM_MAX_NUM_UNITS];
     37 
     38 /* Flag to check initialized status */
     39 STATIC int _bcm_hr3_encap_initialized[BCM_MAX_NUM_UNITS];
     40 
     41 STATIC sal_mutex_t _hr3_encap_mutex[BCM_MAX_NUM_UNITS] = {NULL};
     42 
     43 #define HR3_ENCAP_INFO(_unit_) (&_bcm_hr3_switch_encap_bk_info[_unit_])
     44 
     45 #define HR3_ENCAP_CONTINUOUS_ENTRIES_MAX 128
     46 
     47 #define HR3_ENCAP_INIT(unit)                              \
     48     do {                                                  \
     49         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) {  \
     50             return BCM_E_UNIT;                            \
     51         }                                                 \
     52         if (!_bcm_hr3_encap_initialized[unit]) {          \
     53             return BCM_E_INIT;                            \
     54         }                                                 \
     55     } while (0)
     56 
     57 /* Function Enter/Leave Tracing */
     58 #define HR3_ENCAP_FUNCTION_TRACE(_u_, _str_)                                  \
     59     do {                                                                      \
     60         LOG_VERBOSE(BSL_LS_BCM_SWITCH,                                        \
     61                     (BSL_META_U((_u_),                                        \
     62                                 "%s: " _str_ "\n"), __FUNCTION__));           \
     63     } while (0)
     64 
     65 /*
     66  * Switch Encap lock
     67  */
     68 #define HR3_ENCAP_LOCK(unit) \
     69         sal_mutex_take(_hr3_encap_mutex[unit], sal_mutex_FOREVER);
     70 
     71 #define HR3_ENCAP_UNLOCK(unit) \
     72         sal_mutex_give(_hr3_encap_mutex[unit]);
     73 
     74 #ifdef INCLUDE_L3
     75 #define HR3_L3_INFO(unit)    (&_bcm_l3_bk_info[unit])
     76 /*
     77  * L3 interface usage bitmap operations
     78  */
     79 #define HR3_MIML_INTF_USED_GET(_u_, _intf_) \
     80     SHR_BITGET(HR3_ENCAP_INFO(_u_)->intf_bitmap, (_intf_))
     81 #define HR3_MIML_INTF_USED_SET(_u_, _intf_) \
     82     SHR_BITSET(HR3_ENCAP_INFO((_u_))->intf_bitmap, (_intf_))
     83 #define HR3_MIML_INTF_USED_CLR(_u_, _intf_) \
     84     SHR_BITCLR(HR3_ENCAP_INFO((_u_))->intf_bitmap, (_intf_))
     85 
     86 typedef struct _bcm_hr3_ing_nh_info_s {
     87     int      port;
     88     int      module;
     89     int      trunk;
     90 } _bcm_hr3_ing_nh_info_t;
     91 
     92 typedef struct _bcm_hr3_egr_nh_info_s {
     93     uint8    entry_type;
     94     int      intf_num;
     95     int      macda_index;
     96     int      pri;
     97     int      cfi;
     98 } _bcm_hr3_egr_nh_info_t;
     99 #endif /* INCLUDE_L3 */
    100 
    101 /* Function:
    102 *	   _bcm_hr3_switch_encap_idx2id
    103 * Purpose:
    104 *	   Translate hardware table index into encap ID used by API
    105 * Parameters:
    106 * Returns:
    107 *	   BCM_E_XXX
    108 */
    109 int
    110 _bcm_hr3_switch_encap_idx2id
    111     (int unit, int type, int index_count, int *index_array,  bcm_if_t *encap_id)
    112 {
    113     int idx, id = 0;
    114 
    115     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
    116 
    117     if (index_array == NULL) {
    118         return BCM_E_PARAM;
    119     }
    120 
    121     if (encap_id == NULL) {
    122         return BCM_E_PARAM;
    123     }
    124 
    125     switch (type) {
    126         case _BCM_SWITCH_ENCAP_TYPE_MIML:
    127             if (index_count < 2) {
    128                 return BCM_E_PARAM;
    129             }
    130 
    131             for (idx = 0; idx < index_count; idx++) {
    132                 if (idx == 0) {
    133                     id = index_array[idx];
    134                  } else if (idx == 1) {
    135                     id |= (index_array[idx] <<
    136                         _BCM_SWITCH_ENCAP_MIML_EGR_HEADER_ENCAP_SHIFT);
    137                 }
    138             }
    139             break;
    140         case _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER:
    141             if (index_count < 1) {
    142                 return BCM_E_PARAM;
    143             }
    144 
    145             for (idx = 0; idx < index_count; idx++) {
    146                 if (idx == 0) {
    147                     id = index_array[idx];
    148                 }
    149             }
    150             break;
    151         default:
    152             return BCM_E_NOT_FOUND;
    153     }
    154 
    155     *encap_id = id  | (type << _BCM_SWITCH_ENCAP_SHIFT);
    156 
    157     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
    158     return BCM_E_NONE;
    159 }
    160 
    161 /* Function:
    162 *	   _bcm_hr3_switch_encap_id2idx
    163 * Purpose:
    164 *	   Translate encap ID into hardware table index used by API
    165 * Parameters:
    166 * Returns:
    167 *	   BCM_E_XXX
    168 */
    169 int
    170 _bcm_hr3_switch_encap_id2idx
    171     (int unit, bcm_if_t encap_id, int index_count, int *index_array)
    172 {
    173     int idx, id = 0;
    174 
    175     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
    176     if (index_array == NULL) {
    177         return BCM_E_PARAM;
    178     }
    179 
    180     id = encap_id & _BCM_SWITCH_ENCAP_TYPE_MASK;
    181 
    182     switch (encap_id >> _BCM_SWITCH_ENCAP_SHIFT) {
    183         case _BCM_SWITCH_ENCAP_TYPE_MIML:
    184             if (index_count < 2) {
    185                 return BCM_E_PARAM;
    186             }
    187 
    188             for (idx = 0; idx < index_count; idx++) {
    189                 if (idx == 0) {
    190                     index_array[idx] = id & _BCM_SWITCH_ENCAP_MIML_NHI_MASK;
    191                 } else if (idx == 1) {
    192                     index_array[idx] =
    193                         (id >> _BCM_SWITCH_ENCAP_MIML_EGR_HEADER_ENCAP_SHIFT) &
    194                         _BCM_SWITCH_ENCAP_MIML_EGR_HEADER_ENCAP_MASK;
    195                 } else {
    196                     index_array[idx] = 0;
    197                 }
    198             }
    199             break;
    200         case _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER:
    201             if (index_count < 1) {
    202                 return BCM_E_PARAM;
    203             }
    204 
    205             for (idx = 0; idx < index_count; idx++) {
    206                 if (idx == 0) {
    207                     index_array[idx] =
    208                         (id & _BCM_SWITCH_ENCAP_CUSTOM_HEADER_EGR_HEADER_ENCAP_MASK);
    209                 } else {
    210                     index_array[idx] = 0;
    211                 }
    212             }
    213             break;
    214         default:
    215             return BCM_E_NOT_FOUND;
    216     }
    217 
    218     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
    219     return BCM_E_NONE;
    220 }
    221 
    222 #ifdef INCLUDE_L3
    223 STATIC int
    224 _bcm_hr3_miml_l3_intf_add(int unit, _bcm_l3_intf_cfg_t *if_info)
    225 {
    226     int idx, num_intf;
    227     egr_l3_intf_entry_t egr_intf;
    228     bcm_mac_t hw_mac;
    229     bcm_vlan_t hw_ivid;
    230     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
    231     for (idx = 0; idx < num_intf; idx++) {
    232         if (HR3_MIML_INTF_USED_GET(unit, idx)) {
    233             BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm,
    234                 MEM_BLOCK_ANY, idx, &egr_intf));
    235             soc_mem_mac_addr_get(unit, EGR_L3_INTFm,
    236                 &egr_intf, MAC_ADDRESSf, hw_mac);
    237             hw_ivid = soc_mem_field32_get(unit, EGR_L3_INTFm, &egr_intf, IVIDf);
    238             if ((SAL_MAC_ADDR_EQUAL(hw_mac, if_info->l3i_mac_addr)) &&
    239                 (hw_ivid == if_info->l3i_inner_vlan)) {
    240                 if_info->l3i_index = idx;
    241                 return BCM_E_NONE;
    242             }
    243         }
    244     }
    245     /* Create an interface */
    246     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_intf_create(unit, if_info));
    247     HR3_MIML_INTF_USED_SET(unit, if_info->l3i_index);
    248 
    249     return BCM_E_NONE;
    250 }
    251 
    252 STATIC int
    253 _bcm_hr3_miml_l3_nh_info_add(int unit,
    254     bcm_switch_encap_info_t *encap_info, int *nh_index, int replace)
    255 {
    256     int rv = BCM_E_NONE;
    257     int hw_idx = 0;
    258     egr_l3_next_hop_entry_t egr_nh_entry;
    259     ing_l3_next_hop_entry_t ing_nh_entry;
    260     egr_mac_da_profile_entry_t macda;
    261     _bcm_hr3_ing_nh_info_t ing_nh_info;
    262     _bcm_hr3_egr_nh_info_t egr_nh_info;
    263     bcm_l3_egress_t nh_info;
    264     _bcm_l3_intf_cfg_t if_info;
    265     uint32 nh_flags;
    266     int gport_id, is_local;
    267     bcm_module_t mod_out;
    268     bcm_port_t port_out;
    269     bcm_trunk_t trunk_id;
    270     int old_macda_idx = -1;
    271     uint64 temp_mac;
    272     void *entries[1];
    273 
    274     /* Initialize values */
    275     is_local = -1;
    276     ing_nh_info.port = -1;
    277     ing_nh_info.module = -1;
    278     ing_nh_info.trunk = -1;
    279 
    280     /* Parameter checking */
    281     if (encap_info->encap_service != BCM_SWITCH_ENCAP_SERVICE_MIML) {
    282         return BCM_E_PARAM;
    283     }
    284 
    285     /* Resolve the gport */
    286     rv = _bcm_esw_gport_resolve(unit, encap_info->port, &mod_out,
    287               &port_out, &trunk_id, &gport_id);
    288     BCM_IF_ERROR_RETURN(rv);
    289 
    290     /* Note: encap_info->port is must set for MiML to indicate the destination port */
    291     if (BCM_GPORT_IS_TRUNK(encap_info->port)) {
    292         ing_nh_info.module = -1;
    293         ing_nh_info.port = -1;
    294         ing_nh_info.trunk = trunk_id;
    295     } else {
    296         ing_nh_info.module = mod_out;
    297         ing_nh_info.port = port_out;
    298         ing_nh_info.trunk = -1;
    299         BCM_IF_ERROR_RETURN(
    300             _bcm_esw_modid_is_local(unit, mod_out, &is_local));
    301     }
    302 
    303     if (replace) {
    304         if ((*nh_index > soc_mem_index_max(unit, EGR_L3_NEXT_HOPm)) ||
    305             (*nh_index < soc_mem_index_min(unit, EGR_L3_NEXT_HOPm)))  {
    306             return BCM_E_PARAM;
    307         }
    308         /* Read the existing egress next_hop entry */
    309         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
    310             MEM_BLOCK_ANY, *nh_index, &egr_nh_entry);
    311         BCM_IF_ERROR_RETURN(rv);
    312     } else {
    313         /*
    314          * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
    315          * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
    316          * allocated but nothing is written to hardware. The "nh_info"
    317          * in this case is not used, so just set to all zeros.
    318          */
    319          bcm_l3_egress_t_init(&nh_info);
    320 
    321         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
    322         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, nh_index);
    323         BCM_IF_ERROR_RETURN(rv);
    324     }
    325 
    326     /* ENTRY_TYPE is MiML */
    327     if (replace) {
    328         /* Be sure that the existing entry is programmed to MiML */
    329         egr_nh_info.entry_type =
    330             soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry, ENTRY_TYPEf);
    331         if (egr_nh_info.entry_type != 0x3) { /* != MiML */
    332             return BCM_E_PARAM;
    333         }
    334         /* Remember old MAC DA profile index */
    335         old_macda_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    336             &egr_nh_entry, MIML__MAC_DA_PROFILE_INDEXf);
    337     }
    338     egr_nh_info.entry_type = 0x3;
    339 
    340     /* MIML-DA: Add MAC DA profile */
    341     sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t));
    342     soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm,
    343         &macda, MAC_ADDRESSf, encap_info->egress_dstmac);
    344     entries[0] = &macda;
    345     rv = _bcm_mac_da_profile_entry_add(unit,
    346               entries, 1, (uint32 *) &egr_nh_info.macda_index);
    347     if (BCM_FAILURE(rv)) {
    348         goto cleanup;
    349     }
    350 
    351     /* MIML-SA: Add MAC SA to an L3 interface entry - ref count if exists */
    352     if (!BCM_VLAN_VALID(encap_info->egress_vlan)) {
    353         rv = BCM_E_PARAM;
    354         goto cleanup;
    355     }
    356     sal_memset(&if_info, 0, sizeof(_bcm_l3_intf_cfg_t));
    357     SAL_MAC_ADDR_TO_UINT64(encap_info->egress_srcmac, temp_mac);
    358     SAL_MAC_ADDR_FROM_UINT64(if_info.l3i_mac_addr, temp_mac);
    359 
    360     /* MIML-VID */
    361     if_info.l3i_inner_vlan = encap_info->egress_vlan;
    362 
    363     /* HiGig Header OVID */
    364     if (encap_info->flags & BCM_SWITCH_ENCAP_MIML_OVERRIDE_HG_HEADER_VID) {
    365         if (!BCM_VLAN_VALID(encap_info->higig_vlan)) {
    366             rv = BCM_E_PARAM;
    367             goto cleanup;
    368         }
    369         if (is_local && !IS_HG_PORT(unit, port_out)) {
    370             rv = BCM_E_PARAM;
    371             goto cleanup;
    372         }
    373         if_info.l3i_vid = encap_info->higig_vlan;
    374     } else {
    375         /* For non-HiGig port, the OVID must be dropped by configuring VLAN as untagged set */
    376         if_info.l3i_vid = encap_info->egress_vlan;
    377     }
    378 
    379     rv = _bcm_hr3_miml_l3_intf_add(unit, &if_info);
    380     if (BCM_FAILURE(rv)) {
    381         goto cleanup;
    382     }
    383 
    384     /* Populate the fields of MIML::EGR_l3_NEXT_HOP */
    385     if (!replace) {
    386         sal_memset(&egr_nh_entry, 0, sizeof(egr_l3_next_hop_entry_t));
    387     }
    388 
    389     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    390         &egr_nh_entry, ENTRY_TYPEf, egr_nh_info.entry_type);
    391     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    392         &egr_nh_entry, MIML__INTF_NUMf, if_info.l3i_index);
    393     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    394         &egr_nh_entry, MIML__HG_HDR_SELf, 1); /* HG 2 */
    395     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    396         &egr_nh_entry, MIML__MAC_DA_PROFILE_INDEXf, egr_nh_info.macda_index);
    397 
    398     /* encap priority selection */
    399     if (encap_info->flags & BCM_SWITCH_ENCAP_MIML_QOS_MAP_INT_PRI) {
    400         /* USE_MAPPING */
    401         rv = _bcm_tr2_qos_id2idx(unit, encap_info->qos_map_id, &hw_idx);
    402         if (BCM_FAILURE(rv)) {
    403             goto cleanup;
    404         }
    405         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    406             &egr_nh_entry, MIML__DOT1P_PRI_SELECTf, 0x1);
    407         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    408             &egr_nh_entry, MIML__DOT1P_MAPPING_PTRf, hw_idx);
    409     } else {
    410         /* USE_FIXED */
    411         if ((encap_info->pkt_pri > 7) || (encap_info->pkt_cfi > 1)) {
    412             rv = BCM_E_PARAM;
    413             goto cleanup;
    414         }
    415 
    416         /* MIML-NEW_PCP/NEW_CFI */
    417         egr_nh_info.pri = encap_info->pkt_pri;
    418         egr_nh_info.cfi = encap_info->pkt_cfi;
    419 
    420         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    421             &egr_nh_entry, MIML__DOT1P_PRI_SELECTf, 0x0);
    422         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    423             &egr_nh_entry, MIML__NEW_PCPf, egr_nh_info.pri);
    424         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
    425             &egr_nh_entry, MIML__NEW_CFIf, egr_nh_info.cfi);
    426     }
    427 
    428     /* Write EGR_L3_NEXT_HOP entry */
    429     rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    430                MEM_BLOCK_ALL, *nh_index, &egr_nh_entry);
    431     if (rv < 0) {
    432         goto cleanup;
    433     }
    434 
    435     /* Write ING_L3_NEXT_HOP entry */
    436     sal_memset(&ing_nh_entry, 0, sizeof(ing_l3_next_hop_entry_t));
    437     if (ing_nh_info.trunk == -1) {
    438         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    439             &ing_nh_entry, PORT_NUMf, ing_nh_info.port);
    440         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    441             &ing_nh_entry, MODULE_IDf, ing_nh_info.module);
    442     } else {
    443         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    444             &ing_nh_entry, Tf, 1);
    445         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    446             &ing_nh_entry, TGIDf, ing_nh_info.trunk);
    447     }
    448     rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
    449                MEM_BLOCK_ALL, *nh_index, &ing_nh_entry);
    450     if (rv < 0) {
    451         goto cleanup;
    452     }
    453 
    454     /* Delete MAC_DA indexes */
    455     if (old_macda_idx != -1) {
    456         rv = _bcm_mac_da_profile_entry_delete(unit, old_macda_idx);
    457         BCM_IF_ERROR_RETURN(rv);
    458     }
    459 
    460     return rv;
    461 
    462 cleanup:
    463     if (!replace) {
    464         (void) bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, *nh_index);
    465     }
    466     if (egr_nh_info.macda_index != -1) {
    467         (void) _bcm_mac_da_profile_entry_delete(unit, egr_nh_info.macda_index);
    468     }
    469 
    470     return rv;
    471 }
    472 
    473 STATIC int
    474 _bcm_hr3_miml_l3_nh_info_delete(int unit, int nh_index)
    475 {
    476     int rv, old_macda_idx = -1;
    477     egr_l3_next_hop_entry_t egr_nh_entry;
    478     ing_l3_next_hop_entry_t ing_nh_entry;
    479 
    480     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm,
    481         MEM_BLOCK_ANY, nh_index, &egr_nh_entry));
    482     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm,
    483         MEM_BLOCK_ANY, nh_index, &ing_nh_entry));
    484 
    485     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry, ENTRY_TYPEf) == 0x3) {
    486         old_macda_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    487             &egr_nh_entry, MIML__MAC_DA_PROFILE_INDEXf);
    488     } else {
    489         return BCM_E_NOT_FOUND;
    490     }
    491 
    492     /* Clear EGR_L3_NEXT_HOP entry */
    493     sal_memset(&egr_nh_entry, 0, sizeof(egr_l3_next_hop_entry_t));
    494     BCM_IF_ERROR_RETURN (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    495         MEM_BLOCK_ALL, nh_index, &egr_nh_entry));
    496 
    497     /* Clear ING_L3_NEXT_HOP entry */
    498     sal_memset(&ing_nh_entry, 0, sizeof(ing_l3_next_hop_entry_t));
    499     BCM_IF_ERROR_RETURN (soc_mem_write (unit, ING_L3_NEXT_HOPm,
    500         MEM_BLOCK_ALL, nh_index, &ing_nh_entry));
    501 
    502     /* Delete old MAC profile reference */
    503     if (old_macda_idx != -1) {
    504         rv = _bcm_mac_da_profile_entry_delete(unit, old_macda_idx);
    505         if (BCM_FAILURE(rv)) {
    506             return rv;
    507         }
    508     }
    509 
    510     /* Free the next-hop entry. */
    511     rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
    512 
    513     return rv;
    514 }
    515 
    516 STATIC int
    517 _bcm_hr3_miml_l3_nh_info_get(int unit,
    518     int nh_index, bcm_switch_encap_info_t *encap_info)
    519 {
    520     int rv = BCM_E_NONE;
    521     egr_l3_next_hop_entry_t egr_nh_entry;
    522     ing_l3_next_hop_entry_t ing_nh_entry;
    523     egr_l3_intf_entry_t egr_intf;
    524     egr_mac_da_profile_entry_t macda;
    525     int intf_num = -1, macda_idx = -1;
    526     int hw_idx = 0;
    527     bcm_module_t mod_out, mod_in;
    528     bcm_port_t port_out, port_in;
    529     bcm_trunk_t trunk_id;
    530     int is_local = 0;
    531 
    532     /* Read the HW entries */
    533     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm,
    534         MEM_BLOCK_ANY, nh_index, &egr_nh_entry));
    535     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm,
    536         MEM_BLOCK_ANY, nh_index, &ing_nh_entry));
    537 
    538     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
    539         trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, TGIDf);
    540         BCM_GPORT_TRUNK_SET(encap_info->port, trunk_id);
    541     } else {
    542         mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, MODULE_IDf);
    543         port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, PORT_NUMf);
    544         SOC_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit,
    545             BCM_STK_MODMAP_GET, mod_in, port_in, &mod_out, &port_out));
    546         BCM_GPORT_MODPORT_SET(encap_info->port, mod_out, port_out);
    547 
    548         BCM_IF_ERROR_RETURN(
    549             _bcm_esw_modid_is_local(unit, mod_out, &is_local));
    550     }
    551 
    552     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry, ENTRY_TYPEf) == 0x3) {
    553         /* Get the MiML encap attributes */
    554         intf_num = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    555             &egr_nh_entry, MIML__INTF_NUMf);
    556         macda_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    557             &egr_nh_entry, MIML__MAC_DA_PROFILE_INDEXf);
    558 
    559         BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm,
    560             MEM_BLOCK_ANY, intf_num, &egr_intf));
    561         BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
    562             MEM_BLOCK_ANY, macda_idx, &macda));
    563 
    564         soc_mem_mac_addr_get(unit, EGR_L3_INTFm,
    565             &egr_intf, MAC_ADDRESSf, encap_info->egress_srcmac);
    566         encap_info->egress_vlan =
    567             soc_mem_field32_get(unit, EGR_L3_INTFm, &egr_intf, IVIDf);
    568 
    569         encap_info->higig_vlan =
    570             soc_mem_field32_get(unit, EGR_L3_INTFm, &egr_intf, OVIDf);
    571         /* HiGig Header OVID */
    572         if (!is_local || (is_local && IS_HG_PORT(unit, port_out))) {
    573             encap_info->flags |= BCM_SWITCH_ENCAP_MIML_OVERRIDE_HG_HEADER_VID;
    574         }
    575 
    576         soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm,
    577             &macda, MAC_ADDRESSf, encap_info->egress_dstmac);
    578 
    579         if (soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    580             &egr_nh_entry, MIML__DOT1P_PRI_SELECTf) == 0x1) {
    581             /* USE_MAPPING */
    582             hw_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    583                 &egr_nh_entry, MIML__DOT1P_MAPPING_PTRf);
    584 
    585             rv = _bcm_tr2_qos_idx2id(unit, hw_idx,
    586                 _BCM_QOS_MAP_TYPE_EGR_MPLS_MAPS, &encap_info->qos_map_id);
    587             if (BCM_FAILURE(rv)) {
    588                 return rv;
    589             }
    590 
    591             encap_info->flags |= BCM_SWITCH_ENCAP_MIML_QOS_MAP_INT_PRI;
    592         } else {
    593             /* USE_FIXED */
    594             encap_info->pkt_pri = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    595                 &egr_nh_entry, MIML__NEW_PCPf);
    596             encap_info->pkt_cfi = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    597                 &egr_nh_entry, MIML__NEW_CFIf);
    598         }
    599 
    600     } else {
    601         return BCM_E_NOT_FOUND;
    602     }
    603 
    604     return rv;
    605 }
    606 #endif /* INCLUDE_L3 */
    607 
    608 STATIC int
    609 bcmi_hr3_egr_header_encap_data_fill_content(
    610     int unit,
    611     bcm_switch_encap_info_t *encap_info,
    612     int value_offset,
    613     egr_header_encap_data_entry_t *egr_header_encap_data)
    614 {
    615     int rv = BCM_E_NONE;
    616     uint32 value32;
    617     int hw_idx = 0;
    618 
    619     /* Parameter checking */
    620     if (encap_info == NULL) {
    621         return BCM_E_PARAM;
    622     }
    623     if (egr_header_encap_data == NULL) {
    624         return BCM_E_PARAM;
    625     }
    626 
    627     if (encap_info->encap_service == BCM_SWITCH_ENCAP_SERVICE_MIML) {
    628         value32 =
    629             (encap_info->length & _BCM_SWITCH_ENCAP_MIML_LENGTH_MASK)
    630             << _BCM_SWITCH_ENCAP_MIML_LENGTH_SHIFT;
    631         value32 |=
    632             (encap_info->iid & _BCM_SWITCH_ENCAP_MIML_IID_MASK)
    633             << _BCM_SWITCH_ENCAP_MIML_IID_SHIFT;
    634         value32 |=
    635             (encap_info->pkt_type &
    636              _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_MASK)
    637             << _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_SHIFT;
    638 
    639         soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    640             egr_header_encap_data, CUSTOM_PACKET_HEADERf, value32);
    641     } else if (encap_info->encap_service ==
    642         BCM_SWITCH_ENCAP_SERVICE_CUSTOM_HEADER) {
    643         /* Set 32-bit data value for encapsulation */
    644         value32 = encap_info->value32 + value_offset;
    645 
    646         soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    647             egr_header_encap_data, CUSTOM_PACKET_HEADERf, value32);
    648 
    649         /* encap priority selection */
    650         if (encap_info->flags &
    651             BCM_SWITCH_ENCAP_CUSTOM_HEADER_QOS_MAP_INT_PRI) {
    652             /* USE_MAPPING */
    653             rv = _bcm_tr2_qos_id2idx(
    654                     unit, encap_info->qos_map_id, &hw_idx);
    655             if (BCM_FAILURE(rv)) {
    656                 return rv;
    657             }
    658             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    659                 egr_header_encap_data, CUSTOM_PRI_SELECTf, 0x1);
    660             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    661                 egr_header_encap_data, CUSTOM_PRI_MAPPING_PTRf,
    662                 hw_idx);
    663         } else {
    664             /* USE_FIXED */
    665             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    666                 egr_header_encap_data, CUSTOM_PRI_SELECTf, 0x0);
    667         }
    668     } else {
    669         return BCM_E_PARAM;
    670     }
    671 
    672     return BCM_E_NONE;
    673 }
    674 
    675 STATIC int
    676 bcmi_hr3_egr_header_encap_data_add_one_entry(
    677     int unit,
    678     bcm_switch_encap_info_t *encap_info,
    679     int value_offset_base,
    680     uint32 *eh_idx)
    681 {
    682     int rv = BCM_E_NONE;
    683 
    684     void *entries[1];
    685     int entries_per_set;
    686     int value_offset = value_offset_base;
    687     egr_header_encap_data_entry_t egr_header_encap_data;
    688     egr_header_encap_data_entry_t egr_header_encap_data_war[4];
    689 
    690     /* Parameter checking */
    691     if (encap_info == NULL) {
    692         return BCM_E_PARAM;
    693     }
    694     if (eh_idx == NULL) {
    695         return BCM_E_PARAM;
    696     }
    697 
    698     while (1) {
    699         sal_memset(&egr_header_encap_data, 0,
    700             sizeof(egr_header_encap_data_entry_t));
    701         sal_memset(egr_header_encap_data_war, 0,
    702             sizeof(egr_header_encap_data_war));
    703         BCM_IF_ERROR_RETURN(
    704             bcmi_hr3_egr_header_encap_data_fill_content(
    705                 unit, encap_info, value_offset, &egr_header_encap_data));
    706 
    707         /* Add EGR_HEADER_ENCAP_DATA profile */
    708         if (soc_feature(unit,
    709                         soc_feature_hr3_switch_encap_index_shift2_war)) {
    710             /* WAR for A0: The index of */
    711             /* EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    712             sal_memcpy(&egr_header_encap_data_war[0],
    713                 &egr_header_encap_data, sizeof(egr_header_encap_data));
    714             entries[0] = &egr_header_encap_data_war;
    715             entries_per_set = 4;
    716         } else {
    717             entries[0] = &egr_header_encap_data;
    718             entries_per_set = 1;
    719         }
    720 
    721         rv = _bcm_egr_header_encap_data_entry_search(
    722                 unit, entries, entries_per_set, eh_idx);
    723         if (value_offset == 0 && rv == BCM_E_EXISTS) {
    724             /* First entry value already existed */
    725             return BCM_E_EXISTS;
    726         } else if (rv == BCM_E_EXISTS) {
    727             value_offset++;
    728             continue;
    729         }
    730         BCM_IF_ERROR_RETURN(rv);
    731 
    732         rv = _bcm_egr_header_encap_data_entry_add(
    733                 unit, entries, entries_per_set, eh_idx);
    734         BCM_IF_ERROR_RETURN(rv);
    735         break;
    736     }
    737     return BCM_E_NONE;
    738 }
    739 
    740 STATIC int
    741 bcmi_hr3_egr_header_encap_data_update_one_entry(
    742     int unit,
    743     bcm_switch_encap_info_t *encap_info,
    744     int value_offset,
    745     uint32 eh_idx)
    746 {
    747     int rv = BCM_E_NONE;
    748 
    749     void *entries[1];
    750     egr_header_encap_data_entry_t egr_header_encap_data;
    751     egr_header_encap_data_entry_t egr_header_encap_data_war[4];
    752 
    753     /* Parameter checking */
    754     if (encap_info == NULL) {
    755         return BCM_E_PARAM;
    756     }
    757     sal_memset(&egr_header_encap_data, 0,
    758         sizeof(egr_header_encap_data_entry_t));
    759     sal_memset(egr_header_encap_data_war, 0,
    760         sizeof(egr_header_encap_data_war));
    761     BCM_IF_ERROR_RETURN(
    762         bcmi_hr3_egr_header_encap_data_fill_content(
    763             unit, encap_info, value_offset, &egr_header_encap_data));
    764 
    765     /* Add EGR_HEADER_ENCAP_DATA profile */
    766     if (soc_feature(unit,
    767                     soc_feature_hr3_switch_encap_index_shift2_war)) {
    768         /* WAR for A0: The index of */
    769         /* EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    770         sal_memcpy(&egr_header_encap_data_war[0],
    771             &egr_header_encap_data, sizeof(egr_header_encap_data));
    772         entries[0] = &egr_header_encap_data_war;
    773     } else {
    774         entries[0] = &egr_header_encap_data;
    775     }
    776     rv = _bcm_egr_header_encap_data_entry_update(
    777             unit, entries, eh_idx);
    778     BCM_IF_ERROR_RETURN(rv);
    779     return BCM_E_NONE;
    780 }
    781 
    782 STATIC int
    783 _bcm_hr3_egr_header_encap_data_add(int unit,
    784     bcm_switch_encap_info_t *encap_info,
    785     uint32 count,
    786     int *eh_index)
    787 {
    788     int rv = BCM_E_NONE;
    789     uint32 eh_idx = 0;
    790     uint32 continue_cnt = 0;
    791     uint32 eh_idx_arry[HR3_ENCAP_CONTINUOUS_ENTRIES_MAX];
    792     int idx_first, idx_next, idx;
    793 
    794     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
    795 
    796     /* MIML doesn't support continued N encap entries */
    797     if (count != 1 &&
    798         encap_info->encap_service == BCM_SWITCH_ENCAP_SERVICE_MIML) {
    799         return BCM_E_UNAVAIL;
    800     }
    801 
    802     assert(count <= HR3_ENCAP_CONTINUOUS_ENTRIES_MAX);
    803 
    804     /*
    805      * Since the utility soc_profile_mem_add cannot add the same entry data content
    806      * , for loop here is to create continuous encap custom data by increase
    807      * CUSTOM_PACKET_HEADERf
    808      * i.e
    809      * CUSTOM_PACKET_HEADER=0x99990000
    810      * CUSTOM_PACKET_HEADER=0x99990001
    811      * ...
    812      * CUSTOM_PACKET_HEADER=0x99990000 + count -1
    813  */
    814 
    815     /* 1. Add 1st entry */
    816     rv = bcmi_hr3_egr_header_encap_data_add_one_entry
    817              (unit, encap_info, 0, &eh_idx);
    818     if (BCM_FAILURE(rv)) {
    819         if (rv == BCM_E_EXISTS) {
    820             *eh_index = eh_idx;
    821         }
    822         return rv;
    823     }
    824     continue_cnt = 1;
    825     idx_first = 0;
    826     idx_next = idx_first + 1;
    827     eh_idx_arry[idx_first] = eh_idx;
    828 
    829     /* 2. keep adding 1 entry until reaching continues "count" entries */
    830     while (1) {
    831         if (continue_cnt == count) {
    832             break;
    833         }
    834         BCM_IF_ERROR_RETURN(
    835             bcmi_hr3_egr_header_encap_data_add_one_entry(
    836                 unit, encap_info, 1, &eh_idx));
    837         eh_idx_arry[idx_next] = eh_idx;
    838         if (eh_idx_arry[idx_next - 1] == eh_idx_arry[idx_next] - 1) {
    839             continue_cnt++;
    840         } else {
    841             continue_cnt = 1;
    842             idx_first = idx_next;
    843         }
    844         idx_next++;
    845         if (idx_next >= HR3_ENCAP_CONTINUOUS_ENTRIES_MAX) {
    846             return BCM_E_RESOURCE;
    847         }
    848     }
    849 
    850     /* 3. Delete entries from 0 to idx_first -1 */
    851     for (idx = 0; idx < idx_first; idx++) {
    852         rv = _bcm_egr_header_encap_data_entry_delete(unit, eh_idx_arry[idx]);
    853         BCM_IF_ERROR_RETURN(rv);
    854     }
    855 
    856     /* 4. refill value for 1st entry */
    857     BCM_IF_ERROR_RETURN(
    858         bcmi_hr3_egr_header_encap_data_update_one_entry(
    859             unit, encap_info, 0, eh_idx_arry[idx_first]));
    860 
    861     /* Add EGR_HEADER_ENCAP_DATA profile */
    862     if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
    863         /* Shift >> 2 bits for software index */
    864         *eh_index = (eh_idx_arry[idx_first] >> 2);
    865     } else {
    866         *eh_index = eh_idx_arry[idx_first];
    867     }
    868 
    869     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
    870     return rv;
    871 }
    872 
    873 STATIC int
    874 _bcm_hr3_egr_header_encap_data_delete(int unit, int eh_index)
    875 {
    876     int rv = BCM_E_NONE;
    877 
    878     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
    879     if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
    880         /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    881         /* Shift << 2 bits for hardware index */
    882         eh_index = (eh_index << 2);
    883     }
    884 
    885     /* Delete existing EGR_HEADER_ENCAP_DATA profile reference */
    886     rv = _bcm_egr_header_encap_data_entry_delete(unit, eh_index);
    887     BCM_IF_ERROR_RETURN(rv);
    888 
    889     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
    890     return rv;
    891 }
    892 
    893 STATIC int
    894 _bcm_hr3_egr_header_encap_data_update(int unit, bcm_if_t encap_id,
    895     int eh_index, bcm_switch_encap_info_t *encap_info)
    896 {
    897     int rv = BCM_E_NONE;
    898     int hw_idx;
    899     uint32 value32;
    900     egr_header_encap_data_entry_t egr_header_encap_data;
    901     egr_header_encap_data_entry_t egr_header_encap_data_war[4];
    902     void *entries[1];
    903 
    904     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
    905 
    906     if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
    907         /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    908         /* Shift << 2 bits for hardware index */
    909         eh_index = (eh_index << 2);
    910     }
    911 
    912     if ((eh_index > soc_mem_index_max(unit, EGR_HEADER_ENCAP_DATAm)) ||
    913         (eh_index < soc_mem_index_min(unit, EGR_HEADER_ENCAP_DATAm)))  {
    914         return BCM_E_PARAM;
    915     }
    916 
    917     sal_memset(&egr_header_encap_data, 0, sizeof(egr_header_encap_data_entry_t));
    918     sal_memset(egr_header_encap_data_war, 0, sizeof(egr_header_encap_data_war));
    919 
    920     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) == _BCM_SWITCH_ENCAP_TYPE_MIML) {
    921         /* Set MiML Packet Type, IID and Length: use the same field as Custom Header */
    922         value32 =
    923             (encap_info->length & _BCM_SWITCH_ENCAP_MIML_LENGTH_MASK) <<
    924             _BCM_SWITCH_ENCAP_MIML_LENGTH_SHIFT;
    925         value32 |=
    926             (encap_info->iid & _BCM_SWITCH_ENCAP_MIML_IID_MASK) <<
    927             _BCM_SWITCH_ENCAP_MIML_IID_SHIFT;
    928         value32 |=
    929             (encap_info->pkt_type & _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_MASK) <<
    930             _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_SHIFT ;
    931 
    932         soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    933             &egr_header_encap_data, CUSTOM_PACKET_HEADERf, value32);
    934     } else if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
    935         _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
    936         /* Set 32-bit data value for encapsulation */
    937         value32 = encap_info->value32;
    938 
    939         soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    940             &egr_header_encap_data, CUSTOM_PACKET_HEADERf, value32);
    941 
    942         /* encap priority selection */
    943         if (encap_info->flags & BCM_SWITCH_ENCAP_CUSTOM_HEADER_QOS_MAP_INT_PRI) {
    944             /* USE_MAPPING */
    945             rv = _bcm_tr2_qos_id2idx(unit, encap_info->qos_map_id, &hw_idx);
    946             if (BCM_FAILURE(rv)) {
    947                 return rv;
    948             }
    949             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    950                 &egr_header_encap_data, CUSTOM_PRI_SELECTf, 0x1);
    951             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    952                 &egr_header_encap_data, CUSTOM_PRI_MAPPING_PTRf, hw_idx);
    953         } else {
    954             /* USE_FIXED */
    955             soc_mem_field32_set(unit, EGR_HEADER_ENCAP_DATAm,
    956                 &egr_header_encap_data, CUSTOM_PRI_SELECTf, 0x0);
    957         }
    958     } else {
    959         return BCM_E_PARAM;
    960     }
    961 
    962     /* Update EGR_HEADER_ENCAP_DATA profile */
    963     if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
    964         /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    965         sal_memcpy(&egr_header_encap_data_war[0],
    966             &egr_header_encap_data, sizeof(egr_header_encap_data));
    967         /* entries_per_set = 4 */
    968         entries[0] = &egr_header_encap_data_war;
    969     } else {
    970         entries[0] = &egr_header_encap_data;
    971     }
    972 
    973     rv = _bcm_egr_header_encap_data_entry_update(unit, entries, (uint32)eh_index);
    974     BCM_IF_ERROR_RETURN(rv);
    975 
    976     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
    977     return rv;
    978 }
    979 
    980 STATIC int
    981 _bcm_hr3_egr_header_encap_data_get(int unit, bcm_if_t encap_id,
    982     int eh_index, bcm_switch_encap_info_t *encap_info)
    983 {
    984     int rv = BCM_E_NONE;
    985     int hw_idx = 0;
    986     uint32 value32;
    987     egr_header_encap_data_entry_t egr_header_encap_data;
    988 
    989     if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
    990         /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
    991         /* Shift << 2 bits for hardware index */
    992         eh_index = (eh_index << 2);
    993     }
    994 
    995     if ((eh_index > soc_mem_index_max(unit, EGR_HEADER_ENCAP_DATAm)) ||
    996         (eh_index < soc_mem_index_min(unit, EGR_HEADER_ENCAP_DATAm)))  {
    997         return BCM_E_PARAM;
    998     }
    999 
   1000     /* Read the existing egress next_hop entry */
   1001     rv = soc_mem_read(unit, EGR_HEADER_ENCAP_DATAm,
   1002         MEM_BLOCK_ANY, eh_index, &egr_header_encap_data);
   1003 
   1004     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) == _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1005         /* Get MiML Packet Type, IID and Length: use the same field as Custom Header */
   1006         value32 = soc_mem_field32_get(unit, EGR_HEADER_ENCAP_DATAm,
   1007             &egr_header_encap_data, CUSTOM_PACKET_HEADERf);
   1008 
   1009         encap_info->length =
   1010             (value32 >> _BCM_SWITCH_ENCAP_MIML_LENGTH_SHIFT) &
   1011             _BCM_SWITCH_ENCAP_MIML_LENGTH_MASK;
   1012         encap_info->iid =
   1013             (value32 >> _BCM_SWITCH_ENCAP_MIML_IID_SHIFT) &
   1014             _BCM_SWITCH_ENCAP_MIML_IID_MASK;
   1015         encap_info->pkt_type =
   1016             (value32 >> _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_SHIFT) &
   1017             _BCM_SWITCH_ENCAP_MIML_PKT_TYPE_MASK;
   1018     } else if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
   1019         _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1020         /* Get 32-bit data value for encapsulation */
   1021         value32 = soc_mem_field32_get(unit, EGR_HEADER_ENCAP_DATAm,
   1022             &egr_header_encap_data, CUSTOM_PACKET_HEADERf);
   1023         encap_info->value32 = value32;
   1024 
   1025         encap_info->flags = 0;
   1026         /* encap priority selection */
   1027         if (soc_EGR_HEADER_ENCAP_DATAm_field32_get(unit,
   1028             &egr_header_encap_data, CUSTOM_PRI_SELECTf) == 0x1) {
   1029             /* USE_MAPPING */
   1030             hw_idx = soc_mem_field32_get(unit, EGR_HEADER_ENCAP_DATAm,
   1031                 &egr_header_encap_data, CUSTOM_PRI_MAPPING_PTRf);
   1032 
   1033             rv = _bcm_tr2_qos_idx2id(unit, hw_idx,
   1034                 _BCM_QOS_MAP_TYPE_EGR_MPLS_MAPS, &encap_info->qos_map_id);
   1035             if (BCM_FAILURE(rv)) {
   1036                 return rv;
   1037             }
   1038 
   1039             encap_info->flags |= BCM_SWITCH_ENCAP_CUSTOM_HEADER_QOS_MAP_INT_PRI;
   1040         }
   1041     } else {
   1042         return BCM_E_PARAM;
   1043     }
   1044 
   1045     return rv;
   1046 }
   1047 
   1048 #ifdef INCLUDE_L3
   1049 STATIC int
   1050 _bcm_hr3_miml_switch_encap_delete(int unit, int nh_index, int eh_index)
   1051 {
   1052     int rv = BCM_E_NONE;
   1053 
   1054     rv = _bcm_hr3_miml_l3_nh_info_delete(unit, nh_index);
   1055     if (BCM_FAILURE(rv)) {
   1056         return rv;
   1057     }
   1058 
   1059     rv = _bcm_hr3_egr_header_encap_data_delete(unit, eh_index);
   1060     if (BCM_FAILURE(rv)) {
   1061         return rv;
   1062     }
   1063 
   1064     return rv;
   1065 }
   1066 
   1067 STATIC int
   1068 _bcm_hr3_miml_switch_encap_create(int unit,
   1069     bcm_switch_encap_info_t *encap_info, bcm_if_t *encap_id)
   1070 {
   1071     int rv = BCM_E_NONE;
   1072     int nh_index, eh_index, index_array[2];
   1073     int idx, num_miml, free_set;
   1074 
   1075     num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);  /* Depend on IFP */
   1076 
   1077     /* Parameter checking */
   1078     if (encap_info == NULL) {
   1079         return BCM_E_PARAM;
   1080     }
   1081     if (encap_id == NULL) {
   1082         return BCM_E_PARAM;
   1083     }
   1084     if (encap_info->encap_service != BCM_SWITCH_ENCAP_SERVICE_MIML) {
   1085         return BCM_E_PARAM;
   1086     }
   1087 
   1088     rv = _bcm_hr3_miml_l3_nh_info_add(unit, encap_info, &nh_index, FALSE);
   1089     if (BCM_FAILURE(rv)) {
   1090         return rv;
   1091     }
   1092 
   1093     rv = _bcm_hr3_egr_header_encap_data_add(unit, encap_info, 1, &eh_index);
   1094     if (BCM_FAILURE(rv)) {
   1095         return rv;
   1096     }
   1097 
   1098     index_array[0] = nh_index;
   1099     index_array[1] = eh_index;
   1100     rv = _bcm_hr3_switch_encap_idx2id(unit,
   1101         _BCM_SWITCH_ENCAP_TYPE_MIML, 2, index_array, encap_id);
   1102     if (BCM_FAILURE(rv)) {
   1103         return rv;
   1104     }
   1105 
   1106     /* Check if created encap entry is already existed */
   1107     free_set = -1;
   1108     for (idx = 0; idx < num_miml; idx++) {
   1109         if (HR3_ENCAP_INFO(unit)->miml_encap[idx] == 0x0) {
   1110             if (free_set == -1) {
   1111                 free_set = idx;
   1112             }
   1113         }
   1114 
   1115         if (HR3_ENCAP_INFO(unit)->miml_encap[idx] == *encap_id) {
   1116             rv = _bcm_hr3_miml_switch_encap_delete(unit, nh_index, eh_index);
   1117             if (BCM_FAILURE(rv)) {
   1118                 return rv;
   1119             }
   1120             return BCM_E_EXISTS;
   1121         }
   1122     }
   1123 
   1124     if (free_set != -1) {
   1125         HR3_ENCAP_INFO(unit)->miml_encap[free_set] = *encap_id;
   1126     } else {
   1127         /* Delete previous added nh_info and egr_header_encap_data */
   1128         rv = _bcm_hr3_miml_switch_encap_delete(unit, nh_index, eh_index);
   1129         if (BCM_FAILURE(rv)) {
   1130             return rv;
   1131         }
   1132         rv = BCM_E_FULL;
   1133     }
   1134 
   1135     return rv;
   1136 }
   1137 
   1138 STATIC int
   1139 _bcm_hr3_miml_switch_encap_set(int unit,
   1140     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   1141 {
   1142     int rv = BCM_E_NONE;
   1143     int nh_index, eh_index, index_array[2];
   1144 
   1145     /* Parameter checking */
   1146     if (encap_info == NULL) {
   1147         return BCM_E_PARAM;
   1148     }
   1149 
   1150     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) != _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1151         return BCM_E_PARAM;
   1152     }
   1153 
   1154     rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, 2, index_array);
   1155     if (BCM_FAILURE(rv)) {
   1156         return rv;
   1157     }
   1158     nh_index = index_array[0];
   1159     eh_index = index_array[1];
   1160 
   1161     rv = _bcm_hr3_miml_l3_nh_info_add(unit, encap_info, &nh_index, TRUE);
   1162     if (BCM_FAILURE(rv)) {
   1163         return rv;
   1164     }
   1165 
   1166     rv = _bcm_hr3_egr_header_encap_data_update(unit,
   1167         encap_id, eh_index, encap_info);
   1168 
   1169     return rv;
   1170 }
   1171 
   1172 STATIC int
   1173 _bcm_hr3_miml_switch_encap_get(int unit,
   1174     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   1175 {
   1176     int rv = BCM_E_NONE;
   1177     int nh_index, eh_index, index_array[2];
   1178 
   1179     /* Parameter checking */
   1180     if (encap_info == NULL) {
   1181         return BCM_E_PARAM;
   1182     }
   1183 
   1184     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) != _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1185         return BCM_E_PARAM;
   1186     }
   1187 
   1188     rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, 2, index_array);
   1189     if (BCM_FAILURE(rv)) {
   1190         return rv;
   1191     }
   1192     nh_index = index_array[0];
   1193     eh_index = index_array[1];
   1194 
   1195     rv = _bcm_hr3_miml_l3_nh_info_get(unit, nh_index, encap_info);
   1196     if (BCM_FAILURE(rv)) {
   1197         return rv;
   1198     }
   1199 
   1200     rv = _bcm_hr3_egr_header_encap_data_get(unit, encap_id, eh_index, encap_info);
   1201     if (BCM_FAILURE(rv)) {
   1202         return rv;
   1203     }
   1204 
   1205     encap_info->encap_service = BCM_SWITCH_ENCAP_SERVICE_MIML;
   1206 
   1207     return rv;
   1208 }
   1209 #endif /* INCLUDE_L3 */
   1210 
   1211 /* create N Customer header encap objects */
   1212 STATIC int
   1213 _bcm_hr3_custom_header_switch_encap_create(int unit,
   1214     bcm_switch_encap_info_t *encap_info,
   1215     uint32 count,
   1216     bcm_if_t *encap_id)
   1217 {
   1218     int rv = BCM_E_NONE;
   1219     int eh_index, base_eh_index, index_array[1];
   1220     int ref_count = 0;
   1221     int i;
   1222 
   1223     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1224     /* Parameter checking */
   1225     if (encap_info == NULL) {
   1226         return BCM_E_PARAM;
   1227     }
   1228     if (encap_id == NULL) {
   1229         return BCM_E_PARAM;
   1230     }
   1231     if (encap_info->encap_service != BCM_SWITCH_ENCAP_SERVICE_CUSTOM_HEADER) {
   1232         return BCM_E_PARAM;
   1233     }
   1234 
   1235     rv = _bcm_hr3_egr_header_encap_data_add(unit,
   1236             encap_info, count, &base_eh_index);
   1237     if (BCM_FAILURE(rv)) {
   1238         if (rv == BCM_E_EXISTS) {
   1239             index_array[0] = base_eh_index;
   1240             rv = _bcm_hr3_switch_encap_idx2id
   1241                      (unit, _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER, 1,
   1242                       index_array, encap_id);
   1243             BCM_IF_ERROR_RETURN(rv);
   1244             return BCM_E_EXISTS;
   1245         } else {
   1246             return rv;
   1247         }
   1248     }
   1249 
   1250     for (i = count - 1; i >= 0; i--) {
   1251         eh_index = base_eh_index + i;
   1252         /* Check if created encap entry is existed */
   1253         if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
   1254             /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
   1255             rv = _bcm_egr_header_encap_data_entry_ref_count_get(unit,
   1256                       ((uint32)eh_index << 2), &ref_count);
   1257         } else {
   1258             rv = _bcm_egr_header_encap_data_entry_ref_count_get(unit,
   1259                       (uint32)eh_index, &ref_count);
   1260         }
   1261         BCM_IF_ERROR_RETURN(rv);
   1262 
   1263         if (ref_count >= 2) {
   1264             /* Delete previous added egr_header_encap_data entry */
   1265             rv = _bcm_hr3_egr_header_encap_data_delete(unit, eh_index);
   1266             if (BCM_FAILURE(rv)) {
   1267                 return rv;
   1268             }
   1269             return BCM_E_EXISTS;
   1270         }
   1271 
   1272         index_array[0] = eh_index;
   1273         rv = _bcm_hr3_switch_encap_idx2id(unit,
   1274                   _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER, 1, index_array, encap_id);
   1275         BCM_IF_ERROR_RETURN(rv);
   1276 
   1277         HR3_ENCAP_INFO(unit)->custom_header_encap[eh_index] = *encap_id;
   1278     }
   1279 
   1280     return rv;
   1281 }
   1282 
   1283 STATIC int
   1284 _bcm_hr3_custom_header_switch_encap_set(int unit,
   1285     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   1286 {
   1287     int rv = BCM_E_NONE;
   1288     int eh_index, index_array[1];
   1289 
   1290     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1291     /* Parameter checking */
   1292     if (encap_info == NULL) {
   1293         return BCM_E_PARAM;
   1294     }
   1295 
   1296     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) !=
   1297         _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1298         return BCM_E_PARAM;
   1299     }
   1300 
   1301     rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, 1, index_array);
   1302     if (BCM_FAILURE(rv)) {
   1303         return rv;
   1304     }
   1305     eh_index = index_array[0];
   1306 
   1307     rv = _bcm_hr3_egr_header_encap_data_update(unit,
   1308         encap_id, eh_index, encap_info);
   1309     BCM_IF_ERROR_RETURN(rv);
   1310 
   1311     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1312     return rv;
   1313 }
   1314 
   1315 STATIC int
   1316 _bcm_hr3_custom_header_switch_encap_get(int unit,
   1317     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   1318 {
   1319     int rv = BCM_E_NONE;
   1320     int eh_index, index_array[1];
   1321 
   1322     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1323     /* Parameter checking */
   1324     if (encap_info == NULL) {
   1325         return BCM_E_PARAM;
   1326     }
   1327 
   1328     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) !=
   1329         _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1330         return BCM_E_PARAM;
   1331     }
   1332 
   1333     rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, 1, index_array);
   1334     if (BCM_FAILURE(rv)) {
   1335         return rv;
   1336     }
   1337     eh_index = index_array[0];
   1338 
   1339     rv = _bcm_hr3_egr_header_encap_data_get(unit,
   1340         encap_id, eh_index, encap_info);
   1341     BCM_IF_ERROR_RETURN(rv);
   1342 
   1343     encap_info->encap_service = BCM_SWITCH_ENCAP_SERVICE_CUSTOM_HEADER;
   1344 
   1345     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1346     return rv;
   1347 }
   1348 
   1349 /*
   1350  * Function:
   1351  *      _bcm_hr3_switch_encap_free_resources
   1352  * Purpose:
   1353  *      Free all allocated tables and memory
   1354  * Parameters:
   1355  *      unit - SOC unit number
   1356  * Returns:
   1357  *      Nothing
   1358  */
   1359 STATIC void
   1360 _bcm_hr3_switch_encap_free_resources(int unit)
   1361 {
   1362     _bcm_hr3_switch_encap_bookkeeping_t *sw_encap_info = HR3_ENCAP_INFO(unit);
   1363 
   1364     if (_hr3_encap_mutex[unit]) {
   1365         sal_mutex_destroy(_hr3_encap_mutex[unit]);
   1366         _hr3_encap_mutex[unit] = NULL;
   1367     }
   1368 #ifdef INCLUDE_L3
   1369     if (sw_encap_info->intf_bitmap) {
   1370         sal_free(sw_encap_info->intf_bitmap);
   1371         sw_encap_info->intf_bitmap = NULL;
   1372     }
   1373 
   1374     if (sw_encap_info->miml_encap) {
   1375         sal_free(sw_encap_info->miml_encap);
   1376         sw_encap_info->miml_encap = NULL;
   1377     }
   1378 #endif /* INCLUDE_L3 */
   1379     if (sw_encap_info->custom_header_encap) {
   1380         sal_free(sw_encap_info->custom_header_encap);
   1381         sw_encap_info->custom_header_encap = NULL;
   1382     }
   1383 }
   1384 
   1385 #ifdef BCM_WARM_BOOT_SUPPORT
   1386 /*
   1387  * Function:
   1388  *      _bcm_hr3_switch_encap_wb_scache_size_get
   1389  * Purpose:
   1390  *      Helper utility to determine scache details.
   1391  * Parameters:
   1392  *      unit        : (IN) Device Unit Number
   1393  *      scache_len  : (OUT) Total required scache length
   1394  * Returns:
   1395  *      BCM_E_XXX
   1396  */
   1397 int
   1398 _bcm_hr3_switch_encap_wb_scache_size_get(int unit,
   1399     int *req_scache_size)
   1400 {
   1401    int alloc_size = 0;
   1402 #ifdef INCLUDE_L3
   1403     int num_miml = 0;
   1404 #endif /* INCLUDE_L3 */
   1405     int num_custom_header = 0;
   1406 
   1407 #ifdef INCLUDE_L3
   1408     /* Depend on IFP */
   1409     num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);
   1410     alloc_size += (num_miml * sizeof(uint32));
   1411 #endif /* INCLUDE_L3 */
   1412     num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   1413     alloc_size += (num_custom_header * sizeof(uint32));
   1414 
   1415     *req_scache_size = alloc_size;
   1416 
   1417     return BCM_E_NONE;
   1418 }
   1419 
   1420 STATIC int
   1421 _bcm_hr3_switch_encap_associated_data_recover(int unit,
   1422     bcm_if_t encap_id)
   1423 {
   1424     int rv = BCM_E_NONE;
   1425     int index_array[2];
   1426     int eh_index;
   1427 #ifdef INCLUDE_L3
   1428     int nh_index, macda_idx, intf_num;
   1429     uint32 nh_flags;
   1430     egr_l3_next_hop_entry_t egr_nh_entry;
   1431     bcm_l3_egress_t nh_info;
   1432 #endif /* INCLUDE_L3 */
   1433 
   1434     rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, 2, index_array);
   1435     if (BCM_FAILURE(rv)) {
   1436         return rv;
   1437     }
   1438 
   1439     if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
   1440          _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1441 #ifdef INCLUDE_L3
   1442         nh_index = index_array[0];
   1443         eh_index = index_array[1];
   1444 
   1445         BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1446             MEM_BLOCK_ANY, nh_index, &egr_nh_entry));
   1447 
   1448         bcm_l3_egress_t_init(&nh_info);
   1449 
   1450         nh_flags = _BCM_L3_SHR_UPDATE | _BCM_L3_SHR_WRITE_DISABLE |
   1451             _BCM_L3_SHR_WITH_ID;
   1452         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
   1453         BCM_IF_ERROR_RETURN(rv);
   1454 
   1455         if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry, ENTRY_TYPEf) == 0x3) {
   1456             /* MIML view - recover MACDA profile and interface reference counts */
   1457             macda_idx = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   1458                 &egr_nh_entry, MIML__MAC_DA_PROFILE_INDEXf);
   1459             _bcm_common_profile_mem_ref_cnt_update(unit,
   1460                 EGR_MAC_DA_PROFILEm, macda_idx, 1);
   1461             intf_num = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   1462                 &egr_nh_entry, MIML__INTF_NUMf);
   1463 
   1464             HR3_MIML_INTF_USED_SET(unit, intf_num);
   1465             BCM_L3_INTF_USED_SET(unit, intf_num);
   1466 
   1467             if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
   1468                 /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
   1469                 _bcm_common_profile_mem_ref_cnt_update(unit,
   1470                     EGR_HEADER_ENCAP_DATAm, (eh_index << 2), 1);
   1471             } else {
   1472                 _bcm_common_profile_mem_ref_cnt_update(unit,
   1473                     EGR_HEADER_ENCAP_DATAm, eh_index, 1);
   1474             }
   1475         }
   1476 #else
   1477         rv = BCM_E_UNAVAIL;
   1478 #endif /* INCLUDE_L3 */
   1479     } else if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
   1480         _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1481         eh_index = index_array[0];
   1482 
   1483         if (soc_feature(unit, soc_feature_hr3_switch_encap_index_shift2_war)) {
   1484             /* WAR for A0: The index of EGR_HEADER_ENCAP_DATA is shifted << 2 bits. */
   1485             _bcm_common_profile_mem_ref_cnt_update(unit,
   1486                 EGR_HEADER_ENCAP_DATAm, (eh_index << 2), 1);
   1487         } else {
   1488             _bcm_common_profile_mem_ref_cnt_update(unit,
   1489                 EGR_HEADER_ENCAP_DATAm, eh_index, 1);
   1490         }
   1491     }
   1492 
   1493     return rv;
   1494 }
   1495 
   1496 /*
   1497  * Function:
   1498  *      _bcm_hr3_switch_encap_reinit
   1499  * Purpose:
   1500  *      Warm boot recovery for the Switch Encap software module
   1501  * Parameters:
   1502  *      unit     - Device Number
   1503  * Returns:
   1504  *      BCM_E_XXX
   1505  */
   1506 int
   1507 _bcm_hr3_switch_encap_reinit(int unit, uint8 **scache_ptr)
   1508 {
   1509     uint32 *u32_scache_p;
   1510     uint32 encap_id;
   1511     int idx, num_custom_header = 0;
   1512 #ifdef INCLUDE_L3
   1513     int num_miml = 0;
   1514 #endif /* INCLUDE_L3 */
   1515 
   1516 #ifdef INCLUDE_L3
   1517     num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);  /* Depend on IFP */
   1518 #endif /* INCLUDE_L3 */
   1519     num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   1520 
   1521     u32_scache_p = (uint32 *)(*scache_ptr);
   1522 
   1523     /* recover from scache into book-keeping structs */
   1524 #ifdef INCLUDE_L3
   1525     for (idx = 0; idx < num_miml; idx++) {
   1526         encap_id = *u32_scache_p;
   1527         u32_scache_p++;
   1528         if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
   1529             _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1530             HR3_ENCAP_INFO(unit)->miml_encap[idx] = encap_id;
   1531 
   1532             BCM_IF_ERROR_RETURN(
   1533                 _bcm_hr3_switch_encap_associated_data_recover(unit, encap_id));
   1534         }
   1535     }
   1536 #endif /* INCLUDE_L3 */
   1537     for (idx = 0; idx < num_custom_header; idx++) {
   1538         encap_id = *u32_scache_p;
   1539         u32_scache_p++;
   1540         if ((encap_id >> _BCM_SWITCH_ENCAP_SHIFT) ==
   1541             _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1542             HR3_ENCAP_INFO(unit)->custom_header_encap[idx] = encap_id;
   1543 
   1544             BCM_IF_ERROR_RETURN(
   1545                 _bcm_hr3_switch_encap_associated_data_recover(unit, encap_id));
   1546         }
   1547     }
   1548 
   1549     return BCM_E_NONE;
   1550 }
   1551 
   1552 /*
   1553  * Function:
   1554  *      _bcm_hr3_switch_encap_sync
   1555  * Purpose:
   1556  *      This routine extracts the state that needs to be stored from the
   1557  *      book-keeping structs and stores it in the allocated scache location
   1558  * Parameters:
   1559  *      unit    : (IN) Device Unit Number
   1560  * Returns:
   1561  *      BCM_E_XXX
   1562  */
   1563 int
   1564 _bcm_hr3_switch_encap_sync(int unit, uint8 **scache_ptr)
   1565 {
   1566     uint32 *u32_scache_p;
   1567     uint32 encap_id;
   1568     int idx, num_custom_header = 0;
   1569 #ifdef INCLUDE_L3
   1570     int num_miml = 0;
   1571 #endif /* INCLUDE_L3 */
   1572 
   1573 #ifdef INCLUDE_L3
   1574     num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);  /* Depend on IFP */
   1575 #endif /* INCLUDE_L3 */
   1576     num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   1577 
   1578     u32_scache_p = (uint32 *)(*scache_ptr);
   1579 
   1580     /* now store the state into the compressed format */
   1581 #ifdef INCLUDE_L3
   1582     for (idx = 0; idx < num_miml; idx++) {
   1583         if ((HR3_ENCAP_INFO(unit)->miml_encap[idx] >>
   1584             _BCM_SWITCH_ENCAP_SHIFT) == _BCM_SWITCH_ENCAP_TYPE_MIML) {
   1585             encap_id = HR3_ENCAP_INFO(unit)->miml_encap[idx];
   1586         } else {
   1587             encap_id = 0x0;
   1588         }
   1589         *u32_scache_p = encap_id;
   1590         u32_scache_p++;
   1591     }
   1592 #endif /* INCLUDE_L3 */
   1593     for (idx = 0; idx < num_custom_header; idx++) {
   1594         if ((HR3_ENCAP_INFO(unit)->custom_header_encap[idx] >>
   1595             _BCM_SWITCH_ENCAP_SHIFT) == _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER) {
   1596             encap_id = HR3_ENCAP_INFO(unit)->custom_header_encap[idx];
   1597         } else {
   1598             encap_id = 0x0;
   1599         }
   1600         *u32_scache_p = encap_id;
   1601         u32_scache_p++;
   1602     }
   1603 
   1604     return BCM_E_NONE;
   1605 }
   1606 
   1607 #endif /* BCM_WARM_BOOT_SUPPORT */
   1608 
   1609 /*
   1610  * Function:
   1611  *      bcm_hr3_switch_encap_detach
   1612  * Purpose:
   1613  *      Detach the Switch Encap software module
   1614  * Parameters:
   1615  *      unit     - Device Number
   1616  * Returns:
   1617  *      BCM_E_XXX
   1618  */
   1619 int
   1620 bcm_hr3_switch_encap_detach(int unit)
   1621 {
   1622     int rv = BCM_E_NONE;
   1623 
   1624     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1625     if (_bcm_hr3_encap_initialized[unit] == FALSE) {
   1626         return BCM_E_NONE;
   1627     }
   1628 
   1629     _bcm_hr3_switch_encap_free_resources(unit);
   1630     _bcm_hr3_encap_initialized[unit] = FALSE;
   1631     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1632     return rv;
   1633 }
   1634 
   1635 /*
   1636  * Function:
   1637  *      bcm_hr3_switch_encap_init
   1638  * Description:
   1639  *      Initialize switch encap.
   1640  * Parameters:
   1641  *      unit        - Device unit number
   1642  * Returns:
   1643  *      BCM_E_xxx
   1644  */
   1645 int
   1646 bcm_hr3_switch_encap_init(int unit)
   1647 {
   1648     int rv = BCM_E_NONE;
   1649 #ifdef INCLUDE_L3
   1650     int num_intf = 0, num_miml = 0;
   1651 #endif /* INCLUDE_L3 */
   1652     int num_custom_header = 0;
   1653     _bcm_hr3_switch_encap_bookkeeping_t *sw_encap_info = HR3_ENCAP_INFO(unit);
   1654 
   1655     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1656 
   1657     if (!(soc_feature(unit, soc_feature_miml) ||
   1658            soc_feature(unit, soc_feature_custom_header))) {
   1659         return BCM_E_UNAVAIL;
   1660     }
   1661 
   1662 #ifdef INCLUDE_L3
   1663     if (soc_feature(unit, soc_feature_miml) && !HR3_L3_INFO(unit)->l3_initialized) {
   1664         LOG_INFO(BSL_LS_BCM_L3,
   1665                  (BSL_META_U(unit,
   1666                              "L3 module must be initialized first\n")));
   1667         return BCM_E_NONE;
   1668     }
   1669 #endif /* INCLUDE_L3 */
   1670 
   1671     if (_bcm_hr3_encap_initialized[unit]) {
   1672         BCM_IF_ERROR_RETURN(bcm_hr3_switch_encap_detach(unit));
   1673     }
   1674 #ifdef INCLUDE_L3
   1675     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1676     num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);  /* Depend on IFP */
   1677 #endif /* INCLUDE_L3 */
   1678     num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   1679 
   1680     sal_memset(sw_encap_info, 0, sizeof(_bcm_hr3_switch_encap_bookkeeping_t));
   1681 
   1682 #ifdef INCLUDE_L3
   1683     /* Allocate MiML encap L3 intf usage bitmap */
   1684     if (sw_encap_info->intf_bitmap == NULL) {
   1685         sw_encap_info->intf_bitmap =
   1686             sal_alloc(SHR_BITALLOCSIZE(num_intf), "intf_bitmap");
   1687         if (sw_encap_info->intf_bitmap == NULL) {
   1688             _bcm_hr3_switch_encap_free_resources(unit);
   1689             return BCM_E_MEMORY;
   1690         }
   1691     }
   1692     sal_memset(sw_encap_info->intf_bitmap, 0, SHR_BITALLOCSIZE(num_intf));
   1693 
   1694     /* Allocate MiML encap id */
   1695     if (sw_encap_info->miml_encap == NULL) {
   1696         sw_encap_info->miml_encap =
   1697             sal_alloc((sizeof(uint32) * num_miml), "miml_encap");
   1698         if (sw_encap_info->miml_encap == NULL) {
   1699             _bcm_hr3_switch_encap_free_resources(unit);
   1700             return BCM_E_MEMORY;
   1701         }
   1702     }
   1703     sal_memset(sw_encap_info->miml_encap, 0, (sizeof(uint32) * num_miml));
   1704 #endif /* INCLUDE_L3 */
   1705 
   1706     /* Allocate Custom Header encap id */
   1707     if (sw_encap_info->custom_header_encap == NULL) {
   1708         sw_encap_info->custom_header_encap =
   1709             sal_alloc((sizeof(uint32) * num_custom_header), "custom_header_encap");
   1710         if (sw_encap_info->custom_header_encap == NULL) {
   1711             _bcm_hr3_switch_encap_free_resources(unit);
   1712             return BCM_E_MEMORY;
   1713         }
   1714     }
   1715     sal_memset(sw_encap_info->custom_header_encap, 0,
   1716         (sizeof(uint32) * num_custom_header));
   1717 
   1718     if (_hr3_encap_mutex[unit] == NULL) {
   1719         _hr3_encap_mutex[unit] = sal_mutex_create("sw_encap mutex");
   1720         if (_hr3_encap_mutex[unit] == NULL) {
   1721             _bcm_hr3_switch_encap_free_resources(unit);
   1722             return BCM_E_MEMORY;
   1723         }
   1724     }
   1725 
   1726     _bcm_hr3_encap_initialized[unit] = TRUE;
   1727     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1728     return rv;
   1729 }
   1730 
   1731 /*
   1732  * Function:
   1733  *   _bcm_hr3_switch_encap_create
   1734  * Purpose:
   1735  *   Create N continuous encapsulation objects, base_encap_id will be returned
   1736  *   after the N (base_encap_id ~ base_encap_id + count - 1) encapsulation
   1737  *   objects are created.
   1738  * Parameters:
   1739  *   unit - (IN) Unit number.
   1740  *   encap_info - (IN) Encapsulation info data structure.
   1741  *   count - (IN) Number of encapsulation objects to create
   1742  *   base_encap_id - (OUT) Encapsulation object id.
   1743  * Returns:
   1744  *   BCM_E_xxx
   1745  * Notes:
   1746  */
   1747 int
   1748 _bcm_hr3_switch_encap_create(int unit,
   1749     bcm_switch_encap_info_t *encap_info,
   1750     uint32 count,
   1751     bcm_if_t *base_encap_id)
   1752 {
   1753     int rv = BCM_E_UNAVAIL;
   1754 
   1755     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1756     HR3_ENCAP_INIT(unit);
   1757 
   1758     if (encap_info == NULL) {
   1759         return BCM_E_PARAM;
   1760     }
   1761     if (base_encap_id == NULL) {
   1762         return BCM_E_PARAM;
   1763     }
   1764 
   1765     switch (encap_info->encap_service) {
   1766         case BCM_SWITCH_ENCAP_SERVICE_MIML:
   1767             if (!soc_feature(unit, soc_feature_miml)) {
   1768                 return BCM_E_UNAVAIL;
   1769             }
   1770             if (count != 1) {
   1771                 return BCM_E_PARAM;
   1772             }
   1773 #ifdef INCLUDE_L3
   1774             HR3_ENCAP_LOCK(unit);
   1775             rv = _bcm_hr3_miml_switch_encap_create(unit,
   1776                       encap_info, base_encap_id);
   1777             HR3_ENCAP_UNLOCK(unit);
   1778 #endif /* INCLUDE_L3 */
   1779             break;
   1780         case BCM_SWITCH_ENCAP_SERVICE_CUSTOM_HEADER:
   1781             if (!soc_feature(unit, soc_feature_custom_header)) {
   1782                 return BCM_E_UNAVAIL;
   1783             }
   1784             HR3_ENCAP_LOCK(unit);
   1785             rv = _bcm_hr3_custom_header_switch_encap_create(unit,
   1786                        encap_info, count, base_encap_id);
   1787             HR3_ENCAP_UNLOCK(unit);
   1788             break;
   1789         default:
   1790             return BCM_E_UNAVAIL;
   1791     }
   1792     BCM_IF_ERROR_RETURN(rv);
   1793 
   1794     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1795     return rv;
   1796 }
   1797 
   1798 /*
   1799  * Function:
   1800  *      bcm_hr3_switch_encap_create
   1801  * Purpose:
   1802  *      Create an encapuslation object, encap_id will be returned after the
   1803  *      encapsulation object created. The encap_id will be used by FP.
   1804  * Parameters:
   1805  *      unit - (IN) Unit number.
   1806  *      encap_info - (IN) Encapsulation info data structure.
   1807  *      encap_id - (OUT) Encapsulation object id.
   1808  * Returns:
   1809  *      BCM_E_xxx
   1810  * Notes:
   1811  */
   1812 int
   1813 bcm_hr3_switch_encap_create(int unit,
   1814     bcm_switch_encap_info_t *encap_info, bcm_if_t *encap_id)
   1815 {
   1816     int rv;
   1817 
   1818     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1819     if (encap_info == NULL) {
   1820         return BCM_E_PARAM;
   1821     }
   1822 
   1823     if (encap_id == NULL) {
   1824         return BCM_E_PARAM;
   1825     }
   1826 
   1827     /* create 1 encap_id */
   1828     rv = _bcm_hr3_switch_encap_create(unit, encap_info, 1, encap_id);
   1829     BCM_IF_ERROR_RETURN(rv);
   1830 
   1831     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1832     return rv;
   1833 }
   1834 
   1835 /*
   1836  * Function:
   1837  *      bcm_hr3_switch_encap_destroy
   1838  * Purpose:
   1839  *      Destroy the encap object with the given encap_id.
   1840  * Parameters:
   1841  *      unit - (IN) Unit number.
   1842  *      encap_id - (IN) Encapsulation object id.
   1843  * Returns:
   1844  *      BCM_E_xxx
   1845  * Notes:
   1846  */
   1847 int
   1848 bcm_hr3_switch_encap_destroy(int unit, bcm_if_t encap_id)
   1849 {
   1850     int rv = BCM_E_UNAVAIL;
   1851     int idx, index_count, index_array[2];
   1852 #ifdef INCLUDE_L3
   1853     int num_miml;
   1854 #endif /* INCLUDE_L3 */
   1855 
   1856     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1857     HR3_ENCAP_INIT(unit);
   1858 
   1859     switch (encap_id >> _BCM_SWITCH_ENCAP_SHIFT) {
   1860         case _BCM_SWITCH_ENCAP_TYPE_MIML:
   1861             if (!soc_feature(unit, soc_feature_miml)) {
   1862                 return BCM_E_UNAVAIL;
   1863             }
   1864 #ifdef INCLUDE_L3
   1865             HR3_ENCAP_LOCK(unit);
   1866             index_count = 2;
   1867             rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, index_count, index_array);
   1868             if (BCM_FAILURE(rv)) {
   1869                 HR3_ENCAP_UNLOCK(unit);
   1870                 return rv;
   1871             }
   1872 
   1873             rv = _bcm_hr3_miml_switch_encap_delete(unit,
   1874                       index_array[0], index_array[1]);
   1875             if (BCM_FAILURE(rv)) {
   1876                 HR3_ENCAP_UNLOCK(unit);
   1877                 return rv;
   1878             }
   1879 
   1880             num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);  /* Depend on IFP */
   1881             for (idx = 0; idx < num_miml; idx++) {
   1882                 if (HR3_ENCAP_INFO(unit)->miml_encap[idx] == encap_id) {
   1883                     HR3_ENCAP_INFO(unit)->miml_encap[idx] = 0x0;
   1884                 }
   1885             }
   1886             HR3_ENCAP_UNLOCK(unit);
   1887 #endif /* INCLUDE_L3 */
   1888             break;
   1889         case _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER:
   1890             if (!soc_feature(unit, soc_feature_custom_header)) {
   1891                 return BCM_E_UNAVAIL;
   1892             }
   1893 
   1894             HR3_ENCAP_LOCK(unit);
   1895             index_count = 1;
   1896             rv = _bcm_hr3_switch_encap_id2idx(unit, encap_id, index_count, index_array);
   1897             if (BCM_FAILURE(rv)) {
   1898                 HR3_ENCAP_UNLOCK(unit);
   1899                 return rv;
   1900             }
   1901 
   1902             idx = index_count - 1;
   1903             rv = _bcm_hr3_egr_header_encap_data_delete(unit, index_array[idx]);
   1904             if (BCM_FAILURE(rv)) {
   1905                 HR3_ENCAP_UNLOCK(unit);
   1906                 return rv;
   1907             }
   1908 
   1909             HR3_ENCAP_INFO(unit)->custom_header_encap[index_array[idx]] = 0x0;
   1910 
   1911             HR3_ENCAP_UNLOCK(unit);
   1912             break;
   1913         default:
   1914             return BCM_E_NOT_FOUND;
   1915     }
   1916 
   1917     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1918     return rv;
   1919 }
   1920 
   1921 /*
   1922  * Function:
   1923  *      bcm_hr3_switch_encap_destroy_all
   1924  * Purpose:
   1925  *      Destroy all encap objects.
   1926  * Parameters:
   1927  *      unit - (IN) Unit number.
   1928  * Returns:
   1929  *      BCM_E_xxx
   1930  * Notes:
   1931  */
   1932 int
   1933 bcm_hr3_switch_encap_destroy_all(int unit)
   1934 {
   1935     int rv = BCM_E_NONE;
   1936     int idx, num_custom_header = 0;
   1937 #ifdef INCLUDE_L3
   1938     int num_miml = 0;
   1939 #endif /* INCLUDE_L3 */
   1940     bcm_if_t encap_id;
   1941 
   1942     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   1943     HR3_ENCAP_INIT(unit);
   1944 
   1945 #ifdef INCLUDE_L3
   1946     if (soc_feature(unit, soc_feature_miml)) {
   1947         /* Depend on IFP */
   1948         num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);
   1949     }
   1950 #endif /* INCLUDE_L3 */
   1951     if (soc_feature(unit, soc_feature_custom_header)) {
   1952         num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   1953     }
   1954 
   1955 #ifdef INCLUDE_L3
   1956     /* Destroy all created encap id for MiML */
   1957     for (idx = 0; idx < num_miml; idx++) {
   1958         encap_id = HR3_ENCAP_INFO(unit)->miml_encap[idx];
   1959         if (encap_id != 0x0) {
   1960             rv = bcm_hr3_switch_encap_destroy(unit, encap_id);
   1961             if (BCM_FAILURE(rv)) {
   1962                 return rv;
   1963             }
   1964         }
   1965     }
   1966 #endif /* INCLUDE_L3 */
   1967 
   1968     /* Destroy all created encap id for Custom Header */
   1969     for (idx = 0; idx < num_custom_header; idx++) {
   1970         encap_id = HR3_ENCAP_INFO(unit)->custom_header_encap[idx];
   1971         if (encap_id != 0x0) {
   1972             rv = bcm_hr3_switch_encap_destroy(unit, encap_id);
   1973             if (BCM_FAILURE(rv)) {
   1974                 return rv;
   1975             }
   1976         }
   1977     }
   1978 
   1979     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   1980     return rv;
   1981 }
   1982 
   1983 /*
   1984  * Function:
   1985  *      bcm_hr3_switch_encap_set
   1986  * Purpose:
   1987  *     Modify the configuration of the encap object with the given encap_id.
   1988  * Parameters:
   1989  *      unit - (IN) Unit number.
   1990  *      encap_id - (IN) Encapsulation object id.
   1991  *      encap_info - (IN) Encapsulation info data structure.
   1992  * Returns:
   1993  *      BCM_E_xxx
   1994  * Notes:
   1995  */
   1996 int
   1997 bcm_hr3_switch_encap_set(int unit,
   1998     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   1999 {
   2000     int rv = BCM_E_UNAVAIL;
   2001 
   2002     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   2003     HR3_ENCAP_INIT(unit);
   2004 
   2005     if (encap_info == NULL) {
   2006         return BCM_E_PARAM;
   2007     }
   2008 
   2009     switch (encap_id >> _BCM_SWITCH_ENCAP_SHIFT) {
   2010         case _BCM_SWITCH_ENCAP_TYPE_MIML:
   2011             if (!soc_feature(unit, soc_feature_miml)) {
   2012                 return BCM_E_UNAVAIL;
   2013             }
   2014 #ifdef INCLUDE_L3
   2015             HR3_ENCAP_LOCK(unit);
   2016             rv = _bcm_hr3_miml_switch_encap_set(unit,
   2017                       encap_id, encap_info);
   2018             HR3_ENCAP_UNLOCK(unit);
   2019 #endif /* INCLUDE_L3 */
   2020             break;
   2021         case _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER:
   2022             if (!soc_feature(unit, soc_feature_custom_header)) {
   2023                 return BCM_E_UNAVAIL;
   2024             }
   2025             HR3_ENCAP_LOCK(unit);
   2026             rv = _bcm_hr3_custom_header_switch_encap_set(unit,
   2027                        encap_id, encap_info);
   2028             HR3_ENCAP_UNLOCK(unit);
   2029             break;
   2030         default:
   2031             return BCM_E_NOT_FOUND;
   2032     }
   2033     BCM_IF_ERROR_RETURN(rv);
   2034 
   2035     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   2036     return rv;
   2037 }
   2038 
   2039 /*
   2040  * Function:
   2041  *      bcm_hr3_switch_encap_get
   2042  * Purpose:
   2043  *     Get the configuration of the encap object with the given encap_id.
   2044  * Parameters:
   2045  *      unit - (IN) Unit number.
   2046  *      encap_id - (IN) Encapsulation object id.
   2047  *      encap_info - (OUT) Encapsulation info data structure.
   2048  * Returns:
   2049  *      BCM_E_xxx
   2050  * Notes:
   2051  */
   2052 int
   2053 bcm_hr3_switch_encap_get(int unit,
   2054     bcm_if_t encap_id, bcm_switch_encap_info_t *encap_info)
   2055 {
   2056     int rv = BCM_E_UNAVAIL;
   2057 
   2058     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   2059     HR3_ENCAP_INIT(unit);
   2060 
   2061     if (encap_info == NULL) {
   2062         return BCM_E_PARAM;
   2063     }
   2064 
   2065     bcm_switch_encap_info_t_init(encap_info);
   2066 
   2067     switch (encap_id >> _BCM_SWITCH_ENCAP_SHIFT) {
   2068         case _BCM_SWITCH_ENCAP_TYPE_MIML:
   2069             if (!soc_feature(unit, soc_feature_miml)) {
   2070                 return BCM_E_UNAVAIL;
   2071             }
   2072 #ifdef INCLUDE_L3
   2073             HR3_ENCAP_LOCK(unit);
   2074             rv = _bcm_hr3_miml_switch_encap_get(unit,
   2075                       encap_id, encap_info);
   2076             HR3_ENCAP_UNLOCK(unit);
   2077 #endif /* INCLUDE_L3 */
   2078             break;
   2079         case _BCM_SWITCH_ENCAP_TYPE_CUSTOM_HEADER:
   2080             if (!soc_feature(unit, soc_feature_custom_header)) {
   2081                 return BCM_E_UNAVAIL;
   2082             }
   2083             HR3_ENCAP_LOCK(unit);
   2084             rv = _bcm_hr3_custom_header_switch_encap_get(unit,
   2085                        encap_id, encap_info);
   2086             HR3_ENCAP_UNLOCK(unit);
   2087             break;
   2088         default:
   2089             return BCM_E_NOT_FOUND;
   2090     }
   2091     BCM_IF_ERROR_RETURN(rv);
   2092 
   2093     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   2094     return rv;
   2095 }
   2096 
   2097 /*
   2098  * Function:
   2099  *      bcm_hr3_switch_encap_traverse
   2100  * Purpose:
   2101  *     To traverse all created encapsulation entries and call provided callback function
   2102  *     with matched entry.
   2103  * Parameters:
   2104  *      unit - (IN) Unit number.
   2105  *      cb_fn - (IN) User specified callback function.
   2106  *      user_data - (IN) User specified cookie.
   2107  * Returns:
   2108  *      BCM_E_xxx
   2109  * Notes:
   2110  */
   2111 int
   2112 bcm_hr3_switch_encap_traverse(int unit,
   2113     bcm_switch_encap_traverse_cb cb_fn, void *user_data)
   2114 {
   2115     int rv = BCM_E_NONE;
   2116     int idx, num_custom_header = 0;
   2117 #ifdef INCLUDE_L3
   2118     int num_miml = 0;
   2119 #endif /* INCLUDE_L3 */
   2120     bcm_if_t encap_id;
   2121     bcm_switch_encap_info_t encap_info;
   2122 
   2123     HR3_ENCAP_FUNCTION_TRACE(unit, "IN");
   2124     HR3_ENCAP_INIT(unit);
   2125 
   2126 #ifdef INCLUDE_L3
   2127     if (soc_feature(unit, soc_feature_miml)) {
   2128         /* Depend on IFP */
   2129         num_miml = soc_mem_index_count(unit, FP_POLICY_TABLEm);
   2130     }
   2131 #endif /* INCLUDE_L3 */
   2132     if (soc_feature(unit, soc_feature_custom_header)) {
   2133         num_custom_header = soc_mem_index_count(unit, EGR_HEADER_ENCAP_DATAm);
   2134     }
   2135 
   2136     bcm_switch_encap_info_t_init(&encap_info);
   2137 
   2138     HR3_ENCAP_LOCK(unit);
   2139 #ifdef INCLUDE_L3
   2140     /* Traverse all created encap id for MiML */
   2141     for (idx = 0; idx < num_miml; idx++) {
   2142         encap_id = HR3_ENCAP_INFO(unit)->miml_encap[idx];
   2143         if (encap_id != 0x0) {
   2144             /* Get the configuration of the encap info */
   2145             rv = bcm_hr3_switch_encap_get(unit, encap_id, &encap_info);
   2146             if (BCM_FAILURE(rv)) {
   2147                 HR3_ENCAP_UNLOCK(unit);
   2148                 return rv;
   2149             }
   2150 
   2151             /* Call application call-back */
   2152             rv = cb_fn(unit, encap_id, &encap_info, user_data);
   2153             if (BCM_FAILURE(rv)) {
   2154 #ifdef BCM_CB_ABORT_ON_ERR
   2155                 if (SOC_CB_ABORT_ON_ERR(unit)) {
   2156                     HR3_ENCAP_UNLOCK(unit);
   2157                     return rv;
   2158                 }
   2159 #endif
   2160             }
   2161         }
   2162     }
   2163 #endif /* INCLUDE_L3 */
   2164 
   2165     /* Traverse all created encap id for Custom Header */
   2166     for (idx = 0; idx < num_custom_header; idx++) {
   2167         encap_id = HR3_ENCAP_INFO(unit)->custom_header_encap[idx];
   2168         if (encap_id != 0x0) {
   2169             /* Get the configuration of the encap info */
   2170             rv = bcm_hr3_switch_encap_get(unit, encap_id, &encap_info);
   2171             if (BCM_FAILURE(rv)) {
   2172                 HR3_ENCAP_UNLOCK(unit);
   2173                 return rv;
   2174             }
   2175             /* Call application call-back */
   2176             rv = cb_fn(unit, encap_id, &encap_info, user_data);
   2177             if (BCM_FAILURE(rv)) {
   2178 #ifdef BCM_CB_ABORT_ON_ERR
   2179                 if (SOC_CB_ABORT_ON_ERR(unit)) {
   2180                     HR3_ENCAP_UNLOCK(unit);
   2181                     return rv;
   2182                 }
   2183 #endif
   2184             }
   2185         }
   2186     }
   2187 
   2188     HR3_ENCAP_UNLOCK(unit);
   2189 
   2190     HR3_ENCAP_FUNCTION_TRACE(unit, "OUT");
   2191     return rv;
   2192 }
   2193 #endif /* BCM_HURRICANE3_SUPPORT */
   2194