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

tnl_term.c (96040B)


      1 /* 
      2  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      3  * 
      4  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      5  *
      6  * Tunnel terminator TCAM table insert/delete/lookup routines
      7  * soc_tunnel_term_init    - Called from bcm_l3_init
      8  * soc_tunnel_term_insert  - Insert/Update an IPv4/IPV6 tunnel 
      9  *                           termination entry into L3_TUNNEL table
     10  * soc_tunnel_term_delete  - Delete an IPv4/IPV6 tunnel termination 
     11  *                           entry from L3_TUNNEL table
     12  * soc_tunnel_term_match  -  Exact match for the key. 
     13  *                           Will match  tunnel type (GRE/IP/MCAST) &&
     14  *                                                   (DIP & DIP_MASK)&&
     15  *                                                   (SIP & SIP_MASK)
     16  */
     17 
     18 #include <soc/mem.h>
     19 #include <soc/drv.h>
     20 #include <soc/debug.h>
     21 #include <soc/error.h>
     22 #include <soc/lpm.h>
     23 #include <soc/tnl_term.h>
     24 #include <shared/util.h>
     25 #include <shared/bsl.h>
     26 #include <shared/avl.h>
     27 #include <shared/l3.h>
     28 #if defined(BCM_TRIDENT3_SUPPORT)
     29 #include <soc/esw/flow_db.h>
     30 #endif /*BCM_TRIDENT3_SUPPORT */
     31 
     32 #if defined(BCM_FIREBOLT_SUPPORT)
     33 #if defined(INCLUDE_L3)
     34 
     35 /* Source IP prefix lengths.   */
     36 #define SOC_TNL_TERM_TYPE_SZ(_type_) ((_type_) * (_SHR_L3_IP6_MAX_NETLEN + 1))
     37 
     38 #if defined(BCM_TRIDENT3_SUPPORT)
     39 #define SOC_TNL_TERM_KEY_TYPE_FIXED_MAX               0x03
     40 /*        TUNNEL KEY TYPE                             KEY TYPE PRIORITY */
     41 #define SOC_TNL_TERM_TYPE_FLEX                        SOC_TNL_TERM_TYPE_SZ(0x20)
     42 #endif /*BCM_TRIDENT3_SUPPORT */
     43 /*        TUNNEL KEY TYPE                            KEY TYPE PRIORITY */
     44 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST_L4SRC  SOC_TNL_TERM_TYPE_SZ(0x1f)
     45 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST_L4SRC  SOC_TNL_TERM_TYPE_SZ(0x1e)
     46 #define SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST_L4SRC       SOC_TNL_TERM_TYPE_SZ(0x1d)
     47 #define SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST_L4SRC       SOC_TNL_TERM_TYPE_SZ(0x1c)
     48 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST_L4SRC       SOC_TNL_TERM_TYPE_SZ(0x1b)
     49 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST_L4SRC       SOC_TNL_TERM_TYPE_SZ(0x1a)
     50 #define SOC_TNL_TERM_TYPE_DIP4_L4DST_L4SRC            SOC_TNL_TERM_TYPE_SZ(0x19)
     51 #define SOC_TNL_TERM_TYPE_DIP6_L4DST_L4SRC            SOC_TNL_TERM_TYPE_SZ(0x18)
     52 
     53 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST        SOC_TNL_TERM_TYPE_SZ(0x17)
     54 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST        SOC_TNL_TERM_TYPE_SZ(0x16)
     55 #define SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST             SOC_TNL_TERM_TYPE_SZ(0x15)
     56 #define SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST             SOC_TNL_TERM_TYPE_SZ(0x14)
     57 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST             SOC_TNL_TERM_TYPE_SZ(0x13)
     58 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST             SOC_TNL_TERM_TYPE_SZ(0x12)
     59 #define SOC_TNL_TERM_TYPE_DIP4_L4DST                  SOC_TNL_TERM_TYPE_SZ(0x11)
     60 #define SOC_TNL_TERM_TYPE_DIP6_L4DST                  SOC_TNL_TERM_TYPE_SZ(0x10)
     61 
     62 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4SRC        SOC_TNL_TERM_TYPE_SZ(0xf)
     63 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4SRC        SOC_TNL_TERM_TYPE_SZ(0xe)
     64 #define SOC_TNL_TERM_TYPE_DIP4_PROT_L4SRC             SOC_TNL_TERM_TYPE_SZ(0xd)
     65 #define SOC_TNL_TERM_TYPE_DIP6_PROT_L4SRC             SOC_TNL_TERM_TYPE_SZ(0xc)
     66 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_L4SRC             SOC_TNL_TERM_TYPE_SZ(0xb)
     67 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_L4SRC             SOC_TNL_TERM_TYPE_SZ(0xa)
     68 #define SOC_TNL_TERM_TYPE_DIP4_L4SRC                  SOC_TNL_TERM_TYPE_SZ(9)
     69 #define SOC_TNL_TERM_TYPE_DIP6_L4SRC                  SOC_TNL_TERM_TYPE_SZ(8)
     70 
     71 #define SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT              SOC_TNL_TERM_TYPE_SZ(7)
     72 #define SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT              SOC_TNL_TERM_TYPE_SZ(6)
     73 #define SOC_TNL_TERM_TYPE_DIP4_PROT                   SOC_TNL_TERM_TYPE_SZ(5)
     74 #define SOC_TNL_TERM_TYPE_DIP6_PROT                   SOC_TNL_TERM_TYPE_SZ(4)
     75 
     76 #define SOC_TNL_TERM_TYPE_DIP4_SIP4                   SOC_TNL_TERM_TYPE_SZ(3)
     77 #define SOC_TNL_TERM_TYPE_DIP6_SIP6                   SOC_TNL_TERM_TYPE_SZ(2)
     78 #define SOC_TNL_TERM_TYPE_DIP4                        SOC_TNL_TERM_TYPE_SZ(1)
     79 #define SOC_TNL_TERM_TYPE_DIP6                        SOC_TNL_TERM_TYPE_SZ(0)
     80 
     81 
     82 
     83 /*
     84  * TCAM based tunnel termination implementation. 
     85  * Each table entry holds 1 IPV4 entry
     86  * 4 entries are required for IPv6 tunnel termination. 
     87  * IPV6 entry. 
     88  * Assumption Src + Dst + tunnel type is a unique
     89  * combination.  
     90  *
     91  *              MAX_TNL_TERM_TYPE
     92  * tunnel_term_index[0x20].begin ---> ===============================
     93  *                                 ==                              ==
     94  *                                 ==   0                          ==
     95  * tunnel_term_index[0x20].end   ---> ===============================
     96  *
     97  * tunnel_term_index[0x19].begin ---> ===============================
     98  *                                 == DIP, SIP, PROT, L4SRC, L4DST ==
     99  *                                 ==   IPV4  tunnels              ==
    100  * tunnel_term_index[0x19].end   ---> ===============================
    101  *
    102  * tunnel_term_index[0x18].begin ---> ===============================
    103  *                                 == DIP6, SIP6, PROT,L4SRC,L4DST ==
    104  *                                 ==   IPV6  tunnels              ==
    105  * tunnel_term_index[0x18].end   ---> ===============================
    106  *
    107  *
    108   ................... ETC ...................................... 
    109  *
    110  *
    111  * tunnel_term_index[4].begin ---> ===============================
    112  *                                 ==  DIP + SIP + DON'T CARE   ==
    113  *                                 ==   IPV4  tunnels           ==
    114  * tunnel_term_index[4].end   ---> ===============================
    115  *
    116  *
    117  *
    118  * tunnel_term_index[3].begin ---> ===============================
    119  *                                 ==   DIP6 + SIP6 + DON'T CARE==
    120  *                                 ==   IPV6  tunnels           ==
    121  * tunnel_term_index[3].end   ---> ===============================
    122  *
    123  *
    124  *
    125  * tunnel_term_index[2].begin ---> ===============================
    126  *                                 ==   DIP + DON'T CARE        ==
    127  *                                 ==   IPV4  tunnels           ==
    128  * tunnel_term_index[2].end   ---> ===============================
    129  *
    130  *
    131  *
    132  * tunnel_term_index[1].begin ---> ===============================
    133  *                                 ==   DIP6 + DON'T CARE       ==
    134  *                                 ==   IPV6  tunnels           ==
    135  * tunnel_term_index[1].end   ---> ===============================
    136  */
    137 
    138 
    139 /* Can move to SOC Control structures */
    140 STATIC soc_tnl_term_state_p soc_tnl_term_state[SOC_MAX_NUM_DEVICES];
    141 
    142 #if defined(BCM_TRIDENT3_SUPPORT)
    143 #define MAX_TNL_TERM_TYPES               SOC_TNL_TERM_TYPE_SZ(0x22)
    144 #else
    145 #define MAX_TNL_TERM_TYPES               SOC_TNL_TERM_TYPE_SZ(0x21)
    146 #endif
    147 
    148 #define MAX_TNL_TERM_TYPE                (MAX_TNL_TERM_TYPES - 1)
    149 #define SOC_TNL_TERM_INIT_CHECK(_u_)       (soc_tnl_term_state[(_u_)] != NULL)
    150 #define SOC_TNL_TERM_STATE(_u_)            (soc_tnl_term_state[(_u_)])
    151 #define SOC_TNL_TERM_STATE_START(_u_, _type_) \
    152     (soc_tnl_term_state[(_u_)][(_type_)].start)
    153 
    154 #define SOC_TNL_TERM_STATE_END(_u_, _type_) \
    155     (soc_tnl_term_state[(_u_)][(_type_)].end)
    156 #define SOC_TNL_TERM_STATE_PREV(_u_, _type_) \
    157     (soc_tnl_term_state[(_u_)][(_type_)].prev)
    158 #define SOC_TNL_TERM_STATE_NEXT(_u_, _type_) \
    159     (soc_tnl_term_state[(_u_)][(_type_)].next)
    160 #define SOC_TNL_TERM_STATE_VENT(_u_, _type_) \
    161     (soc_tnl_term_state[(_u_)][(_type_)].vent)
    162 #define SOC_TNL_TERM_STATE_FENT(_u_, _type_) \
    163     (soc_tnl_term_state[(_u_)][(_type_)].fent)
    164 
    165 /* LOCKS */
    166 #define SOC_TNL_TERM_LOCK(_u_)       soc_mem_lock(_u_, ((SOC_MEM_IS_VALID(_u_, L3_TUNNEL_DOUBLEm))?L3_TUNNEL_DOUBLEm:L3_TUNNELm))
    167 #define SOC_TNL_TERM_UNLOCK(_u_)     soc_mem_unlock(_u_, ((SOC_MEM_IS_VALID(_u_, L3_TUNNEL_DOUBLEm))?L3_TUNNEL_DOUBLEm:L3_TUNNELm))
    168 
    169 
    170 #define SOC_TNL_TERM_KEY_WIDTH_MAX     (4) /* 4 words for IPv6  address. */
    171 
    172 typedef int (*_soc_tnl_term_hash_compare_fn)(soc_tnl_term_hash_key_t *key1,
    173                                              soc_tnl_term_hash_key_t *key2);
    174 
    175 STATIC soc_tnl_term_hash_t *_tnl_term_hash_tab[SOC_MAX_NUM_DEVICES];
    176 int SOC_TNL_TERM_BLOCK_SIZE;
    177 STATIC int
    178 _soc_tunnel_term_type_get(int unit, soc_tunnel_term_t *entry,
    179                           int *type, int *entry_type);
    180 
    181 
    182 #define SOC_TNL_TERM_STATE_HASH(_u_)        (_tnl_term_hash_tab[(_u_)])
    183 
    184 #define TNL_TERM_TYPE_NULL        (-1)
    185 #define TNL_TERM_HASH_INDEX_NULL  (0xFFFF)
    186 
    187 /*
    188  * Purpose:
    189  *	 Set SOC_TNL_TERM_BLOCK_SIZE
    190  */ 
    191 
    192 int soc_tunnel_term_block_size_set (int unit, int size)
    193 {
    194     SOC_TNL_TERM_BLOCK_SIZE = size;
    195     return SOC_E_NONE;
    196 }
    197 
    198 /*
    199  * Purpose:
    200  *	 Get SOC_TNL_TERM_BLOCK_SIZE
    201  */ 
    202 
    203 int soc_tunnel_term_block_size_get (int unit, int *size)
    204 {
    205     *size = SOC_TNL_TERM_BLOCK_SIZE;
    206     return SOC_E_NONE;
    207 }
    208 
    209 #if defined(BCM_TRIDENT3_SUPPORT)
    210 /*
    211  * Function:
    212  *      _soc_tunnel_term_flex_type_width_get
    213  * Purpose:
    214  *      Get the width of flex tunnel terminator entry.
    215  * Parameters:
    216  *      unit          - (IN)  Bcm device number.
    217  *      type          - (IN)  Tunnel terminator type.
    218  *      entry         - (IN)  Tunnel termination entry.
    219  *      entry_width   - (IN)  Entry width.
    220  * Returns:
    221  *      SOC_E_XXX
    222  */
    223 STATIC int
    224 _soc_tunnel_term_flex_type_width_get(int unit, int type, soc_tunnel_term_t *entry,
    225                                      int *entry_width) {
    226 
    227     uint32 mode = 0;
    228     if (entry_width == NULL) {
    229         return SOC_E_INTERNAL;
    230     }
    231     if (type != SOC_TNL_TERM_TYPE_FLEX) {
    232          return SOC_E_INTERNAL;
    233     }
    234     mode = soc_mem_field32_get(unit, L3_TUNNELm, (uint32 *)&entry->entry_arr[0], MODEf);
    235     if (mode == SOC_TNL_TERM_ENTRY_MODE_QUAD) {
    236        *entry_width = SOC_TNL_TERM_ENTRY_WIDTH_QUAD;
    237     } else if (mode == SOC_TNL_TERM_ENTRY_MODE_DOUBLE) {
    238        *entry_width = SOC_TNL_TERM_ENTRY_WIDTH_DOUBLE;
    239     }  else {
    240        *entry_width = SOC_TNL_TERM_ENTRY_WIDTH_SINGLE;
    241     }
    242     return SOC_E_NONE;
    243 }
    244 
    245 /*
    246  * Function:
    247  *      _soc_tunnel_term_flex_hash_key_set
    248  * Purpose:
    249  *     Form the hash key for flex tunnel terminator entry.
    250  * Parameters:
    251  *      unit             - (IN)      Bcm device number.
    252  *      entry            - (IN)      Tunnel termination entry.
    253  *      flex_key_entry   - (IN/OUT)  Hash key.
    254  * Returns:
    255  *      SOC_E_XXX
    256  */
    257 STATIC void
    258 _soc_tunnel_term_flex_hash_key_set(int unit, soc_tunnel_term_t *entry,
    259                                 uint32  *flex_key_entry) {
    260     soc_mem_t mem;
    261     soc_mem_t mem_view_id;
    262     uint32 key_type = SOC_FLOW_DB_KEY_TYPE_INVALID;
    263     uint32 data_type = SOC_FLOW_DB_KEY_TYPE_INVALID;
    264     uint32 key_typef[] = {KEY_TYPEf,
    265                          KEY_TYPE0f,
    266                          KEY_TYPE1f};
    267     uint32 data_typef[] = {DATA_TYPEf,
    268                           DATA_TYPE0f,
    269                           DATA_TYPE1f};
    270     uint32 key_list[SOC_FLOW_DB_MAX_VIEW_FIELDS];
    271     uint32 key_count = 0;
    272     uint32 key_value = 0;
    273     uint32 trav_entry[SOC_MAX_MEM_WORDS*4];
    274     uint32 entry_width = sizeof(tunnel_entry_t);
    275     uint32 i = 0;
    276     ip6_addr_t ip6;
    277     int rv = -1;
    278     mem = L3_TUNNELm;
    279     sal_memset(trav_entry, 0, sizeof(trav_entry));
    280 
    281     /* Get the view for the memory */
    282     for (i = 0; i < 4; i++) {
    283         sal_memcpy(((uint8 *)trav_entry + (entry_width * i)),
    284                    &entry->entry_arr[i], entry_width);
    285     }
    286     for (i = 0; i < SOC_FLOW_DB_MAX_KEY_TYPE; i++) {
    287         if (SOC_MEM_FIELD_VALID(unit,mem,key_typef[i])) {
    288              key_type = soc_mem_field32_get(unit, mem, trav_entry, key_typef[i]);
    289              break;
    290         }
    291     }
    292 
    293     for (i = 0; i < SOC_FLOW_DB_MAX_DATA_TYPE; i++) {
    294         if (SOC_MEM_FIELD_VALID(unit,mem,data_typef[i])) {
    295             data_type = soc_mem_field32_get(unit, mem, trav_entry, data_typef[i]);
    296         }
    297     }
    298 
    299     /* find the memory view based on the memory and key type */
    300     rv = soc_flow_db_mem_to_view_id_get (unit, mem, key_type, data_type,
    301                     0, NULL, (uint32 *) &mem_view_id);
    302     if (SOC_FAILURE(rv)) {
    303         return;
    304     }
    305 
    306     rv = soc_flow_db_mem_view_field_list_get(unit,
    307                 mem_view_id,
    308                 SOC_FLOW_DB_FIELD_TYPE_KEY,
    309                 SOC_FLOW_DB_MAX_VIEW_FIELDS,
    310                 key_list,
    311                 &key_count);
    312     if (SOC_FAILURE(rv)) {
    313         return;
    314     }
    315 
    316     for(i = 0; i < key_count; i++) {
    317        if ((key_list[i] == IPV6__SIPf) ||
    318            (key_list[i] == IPV6__DIPf) ||
    319            (key_list[i] == IPV6__SIP_MASKf) ||
    320            (key_list[i] == IPV6__DIP_MASKf)) {
    321            sal_memset(&ip6, 0, sizeof(ip6_addr_t));
    322            soc_mem_ip6_addr_get(unit, mem_view_id,
    323                             trav_entry, key_list[i], ip6, 0);
    324            soc_mem_ip6_addr_set(unit, mem_view_id,
    325                             flex_key_entry, key_list[i], ip6, 0);
    326        } else if ((key_list[i] == KEY_0f) || 
    327                   (key_list[i] == KEY_1f) ) {
    328            /* ignore */
    329            continue;
    330        }
    331        key_value = soc_mem_field32_get(unit,
    332                                        mem_view_id,
    333                                        trav_entry,
    334                                        key_list[i]);
    335        soc_mem_field32_set(unit, mem_view_id,
    336                     flex_key_entry, key_list[i], key_value);
    337     }
    338 
    339     rv = soc_flow_db_mem_view_field_list_get(unit,
    340                 mem_view_id,
    341                 SOC_FLOW_DB_FIELD_TYPE_LOGICAL_KEY,
    342                 SOC_FLOW_DB_MAX_VIEW_FIELDS,
    343                 key_list,
    344                 &key_count);
    345     if (SOC_FAILURE(rv)) {
    346         return;
    347     }
    348 
    349     for(i = 0; i < key_count; i++) {
    350         key_value = soc_mem_field32_get(unit,
    351                                        mem_view_id,
    352                                        trav_entry,
    353                                        key_list[i]);
    354         soc_mem_field32_set(unit, mem_view_id,
    355                 flex_key_entry, key_list[i], key_value);
    356     }
    357     return;
    358 }
    359 
    360 /*
    361  * Function:
    362  *      _soc_tunnel_term_flex_entry_clear
    363  * Purpose:
    364  *      Clear flex tunnel termination entry to the hardware.
    365  * Parameters:
    366  *      unit          - (IN)  Bcm device number.
    367  *      index         - (IN)  Table index.
    368  *      entry         - (IN)  Tunnel termination entry.
    369  *      ipv6          - (IN)  Type.
    370  * Returns:
    371  *      SOC_E_XXX
    372  */
    373 STATIC int
    374 _soc_tunnel_term_flex_entry_clear(int unit, int index,
    375                              soc_tunnel_term_t *entry, int entry_type)
    376 {
    377     int idx;       /* Entry width iteration index. */
    378     int idx_max;   /* Entry width.                 */
    379     int type;
    380     int key_type;
    381     soc_tunnel_term_t null_entry;
    382     soc_tunnel_term_t *entry_ptr = NULL;
    383 
    384     /* Input parameters check. */
    385     if (NULL == entry) {
    386         return (SOC_E_PARAM);
    387     }
    388 
    389     SOC_IF_ERROR_RETURN
    390         (_soc_tunnel_term_type_get(unit, entry, &type, &key_type));
    391     SOC_IF_ERROR_RETURN (
    392         _soc_tunnel_term_flex_type_width_get(unit, type, entry, &idx_max));
    393     /* null entry */
    394     sal_memset(&null_entry, 0, sizeof(soc_tunnel_term_t));
    395     entry_ptr = &null_entry;
    396 
    397     for (idx = 0; idx < idx_max; idx++) {
    398         SOC_IF_ERROR_RETURN (WRITE_L3_TUNNELm(unit, MEM_BLOCK_ALL,
    399                                               (idx + index),
    400                                               (uint32 *)&entry_ptr->entry_arr[idx]));
    401     }
    402     return (SOC_E_NONE);
    403 }
    404 
    405 #endif /*BCM_TRIDENT3_SUPPORT*/
    406 
    407 /*
    408  * Function:
    409  *   _soc_tunnel_term_hash_entry_get
    410  * Purpose:
    411  *	 Extract key data from an entry at the given index.
    412  * Parameters:
    413  *      unit          - (IN) BCM device number. 
    414  *      entry_arr     - (IN) Array of entries forming single 
    415  *                           tunnel termination entry.  
    416  *      ipv6          - (IN) IPv4/IPv6 entry flag.  
    417  *      entry_key     - (OUT) Tunnel termination key. 
    418  * Returns: 
    419  *      none
    420  */ 
    421 STATIC void
    422 _soc_tunnel_term_hash_entry_get(int unit, soc_tunnel_term_t *entry, int entry_type,
    423                                 soc_tnl_term_hash_key_t *entry_key)
    424 {
    425     uint32 *entry_ptr;                       /* HW entry pointer.        */
    426     uint8 sip_mask[_SHR_L3_IP6_ADDRLEN];     /* Source ip subent mask.   */
    427     soc_mem_t mem = L3_TUNNELm;
    428     soc_field_t ipv4f = IP_ADDRf;
    429     soc_field_t ipv4_maskf = IP_ADDR_MASKf;
    430 #if defined(BCM_TRIUMPH2_SUPPORT)
    431     soc_field_t l4_src_port_f = L4_SRC_PORTf; 
    432     soc_field_t l4_dest_port_f = L4_DEST_PORTf;
    433     soc_field_t protocol_f = PROTOCOLf;
    434 #endif
    435     int ipv6_key_type = 0x1;
    436     int ipv4_key_type = 0x0;
    437     uint8 *ip6 = NULL;
    438     uint32              ip6_field[4];
    439 
    440     /* Input parameters check */
    441     if (NULL == entry_key) {
    442         return;
    443     }
    444 
    445     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    446         mem = L3_TUNNEL_DOUBLEm;
    447         ipv6_key_type = 0x2;
    448         ipv4_key_type = 0x1;
    449 #if defined(BCM_TRIUMPH2_SUPPORT)
    450         l4_src_port_f = IPV4__L4_SRC_PORTf;
    451         l4_dest_port_f = IPV4__L4_DEST_PORTf;
    452         protocol_f = IPV4__PROTOCOLf;
    453 #endif
    454         if (entry_type == ipv6_key_type) {
    455             mem = L3_TUNNEL_QUADm;
    456 #if defined(BCM_TRIUMPH2_SUPPORT)
    457             l4_src_port_f = IPV6__L4_SRC_PORTf;
    458             l4_dest_port_f = IPV6__L4_DEST_PORTf;
    459             protocol_f = IPV6__PROTOCOLf;
    460 #endif
    461         }
    462     }
    463 
    464     /* Initialization part. */
    465     sal_memset(entry_key, 0, sizeof(soc_tnl_term_hash_key_t)); 
    466     entry_ptr = (uint32 *)&entry->entry_arr[0];
    467 
    468 #if defined(BCM_TRIUMPH3_SUPPORT) || defined (BCM_KATANA2_SUPPORT) || \
    469     defined(BCM_APACHE_SUPPORT)
    470     /* For Triumph3 get MIM and MPLS L3 tunnel entries */
    471     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit) ||
    472         soc_feature(unit, soc_feature_l3_tunnel_mpls_frr)) {
    473         if (entry_type == 0x3) { /* MIM Type */
    474             /* Get MIM::SGLP */
    475             entry_key->mim_hash_key.sglp = 
    476                    soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr, MIM__SGLPf);
    477             /* Get MIM::BVID */
    478             entry_key->mim_hash_key.bvid = 
    479                    soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr, MIM__BVIDf);
    480             /* Get MIM::BMACSA */
    481             soc_mem_mac_addr_get(unit, L3_TUNNELm, entry_ptr, MIM__SGLPf, 
    482                           entry_key->mim_hash_key.bmacsa);
    483             return;
    484 
    485         } 
    486     } 
    487 #endif /* BCM_TRIUMPH3_SUPPORT || BCM_KATANA2_SUPORT */
    488 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT) || \
    489     defined(BCM_KATANA2_SUPORT) || defined(BCM_APACHE_SUPPORT)
    490     if (SOC_IS_TOMAHAWK2(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit) ||
    491             soc_feature(unit, soc_feature_l3_tunnel_mpls_frr)) {
    492         if (entry_type == 0x2) { /* MPLS Type */
    493             /* Get MPLS::MPLS_LABEL */
    494             entry_key->mpls_hash_key.mpls_label =
    495                     soc_mem_field32_get(unit, mem, entry_ptr,
    496                                      MPLS__MPLS_LABELf);
    497             /* Get MPLS::MODULE_ID */
    498             entry_key->mpls_hash_key.module_id =
    499                     soc_mem_field32_get(unit, mem, entry_ptr, MPLS__MODULE_IDf);
    500             /* Get MPLS::PORT_NUM */
    501             entry_key->mpls_hash_key.port =
    502                     soc_mem_field32_get(unit, mem, entry_ptr, MPLS__PORT_NUMf);
    503             /* Get MPLS::TGID */
    504             entry_key->mpls_hash_key.trunk_id =
    505                     soc_mem_field32_get(unit, mem, entry_ptr, MPLS__TGIDf);
    506             return;
    507         }
    508     }
    509 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIUMPH3_SUPPORT || BCM_KATANA2_SUPORT */
    510 
    511     if (entry_type == ipv6_key_type) { /* IPV6 Type */
    512         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    513             ip6 = entry_key->ip_hash_key.sip;
    514             /* SIP [0-89] */
    515             soc_mem_field_get(unit, mem, (uint32 *)&entry->entry_arr[0], IPV6__SIP_LWR_90f, ip6_field);
    516 
    517             ip6[4] = (ip6_field[2] & 0xff);
    518             ip6[5] = (ip6_field[2]  >> 8) & 0xff;
    519             ip6[6] = (ip6_field[2]  >> 16) & 0xff;
    520             ip6[7] = (ip6_field[2]  >> 24) & 0x3;
    521 
    522             ip6[8] = (ip6_field[1] & 0xff);
    523             ip6[9] = (ip6_field[1]  >> 8) & 0xff;
    524             ip6[10] = (ip6_field[1]  >> 16) & 0xff;
    525             ip6[11] = (ip6_field[1]  >> 24) & 0xff;
    526 
    527             ip6[12] = (ip6_field[0] & 0xff);
    528             ip6[13] = (ip6_field[0]  >> 8) & 0xff;
    529             ip6[14] = (ip6_field[0]  >> 16) & 0xff;
    530             ip6[15] = (ip6_field[0]  >> 24) & 0xff;
    531 
    532             /* SIP [90-127] */
    533             soc_mem_field_get(unit, mem, (uint32 *)&entry->entry_arr[0], IPV6__SIP_UPR_38f, ip6_field);
    534             ip6[0] = (ip6_field[0] & 0xff);
    535             ip6[1] = (ip6_field[1]  >> 8) & 0xff;
    536             ip6[2] = (ip6_field[2]  >> 16) & 0xff;
    537             ip6[3] = (ip6_field[3]  >> 24) & 0xff;
    538 
    539             ip6 = entry_key->ip_hash_key.dip;
    540             /* DIP [0-89] */
    541             soc_mem_field_get(unit, mem, (uint32 *)&entry->entry_arr[0], IPV6__DIP_LWR_90f, ip6_field);
    542             ip6[4] = (ip6_field[2] & 0xff);
    543             ip6[5] = (ip6_field[2]  >> 8) & 0xff;
    544             ip6[6] = (ip6_field[2]  >> 16) & 0xff;
    545             ip6[7] = (ip6_field[2]  >> 24) & 0x3;
    546 
    547             ip6[8] = (ip6_field[1] & 0xff);
    548             ip6[9] = (ip6_field[1]  >> 8) & 0xff;
    549             ip6[10] = (ip6_field[1]  >> 16) & 0xff;
    550             ip6[11] = (ip6_field[1]  >> 24) & 0xff;
    551 
    552             ip6[12] = (ip6_field[0] & 0xff);
    553             ip6[13] = (ip6_field[0]  >> 8) & 0xff;
    554             ip6[14] = (ip6_field[0]  >> 16) & 0xff;
    555             ip6[15] = (ip6_field[0]  >> 24) & 0xff;
    556 
    557             /* DIP [90-127] */
    558             soc_mem_field_get(unit, mem, (uint32 *)&entry->entry_arr[0], IPV6__DIP_UPR_38f, ip6_field);
    559             ip6[0] = (ip6_field[0] & 0xff);
    560             ip6[1] = (ip6_field[1]  >> 8) & 0xff;
    561             ip6[2] = (ip6_field[2]  >> 16) & 0xff;
    562             ip6[3] = (ip6_field[3]  >> 24) & 0xff;
    563             entry_key->ip_hash_key.sip_plen = 128;
    564         } else {
    565             /* SIP [0-63] */
    566             soc_mem_ip6_addr_get(unit, mem,
    567                                  (uint32 *)&entry->entry_arr[0], ipv4f,
    568                                  entry_key->ip_hash_key.sip, SOC_MEM_IP6_LOWER_ONLY);
    569             /* SIP [64-127] */
    570             soc_mem_ip6_addr_get(unit, mem,
    571                                  (uint32 *)&entry->entry_arr[1], ipv4f,
    572                                  entry_key->ip_hash_key.sip, SOC_MEM_IP6_UPPER_ONLY);
    573             /* DIP [0-63] */
    574             soc_mem_ip6_addr_get(unit, mem,
    575                                  (uint32 *)&entry->entry_arr[2], ipv4f,
    576                                  entry_key->ip_hash_key.dip, SOC_MEM_IP6_LOWER_ONLY);
    577             /* DIP [64-127] */
    578             soc_mem_ip6_addr_get(unit, mem,
    579                                  (uint32 *)&entry->entry_arr[3], ipv4f,
    580                                  entry_key->ip_hash_key.dip, SOC_MEM_IP6_UPPER_ONLY);
    581 
    582             /* SIP MASK [0-63] */
    583             soc_mem_ip6_addr_get(unit, mem,
    584                                  (uint32 *)&entry->entry_arr[0], ipv4_maskf,
    585                                  sip_mask, SOC_MEM_IP6_LOWER_ONLY);
    586             /* SIP MASK [64-127] */
    587             soc_mem_ip6_addr_get(unit, mem,
    588                                  (uint32 *)&entry->entry_arr[1], ipv4_maskf,
    589                                  sip_mask, SOC_MEM_IP6_UPPER_ONLY);
    590             entry_key->ip_hash_key.sip_plen =  _shr_ip6_mask_length(sip_mask);
    591         }
    592     } else if (entry_type == ipv4_key_type) { /* IPV4 Type */
    593         soc_field_t dipf = DIPf, sipf = SIPf;
    594         /* Get destination ip. */
    595         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    596             sipf = IPV4__SIPf;
    597             dipf = IPV4__DIPf;
    598         } 
    599         soc_mem_field_get(unit, mem, entry_ptr, dipf,
    600                           (uint32 *)entry_key->ip_hash_key.dip);
    601 
    602         /* Get source ip. */
    603         soc_mem_field_get(unit, mem, entry_ptr, sipf,
    604                           (uint32 *)entry_key->ip_hash_key.sip);
    605 
    606         /* Get source ip. */
    607         if (SOC_MEM_FIELD_VALID(unit, mem, SIP_MASKf)) {
    608             soc_mem_field_get(unit, mem, entry_ptr, SIP_MASKf,
    609                               (uint32 *)sip_mask);
    610             entry_key->ip_hash_key.sip_plen =  
    611                             _shr_ip_mask_length((*(uint32 *)sip_mask));
    612         } else {
    613             entry_key->ip_hash_key.sip_plen = 
    614                             (*(uint32 *)entry_key->ip_hash_key.sip) ? 32 : 0;
    615         }
    616     }
    617 #if defined(BCM_TRIDENT3_SUPPORT)
    618     else if (soc_feature(unit,soc_feature_flex_flow)
    619              && (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)){
    620         /* Flex views */
    621         _soc_tunnel_term_flex_hash_key_set(unit, entry, entry_key->flex_hash_key.entry);
    622         return;
    623     }
    624 #endif /* BCM_TRIDENT3_SUPPORT */
    625 #if defined(BCM_TRIUMPH2_SUPPORT)
    626     if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    627          l4_src_port_f = L4_SRC_PORTf;
    628          l4_dest_port_f = L4_DEST_PORTf;
    629          protocol_f = PROTOCOLf;
    630     }
    631     if (SOC_MEM_FIELD_VALID(unit, mem, l4_src_port_f)) {
    632         entry_key->ip_hash_key.l4_src_port =
    633             soc_mem_field32_get(unit, mem, entry_ptr, l4_src_port_f);
    634     }
    635     if (SOC_MEM_FIELD_VALID(unit, mem, l4_dest_port_f)) {
    636         entry_key->ip_hash_key.l4_dst_port =
    637             soc_mem_field32_get(unit, mem, entry_ptr, l4_dest_port_f);
    638     }
    639     if (SOC_MEM_FIELD_VALID(unit, mem, protocol_f)) {
    640         entry_key->ip_hash_key.ip_protocol =
    641             soc_mem_field32_get(unit, mem, entry_ptr, protocol_f);
    642     }
    643     
    644 #endif /* BCM_TRIUMPH2_SUPPORT */
    645 
    646 #if defined(BCM_TRX_SUPPORT)
    647     if (SOC_MEM_FIELD_VALID(unit, mem, GRE_TUNNELf)) {
    648         entry_key->ip_hash_key.ip_protocol =
    649             soc_mem_field32_get(unit, mem, entry_ptr, GRE_TUNNELf);
    650     }
    651 #endif /* BCM_TRX_SUPPORT*/
    652     return;
    653 }
    654 
    655 #define SOC_TNL_TERM_HASH_ENTRY_GET _soc_tunnel_term_hash_entry_get
    656 /*
    657  * Function:
    658  *   _soc_tunnel_term_type_get
    659  * Purpose:
    660  *	 Extract tunnel terminator entry type 
    661  *   (DIP6/SIP6)/(DIP4/SIP4)/(DIP 6/(*))/(DIP4/(*)) 
    662  * Parameters:
    663  *      unit      - (IN)  BCM device number. 
    664  *      entry     - (IN)  Tunnel terminator entry.
    665  *      type      - (OUT) Tunnel terminator search result.
    666  *      ipv6      - (OUT) IPv6 Tunnel termination flag. 
    667  * Returns: 
    668  *      SOC_E_XXX
    669  */ 
    670 STATIC int
    671 _soc_tunnel_term_type_get(int unit, soc_tunnel_term_t *entry, 
    672                           int *type, int *entry_type)
    673 {
    674     int key;                              /* IPv6 tunnel terminator flag.    */
    675     soc_tnl_term_hash_key_t key_hash; /* Tunnel termination hashing key. */
    676 #if defined(BCM_TRX_SUPPORT)
    677     soc_mem_t  mem = L3_TUNNELm;
    678 #endif
    679     int ipv6_key_type = 0x1;
    680 
    681     /* Input parameters check. */
    682     if (NULL == entry) {
    683         return (SOC_E_PARAM);
    684     }
    685 
    686 #if defined(BCM_TRX_SUPPORT)
    687     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    688         mem = L3_TUNNEL_DOUBLEm;
    689         ipv6_key_type = 0x2;
    690     }
    691 
    692     if (soc_feature(unit,soc_feature_flex_flow) &&
    693         ((soc_mem_field32_get(unit, mem,
    694                (uint32 *)&entry->entry_arr[0], KEY_TYPEf)) > 3)) {
    695          /* flex view */
    696          key = soc_mem_field32_get(unit, mem,
    697                              (uint32 *)&entry->entry_arr[0], KEY_TYPEf);
    698     /* Get tunnel termination type IPv4/IPv6 */     
    699     } else if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) {
    700         key = soc_mem_field32_get(unit, mem,
    701                                  (uint32 *)&entry->entry_arr[0], MODEf);
    702     } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) {
    703         key = soc_mem_field32_get(unit, mem,
    704                                  (uint32 *)&entry->entry_arr[0], KEY_TYPEf);
    705     } else
    706 #endif /* BCM_TRX_SUPPORT */ 
    707     {
    708         key = 0; /* IPV4 default type */
    709     }
    710 
    711     /* Assign ipv6 flag if caller provided ipv6 pointer. */
    712     if (NULL != entry_type) {
    713         *entry_type = key;
    714     }
    715 
    716     /* If caller doesn't want tunnel type skip this section. */
    717     if (NULL == type) {
    718         return (SOC_E_NONE);
    719     }
    720 
    721     /* Extract source ip portion as part of hash. */
    722     SOC_TNL_TERM_HASH_ENTRY_GET(unit, entry, key, &key_hash);
    723 
    724     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
    725         SOC_IS_VALKYRIE2(unit)) {
    726         if (key == ipv6_key_type) { /* IPV6 */
    727 
    728             if (key_hash.ip_hash_key.l4_src_port 
    729                         && key_hash.ip_hash_key.l4_dst_port) {
    730                 if (key_hash.ip_hash_key.ip_protocol) {
    731                     if (0 == key_hash.ip_hash_key.sip_plen) {
    732                         *type = SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST_L4SRC; 
    733                     } else {
    734                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST_L4SRC;
    735                     }
    736                 } else {
    737                     if (0 == key_hash.ip_hash_key.sip_plen) {
    738                         *type = SOC_TNL_TERM_TYPE_DIP6_L4DST_L4SRC; 
    739                     } else {
    740                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST_L4SRC;
    741                     }
    742                 }
    743             } else if (key_hash.ip_hash_key.l4_src_port) {
    744                 if (key_hash.ip_hash_key.ip_protocol) {
    745                     if (0 == key_hash.ip_hash_key.sip_plen) {
    746                         *type = SOC_TNL_TERM_TYPE_DIP6_PROT_L4SRC; 
    747                     } else {
    748                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4SRC;
    749                     }
    750                 } else {
    751                     if (0 == key_hash.ip_hash_key.sip_plen) {
    752                         *type = SOC_TNL_TERM_TYPE_DIP6_L4SRC; 
    753                     } else {
    754                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_L4SRC;
    755                     }
    756                 }
    757             } else if (key_hash.ip_hash_key.l4_dst_port) {
    758                 if (key_hash.ip_hash_key.ip_protocol) {
    759                     if (0 == key_hash.ip_hash_key.sip_plen) {
    760                         *type = SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST; 
    761                     } else {
    762                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST;
    763                     }
    764                 } else {
    765                     if (0 == key_hash.ip_hash_key.sip_plen) {
    766                         *type = SOC_TNL_TERM_TYPE_DIP6_L4DST; 
    767                     } else {
    768                         *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST;
    769                     }
    770                 }
    771             } else if (key_hash.ip_hash_key.ip_protocol) {
    772                 if (0 == key_hash.ip_hash_key.sip_plen) {
    773                     *type = SOC_TNL_TERM_TYPE_DIP6_PROT;
    774                 } else {
    775                     *type = SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT;
    776                 }
    777             } else {
    778                 if (0 == key_hash.ip_hash_key.sip_plen) {
    779                     *type = SOC_TNL_TERM_TYPE_DIP6;
    780                 } else {
    781                     *type = SOC_TNL_TERM_TYPE_DIP6_SIP6;
    782                 }
    783             }
    784         } else  {
    785             if (key_hash.ip_hash_key.l4_src_port 
    786                         && key_hash.ip_hash_key.l4_dst_port) {
    787                 if (key_hash.ip_hash_key.ip_protocol) {
    788                     if (0 == key_hash.ip_hash_key.sip_plen) {
    789                         *type = SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST_L4SRC; 
    790                     } else {
    791                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST_L4SRC;
    792                     }
    793                 } else {
    794                     if (0 == key_hash.ip_hash_key.sip_plen) {
    795                         *type = SOC_TNL_TERM_TYPE_DIP4_L4DST_L4SRC; 
    796                     } else {
    797                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST_L4SRC;
    798                     }
    799                 }
    800             } else if (key_hash.ip_hash_key.l4_src_port) {
    801                 if (key_hash.ip_hash_key.ip_protocol) {
    802                     if (0 == key_hash.ip_hash_key.sip_plen) {
    803                         *type = SOC_TNL_TERM_TYPE_DIP4_PROT_L4SRC; 
    804                     } else {
    805                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4SRC;
    806                     }
    807                 } else {
    808                     if (0 == key_hash.ip_hash_key.sip_plen) {
    809                         *type = SOC_TNL_TERM_TYPE_DIP4_L4SRC; 
    810                     } else {
    811                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_L4SRC;
    812                     }
    813                 }
    814             } else if (key_hash.ip_hash_key.l4_dst_port) {
    815                 if (key_hash.ip_hash_key.ip_protocol) {
    816                     if (0 == key_hash.ip_hash_key.sip_plen) {
    817                         *type = SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST; 
    818                     } else {
    819                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST;
    820                     }
    821                 } else {
    822                     if (0 == key_hash.ip_hash_key.sip_plen) {
    823                         *type = SOC_TNL_TERM_TYPE_DIP4_L4DST; 
    824                     } else {
    825                         *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST;
    826                     }
    827                 }
    828             } else if (key_hash.ip_hash_key.ip_protocol) {
    829                 if (0 == key_hash.ip_hash_key.sip_plen) {
    830                     *type = SOC_TNL_TERM_TYPE_DIP4_PROT;
    831                 } else {
    832                     *type = SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT;
    833                 }
    834             } else {
    835                 if (0 == key_hash.ip_hash_key.sip_plen) {
    836                     *type = SOC_TNL_TERM_TYPE_DIP4;
    837                 } else {
    838                     *type = SOC_TNL_TERM_TYPE_DIP4_SIP4;
    839                 }
    840             }
    841         }
    842     } else {
    843         if (key == ipv6_key_type) { /* IPV6 Type */
    844             if (0 == key_hash.ip_hash_key.sip_plen) { 
    845                 *type = SOC_TNL_TERM_TYPE_DIP6;
    846             } else {
    847                 *type = SOC_TNL_TERM_TYPE_DIP6_SIP6;
    848             }
    849         } else
    850 #if defined(BCM_TRIDENT3_SUPPORT)
    851         if (soc_feature(unit,soc_feature_flex_flow) &&
    852            (key > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
    853             *type = SOC_TNL_TERM_TYPE_FLEX;
    854         } else
    855 #endif /* BCM_TRIDENT3_SUPPORT */
    856         {
    857             if (0 == key_hash.ip_hash_key.sip_plen) {
    858                 *type =SOC_TNL_TERM_TYPE_DIP4;
    859             } else {
    860                 *type = SOC_TNL_TERM_TYPE_DIP4_SIP4;
    861             }
    862         }
    863     }
    864 
    865     if (!(soc_feature(unit,soc_feature_flex_flow) &&
    866            (key > 0x03))) {
    867         /* Add sip prefix length on top of resovled type. */
    868         *type += key_hash.ip_hash_key.sip_plen;
    869     }
    870 
    871     return (SOC_E_NONE);
    872 }
    873 
    874 /*
    875  * Function:
    876  *   _soc_tunnel_term_hash_compare_key
    877  * Purpose:
    878  *   Tunnel termination entry comparison routine 
    879  *   for sw table management operations.
    880  * Parameters:
    881  *      key1  - (IN) First compared tunnel termination key. 
    882  *      key2  - (IN) Second compared tunnel termination key. 
    883  * Returns: 
    884  *      Comparison result(LESS/GREATER/EQUALS) key1 <=> key2.  
    885  */ 
    886 static INLINE int
    887 _soc_tunnel_term_hash_compare_key(soc_tnl_term_hash_key_t *key1,
    888                                   soc_tnl_term_hash_key_t *key2)
    889 {
    890     return sal_memcmp(key1, key2, sizeof(soc_tnl_term_hash_key_t));
    891 }
    892 
    893 /* 
    894  * Function:
    895  *      _soc_tunnel_term_hash_compute
    896  * Purpose:
    897  *      Compute CRC hash for key data.
    898  * Parameters:
    899  *      data       - (IN) Key data
    900  *      data_nbits - (IN) Number of data bits
    901  *      hash_val   - (OUT) Hash value 
    902  * Returns:
    903  *      SOC_E_XXX
    904  */
    905 STATIC int
    906 _soc_tunnel_term_hash_compute(uint8 *data, int data_nbits, uint16 *hash_val)
    907 {
    908     /* Input parameters check. */
    909     if ((NULL == data) || (NULL == hash_val)) {
    910         return (SOC_E_PARAM);
    911     }
    912     *hash_val = _shr_crc16b(0, data, data_nbits);
    913 
    914     return (SOC_E_NONE);
    915 }
    916 
    917 /* 
    918  * Function:
    919  *      _soc_tunnel_term_hash_create
    920  * Purpose:
    921  *      Create an empty hash table
    922  * Parameters:
    923  *      unit        - (IN)BCM device number.  
    924  *      entry_count - (IN) Limit for number of entries in table
    925  *      index_count - (IN) Hash index max + 1. (index_count <= count)
    926  *      tnl_term_hash_ptr - (OUT) Return pointer (handle) to new Hash Table
    927  * Returns:
    928  *      SOC_E_NONE       Success
    929  *      SOC_E_MEMORY     Out of memory (system allocator)
    930  */
    931 
    932 STATIC int 
    933 _soc_tunnel_term_hash_create(int unit, 
    934                              int entry_count,
    935                              int index_count,
    936                              soc_tnl_term_hash_t **tnl_term_hash_ptr)
    937 {
    938     soc_tnl_term_hash_t   *hash;        /* Tunnel termination hash. */
    939     int                   index;        /* Hash iteration index.    */
    940     int                   alloc_size;   /* Allocation size.         */
    941 
    942     /* Input parameters check. */
    943     if ((NULL == tnl_term_hash_ptr) || (index_count > entry_count))  {
    944         return (SOC_E_PARAM);
    945     }
    946 
    947     alloc_size = sizeof (soc_tnl_term_hash_t);
    948     hash = sal_alloc(alloc_size, "tnl_term_hash");
    949     if (hash == NULL) {
    950         return SOC_E_MEMORY;
    951     }
    952     /* Initialize hash structure. */
    953     sal_memset(hash, 0, alloc_size);
    954     hash->unit = unit;
    955     hash->entry_count = entry_count;
    956     hash->index_count = index_count;
    957 
    958     /*
    959      * Pre-allocate the hash table storage.
    960      */
    961     alloc_size = hash->index_count * sizeof(uint16);
    962     hash->table = sal_alloc(alloc_size, "tnl_term_hash_table");
    963     if (hash->table == NULL) {
    964         sal_free(hash);
    965         return (SOC_E_MEMORY);
    966     }
    967 
    968     /*
    969      * In case where all the entries should hash into the same bucket
    970      * this will prevent the hash table overflow
    971      */
    972     alloc_size = hash->entry_count * sizeof(uint16);
    973     hash->link_table = sal_alloc(alloc_size, "tnl_term_link_table");
    974     if (hash->link_table == NULL) {
    975         sal_free(hash->table);
    976         sal_free(hash);
    977         return (SOC_E_MEMORY);
    978     }
    979 
    980     /*
    981      * Set the entries in the hash table to TNL_TERM_HASH_INDEX_NULL
    982      * Link the entries beyond hash->index_max for handling collisions
    983      */
    984     for(index = 0; index < hash->index_count; index++) {
    985         hash->table[index] = TNL_TERM_HASH_INDEX_NULL;
    986     }
    987     for(index = 0; index < hash->entry_count; index++) {
    988         hash->link_table[index] = TNL_TERM_HASH_INDEX_NULL;
    989     }
    990     *tnl_term_hash_ptr = hash;
    991     return (SOC_E_NONE);
    992 }
    993 
    994 /* 
    995  * Function:
    996  *      _soc_tunnel_term_hash_destroy
    997  * Purpose:
    998  *      Destroy the hash table.
    999  * Parameters:
   1000  *      tnl_term_hash - (IN) Hash Table handler address.
   1001  * Returns:
   1002  *      SOC_E_NONE       Success
   1003  */
   1004 STATIC int 
   1005 _soc_tunnel_term_hash_destroy(soc_tnl_term_hash_t **tnl_term_hash)
   1006 {
   1007     soc_tnl_term_hash_t *ptr;   /* Hash pointer. */
   1008 
   1009     if (NULL == tnl_term_hash) {
   1010         return (SOC_E_PARAM);
   1011     }
   1012 
   1013     ptr = *tnl_term_hash;
   1014     if (NULL == ptr) {
   1015         return (SOC_E_NONE);
   1016     }
   1017 
   1018     /* Free hash entries table. */ 
   1019     if (NULL != ptr->table){   
   1020         sal_free(ptr->table);
   1021         ptr->table = NULL;
   1022     }
   1023 
   1024     /* Free collisions table. */ 
   1025     if (NULL != ptr->link_table) {  
   1026         sal_free(ptr->link_table);
   1027         ptr->link_table = NULL;
   1028     }
   1029 
   1030     /* Free hash table itself. */
   1031     sal_free(ptr);
   1032     *tnl_term_hash = NULL;
   1033 
   1034     return (SOC_E_NONE);
   1035 }
   1036 
   1037 /* 
   1038  * Function:
   1039  *      _soc_tunnel_term_entry_read
   1040  * Purpose:
   1041  *      Read tunnel termination entry from hardware. 
   1042  * Parameters:
   1043  *      unit    - (IN)  Bcm device number. 
   1044  *      index   - (IN)  Table index. 
   1045  *      entry   - (OUT) Tunnel termination entry.   
   1046  *      ipv6    - (OUT) Entry is ipv6 tunnel terminator.  
   1047  * Returns:
   1048  *      SOC_E_XXX
   1049  */
   1050 STATIC int 
   1051 _soc_tunnel_term_entry_read(int unit, int index, 
   1052                             soc_tunnel_term_t *entry, int *entry_type)
   1053 {
   1054     int idx;     /* Entry width iteration index. */
   1055     int type;
   1056     soc_mem_t mem = L3_TUNNELm;
   1057     soc_field_t validf = VALIDf;
   1058 #ifdef BCM_TRIDENT3_SUPPORT
   1059     int idx_max;
   1060 #endif /* BCM_TRIDENT3_SUPPORT */
   1061     int ipv6type = 0x1;
   1062 
   1063     /* Input parameters check. */
   1064     if ((NULL == entry) || (NULL == entry_type)) {
   1065         return (SOC_E_PARAM);
   1066     }
   1067 
   1068     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   1069         int ipv6 = 0;
   1070         uint32 *entry_ptr;
   1071 
   1072         mem = L3_TUNNEL_DOUBLEm;
   1073         entry_ptr = (uint32 *)&entry->entry_arr[0];
   1074         ipv6 =
   1075             soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf) - 1;
   1076 
   1077         if (ipv6) {
   1078             mem = L3_TUNNEL_QUADm;
   1079         }
   1080         validf = BASE_VALID_0f;
   1081         ipv6type = 0x2;
   1082     }
   1083 
   1084     SOC_IF_ERROR_RETURN
   1085         (soc_mem_read(unit, mem, MEM_BLOCK_ANY, index,
   1086                          (uint32 *)&entry->entry_arr[0]));
   1087 
   1088     if (!soc_mem_field32_get(unit, mem,
   1089                              (uint32 *)&entry->entry_arr[0], validf)) {
   1090         sal_memset (entry, 0, sizeof(soc_tunnel_term_t));
   1091         *entry_type = FALSE;
   1092         return (SOC_E_NOT_FOUND);
   1093     }
   1094     /* Check if entry is ipv6 */
   1095     SOC_IF_ERROR_RETURN(_soc_tunnel_term_type_get(unit, entry, &type, entry_type));
   1096 
   1097 #ifdef BCM_TRIDENT3_SUPPORT
   1098      if (soc_feature(unit,soc_feature_flex_flow) &&
   1099            (*entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   1100                 SOC_IF_ERROR_RETURN (
   1101         _soc_tunnel_term_flex_type_width_get(unit, type, entry, &idx_max));
   1102         for (idx = 1; idx < idx_max; idx++) {
   1103             SOC_IF_ERROR_RETURN
   1104                    (soc_mem_read(unit, mem, MEM_BLOCK_ANY, (index + idx) ,
   1105                            (uint32 *)&entry->entry_arr[idx]));
   1106         }
   1107     } else
   1108 #endif /* BCM_TRIDENT3_SUPPORT */
   1109     {
   1110         int size = SOC_TNL_TERM_IPV6_ENTRY_WIDTH;
   1111         if (*entry_type == ipv6type) { /* IPV6 */
   1112             if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   1113                 mem = L3_TUNNEL_QUADm;
   1114                 size = 1;
   1115             }
   1116             for (idx = 1; idx < size; idx++) {
   1117                 SOC_IF_ERROR_RETURN
   1118                     (soc_mem_read(unit, mem, MEM_BLOCK_ANY, (idx + index),
   1119                                  (uint32 *)&entry->entry_arr[idx]));
   1120             }
   1121         }
   1122     }
   1123     return (SOC_E_NONE);
   1124 }
   1125 
   1126 
   1127 /* 
   1128  * Function:
   1129  *      _soc_tunnel_term_entry_write
   1130  * Purpose:
   1131  *      Write tunnel termination entry to the hardware. 
   1132  * Parameters:
   1133  *      unit    - (IN)  Bcm device number. 
   1134  *      index   - (IN)  Table index. 
   1135  *      entry   - (IN)  Tunnel termination entry.   
   1136  *      ipv6    - (IN) Entry is ipv6 tunnel terminator.  
   1137  * Returns:
   1138  *      SOC_E_XXX
   1139  */
   1140 STATIC int 
   1141 _soc_tunnel_term_entry_write(int unit, int index, 
   1142                              soc_tunnel_term_t *entry, int entry_type)
   1143 {
   1144     int idx;       /* Entry width iteration index. */
   1145     int idx_max;   /* Entry width.                 */
   1146 #ifdef BCM_TRIDENT3_SUPPORT
   1147     int type;
   1148     int key_type;
   1149 #endif /* BCM_TRIDENT3_SUPPORT */
   1150     int ipv6_key_type = 0x1;
   1151 
   1152     /* Input parameters check. */
   1153     if (NULL == entry) {
   1154         return (SOC_E_PARAM);
   1155     }
   1156 
   1157     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   1158         ipv6_key_type = 0x2;
   1159     }
   1160 
   1161 #ifdef BCM_TRIDENT3_SUPPORT
   1162     if (soc_feature(unit,soc_feature_flex_flow) &&
   1163            (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   1164         SOC_IF_ERROR_RETURN
   1165             (_soc_tunnel_term_type_get(unit, entry, &type, &key_type));
   1166         SOC_IF_ERROR_RETURN (
   1167              _soc_tunnel_term_flex_type_width_get(unit, type, entry, &idx_max));
   1168     } else
   1169  #endif /* BCM_TRIDENT3_SUPPORT */
   1170     {
   1171         idx_max = (entry_type == ipv6_key_type) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \
   1172               SOC_TNL_TERM_IPV4_ENTRY_WIDTH;
   1173     }
   1174 
   1175     
   1176     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   1177         soc_mem_t mem;
   1178         mem = (entry_type == ipv6_key_type)? L3_TUNNEL_QUADm:L3_TUNNEL_DOUBLEm; 
   1179         SOC_IF_ERROR_RETURN(soc_mem_insert(unit, mem, MEM_BLOCK_ANY, entry->entry_arr));
   1180     } else {
   1181         for (idx = 0; idx < idx_max; idx++) {
   1182             SOC_IF_ERROR_RETURN (WRITE_L3_TUNNELm(unit, MEM_BLOCK_ALL, 
   1183                                                   (idx + index), 
   1184                                                   (uint32 *)&entry->entry_arr[idx]));
   1185         }
   1186     }
   1187     return (SOC_E_NONE);
   1188 }
   1189 
   1190 
   1191 /*
   1192  * Function:
   1193  *      _soc_tunnel_term_hash_lookup
   1194  * Purpose:
   1195  *      Look up a key in the hash table
   1196  * Parameters:
   1197  *      hash       - (IN)  Pointer (handle) to Hash Table
   1198  *      key_cmp_fn - (IN)  Compare function which should compare key
   1199  *      entry      - (IN)  The key to lookup
   1200  *      key_index  - (OUT) Index where the key was found.
   1201  * Returns:
   1202  *      SOC_E_NONE      Key found
   1203  *      SOC_E_NOT_FOUND Key not found
   1204  */
   1205 STATIC int 
   1206 _soc_tunnel_term_hash_lookup(soc_tnl_term_hash_t *hash,
   1207                              _soc_tnl_term_hash_compare_fn key_cmp_fn,
   1208                              soc_tnl_term_hash_key_t *entry,
   1209                              uint16 *key_index)
   1210 {
   1211 
   1212     soc_tunnel_term_t hw_entry;          /* Tunnel terminator entry from HW.*/
   1213     soc_tnl_term_hash_key_t  r_entry;   /* Entry key portion.              */
   1214     uint16  hash_val;                    /* Computed hash value.            */
   1215     uint16  index;                       /* Entry index in L3_TUNNEL table. */
   1216     int     type;                        /* Entry type flag.                */
   1217     int     rv;                          /* Operation return status.        */
   1218     int     unit;                        /* BCM device number.              */
   1219     uint16  mask;                        /* Index mask based on hash size   */
   1220 
   1221     /* Input parameters check. */
   1222     if ((NULL == entry) || (NULL == key_index) || (NULL == hash)) {
   1223         return (SOC_E_PARAM);
   1224     }
   1225 
   1226     /* Extract bcm device number. */
   1227     unit = hash->unit;
   1228 
   1229     /* Calculate entry hash. */
   1230     rv = _soc_tunnel_term_hash_compute((uint8 *)entry,
   1231                                        SOC_TNL_TERM_HASH_BIT_WIDTH, &hash_val);
   1232     if (SOC_FAILURE(rv)){
   1233         return (rv);
   1234     }
   1235 
   1236     mask = soc_mem_index_count(unit, L3_TUNNELm) - 1;
   1237     hash_val %= hash->index_count;
   1238 
   1239     /* Iterate over indexes with identical hash value. */
   1240     index = hash->table[hash_val];
   1241     while(index != TNL_TERM_HASH_INDEX_NULL) {
   1242         index &= mask;
   1243         /* Read entry from HW.  */
   1244         rv = _soc_tunnel_term_entry_read(unit, index, &hw_entry, &type);
   1245         if (SOC_FAILURE(rv)){
   1246             return (SOC_E_INTERNAL);
   1247         }
   1248         SOC_TNL_TERM_HASH_ENTRY_GET(unit, &hw_entry, type, &r_entry);
   1249         if ((*key_cmp_fn)(entry, &r_entry) == 0) {
   1250             *key_index = index;
   1251             return(SOC_E_NONE);
   1252         }
   1253         index = hash->link_table[index];
   1254     }
   1255     return(SOC_E_NOT_FOUND);
   1256 }
   1257 
   1258 #define INDEX_ADD(hash, hash_idx, new_idx)                      \
   1259     hash->link_table[new_idx] = hash->table[hash_idx];          \
   1260     hash->table[hash_idx] = new_idx
   1261 
   1262 #define INDEX_UPDATE(hash, hash_idx, old_idx, new_idx)          \
   1263     hash->table[hash_idx] = new_idx;                            \
   1264     hash->link_table[new_idx] = hash->link_table[old_idx];      \
   1265     hash->link_table[old_idx] = TNL_TERM_HASH_INDEX_NULL
   1266 
   1267 #define INDEX_UPDATE_LINK(hash, prev_idx, old_idx, new_idx)     \
   1268     hash->link_table[prev_idx] = new_idx;                       \
   1269     hash->link_table[new_idx] = hash->link_table[old_idx];      \
   1270     hash->link_table[old_idx] = TNL_TERM_HASH_INDEX_NULL
   1271 
   1272 /*
   1273  * Function:
   1274  *      _soc_tunnel_term_hash_insert
   1275  * Purpose:
   1276  *      Insert/Update a key index in the hash table
   1277  * Parameters:
   1278  *      hash       - (IN) Pointer (handle) to Hash Table
   1279  *      key_cmp_fn - (IN) Compare function which should compare key
   1280  *      entry      - (IN) The key to lookup
   1281  *      old_index  - (IN) Index where the key was moved from.
   1282  *                        TNL_TERM_HASH_INDEX_NULL if new entry.
   1283  *      new_index  - (IN) Index where the key was moved to.
   1284  * Returns:
   1285  *      SOC_E_XXX
   1286  * NOTE: 
   1287  *      Should be caled before updating the L3_TUNNEL table so that the
   1288  *      data in the hash table is consistent with the hardware table
   1289  */
   1290 STATIC int 
   1291 _soc_tunnel_term_hash_insert(soc_tnl_term_hash_t *hash,
   1292                              _soc_tnl_term_hash_compare_fn key_cmp_fn,
   1293                              soc_tnl_term_hash_key_t *entry,
   1294                              uint16 old_index,
   1295                              uint16 new_index)
   1296 {
   1297     soc_tunnel_term_t hw_entry;         /* Tunnel terminator entry from HW.  */
   1298     soc_tnl_term_hash_key_t  r_entry;  /* Entry key portion.                */
   1299     uint16  hash_val;                   /* Computed hash value.              */
   1300     uint16  prev_index;                 /* Previous entry with identical hash*/
   1301     uint16  index;                      /* Entry index in L3_TUNNEL table.   */
   1302     int     type;                       /* Entry type  flag.                 */
   1303     int     rv;                         /* Operation return status.          */
   1304     int     unit;                       /* BCM device number.                */
   1305     uint16  mask;                       /* Index mask based on hash size     */
   1306 
   1307     /* Input parameters check. */
   1308     if ((NULL == entry) || (NULL == hash)) {
   1309         return (SOC_E_PARAM);
   1310     }
   1311 
   1312     rv = _soc_tunnel_term_hash_compute((uint8 *)entry, 
   1313                                        SOC_TNL_TERM_HASH_BIT_WIDTH, &hash_val);
   1314     if (SOC_FAILURE(rv)) {
   1315         return (rv);
   1316     }
   1317     hash_val %= hash->index_count;
   1318 
   1319     index = hash->table[hash_val];
   1320     unit = hash->unit;
   1321     mask = soc_mem_index_count(unit, L3_TUNNELm) - 1;
   1322 
   1323     prev_index = TNL_TERM_HASH_INDEX_NULL;
   1324     if (old_index != TNL_TERM_HASH_INDEX_NULL) {
   1325         while(index != TNL_TERM_HASH_INDEX_NULL) {
   1326             index &= mask;
   1327 
   1328             /*
   1329              * Check prefix length and skip index if not valid for given length
   1330              */
   1331 
   1332             rv = _soc_tunnel_term_entry_read(unit, index, &hw_entry, &type);
   1333             if (SOC_FAILURE(rv)) {
   1334                 return (SOC_E_INTERNAL);
   1335             }
   1336             SOC_TNL_TERM_HASH_ENTRY_GET(unit, &hw_entry, type, &r_entry);
   1337             if ((*key_cmp_fn)(entry, &r_entry) == 0) {
   1338                 if (new_index != index) {
   1339                     if (prev_index == TNL_TERM_HASH_INDEX_NULL) {
   1340                         INDEX_UPDATE(hash, hash_val, index & mask,
   1341                                      new_index & mask);
   1342                     } else {
   1343                         INDEX_UPDATE_LINK(hash, prev_index & mask, 
   1344                                           index & mask, new_index & mask);
   1345                     }
   1346                 }
   1347                 return(SOC_E_NONE);
   1348             }
   1349             prev_index = index;
   1350             index = hash->link_table[index];
   1351         }
   1352     }
   1353     INDEX_ADD(hash, hash_val, new_index & mask);  /* new entry */
   1354     return(SOC_E_NONE);
   1355 }
   1356 #undef INDEX_ADD
   1357 #undef INDEX_UPDATE
   1358 #undef INDEX_UPDATE_LINK
   1359 
   1360 #define INDEX_DELETE(hash, hash_idx, del_idx)                 \
   1361      hash->table[hash_idx] = hash->link_table[del_idx];       \
   1362      hash->link_table[del_idx] = TNL_TERM_HASH_INDEX_NULL     \
   1363 
   1364 #define INDEX_DELETE_LINK(hash, prev_idx, del_idx)            \
   1365      hash->link_table[prev_idx] = hash->link_table[del_idx];  \
   1366      hash->link_table[del_idx] = TNL_TERM_HASH_INDEX_NULL      
   1367 /*
   1368  * Function:
   1369  *      _soc_tunnel_term_hash_delete
   1370  * Purpose:
   1371  *      Delete a key index in the hash table
   1372  * Parameters:
   1373  *      hash         - (IN) Pointer (handle) to Hash Table
   1374  *      key_cmp_fn   - (IN) Compare function which should compare key
   1375  *      entry        - (IN) The key to lookup
   1376  *      delete_index - (IN) Index to delete.
   1377  * Returns:
   1378  *      SOC_E_NONE      Success
   1379  *      SOC_E_NOT_FOUND Key index not found.
   1380  */
   1381 STATIC int 
   1382 _soc_tunnel_term_hash_delete(soc_tnl_term_hash_t *hash,
   1383                              _soc_tnl_term_hash_compare_fn key_cmp_fn,
   1384                              soc_tnl_term_hash_key_t *entry,
   1385                              uint16 delete_index)
   1386 {
   1387     uint16  hash_val;                    /* Computed hash value.              */
   1388     uint16  prev_index;                  /* Previous entry with identical hash*/
   1389     uint16  index;                       /* Entry index in L3_TUNNEL table.   */
   1390     int     rv;                          /* Internal operatin return status.  */
   1391     int     unit;                        /* BCM device number.                */
   1392     uint16  mask;                        /* Index mask based on hash size     */
   1393 
   1394     /* Input parameters check. */
   1395     if ((NULL == entry) || (NULL == hash)) {
   1396         return (SOC_E_PARAM);
   1397     }
   1398 
   1399     rv = _soc_tunnel_term_hash_compute((uint8 *)entry, 
   1400                                        SOC_TNL_TERM_HASH_BIT_WIDTH, &hash_val);
   1401     if (SOC_FAILURE(rv)) {
   1402         return (rv);
   1403     }
   1404 
   1405     unit = hash->unit;
   1406     mask = soc_mem_index_count(unit, L3_TUNNELm) - 1;
   1407     hash_val %= hash->index_count;
   1408 
   1409     index = hash->table[hash_val];
   1410     prev_index = TNL_TERM_HASH_INDEX_NULL;
   1411     while(index != TNL_TERM_HASH_INDEX_NULL) {
   1412         if (delete_index == index) {
   1413             if (prev_index == TNL_TERM_HASH_INDEX_NULL) {
   1414                 INDEX_DELETE(hash, hash_val, delete_index & mask);
   1415             } else {
   1416                 INDEX_DELETE_LINK(hash, prev_index & mask, 
   1417                         delete_index & mask);
   1418             }
   1419             return(SOC_E_NONE);
   1420         }
   1421         prev_index = index;
   1422         index = hash->link_table[index & mask];
   1423     }
   1424     return(SOC_E_NOT_FOUND);
   1425 }
   1426 #undef INDEX_DELETE
   1427 #undef INDEX_DELETE_LINK
   1428 #define TNL_TERM_HASH_INSERT(_u_, _entry_data_, _tab_index_)       \
   1429     soc_tunnel_term_hash_insert((_u_), (_entry_data_), (_tab_index_), 0)
   1430 
   1431 #define TNL_TERM_HASH_DELETE(_u_, _key_data_, _tab_index_)         \
   1432     soc_tunnel_term_hash_delete((_u_), (_key_data_), (_tab_index_))
   1433 
   1434 #define TNL_TERM_HASH_LOOKUP(_u_, _key_data_, _tab_index_)         \
   1435     soc_tunnel_term_hash_lookup((_u_), (_key_data_), (_tab_index_))
   1436 /*
   1437  * Function:
   1438  *   soc_tunnel_term_hash_insert
   1439  * Purpose:
   1440  *   Tunnel termination entry hash insertion routine.
   1441  * Parameters:
   1442  *      unit          - (IN) BCM device number. 
   1443  *      entry         - (IN) Inserted entry. 
   1444  *      tab_index     - (IN) Insertion index. 
   1445  *      old_index     - (IN) Original entry index. 
   1446  * Returns: 
   1447  *      SOC_E_XXX
   1448  */ 
   1449 
   1450 STATIC int
   1451 soc_tunnel_term_hash_insert(int unit, soc_tunnel_term_t *entry, 
   1452                             uint32 tab_index, uint32 old_index)
   1453 {
   1454     soc_tnl_term_hash_key_t    key_hash;      /* Entry tcam lookup key.   */
   1455     int type;                                  /* Tunnel Entry Type        */
   1456     int rv;                                    /* Operation return status. */
   1457 
   1458     /* Input parameters check. */
   1459     if (NULL == entry) {
   1460         return (SOC_E_PARAM);
   1461     }
   1462 
   1463     if (!soc_mem_field32_get(unit, L3_TUNNELm, 
   1464                              (uint32 *)&entry->entry_arr[0], VALIDf)) {
   1465         return (SOC_E_EMPTY);
   1466     }
   1467 
   1468     SOC_IF_ERROR_RETURN(_soc_tunnel_term_type_get(unit, entry, NULL, &type));
   1469     SOC_TNL_TERM_HASH_ENTRY_GET(unit, entry, type, &key_hash);
   1470 
   1471     rv = _soc_tunnel_term_hash_insert (SOC_TNL_TERM_STATE_HASH(unit), 
   1472                                        _soc_tunnel_term_hash_compare_key,
   1473                                        &key_hash, old_index, 
   1474                                        ((uint16)tab_index));
   1475     return (rv);
   1476 }
   1477 
   1478 /*
   1479  * Function:
   1480  *   soc_tunnel_term_hash_delete
   1481  * Purpose:
   1482  *   Tunnel termination entry hash removal routine.
   1483  * Parameters:
   1484  *      unit          - (IN) BCM device number.
   1485  *      key_data      - (IN) Deleted entry.
   1486  *      tab_index     - (IN) Removed index.
   1487  * Returns: 
   1488  *      SOC_E_XXX
   1489  */
   1490 STATIC int
   1491 soc_tunnel_term_hash_delete(int unit, soc_tunnel_term_t *key_data, 
   1492                          uint32 tab_index)
   1493 {
   1494     soc_tnl_term_hash_key_t  key_hash;    /* Entry lookup key.        */
   1495     int                       type;        /* Tunnel term type         */
   1496 
   1497     /* Input parameters check. */
   1498     if (NULL == key_data) { 
   1499         return (SOC_E_PARAM);
   1500     }
   1501 
   1502     SOC_IF_ERROR_RETURN(_soc_tunnel_term_type_get(unit, key_data, NULL, &type));
   1503     SOC_TNL_TERM_HASH_ENTRY_GET(unit, key_data, type, &key_hash);
   1504 
   1505     return  _soc_tunnel_term_hash_delete(SOC_TNL_TERM_STATE_HASH(unit),
   1506                                          _soc_tunnel_term_hash_compare_key,
   1507                                          &key_hash, tab_index);
   1508 }
   1509 
   1510 /*
   1511  * Function:
   1512  *   soc_tunnel_term_hash_lookup
   1513  * Purpose:
   1514  *   Tunnel termination entry hash lookup routine.
   1515  * Parameters:
   1516  *      unit          - (IN)  BCM device number. 
   1517  *      key_data      - (IN)  Entry lookup key.
   1518  *      key_index     - (OUT) Search result index if any. 
   1519  * Returns: 
   1520  *      SOC_E_XXX
   1521  */
   1522 
   1523 STATIC int 
   1524 soc_tunnel_term_hash_lookup(int unit, soc_tunnel_term_t *key_data, 
   1525                          int *key_index)
   1526 {
   1527     soc_tnl_term_hash_key_t    key_hash;  /* Entry lookup key.        */
   1528     uint16                      index;     /* Entry index.             */
   1529     int                         type;      /* Tunnel Term type         */
   1530     int                         rv;        /* Operation return status. */
   1531 
   1532     /* Input parameters check. */
   1533     if ((NULL == key_data) || (NULL == key_index))  {
   1534         return (SOC_E_PARAM);
   1535     }
   1536 
   1537     SOC_IF_ERROR_RETURN(_soc_tunnel_term_type_get(unit, key_data, NULL, &type));
   1538     SOC_TNL_TERM_HASH_ENTRY_GET(unit, key_data, type, &key_hash);
   1539 
   1540     rv = _soc_tunnel_term_hash_lookup(SOC_TNL_TERM_STATE_HASH(unit),
   1541                                       _soc_tunnel_term_hash_compare_key,
   1542                                       &key_hash, &index);
   1543     if (SOC_FAILURE(rv)) {
   1544         return (rv);
   1545     }
   1546     *key_index = index;
   1547     return (SOC_E_NONE);
   1548 }
   1549 
   1550 
   1551 /*
   1552  * Function:
   1553  *      soc_tunnel_term_sw_dump
   1554  * Purpose:
   1555  *      Dump tunnel termination hash status for warm boot debug. 
   1556  * Parameters:
   1557  *      unit - (IN) BCM device number.
   1558  * Returns:
   1559  *      none. 
   1560  */
   1561 void
   1562 soc_tunnel_term_sw_dump(int unit)
   1563 {
   1564     int i;
   1565     int max_type;
   1566     max_type = MAX_TNL_TERM_TYPE;
   1567 
   1568     LOG_CLI((BSL_META_U(unit,
   1569                         "\n    Tunnel Terminator State -\n")));
   1570 
   1571     if (!SOC_TNL_TERM_INIT_CHECK(unit)) {
   1572         LOG_CLI((BSL_META_U(unit,
   1573                             "\nTunnel Terminator in Uninitialized state -\n")));
   1574         return;
   1575     }
   1576 
   1577     for(i = max_type; i >= 0 ; i--) {
   1578         if ((i != MAX_TNL_TERM_TYPE) && \
   1579             (SOC_TNL_TERM_STATE_START(unit, i) == TNL_TERM_TYPE_NULL)) {
   1580             continue;
   1581         }
   1582         LOG_CLI((BSL_META_U(unit,
   1583                             "PFX = %d P = %d N = %d START = %d END = %d VENT = %d FENT = %d\n"),
   1584                  i,
   1585                  SOC_TNL_TERM_STATE_PREV(unit, i),
   1586                  SOC_TNL_TERM_STATE_NEXT(unit, i),
   1587                  SOC_TNL_TERM_STATE_START(unit, i),
   1588                  SOC_TNL_TERM_STATE_END(unit, i),
   1589                  SOC_TNL_TERM_STATE_VENT(unit, i),
   1590                  SOC_TNL_TERM_STATE_FENT(unit, i)));
   1591     }
   1592     return;
   1593 }
   1594 
   1595 /*
   1596  * Function:
   1597  *   _soc_tunnel_term_type_width_get
   1598  * Purpose:
   1599  *   Given tunnel terminator type get number of hw slots 
   1600  *   it takes to write it to hardware.  
   1601  * Parameters:
   1602  *      unit      - (IN)  BCM device number. 
   1603  *      type      - (IN)  Tunnel terminator type.
   1604  *      width     - (OUT) Number of hw slot entry requires. 
   1605  * Returns: 
   1606  *      SOC_E_XXX
   1607  */ 
   1608 STATIC int
   1609 _soc_tunnel_term_type_width_get(int unit, int type, int *width)
   1610 {
   1611     /* Input parameters check. */
   1612     if (NULL == width) {
   1613         return (SOC_E_PARAM);
   1614     }
   1615 
   1616     switch (type - (type % (_SHR_L3_IP6_MAX_NETLEN + 1))) {
   1617       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST_L4SRC:
   1618       case  SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST_L4SRC:
   1619       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST_L4SRC:
   1620       case  SOC_TNL_TERM_TYPE_DIP4_L4DST_L4SRC:
   1621       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST:
   1622       case  SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST:
   1623       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST:
   1624       case  SOC_TNL_TERM_TYPE_DIP4_L4DST:
   1625       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4SRC:
   1626       case  SOC_TNL_TERM_TYPE_DIP4_PROT_L4SRC:
   1627       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_L4SRC:
   1628       case  SOC_TNL_TERM_TYPE_DIP4_L4SRC:
   1629       case  SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT:
   1630       case  SOC_TNL_TERM_TYPE_DIP4_PROT:
   1631       case  SOC_TNL_TERM_TYPE_DIP4_SIP4:
   1632       case  SOC_TNL_TERM_TYPE_DIP4:
   1633           *width = SOC_TNL_TERM_IPV4_ENTRY_WIDTH;
   1634           break;
   1635       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST_L4SRC:
   1636       case  SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST_L4SRC:
   1637       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST_L4SRC:
   1638       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4DST:
   1639       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT_L4SRC:
   1640       case  SOC_TNL_TERM_TYPE_DIP6_L4DST_L4SRC:
   1641       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_L4DST:
   1642       case  SOC_TNL_TERM_TYPE_DIP6_PROT_L4SRC:
   1643       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_L4SRC:
   1644       case  SOC_TNL_TERM_TYPE_DIP6_PROT_L4DST:
   1645       case  SOC_TNL_TERM_TYPE_DIP6_SIP6_PROT:
   1646       case  SOC_TNL_TERM_TYPE_DIP6_L4SRC:
   1647       case  SOC_TNL_TERM_TYPE_DIP6_SIP6:
   1648       case  SOC_TNL_TERM_TYPE_DIP6_PROT:
   1649       case  SOC_TNL_TERM_TYPE_DIP6_L4DST:
   1650       case  SOC_TNL_TERM_TYPE_DIP6:
   1651           *width = SOC_TNL_TERM_IPV6_ENTRY_WIDTH;
   1652           break;
   1653       default:
   1654           return (SOC_E_INTERNAL);
   1655     }
   1656     return (SOC_E_NONE);
   1657 }
   1658 
   1659 /*
   1660  * Function:
   1661  *      _soc_tunnel_term_entry_shift
   1662  * Purpose:
   1663  *      Move entry from one index to another tcam. 
   1664  * Parameters:
   1665  *      unit       - (IN) BCM device number.
   1666  *      from_ent   - (IN) Entry source. 
   1667  *      to_ent     - (IN) Entry destination. 
   1668  * Returns:
   1669  *      SOC_E_XXX.
   1670  */
   1671 STATIC int 
   1672 _soc_tunnel_term_entry_shift(int unit, int from_ent, int to_ent)
   1673 {
   1674     soc_tunnel_term_t hw_entry;       /* Tunnel terminator entry from hw. */
   1675     int entry_type;                   /* Entry type indicator.            */
   1676     int rv;                           /* Operation return status.         */
   1677 
   1678     if (from_ent == to_ent) {
   1679         return (SOC_E_NONE);
   1680     }
   1681 
   1682     /* Read source entry. */
   1683     rv = _soc_tunnel_term_entry_read(unit, from_ent, &hw_entry, &entry_type);
   1684     if (SOC_FAILURE(rv)) {
   1685         return ((SOC_E_NOT_FOUND == rv) ? (SOC_E_NONE) : (rv));
   1686     }
   1687     TNL_TERM_HASH_INSERT(unit, &hw_entry, to_ent);
   1688 
   1689     /* Write destination entry. */
   1690     SOC_IF_ERROR_RETURN
   1691         (_soc_tunnel_term_entry_write(unit, to_ent, &hw_entry, entry_type));
   1692 
   1693     /* Reset source entry. */ 
   1694     sal_memset(&hw_entry, 0, sizeof(soc_tunnel_term_t));
   1695     SOC_IF_ERROR_RETURN
   1696         (_soc_tunnel_term_entry_write(unit, from_ent, &hw_entry, entry_type));
   1697 
   1698     return (SOC_E_NONE);
   1699 }
   1700 
   1701 /*
   1702  * Function:
   1703  *      _soc_tunnel_term_entry_block_shift
   1704  * Purpose:
   1705  *      Create a slot for the new entry rippling the entries if required.
   1706  * Parameters:
   1707  *      unit       - (IN) BCM device number.
   1708  *      from_ent   - (IN) Block source start index.
   1709  *      to_ent     - (IN) Block destination start index. 
   1710  *      type       - (IN) Block entries type. 
   1711  * Returns:
   1712  *      SOC_E_XXX.
   1713  */
   1714 STATIC int 
   1715 _soc_tunnel_term_entry_block_shift(int unit, int from_ent, int to_ent,int type)
   1716 {
   1717     int width;                             /* Single entry width in block. */
   1718     int idx;                               /* Block indexes iterator.      */
   1719 #ifdef BCM_TRIDENT3_SUPPORT
   1720     soc_tunnel_term_t hw_entry;            /* Tunnel terminator entry from hw. */
   1721     int entry_type;                        /* Entry type indicator.            */
   1722 #endif /* BCM_TRIDENT3_SUPPORT */
   1723 
   1724     if (from_ent == to_ent) {
   1725         return (SOC_E_NONE);
   1726     }
   1727 #ifdef BCM_TRIDENT3_SUPPORT
   1728     if (soc_feature(unit,soc_feature_flex_flow) &&
   1729        (type == SOC_TNL_TERM_TYPE_FLEX)) {
   1730 
   1731        /* Read source entry. */
   1732        SOC_IF_ERROR_RETURN (
   1733         _soc_tunnel_term_entry_read(unit, from_ent, &hw_entry, &entry_type));
   1734        SOC_IF_ERROR_RETURN (
   1735         _soc_tunnel_term_flex_type_width_get(unit, type, &hw_entry, &width));
   1736     } else
   1737 #endif /* BCM_TRIDENT3_SUPPORT */
   1738     {
   1739         /* Get entry width for tunnel termination type. */
   1740         SOC_IF_ERROR_RETURN(_soc_tunnel_term_type_width_get(unit, type, &width));
   1741     }
   1742 
   1743     for (idx = 0; idx < SOC_TNL_TERM_BLOCK_SIZE; idx += width) {
   1744         SOC_IF_ERROR_RETURN
   1745             (_soc_tunnel_term_entry_shift(unit, from_ent + idx, to_ent + idx));
   1746     }
   1747     return (SOC_E_NONE);
   1748 }
   1749 
   1750 /*
   1751  * Function:
   1752  *      _soc_tunnel_term_entry_shift_up
   1753  * Purpose:
   1754  *      Shift entries 4 entries UP, while preserving  
   1755  *      last 4 ipv4 entries last.
   1756  * Parameters:
   1757  *      unit       - (IN) BCM device number.
   1758  *      type       - (IN) Free entry type. 
   1759  * Returns:
   1760  *      SOC_E_XXX.
   1761  */
   1762 STATIC
   1763 int _soc_tunnel_term_shift_type_up(int unit, int type)
   1764 {
   1765     int from_ent;      /* Moved entry block index.                  */
   1766     int to_ent;        /* Destination entry block index.            */
   1767     int entry_width;   /* Number of hw slots single entry occupies. */
   1768     int from_block;    /* "From" block start index.                 */
   1769     int to_block;      /* "To" block start index.                   */
   1770 
   1771 #ifdef BCM_TRIDENT3_SUPPORT
   1772     soc_tunnel_term_t hw_entry;            /* Tunnel terminator entry from hw. */
   1773     int entry_type;                        /* Entry type indicator.            */
   1774 #endif /* BCM_TRIDENT3_SUPPORT */
   1775 
   1776     to_ent = SOC_TNL_TERM_STATE_END(unit, type) + SOC_TNL_TERM_BLOCK_SIZE;
   1777     SOC_TNL_TERM_IDX_TO_BLOCK_START(to_ent, to_block,SOC_TNL_TERM_BLOCK_SIZE);
   1778 
   1779 #ifdef BCM_TRIDENT3_SUPPORT
   1780     if (soc_feature(unit,soc_feature_flex_flow) &&
   1781        (type == SOC_TNL_TERM_TYPE_FLEX)) {
   1782         from_ent = SOC_TNL_TERM_STATE_END(unit, type);
   1783         SOC_TNL_TERM_IDX_TO_BLOCK_START(from_ent,
   1784                          from_block,SOC_TNL_TERM_BLOCK_SIZE);
   1785         /* Read source entry. */
   1786         SOC_IF_ERROR_RETURN (
   1787          _soc_tunnel_term_entry_read(unit, from_block, &hw_entry, &entry_type));
   1788         SOC_IF_ERROR_RETURN (
   1789         _soc_tunnel_term_flex_type_width_get(unit, type,
   1790                              &hw_entry, &entry_width));
   1791         if (SOC_TNL_TERM_BLOCK_SIZE != entry_width) {
   1792 
   1793             if (from_ent != (from_block + SOC_TNL_TERM_BLOCK_SIZE - 1)) {
   1794                 /* Last block is not full -> keep it last. */
   1795                 SOC_IF_ERROR_RETURN
   1796                     (_soc_tunnel_term_entry_block_shift(unit, from_block,
   1797                                                     to_block, type));
   1798 
   1799                 to_block -= SOC_TNL_TERM_BLOCK_SIZE;
   1800             }
   1801 
   1802         }
   1803 
   1804         from_ent = SOC_TNL_TERM_STATE_START(unit, type);
   1805         SOC_TNL_TERM_IDX_TO_BLOCK_START(from_ent,
   1806                    from_block,SOC_TNL_TERM_BLOCK_SIZE);
   1807 
   1808         if(from_block != to_block) {
   1809             SOC_IF_ERROR_RETURN(
   1810                     _soc_tunnel_term_entry_block_shift(unit, from_block,
   1811                                                        to_block, type));
   1812         }
   1813 
   1814     } else
   1815 #endif /* BCM_TRIDENT3_SUPPORT */
   1816     {
   1817         SOC_IF_ERROR_RETURN
   1818             (_soc_tunnel_term_type_width_get(unit, type, &entry_width));
   1819 
   1820         if (SOC_TNL_TERM_BLOCK_SIZE != entry_width) {
   1821             from_ent = SOC_TNL_TERM_STATE_END(unit, type);
   1822             SOC_TNL_TERM_IDX_TO_BLOCK_START(from_ent,
   1823                        from_block,SOC_TNL_TERM_BLOCK_SIZE);
   1824 
   1825             if (from_ent != (from_block + SOC_TNL_TERM_BLOCK_SIZE - 1)) {
   1826                 /* Last block is not full -> keep it last. */
   1827                 SOC_IF_ERROR_RETURN
   1828                     (_soc_tunnel_term_entry_block_shift(unit, from_block,
   1829                                                         to_block, type));
   1830 
   1831                 to_block -= SOC_TNL_TERM_BLOCK_SIZE;
   1832             }
   1833         }
   1834 
   1835         from_ent = SOC_TNL_TERM_STATE_START(unit, type);
   1836         SOC_TNL_TERM_IDX_TO_BLOCK_START(from_ent,
   1837                              from_block,SOC_TNL_TERM_BLOCK_SIZE);
   1838 
   1839         if(from_block != to_block) {
   1840             SOC_IF_ERROR_RETURN(
   1841                   _soc_tunnel_term_entry_block_shift(unit, from_block,
   1842                                                      to_block, type));
   1843         }
   1844     }
   1845 
   1846     SOC_TNL_TERM_STATE_START(unit, type) += SOC_TNL_TERM_BLOCK_SIZE;
   1847     SOC_TNL_TERM_STATE_END(unit, type) += SOC_TNL_TERM_BLOCK_SIZE;
   1848     return (SOC_E_NONE);
   1849 }
   1850 
   1851 /*
   1852  * Function:
   1853  *      _soc_tunnel_term_entry_shift_down
   1854  * Purpose:
   1855  *      Shift entries 4 entries DOWN, while preserving  
   1856  *      last 4 ipv4 entries last.
   1857  * Parameters:
   1858  *      unit       - (IN) BCM device number.
   1859  *      type       - (IN) Free entry type. 
   1860  * Returns:
   1861  *      SOC_E_XXX.
   1862  */
   1863 STATIC int 
   1864 _soc_tunnel_term_shift_type_down(int unit, int type)
   1865 {
   1866     int from_ent;      /* Moved entry block index.                  */
   1867     int to_ent;        /* Destination entry block index.            */
   1868     int entry_width;   /* Number of hw slots single entry occupies. */
   1869     int from_block;    /* "From" block start index.                 */
   1870     int to_block;      /* "To" block start index.                   */
   1871 #ifdef BCM_TRIDENT3_SUPPORT
   1872     soc_tunnel_term_t hw_entry;            /* Tunnel terminator entry from hw. */
   1873     int entry_type;                        /* Entry type indicator.            */
   1874 #endif /* BCM_TRIDENT3_SUPPORT */
   1875 
   1876     to_ent = SOC_TNL_TERM_STATE_START(unit, type) - SOC_TNL_TERM_BLOCK_SIZE;
   1877     to_block = to_ent;
   1878 
   1879     /* Don't move empty types. */ 
   1880     if (SOC_TNL_TERM_STATE_VENT(unit, type) == 0) {
   1881         SOC_TNL_TERM_STATE_START(unit, type) = to_ent;
   1882         SOC_TNL_TERM_STATE_END(unit, type) = to_ent - 1;
   1883         return (SOC_E_NONE);
   1884     }
   1885 
   1886     from_ent = SOC_TNL_TERM_STATE_END(unit, type);
   1887     SOC_TNL_TERM_IDX_TO_BLOCK_START(from_ent, from_block,SOC_TNL_TERM_BLOCK_SIZE);
   1888 
   1889 #ifdef BCM_TRIDENT3_SUPPORT
   1890     if (soc_feature(unit,soc_feature_flex_flow) &&
   1891        (type == SOC_TNL_TERM_TYPE_FLEX)) {
   1892         SOC_IF_ERROR_RETURN (
   1893          _soc_tunnel_term_entry_read(unit, from_block, &hw_entry, &entry_type));
   1894         SOC_IF_ERROR_RETURN (
   1895         _soc_tunnel_term_flex_type_width_get(unit, type, &hw_entry, &entry_width));
   1896     } else
   1897 #endif /* BCM_TRIDENT3_SUPPORT */
   1898     {
   1899         SOC_IF_ERROR_RETURN
   1900             (_soc_tunnel_term_type_width_get(unit, type, &entry_width));
   1901     }
   1902 
   1903     if ((SOC_TNL_TERM_BLOCK_SIZE != entry_width) && 
   1904         (SOC_TNL_TERM_STATE_VENT(unit, type) > SOC_TNL_TERM_BLOCK_SIZE))  {  
   1905 
   1906         if (from_ent != (from_block + SOC_TNL_TERM_BLOCK_SIZE - 1)) {
   1907             /* Last block is not full -> keep it last. */
   1908             /* Shift entry before last to start - 1 position. */
   1909             from_block -= SOC_TNL_TERM_BLOCK_SIZE;
   1910             SOC_IF_ERROR_RETURN
   1911                 (_soc_tunnel_term_entry_block_shift(unit, from_block,
   1912                                                     to_block, type));
   1913             to_block = from_block; 
   1914             from_block += SOC_TNL_TERM_BLOCK_SIZE;
   1915         }
   1916     }
   1917     SOC_IF_ERROR_RETURN (_soc_tunnel_term_entry_block_shift(unit, from_block,
   1918                                                             to_block, type));
   1919 
   1920     SOC_TNL_TERM_STATE_START(unit, type) -= SOC_TNL_TERM_BLOCK_SIZE;
   1921     SOC_TNL_TERM_STATE_END(unit, type) -= SOC_TNL_TERM_BLOCK_SIZE;
   1922     return (SOC_E_NONE);
   1923 }
   1924 /*
   1925  * Function:
   1926  *   _soc_tunnel_term_type_entries_ripple
   1927  * Purpose:
   1928  *	    Ceate a slot for the new entry rippling the entries if required. 
   1929  * Parameters:
   1930  *      unit      - (IN)  BCM device number. 
   1931  *      type     - (IN)  Inserted Tunnel terminator entry type.
   1932  * Returns: 
   1933  *      SOC_E_XXX
   1934  */ 
   1935 STATIC int 
   1936 _soc_tunnel_term_type_entries_ripple (int unit, int type) 
   1937 {
   1938     int         prev_type;
   1939     int         next_type;
   1940     int         free_type;
   1941 
   1942     free_type = type;
   1943     while (SOC_TNL_TERM_STATE_FENT(unit, free_type) <
   1944            SOC_TNL_TERM_BLOCK_SIZE) {
   1945         free_type = SOC_TNL_TERM_STATE_NEXT(unit, free_type);
   1946         if (free_type == TNL_TERM_TYPE_NULL) {
   1947             /* No free entries on this side try the other side */
   1948             free_type = type;
   1949             break;
   1950         }
   1951     }
   1952 		
   1953     while (SOC_TNL_TERM_STATE_FENT(unit, free_type) < SOC_TNL_TERM_BLOCK_SIZE) {
   1954         free_type = SOC_TNL_TERM_STATE_PREV(unit, free_type);
   1955         if (free_type == TNL_TERM_TYPE_NULL) {
   1956             return (SOC_E_FULL);
   1957         }
   1958     }
   1959 
   1960     /*
   1961      * Ripple entries to create free space
   1962      */
   1963     while (free_type > type) {
   1964         next_type = SOC_TNL_TERM_STATE_NEXT(unit, free_type);
   1965         SOC_IF_ERROR_RETURN(_soc_tunnel_term_shift_type_down(unit, next_type));
   1966         SOC_TNL_TERM_STATE_FENT(unit, free_type) -= SOC_TNL_TERM_BLOCK_SIZE;
   1967         SOC_TNL_TERM_STATE_FENT(unit, next_type) += SOC_TNL_TERM_BLOCK_SIZE;
   1968         free_type = next_type;
   1969     }
   1970 
   1971     while (free_type < type) {
   1972         SOC_IF_ERROR_RETURN(_soc_tunnel_term_shift_type_up(unit, free_type));
   1973         SOC_TNL_TERM_STATE_FENT(unit, free_type) -= SOC_TNL_TERM_BLOCK_SIZE;
   1974         prev_type = SOC_TNL_TERM_STATE_PREV(unit, free_type); 
   1975         SOC_TNL_TERM_STATE_FENT(unit, prev_type) += SOC_TNL_TERM_BLOCK_SIZE;
   1976         free_type = prev_type;
   1977     }
   1978     return (SOC_E_NONE);
   1979 }
   1980 
   1981 /*
   1982  * Function:
   1983  *   _soc_tunnel_term_slot_allocate
   1984  * Purpose:
   1985  *	    Create a slot for the new entry rippling the entries if required. 
   1986  * Parameters:
   1987  *      unit      - (IN)  BCM device number. 
   1988  *      entry     - (IN)  Inserted Tunnel terminator entry.
   1989  *      index     - (OUT) Allocated index. 
   1990  * Returns: 
   1991  *      SOC_E_XXX
   1992  */ 
   1993 STATIC
   1994 int _soc_tunnel_term_slot_allocate(int unit, soc_tunnel_term_t *entry, int *index)
   1995 {
   1996     int         type;          /* Tunnel entry type.                      */
   1997     int         entry_type;    /* entry type                              */
   1998     int         entry_size;    /* Requested entry size.                   */ 
   1999     int         curr_type;     /* Iteration index to find insertion index.*/
   2000     int         prev_type;     /* Previous entry type in tcam.            */
   2001     int         next_type;     /* Next entry type in tcam.                */
   2002     int         rv;            /* Operation return status.                */
   2003 
   2004     /* Get tunnel termination type. */
   2005     SOC_IF_ERROR_RETURN (_soc_tunnel_term_type_get(unit, entry, &type, 
   2006                         &entry_type));
   2007 #ifdef BCM_TRIDENT3_SUPPORT
   2008     if (soc_feature(unit,soc_feature_flex_flow) &&
   2009            (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   2010         SOC_IF_ERROR_RETURN (
   2011         _soc_tunnel_term_flex_type_width_get(unit, type, entry, &entry_size));
   2012     } else
   2013 #endif /* BCM_TRIDENT3_SUPPORT */
   2014 
   2015     {
   2016         entry_size = (entry_type == 0x1) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH :
   2017            SOC_TNL_TERM_IPV4_ENTRY_WIDTH;
   2018     }
   2019     if (SOC_TNL_TERM_STATE_VENT(unit, type) == 0) {
   2020         /*
   2021          * Find the type position. Only type with valid
   2022          * entries are in the list.
   2023          * next -> high to low type priority. low to high index
   2024          * prev -> low to high type priority. high to low index
   2025          * Unused prefix length MAX_TNL_TERM_TYPE is the head of the
   2026          * list and is node corresponding to this is always
   2027          * present.
   2028          */
   2029         curr_type = MAX_TNL_TERM_TYPE;
   2030         while ((SOC_TNL_TERM_STATE_NEXT(unit, curr_type) !=
   2031                 TNL_TERM_TYPE_NULL) &&  
   2032                (SOC_TNL_TERM_STATE_NEXT(unit, curr_type) > type)) {
   2033             curr_type = SOC_TNL_TERM_STATE_NEXT(unit, curr_type);
   2034         }
   2035 
   2036         /* Insert the new prefix */
   2037         next_type = SOC_TNL_TERM_STATE_NEXT(unit, curr_type);
   2038         if (next_type != TNL_TERM_TYPE_NULL) {
   2039             SOC_TNL_TERM_STATE_PREV(unit, next_type) = type;
   2040         }
   2041         SOC_TNL_TERM_STATE_NEXT(unit, type) = 
   2042             SOC_TNL_TERM_STATE_NEXT(unit, curr_type);
   2043         SOC_TNL_TERM_STATE_PREV(unit, type) = curr_type;
   2044         SOC_TNL_TERM_STATE_NEXT(unit, curr_type) = type;
   2045 
   2046         SOC_TNL_TERM_STATE_VENT(unit, type) = 0;
   2047         SOC_TNL_TERM_STATE_FENT(unit, type) = 
   2048             (SOC_TNL_TERM_STATE_FENT(unit, curr_type) + 1) / 2;
   2049 
   2050         /* Adjust number of free entries to 
   2051          * multiples of SOC_TNL_TERM_BLOCK_SIZE  boundary.
   2052          */  
   2053         SOC_TNL_TERM_STATE_FENT(unit, type) /= SOC_TNL_TERM_BLOCK_SIZE;
   2054         SOC_TNL_TERM_STATE_FENT(unit, type) *= SOC_TNL_TERM_BLOCK_SIZE;
   2055         SOC_TNL_TERM_STATE_FENT(unit, curr_type) -= SOC_TNL_TERM_STATE_FENT(unit, type);
   2056 
   2057         SOC_TNL_TERM_STATE_START(unit, type) =  
   2058             SOC_TNL_TERM_STATE_END(unit, curr_type) +
   2059             SOC_TNL_TERM_STATE_FENT(unit, curr_type) + 1;
   2060         SOC_TNL_TERM_STATE_END(unit, type) = SOC_TNL_TERM_STATE_START(unit, type) - 1;
   2061 
   2062     } 
   2063 
   2064     /* Check if there is sufficient room  to accomodate the entry.*/ 
   2065     if (SOC_TNL_TERM_STATE_FENT(unit, type) < entry_size) {
   2066         rv = _soc_tunnel_term_type_entries_ripple (unit, type);
   2067         if (SOC_FAILURE(rv)) {
   2068             if (!SOC_TNL_TERM_STATE_VENT(unit, type)) {
   2069                 /* We failed to allocate entries for a newly allocated type.*/
   2070                 prev_type = SOC_TNL_TERM_STATE_PREV(unit, type);
   2071                 next_type = SOC_TNL_TERM_STATE_NEXT(unit, type);
   2072                 if (TNL_TERM_TYPE_NULL != prev_type) {
   2073                     SOC_TNL_TERM_STATE_NEXT(unit, prev_type) = next_type;
   2074                 }
   2075                 if (TNL_TERM_TYPE_NULL != next_type) {
   2076                     SOC_TNL_TERM_STATE_PREV(unit, next_type) = prev_type;
   2077                 }
   2078             }
   2079             return (rv);
   2080         }
   2081     }
   2082 
   2083     /* Insert the entry. */
   2084     SOC_TNL_TERM_STATE_VENT(unit, type) += entry_size;
   2085     SOC_TNL_TERM_STATE_FENT(unit, type) -= entry_size;
   2086     *index = SOC_TNL_TERM_STATE_END(unit, type) + 1;
   2087     SOC_TNL_TERM_STATE_END(unit, type) += entry_size;
   2088 
   2089     return(SOC_E_NONE);
   2090 }
   2091 
   2092 /*
   2093  * Function:
   2094  *   _soc_tunnel_term_slot_free
   2095  * Purpose:
   2096  *      Delete a slot and adjust entry pointers if required.
   2097  * Parameters:
   2098  *      unit      - (IN)  BCM device number. 
   2099  *      entry     - (IN)  Inserted Tunnel terminator entry.
   2100  *      index     - (OUT) Allocated index. 
   2101  * Returns: 
   2102  *      SOC_E_XXX
   2103  */ 
   2104 STATIC int 
   2105 _soc_tunnel_term_slot_free (int unit, soc_tunnel_term_t *entry, int index)
   2106 {
   2107     int         type;          /* Tunnel entry type.                      */
   2108     int         entry_type;    /* entry type                              */
   2109     int         from_ent;      /* Moved entry block index.                */
   2110     int         to_ent;        /* Destination entry block index.          */
   2111     int         entry_size;    /* Requested entry size.                   */ 
   2112     int         prev_type;     /* Previous entry type in tcam.            */
   2113     int         next_type;     /* Next entry type in tcam.                */
   2114     soc_tunnel_term_t null_entry;   /* NULL entry buffer.                 */
   2115 
   2116     /* Input parameters check. */
   2117     if (NULL == entry) {
   2118         return (SOC_E_PARAM);
   2119     }
   2120 
   2121     /* Get tunnel termination type. */
   2122     SOC_IF_ERROR_RETURN (_soc_tunnel_term_type_get(unit, entry, &type,
   2123                         &entry_type));
   2124 #ifdef BCM_TRIDENT3_SUPPORT
   2125     if (soc_feature(unit,soc_feature_flex_flow) &&
   2126            (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   2127         SOC_IF_ERROR_RETURN (
   2128         _soc_tunnel_term_flex_type_width_get(unit, type,
   2129                                   entry, &entry_size));
   2130     } else
   2131 #endif /* BCM_TRIDENT3_SUPPORT */
   2132     {
   2133         SOC_IF_ERROR_RETURN (
   2134         _soc_tunnel_term_type_width_get(unit, type, &entry_size));
   2135     }
   2136 
   2137     SOC_TNL_TERM_STATE_VENT(unit, type) -= entry_size;
   2138     SOC_TNL_TERM_STATE_FENT(unit, type) += entry_size;
   2139     
   2140     if (SOC_TNL_TERM_STATE_VENT(unit, type) != 0) {
   2141         from_ent = SOC_TNL_TERM_STATE_END(unit, type) + 1  - entry_size;
   2142         to_ent = index;
   2143         /* Move last entry to deleted entry position. */
   2144         SOC_IF_ERROR_RETURN(
   2145           _soc_tunnel_term_entry_shift(unit, from_ent, to_ent));
   2146     } else {
   2147         from_ent = index;
   2148     }
   2149 
   2150     /* Update number of free & valid entries for this type. */
   2151     SOC_TNL_TERM_STATE_END(unit, type) -= entry_size;
   2152 
   2153     /* Reset deleted entry. */
   2154     sal_memset(&null_entry, 0, sizeof(soc_tunnel_term_t));
   2155 #ifdef BCM_TRIDENT3_SUPPORT
   2156     if (soc_feature(unit,soc_feature_flex_flow) &&
   2157            (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   2158         SOC_IF_ERROR_RETURN
   2159             (_soc_tunnel_term_flex_entry_clear(unit,
   2160                          from_ent, entry, entry_type));
   2161     } else
   2162 #endif /* BCM_TRIDENT3_SUPPORT */
   2163     {
   2164         SOC_IF_ERROR_RETURN
   2165             (_soc_tunnel_term_entry_write(unit,
   2166                      from_ent, &null_entry, entry_type));
   2167     }
   2168     /* 
   2169      * If last entry for the type was deleted -> remove the type 
   2170      * from hash tracking table. 
   2171      */
   2172     if (SOC_TNL_TERM_STATE_VENT(unit, type) == 0) {
   2173         /* remove from the list */
   2174         prev_type = SOC_TNL_TERM_STATE_PREV(unit, type); /* Always present */
   2175         next_type = SOC_TNL_TERM_STATE_NEXT(unit, type);
   2176         SOC_TNL_TERM_STATE_NEXT(unit, prev_type) = next_type;
   2177         SOC_TNL_TERM_STATE_FENT(unit, prev_type) += SOC_TNL_TERM_STATE_FENT(unit, type);
   2178         SOC_TNL_TERM_STATE_FENT(unit, type) = 0;
   2179         if (next_type != TNL_TERM_TYPE_NULL) {
   2180             SOC_TNL_TERM_STATE_PREV(unit, next_type) = prev_type;
   2181         }
   2182         SOC_TNL_TERM_STATE_NEXT(unit, type) = TNL_TERM_TYPE_NULL;
   2183         SOC_TNL_TERM_STATE_PREV(unit, type) = TNL_TERM_TYPE_NULL;
   2184         SOC_TNL_TERM_STATE_START(unit, type) = TNL_TERM_TYPE_NULL;
   2185         SOC_TNL_TERM_STATE_END(unit, type) = TNL_TERM_TYPE_NULL;
   2186     }
   2187 
   2188     return(SOC_E_NONE);
   2189 }
   2190 
   2191 /*
   2192  * Function:
   2193  *   _soc_tunnel_term_match
   2194  * Purpose:
   2195  *	 Find tunnel terminator entry.  
   2196  * Parameters:
   2197  *      unit      - (IN)  BCM device number. 
   2198  *      key       - (IN)  Tunnel terminator lookup key.
   2199  *      result    - (OUT) Tunnel terminator search result.
   2200  *      index     - (OUT) Tunnel termination entry index. 
   2201  * Returns: 
   2202  *      SOC_E_XXX
   2203  */ 
   2204 STATIC int
   2205 _soc_tunnel_term_match(int unit, soc_tunnel_term_t *key,
   2206                        soc_tunnel_term_t *result, int *index)
   2207 {
   2208     int         key_index;  /* Entry key lookup result. */
   2209     int         entry_type; /* Entry type               */
   2210     int         rv;         /* Operation return status. */
   2211 
   2212     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   2213         /* Perform lookup hw. */
   2214         int ipv6 = 0;
   2215         uint32 *entry_ptr;
   2216         soc_mem_t mem = L3_TUNNEL_DOUBLEm;
   2217 
   2218         entry_ptr = (uint32 *)&key->entry_arr[0];
   2219         ipv6 =
   2220             soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf) - 1;
   2221 
   2222         if (ipv6) {
   2223             mem = L3_TUNNEL_QUADm;
   2224         }
   2225         rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, -1,
   2226                                     ((void *)key->entry_arr[0].entry_data), result, index);
   2227         if (SOC_SUCCESS(rv)) {
   2228             rv = _soc_tunnel_term_entry_read(unit, *index, result, &entry_type);
   2229         }
   2230 
   2231         return(rv);
   2232     }
   2233 
   2234     rv = TNL_TERM_HASH_LOOKUP(unit, key, &key_index);
   2235     if (SOC_SUCCESS(rv)) {
   2236         *index = key_index;
   2237         rv = _soc_tunnel_term_entry_read(unit, key_index, result, &entry_type);
   2238     }
   2239     return (rv);
   2240 }
   2241 
   2242 
   2243 /*
   2244  * Function:
   2245  *   soc_tunnel_term_init
   2246  * Purpose:
   2247  *	 Initialize tunnel terminator table tracking start/end   
   2248  *   valid/free indexes for each tunnel type. 
   2249  * Parameters:
   2250  *      unit      - (IN)  BCM device number. 
   2251  * Returns: 
   2252  *      SOC_E_XXX
   2253  */ 
   2254 int
   2255 soc_tunnel_term_init(int unit)
   2256 {
   2257     int max_type;
   2258     int tnl_term_table_size;
   2259     int tnl_term_state_size;
   2260     int idx;
   2261     int rv = SOC_E_NONE;
   2262 
   2263     SOC_TNL_TERM_BLOCK_SIZE  = SOC_TNL_TERM_IPV6_ENTRY_WIDTH;
   2264 
   2265     max_type = MAX_TNL_TERM_TYPES;
   2266     tnl_term_state_size = sizeof(soc_tnl_term_state_t) * max_type;
   2267 
   2268     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   2269         return(rv);
   2270     }
   2271 
   2272     /* Allocated tunnel types tracking table. */
   2273     if (!SOC_TNL_TERM_INIT_CHECK(unit)) {
   2274         SOC_TNL_TERM_STATE(unit) = sal_alloc(tnl_term_state_size, "tnl_term_tcam");
   2275         if (NULL == SOC_TNL_TERM_STATE(unit)) {
   2276             return(SOC_E_MEMORY);
   2277         }
   2278     }
   2279 
   2280     SOC_TNL_TERM_LOCK(unit);
   2281     sal_memset(SOC_TNL_TERM_STATE(unit), 0, tnl_term_state_size);
   2282 
   2283     /* Initialize all tunnel types ranges to empty ones. */
   2284     for(idx = 0; idx < max_type; idx++) {
   2285         SOC_TNL_TERM_STATE_START(unit, idx) = TNL_TERM_TYPE_NULL;
   2286         SOC_TNL_TERM_STATE_END(unit, idx)   = TNL_TERM_TYPE_NULL;
   2287         SOC_TNL_TERM_STATE_PREV(unit, idx)  = TNL_TERM_TYPE_NULL;
   2288         SOC_TNL_TERM_STATE_NEXT(unit, idx)  = TNL_TERM_TYPE_NULL;
   2289         SOC_TNL_TERM_STATE_VENT(unit, idx)  = 0;
   2290         SOC_TNL_TERM_STATE_FENT(unit, idx)  = 0;
   2291     }
   2292 
   2293     tnl_term_table_size = soc_mem_index_count(unit, L3_TUNNELm);
   2294     SOC_TNL_TERM_STATE_FENT(unit, (MAX_TNL_TERM_TYPE)) = tnl_term_table_size;
   2295 
   2296     if (SOC_TNL_TERM_STATE_HASH(unit) != NULL) {
   2297         rv =_soc_tunnel_term_hash_destroy(&SOC_TNL_TERM_STATE_HASH(unit));
   2298         if (SOC_FAILURE(rv)) {
   2299             SOC_TNL_TERM_UNLOCK(unit);
   2300             return SOC_E_INTERNAL;
   2301         }
   2302         SOC_TNL_TERM_STATE_HASH(unit) = NULL;
   2303     }
   2304 
   2305     rv = _soc_tunnel_term_hash_create(unit, tnl_term_table_size, 
   2306                                       tnl_term_table_size,
   2307                                       &SOC_TNL_TERM_STATE_HASH(unit));
   2308 
   2309     SOC_TNL_TERM_UNLOCK(unit);
   2310     return (rv);
   2311 }
   2312 
   2313 /*
   2314  * Function:
   2315  *   soc_tunnel_term_deinit
   2316  * Purpose:
   2317  *	 Deinitialize tunnel terminator table. 
   2318  * Parameters:
   2319  *      unit      - (IN)  BCM device number. 
   2320  * Returns: 
   2321  *      SOC_E_XXX
   2322  */ 
   2323 int
   2324 soc_tunnel_term_deinit(int unit)
   2325 {
   2326 
   2327     SOC_TNL_TERM_LOCK(unit);
   2328 
   2329     if (SOC_TNL_TERM_STATE_HASH(unit) != NULL) {
   2330         _soc_tunnel_term_hash_destroy(&SOC_TNL_TERM_STATE_HASH(unit));
   2331         SOC_TNL_TERM_STATE_HASH(unit) = NULL;
   2332     }
   2333 
   2334     if (SOC_TNL_TERM_INIT_CHECK(unit)) {
   2335         sal_free(SOC_TNL_TERM_STATE(unit));
   2336         SOC_TNL_TERM_STATE(unit) = NULL;
   2337     }
   2338 
   2339     SOC_TNL_TERM_UNLOCK(unit);
   2340 
   2341     return(SOC_E_NONE);
   2342 }
   2343 
   2344 #ifdef BCM_WARM_BOOT_SUPPORT
   2345 /*
   2346  * Function:
   2347  *   _soc_tunnel_term_reinit_done
   2348  * Purpose:
   2349  *	 Adjust tunnel types start/end index after warm reboot 
   2350  *   reinitialization is complete.
   2351  * Parameters:
   2352  *      unit      - (IN)  BCM device number. 
   2353  * Returns: 
   2354  *      SOC_E_XXX
   2355  */ 
   2356 STATIC int
   2357 _soc_tunnel_term_reinit_done(int unit)
   2358 {
   2359     int idx, first = 0, first_valid_entry = 0;
   2360     int prev_idx = MAX_TNL_TERM_TYPE;
   2361     int tnl_term_table_size = soc_mem_index_count(unit, L3_TUNNELm);
   2362 
   2363     SOC_TNL_TERM_STATE_PREV(unit, MAX_TNL_TERM_TYPE) = TNL_TERM_TYPE_NULL;
   2364 
   2365     for (idx = MAX_TNL_TERM_TYPE; idx >= 0 ; idx--) {
   2366         if (TNL_TERM_TYPE_NULL == SOC_TNL_TERM_STATE_START(unit, idx)) {
   2367             continue;
   2368         }
   2369 
   2370         SOC_TNL_TERM_STATE_PREV(unit, idx) = prev_idx;
   2371         SOC_TNL_TERM_STATE_NEXT(unit, prev_idx) = idx;
   2372 
   2373         if ((SOC_TNL_TERM_STATE_START(unit, prev_idx) == TNL_TERM_TYPE_NULL) &&
   2374             (SOC_TNL_TERM_STATE_END(unit, prev_idx) == TNL_TERM_TYPE_NULL)) {
   2375             first = prev_idx;
   2376             first_valid_entry = SOC_TNL_TERM_STATE_START(unit, idx);
   2377         } else {
   2378             SOC_TNL_TERM_STATE_FENT(unit, prev_idx) = 
   2379             SOC_TNL_TERM_STATE_START(unit, idx) - \
   2380                     SOC_TNL_TERM_STATE_END(unit, prev_idx) - 1;       
   2381         } 
   2382         if (SOC_TNL_TERM_STATE_NEXT(unit, idx) == TNL_TERM_TYPE_NULL) {
   2383             SOC_TNL_TERM_STATE_FENT(unit, idx) =
   2384               tnl_term_table_size - SOC_TNL_TERM_STATE_END(unit, idx) - 1;
   2385         }
   2386 
   2387         prev_idx = idx;
   2388     }
   2389     SOC_TNL_TERM_STATE_FENT(unit, first) = first_valid_entry;
   2390     SOC_TNL_TERM_STATE_NEXT(unit, prev_idx) = TNL_TERM_TYPE_NULL;
   2391 
   2392     return (SOC_E_NONE);
   2393 }
   2394 
   2395 
   2396 /*
   2397  * Function:
   2398  *   soc_tunnel_term_reinit
   2399  * Purpose:
   2400  *	 Insert tunnel terminator entry.
   2401  * Parameters:
   2402  *      unit      - (IN)  BCM device number. 
   2403  * Returns: 
   2404  *      SOC_E_XXX
   2405  */ 
   2406 int
   2407 soc_tunnel_term_reinit(int unit)
   2408 {
   2409     soc_tunnel_term_t entry;/* Tunnel terminator entry. */
   2410     int entry_size;         /* Entry size.              */ 
   2411     int entry_type;         /* Tunnel entry type.       */
   2412     int type;               /* soc Tunnel  type.       */
   2413     int idx;                /* Table iteration index.   */
   2414     int idx_max;            /* Maximum Table index.     */
   2415     int rv;                 /* Operation return status. */
   2416 
   2417     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   2418         rv = SOC_E_NONE;
   2419         return(rv);
   2420     }
   2421 
   2422     if (!SOC_MEM_IS_VALID(unit,L3_TUNNELm)) {
   2423         /* if (SOC_IS_HURRICANE(unit)) */
   2424         return SOC_E_NONE;
   2425     }
   2426 
   2427     idx = soc_mem_index_min(unit, L3_TUNNELm);
   2428     idx_max = soc_mem_index_max(unit, L3_TUNNELm); 
   2429 
   2430     while (idx <= idx_max) {
   2431         rv = _soc_tunnel_term_entry_read(unit, idx, &entry, &entry_type);
   2432         /* Skip invalid entries. */
   2433         if (SOC_E_NOT_FOUND == rv) {
   2434             idx++;
   2435             continue;
   2436         }
   2437 
   2438         /* If read failed return. */
   2439         if (SOC_FAILURE(rv)){
   2440             return (rv);
   2441         }
   2442 
   2443         /* Get entry type.(SIP/DIP SIP6/DIP6 DIP/(*) DIP6/(*) */
   2444         SOC_IF_ERROR_RETURN
   2445             (_soc_tunnel_term_type_get(unit, &entry, &type, &entry_type));
   2446 
   2447 #ifdef BCM_TRIDENT3_SUPPORT
   2448         if (soc_feature(unit,soc_feature_flex_flow) &&
   2449                (entry_type > SOC_TNL_TERM_KEY_TYPE_FIXED_MAX)) {
   2450             SOC_IF_ERROR_RETURN (
   2451             _soc_tunnel_term_flex_type_width_get(unit, type,
   2452                        &entry, &entry_size));
   2453         } else
   2454 #endif /* BCM_TRIDENT3_SUPPORT */
   2455         {
   2456             entry_size = (entry_type == 0x1) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH :
   2457                SOC_TNL_TERM_IPV4_ENTRY_WIDTH;
   2458         }
   2459 
   2460         /* Insert type into software range tracking structure. */ 
   2461         if (SOC_TNL_TERM_STATE_VENT(unit, type) == 0) {
   2462             SOC_TNL_TERM_STATE_START(unit, type) = idx;
   2463         }
   2464 
   2465         SOC_TNL_TERM_STATE_END(unit, type) = idx + entry_size - 1;
   2466         SOC_TNL_TERM_STATE_VENT(unit, type)+= entry_size;
   2467         TNL_TERM_HASH_INSERT(unit, &entry, idx);
   2468         idx += entry_size;
   2469     }
   2470 
   2471     rv = _soc_tunnel_term_reinit_done(unit);
   2472     return (rv);
   2473 }
   2474 #endif /* BCM_WARM_BOOT_SUPPORT */
   2475 
   2476 
   2477 
   2478 
   2479 /*
   2480  * Function:
   2481  *   soc_tunnel_term_insert
   2482  * Purpose:
   2483  *	 Insert tunnel terminator entry.  
   2484  * Parameters:
   2485  *      unit      - (IN)  BCM device number. 
   2486  *      entry     - (IN)  Inserted Tunnel terminator entry.
   2487  *      index     - (OUT) Index used for inserted entry.
   2488  * Returns: 
   2489  *      SOC_E_XXX
   2490  */ 
   2491 int
   2492 soc_tunnel_term_insert(int unit, soc_tunnel_term_t *entry, uint32 *index)
   2493 {
   2494     soc_tunnel_term_t lkup_result;  /* Tunnel terminator identical */
   2495     /* entry lookup result.        */
   2496     int   temp_index;               /* Entry write index.          */
   2497     int   entry_type;               /* entry type                  */
   2498     int   rv = SOC_E_NONE;          /* Operation return status.    */
   2499 
   2500 
   2501     /* Input parameters check. */
   2502     if (NULL == entry) {
   2503         return (SOC_E_PARAM);
   2504     }
   2505 
   2506 
   2507     SOC_TNL_TERM_LOCK(unit);
   2508 
   2509     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   2510         int ipv6 = 0;
   2511         uint32 *entry_ptr;
   2512         soc_mem_t mem = L3_TUNNEL_DOUBLEm;
   2513 
   2514         entry_ptr = (uint32 *)&entry->entry_arr[0];
   2515         ipv6 =
   2516             soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf) - 1;
   2517 
   2518         if (ipv6) {
   2519             mem = L3_TUNNEL_QUADm;
   2520         }
   2521 
   2522         rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)entry);
   2523 
   2524         if (SOC_E_EXISTS == rv) {
   2525             rv = SOC_E_NONE;
   2526         }
   2527         SOC_TNL_TERM_UNLOCK(unit);
   2528         return(rv);
   2529     }
   2530 
   2531     /* Check if identical entry already exists. */
   2532     rv = _soc_tunnel_term_match(unit, entry, &lkup_result, &temp_index);
   2533 
   2534     if (rv == SOC_E_NOT_FOUND) {
   2535         /* Allocate a new slot if we are writing a new entry. */
   2536         rv = _soc_tunnel_term_slot_allocate(unit, entry, &temp_index);
   2537     }
   2538 
   2539     if (SOC_SUCCESS(rv)) {
   2540   
   2541         rv = _soc_tunnel_term_type_get(unit, entry, NULL, &entry_type);
   2542         if (SOC_FAILURE(rv)) {
   2543             SOC_TNL_TERM_UNLOCK(unit);
   2544             return(rv);
   2545         }
   2546         
   2547         /* Entry already present. Update the entry */
   2548         TNL_TERM_HASH_INSERT(unit, entry, temp_index);
   2549         rv = _soc_tunnel_term_entry_write(unit, temp_index, entry, entry_type);
   2550         *index = temp_index;
   2551     }
   2552     SOC_TNL_TERM_UNLOCK(unit);
   2553     return(rv);
   2554 }
   2555 
   2556 /*
   2557  * Function:
   2558  *   soc_tunnel_term_delete
   2559  * Purpose:
   2560  *	 Delete tunnel terminator entry.  
   2561  * Parameters:
   2562  *      unit      - (IN)  BCM device number. 
   2563  *      key       - (IN)  Deleted Tunnel terminator entry.
   2564  * Returns: 
   2565  *      SOC_E_XXX
   2566  */ 
   2567 int
   2568 soc_tunnel_term_delete(int unit, soc_tunnel_term_t *key)
   2569 {
   2570     soc_tunnel_term_t hw_entry; /* Entry lookup result.     */
   2571     int index;                        /* Lookup result index.     */
   2572     int rv;                           /* Operation return status. */
   2573 
   2574     /* Input parameters check. */
   2575     if (NULL == key) {
   2576         return (SOC_E_PARAM);
   2577     }
   2578 
   2579     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   2580         int ipv6 = 0;
   2581         uint32 *entry_ptr;
   2582         soc_mem_t mem = L3_TUNNEL_DOUBLEm;
   2583 
   2584         entry_ptr = (uint32 *)&key->entry_arr[0];
   2585         ipv6 =
   2586             soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf) - 1;
   2587 
   2588         if (ipv6) {
   2589             mem = L3_TUNNEL_QUADm;
   2590         }
   2591 
   2592         rv = soc_mem_generic_delete(unit, mem, MEM_BLOCK_ANY,
   2593                                     -1, ((void *)key->entry_arr[0].entry_data),
   2594                                     NULL, 0);
   2595         return(rv);
   2596     }
   2597 
   2598     SOC_TNL_TERM_LOCK(unit);
   2599     /* Find entry matching deletion key. */
   2600     rv = _soc_tunnel_term_match(unit, key, &hw_entry, &index);
   2601     if (SOC_SUCCESS(rv)) {
   2602         TNL_TERM_HASH_DELETE(unit, key, index);
   2603         rv = _soc_tunnel_term_slot_free(unit, &hw_entry, index);
   2604     }
   2605     SOC_TNL_TERM_UNLOCK(unit);
   2606     return(rv);
   2607 }
   2608 #undef TNL_TERM_HASH_INSERT
   2609 #undef TNL_TERM_HASH_DELETE
   2610 #undef TNL_TERM_HASH_LOOKUP
   2611 
   2612 /*
   2613  * Function:
   2614  *      soc_tunnel_term_match
   2615  * Purpose:
   2616  *	    Flush all tunnel terminator entries. 
   2617  * Parameters:
   2618  *      unit      - (IN)  BCM device number. 
   2619  * Returns: 
   2620  *      SOC_E_XXX
   2621  */ 
   2622 int
   2623 soc_tunnel_term_delete_all(int unit)
   2624 {
   2625     return soc_tunnel_term_init(unit);
   2626 }
   2627 
   2628 /*
   2629  * Function:
   2630  *   soc_tunnel_term_match
   2631  * Purpose:
   2632  *	 Find tunnel terminator entry.  
   2633  * Parameters:
   2634  *      unit      - (IN)  BCM device number. 
   2635  *      key       - (IN)  Tunnel terminator lookup key.
   2636  *      result    - (OUT) Tunnel terminator search result.
   2637  *      index     - (OUT) Tunnel termination entry index. 
   2638  * Returns: 
   2639  *      SOC_E_XXX
   2640  */ 
   2641 int
   2642 soc_tunnel_term_match(int unit, soc_tunnel_term_t *key,
   2643                       soc_tunnel_term_t *result, int *entry_index)
   2644 {
   2645     int       rv = SOC_E_NONE;  /* Operation return status. */
   2646     int       index;    /* Lookup result index.     */
   2647 
   2648     /* Input parameters check. */
   2649     if ((NULL == result) || (NULL == key)) {
   2650         return (SOC_E_PARAM);
   2651     }
   2652 
   2653     SOC_TNL_TERM_LOCK(unit);
   2654 
   2655     rv = _soc_tunnel_term_match(unit, key, result, &index);
   2656     *entry_index = index;
   2657     SOC_TNL_TERM_UNLOCK(unit);
   2658     return(rv);
   2659 }
   2660 
   2661 /*
   2662  * Function:
   2663  *   soc_tunnel_term_used_get
   2664  * Purpose:
   2665  *	 Obtain Used Tunnel terminator entry size
   2666  * Parameters:
   2667  *      unit      - (IN)  BCM device number. 
   2668  * Returns: 
   2669  *      used_count
   2670  */ 
   2671 int 
   2672 soc_tunnel_term_used_get(int unit)
   2673 {
   2674    int used_count=0;
   2675 
   2676     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4);
   2677     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4);    
   2678     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT);
   2679     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_PROT);
   2680     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST);
   2681     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_L4DST);
   2682     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST);
   2683     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST);
   2684     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_L4SRC);
   2685     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_L4SRC);
   2686     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_PROT_L4SRC);
   2687     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4SRC);
   2688     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_PROT_L4SRC);
   2689     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_L4DST_L4SRC);
   2690     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_L4DST_L4SRC);
   2691     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_SIP4_PROT_L4DST_L4SRC);
   2692     used_count += SOC_TNL_TERM_STATE_VENT(unit, SOC_TNL_TERM_TYPE_DIP4_PROT_L4DST_L4SRC);
   2693 
   2694     return used_count;
   2695 }
   2696 #endif /* BCM_FIREBOLT_SUPPORT */
   2697 #endif /* INCLUDE_L3 */
   2698