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

l3.c (42737B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        l3.c
      8  * Purpose:     Triumph L3 function implementations
      9  */
     10 
     11 
     12 #include <soc/defs.h>
     13 
     14 #include <assert.h>
     15 
     16 #include <sal/core/libc.h>
     17 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
     18 
     19 #include <shared/util.h>
     20 #include <soc/mem.h>
     21 #include <soc/cm.h>
     22 #include <soc/drv.h>
     23 #include <soc/register.h>
     24 #include <soc/memory.h>
     25 #include <soc/l3x.h>
     26 #include <soc/lpm.h>
     27 #include <soc/tnl_term.h>
     28 
     29 #include <bcm/l3.h>
     30 #include <bcm/tunnel.h>
     31 #include <bcm/debug.h>
     32 #include <bcm/error.h>
     33 #include <bcm/stack.h>
     34 
     35 #include <bcm_int/esw/mbcm.h>
     36 #include <bcm_int/esw/firebolt.h>
     37 #if defined(BCM_TRX_SUPPORT)
     38 #include <bcm_int/esw/trx.h>
     39 #endif /* BCM_TRX_SUPPORT */
     40 #if defined(BCM_TRIUMPH_SUPPORT)
     41 #include <bcm_int/esw/triumph.h>
     42 #endif /* BCM_TRIUMPH_SUPPORT */
     43 #include <bcm_int/esw/l3.h>
     44 #include <bcm_int/esw/xgs3.h>
     45 #include <bcm_int/esw_dispatch.h>
     46 
     47 
     48 _bcm_l3_defip_128_table_t *l3_trx_defip_128[BCM_MAX_NUM_UNITS];
     49 
     50 /*
     51  * Function:
     52  *      _bcm_tr_tnl_type_to_hw_code
     53  * Purpose:
     54  *      Translate tunnel type into value used in hardware
     55  *      (56624(Triumph) only.
     56  * Parameters:
     57  *      unit        - (IN) SOC unit number.
     58  *      tnl_type    - (IN) Tunnel type.
     59  *      hw_code     - (OUT) HW code for tunnel type. 
     60  *      entry_type  - (OUT) Entry type.  
     61  * Returns:
     62  *      BCM_E_XXX
     63  */
     64 int
     65 _bcm_trx_tnl_type_to_hw_code(int unit, bcm_tunnel_type_t tnl_type, 
     66                                  int *hw_code, int *entry_type)
     67 {
     68     /* Input parameters check. */
     69     if ((NULL == hw_code) || (NULL == entry_type)) {
     70         return (BCM_E_PARAM);
     71     }
     72 
     73     switch (tnl_type) {
     74       case bcmTunnelTypeNone:
     75            *hw_code = 0;
     76            *entry_type = BCM_XGS3_TUNNEL_INIT_NONE;
     77            break;
     78 
     79       case bcmTunnelTypeIp4In4:
     80       case bcmTunnelTypeIp6In4:
     81       case bcmTunnelTypeIpAnyIn4:
     82            *hw_code = 0;
     83            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
     84            break;
     85 
     86       case bcmTunnelTypeIp4In6:
     87       case bcmTunnelTypeIp6In6:
     88       case bcmTunnelTypeIpAnyIn6:
     89            *hw_code = 0;
     90            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
     91 #ifdef BCM_TRIDENT3_SUPPORT
     92            if (SOC_IS_TRIDENT3X(unit)) {
     93                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
     94            }
     95 #endif
     96            break;
     97 
     98       case bcmTunnelType6In4Uncheck:
     99            *hw_code = 0x1;
    100            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    101            break;
    102 
    103       case bcmTunnelTypeIsatap:
    104            *hw_code = 0x2;
    105            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    106            break;
    107 
    108       case bcmTunnelType6In4:
    109            *hw_code = 0x3;
    110            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    111            break;
    112 
    113       case bcmTunnelTypeGre4In4:
    114       case bcmTunnelTypeGre6In4:
    115       case bcmTunnelTypeGreAnyIn4:
    116            *hw_code = 0x4;
    117            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    118            break;
    119 
    120       case bcmTunnelTypeGre4In6:
    121       case bcmTunnelTypeGre6In6:
    122       case bcmTunnelTypeGreAnyIn6:
    123            *hw_code = 0x4;
    124            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    125 #ifdef BCM_TRIDENT3_SUPPORT
    126            if (SOC_IS_TRIDENT3X(unit)) {
    127                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    128            }
    129 #endif
    130            break;
    131 
    132       case bcmTunnelTypePimSmDr1:
    133            *hw_code = 0x5;
    134            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    135            break;
    136 
    137       case bcmTunnelTypePimSmDr2:
    138            *hw_code = 0x6;
    139            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    140            break;
    141 
    142       case bcmTunnelTypePim6SmDr1:
    143            *hw_code = 0x5;
    144            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    145 #ifdef BCM_TRIDENT3_SUPPORT
    146            if (SOC_IS_TRIDENT3X(unit)) {
    147                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    148            }
    149 #endif
    150            break;
    151 
    152       case bcmTunnelTypePim6SmDr2:
    153            *hw_code = 0x6;
    154            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    155 #ifdef BCM_TRIDENT3_SUPPORT
    156            if (SOC_IS_TRIDENT3X(unit)) {
    157                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    158            }
    159 #endif
    160            break;
    161 
    162       case bcmTunnelTypeL2Gre:
    163            *hw_code = 0x7;
    164            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    165            break;
    166 
    167       case bcmTunnelTypeWlanAcToAc:
    168            *hw_code = 0x8;
    169            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    170            break;
    171 
    172       case bcmTunnelTypeWlanAcToAc6:
    173            *hw_code = 0x8;
    174            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    175 #ifdef BCM_TRIDENT3_SUPPORT
    176            if (SOC_IS_TRIDENT3X(unit)) {
    177                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    178            }
    179 #endif
    180            break;
    181 
    182       case bcmTunnelTypeWlanWtpToAc:
    183            *hw_code = 0x9;
    184            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    185            break;
    186 
    187       case bcmTunnelTypeWlanWtpToAc6:
    188            *hw_code = 0x9;
    189            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    190 #ifdef BCM_TRIDENT3_SUPPORT
    191            if (SOC_IS_TRIDENT3X(unit)) {
    192                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    193            }
    194 #endif
    195            break;
    196 
    197       case bcmTunnelTypeAutoMulticast:
    198            *hw_code = 0xA;
    199            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    200            break;
    201 
    202       case bcmTunnelTypeAutoMulticast6:
    203            *hw_code = 0xA;
    204            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    205 #ifdef BCM_TRIDENT3_SUPPORT
    206            if (SOC_IS_TRIDENT3X(unit)) {
    207                *entry_type = BCM_XGS3_TUNNEL_INIT_V6_TD3;
    208            }
    209 #endif
    210            break;
    211 #ifdef BCM_MONTEREY_SUPPORT
    212       case bcmTunnelTypeRoeIn4:
    213            *hw_code = 0xC;
    214            *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
    215            break;
    216 
    217       case bcmTunnelTypeRoeIn6:
    218            *hw_code = 0xC;
    219            *entry_type = BCM_XGS3_TUNNEL_INIT_V6;
    220            break;
    221 #endif
    222       default:
    223            break;
    224     }
    225     return (BCM_E_NONE);
    226 }
    227 
    228 /*
    229  * Function:
    230  *      _bcm_trx_tnl_hw_code_to_type
    231  * Purpose:
    232  *      Translate hw code for tunnel type into api value 
    233  * Parameters:
    234  *      unit        - (IN) SOC unit number.
    235  *      hw_tnl_type - (IN) HW tunnel code.
    236  *      entry_type  - (IN) IPv4/IPv6/MPLS entry. 
    237  *      tunnel_type - (OUT) Tunnel type. 
    238  * Returns:
    239  *      BCM_E_XXX
    240  */
    241 int
    242 _bcm_trx_tnl_hw_code_to_type(int unit, int hw_tnl_type, 
    243                              int entry_type, bcm_tunnel_type_t *tunnel_type)
    244 {
    245     /* Input parameters check. */
    246     if (NULL == tunnel_type) {
    247        return (BCM_E_PARAM);
    248     }
    249 
    250     if (BCM_XGS3_TUNNEL_INIT_NONE == entry_type) {
    251           *tunnel_type = bcmTunnelTypeNone;
    252           return (BCM_E_NONE);
    253     }
    254 
    255     switch (hw_tnl_type) {
    256       case 0:
    257           if (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) {
    258               *tunnel_type = bcmTunnelTypeIpAnyIn4;
    259           } else {
    260               *tunnel_type = bcmTunnelTypeIpAnyIn6;
    261           }
    262           break;
    263       case 0x1:
    264           *tunnel_type = bcmTunnelType6In4Uncheck;
    265           break;
    266       case 0x2:
    267           *tunnel_type = bcmTunnelTypeIsatap;
    268           break;
    269       case 0x3:
    270           *tunnel_type = bcmTunnelType6In4;
    271           break;
    272       case 0x4:
    273           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    274                    bcmTunnelTypeGreAnyIn4 : bcmTunnelTypeGreAnyIn6;
    275           break;
    276       case 0x5:
    277           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    278                          bcmTunnelTypePimSmDr1 : bcmTunnelTypePim6SmDr1;
    279           break;
    280       case 0x6:
    281           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    282                          bcmTunnelTypePimSmDr2 : bcmTunnelTypePim6SmDr2;
    283           break;
    284       case 0x7:
    285           *tunnel_type = bcmTunnelTypeL2Gre;
    286           break;
    287       case 0x8:
    288           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    289                          bcmTunnelTypeWlanAcToAc : bcmTunnelTypeWlanAcToAc6;
    290           break;
    291       case 0x9:
    292           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    293                          bcmTunnelTypeWlanWtpToAc : bcmTunnelTypeWlanWtpToAc6;
    294           break;
    295       case 0xA:
    296           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    297                          bcmTunnelTypeAutoMulticast : bcmTunnelTypeAutoMulticast6;
    298           break;
    299       case 0xB:
    300           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    301                          bcmTunnelTypeVxlan : bcmTunnelTypeVxlan6;
    302           break;
    303 #ifdef BCM_MONTEREY_SUPPORT
    304       case 0xC:
    305           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
    306                          bcmTunnelTypeRoeIn4 : bcmTunnelTypeRoeIn6;
    307           break;
    308 #endif
    309       default: 
    310           return (BCM_E_PARAM);
    311     }
    312     return (BCM_E_NONE);
    313 }
    314 
    315 /*
    316  * Function:
    317  *      _bcm_trx_defip_128_hash
    318  * Purpose:
    319  *      Calculate an entry 8 bit hash.
    320  * Parameters:
    321  *      unit        - (IN)SOC unit number.
    322  *      lpm_cfg     - (IN)Buffer to fill defip information. 
    323  *      entry_hash  - (OUT)Entry hash
    324  * Returns:
    325  *      BCM_E_XXX
    326  */
    327 STATIC int
    328 _trx_defip_128_hash(int unit, _bcm_defip_cfg_t *lpm_cfg, uint8 *hash) 
    329 {
    330     uint32 key[BCM_TRX_DEFIP128_HASH_SZ];
    331 
    332     if (NULL == hash) {
    333         return (BCM_E_PARAM);
    334     }
    335 
    336     SAL_IP6_ADDR_TO_UINT32(lpm_cfg->defip_ip6_addr, key);
    337     key[4] = lpm_cfg->defip_sub_len;
    338     key[5] = lpm_cfg->defip_vrf;
    339 
    340     *hash = (_shr_crc16b(0, (void *)key,
    341                          WORDS2BITS((BCM_TRX_DEFIP128_HASH_SZ))) & 0xff);
    342     return (BCM_E_NONE);
    343 }
    344 
    345 #ifdef BCM_WARM_BOOT_SUPPORT
    346 /*
    347  * Function:
    348  *      _trx_defip_128_reinit
    349  * Purpose:
    350  *      Re-Initialize sw image for L3_DEFIP_128 internal tcam.
    351  *      during warm boot. 
    352  * Parameters:
    353  *      unit    - (IN)SOC unit number.
    354  *      idx     - (IN)Entry index   
    355  *      lpm_cfg - (IN)Inserted entry. 
    356  * Returns:
    357  *      BCM_E_XXX
    358  */
    359 STATIC int 
    360 _trx_defip_128_reinit(int unit, int idx, _bcm_defip_cfg_t *lpm_cfg)
    361 {
    362     int   lkup_plen;         /* Vrf weighted lookup prefix. */
    363     uint8 hash;              /* Entry hash value.           */
    364 
    365     /* Calculate vrf weighted prefix length. */
    366     lkup_plen = lpm_cfg->defip_sub_len * 
    367         ((BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) ? 2 : 1);
    368 
    369     /* Calculate entry lookup hash. */
    370     BCM_IF_ERROR_RETURN(_trx_defip_128_hash(unit, lpm_cfg, &hash));
    371 
    372     /* Set software structure info. */
    373     BCM_TRX_DEFIP128_ENTRY_SET(unit, idx, lkup_plen, hash);
    374 
    375     /* Update software usage counter. */
    376     BCM_TRX_DEFIP128_USED_COUNT(unit)++;
    377 
    378     return (BCM_E_NONE);
    379 }
    380 
    381 #endif /* BCM_WARM_BOOT_SUPPORT */
    382 
    383 /*
    384  * Function:
    385  *      _bcm_trx_defip_128_init
    386  * Purpose:
    387  *      Initialize sw image for L3_DEFIP_128 internal tcam.
    388  * Parameters:
    389  *      unit        - (IN)SOC unit number.
    390  * Returns:
    391  *      BCM_E_XXX
    392  */
    393 int 
    394 _bcm_trx_defip_128_init(int unit)
    395 {   
    396     int mem_sz;    /* Memory allocation size     */
    397     int rv;        /* Internal operation status. */
    398 
    399     /* De-allocate any existing structures. */
    400     if (NULL != BCM_TRX_DEFIP128(unit)) {
    401         rv = _bcm_trx_defip_128_deinit(unit);
    402         BCM_IF_ERROR_RETURN(rv);
    403     }
    404 
    405     /* Allocate cam control structure. */
    406     mem_sz = sizeof(_bcm_l3_defip_128_table_t);
    407     BCM_TRX_DEFIP128(unit) = sal_alloc(mem_sz, "l3_trx_defip_128");
    408     if (NULL == BCM_TRX_DEFIP128(unit)) {
    409         return (BCM_E_MEMORY);
    410     }
    411 
    412     /* Reset cam control structure. */
    413     sal_memset(BCM_TRX_DEFIP128(unit), 0, mem_sz);
    414 
    415     BCM_TRX_DEFIP128_TOTAL(unit) = soc_mem_index_count(unit, L3_DEFIP_128m);
    416 
    417                                                                 
    418     if (SOC_URPF_STATUS_GET(unit)) {
    419         BCM_TRX_DEFIP128_TOTAL(unit) >>= 1;
    420         BCM_TRX_DEFIP128_URPF_OFFSET(unit) = BCM_TRX_DEFIP128_TOTAL(unit);
    421     } else {
    422         BCM_TRX_DEFIP128_URPF_OFFSET(unit) = 0;
    423     }
    424 
    425     BCM_TRX_DEFIP128_IDX_MAX(unit) = BCM_TRX_DEFIP128_TOTAL(unit) - 1;
    426 
    427     mem_sz = BCM_TRX_DEFIP128_TOTAL(unit) * sizeof(_bcm_l3_defip_128_entry_t);
    428 
    429     BCM_TRX_DEFIP128_ARR(unit) = sal_alloc(mem_sz, "l3_defip_128_entry_array");
    430     if (NULL == BCM_TRX_DEFIP128_ARR(unit)) {
    431         BCM_IF_ERROR_RETURN(_bcm_trx_defip_128_deinit(unit));
    432         return (BCM_E_MEMORY);
    433     }
    434     sal_memset(BCM_TRX_DEFIP128_ARR(unit), 0, mem_sz);
    435 
    436     return (BCM_E_NONE);
    437 }
    438 
    439 /*
    440  * Function:
    441  *      _bcm_trx_defip_128_deinit
    442  * Purpose:
    443  *      De-initialize sw image for L3_DEFIP_128 internal tcam.
    444  * Parameters:
    445  *      unit        - (IN)SOC unit number.
    446  * Returns:
    447  *      BCM_E_XXX
    448  */
    449 int 
    450 _bcm_trx_defip_128_deinit(int unit)
    451 {   
    452     if (NULL == BCM_TRX_DEFIP128(unit)) {
    453         return (BCM_E_NONE);
    454     }
    455 
    456 
    457     /* De-allocate any existing structures. */
    458     if (NULL != BCM_TRX_DEFIP128_ARR(unit)) {
    459         sal_free(BCM_TRX_DEFIP128_ARR(unit));
    460         BCM_TRX_DEFIP128_ARR(unit) = NULL;
    461     }
    462     sal_free(BCM_TRX_DEFIP128(unit));
    463     BCM_TRX_DEFIP128(unit) = NULL;
    464 
    465     return (BCM_E_NONE);
    466 }
    467 
    468 /*
    469  * Function:
    470  *      _trx_defip_128_get_key
    471  * Purpose:
    472  *      Parse route entry key from L3_DEFIP_128 table.
    473  * Parameters:
    474  *      unit        - (IN)SOC unit number.
    475  *      entry       - (IN)Hw entry buffer. 
    476  *      lpm_cfg     - (IN/OUT)Buffer to fill defip information. 
    477  * Returns:
    478  *      BCM_E_XXX
    479  */
    480 STATIC int 
    481 _trx_defip_128_get_key(int unit, uint32 *hw_entry, 
    482                        _bcm_defip_cfg_t *lpm_cfg)
    483 {
    484     soc_mem_t mem = L3_DEFIP_128m;  /* Route table memory. */ 
    485     bcm_ip6_t mask;                 /* Subnet mask.        */
    486 
    487     /* Input parameters check. */
    488     if ((NULL == lpm_cfg) || (NULL == hw_entry)) {
    489         return (BCM_E_PARAM);
    490     }
    491 
    492     /* Extract ip6 address. */
    493     soc_mem_ip6_addr_get(unit, mem, hw_entry, IP_ADDRf, lpm_cfg->defip_ip6_addr,
    494                          SOC_MEM_IP6_FULL_ADDR);
    495 
    496     /* Extract subnet mask. */
    497     soc_mem_ip6_addr_get(unit, mem, hw_entry, IP_ADDR_MASKf, mask,
    498                          SOC_MEM_IP6_FULL_ADDR);
    499     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
    500 
    501     /* Extract vrf id & vrf mask. */
    502     if(!soc_mem_field32_get(unit, mem, hw_entry, VRF_ID_MASKf)) {
    503         lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE;
    504     } else {
    505         lpm_cfg->defip_vrf = soc_mem_field32_get(unit, mem, hw_entry, VRF_IDf);
    506     }
    507     return (BCM_E_NONE);
    508 }
    509 
    510 /*
    511  * Function:
    512  *      _trx_defip_128_parse
    513  * Purpose:
    514  *      Parse route entry from L3_DEFIP_128 table to sw structure.
    515  * Parameters:
    516  *      unit        - (IN)SOC unit number.
    517  *      hw_entry    - (IN)Hw entry buffer. 
    518  *      lpm_cfg     - (IN/OUT)Buffer to fill defip information. 
    519  *      nh_ecmp_idx - (OUT)Next hop ecmp table index. 
    520  * Returns:
    521  *      BCM_E_XXX
    522  */
    523 STATIC INLINE int 
    524 _trx_defip_128_parse(int unit, uint32 *hw_entry,
    525                      _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
    526 {
    527     soc_mem_t mem = L3_DEFIP_128m;  /* Route table memory. */ 
    528 
    529     /* Input parameters check. */
    530     if ((NULL == hw_entry) || (NULL == lpm_cfg)) {
    531         return (BCM_E_PARAM);
    532     }
    533 
    534     /* Reset entry flags first. */
    535     lpm_cfg->defip_flags = 0;
    536 
    537     /* Check if entry points to ecmp group. */
    538     if (soc_mem_field32_get(unit, mem, hw_entry, ECMPf)) {
    539         /* Mark entry as ecmp */
    540         lpm_cfg->defip_ecmp = TRUE;
    541         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
    542 
    543         /* Get ecmp group id. */
    544         if (NULL != nh_ecmp_idx) {
    545             *nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, ECMP_PTRf);
    546         }
    547     } else {
    548         /* Mark entry as non-ecmp. */
    549         lpm_cfg->defip_ecmp = 0;
    550 
    551         /* Reset ecmp group next hop count. */
    552         lpm_cfg->defip_ecmp_count = 0;
    553 
    554         /* Get next hop index. */
    555         if (NULL != nh_ecmp_idx) {
    556             *nh_ecmp_idx =
    557                 soc_mem_field32_get(unit, mem, hw_entry, NEXT_HOP_INDEXf);
    558         }
    559     }
    560 
    561     /* Mark entry as IPv6 */
    562     lpm_cfg->defip_flags |= BCM_L3_IP6;
    563 
    564     /* Get entry priority. */
    565     lpm_cfg->defip_prio = soc_mem_field32_get(unit, mem, hw_entry, PRIf);
    566 
    567     /* Get classification group id. */
    568     lpm_cfg->defip_lookup_class = 
    569         soc_mem_field32_get(unit, mem, hw_entry, CLASS_IDf);
    570 
    571     /* Get hit bit. */
    572     if (soc_mem_field32_get(unit, mem, hw_entry, HITf)) {
    573         lpm_cfg->defip_flags |= BCM_L3_HIT;
    574     }
    575 
    576     /* Get priority override bit. */
    577     if (soc_mem_field32_get(unit, mem, hw_entry, RPEf)) {
    578         lpm_cfg->defip_flags |= BCM_L3_RPE;
    579     }
    580 
    581     /* Get destination discard field. */
    582     if(soc_mem_field32_get(unit, mem, hw_entry, DST_DISCARDf)) {
    583         lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
    584     }
    585     return (BCM_E_NONE);
    586 }
    587 
    588 /*
    589  * Function:
    590  *      _trx_defip_128_match
    591  * Purpose:
    592  *      Lookup route entry from L3_DEFIP_128 table.
    593  * Parameters:
    594  *      unit        - (IN)SOC unit number.
    595  *      lpm_cfg     - (IN)Buffer to fill defip information. 
    596  *      hw_entry    - (OUT)Matching hw entry. 
    597  *      hw_index    - (OUT)HW table index. 
    598  * Returns:
    599  *      BCM_E_XXX
    600  */
    601 STATIC int 
    602 _trx_defip_128_match(int unit, _bcm_defip_cfg_t *lpm_cfg, 
    603                      uint32 *hw_entry, int *hw_index)
    604 {
    605     _bcm_defip_cfg_t candidate;        /* Match condidate.            */
    606     int   lkup_plen;                   /* Vrf weighted lookup prefix. */
    607     int   index;                       /* Table iteration index.      */
    608     uint8 hash;                        /* Entry hash value.           */
    609     int   rv = BCM_E_NONE;             /* Internal operation status.  */
    610 
    611 
    612     /* Initialization */
    613     sal_memset(&candidate, 0, sizeof(_bcm_defip_cfg_t));
    614     
    615     /* Calculate vrf weighted prefix length. */
    616     lkup_plen = lpm_cfg->defip_sub_len * 
    617         ((BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) ? 2 : 1);
    618 
    619     /* Calculate entry lookup hash. */
    620     BCM_IF_ERROR_RETURN(_trx_defip_128_hash(unit, lpm_cfg, &hash));
    621 
    622     /*    coverity[assignment : FALSE]    */
    623     for (index = 0; index <= BCM_TRX_DEFIP128_IDX_MAX(unit); index++) {
    624 
    625         /* Route prefix length comparison. */
    626         if (lkup_plen != BCM_TRX_DEFIP128_ARR(unit)[index].prefix_len) {
    627             continue;
    628         }
    629 
    630         /* Route lookup key hash comparison. */
    631         if (hash != BCM_TRX_DEFIP128_ARR(unit)[index].entry_hash) {
    632             continue;
    633         }
    634 
    635         /* Hash & prefix length match -> read and compare hw entry itself. */
    636         rv = BCM_XGS3_MEM_READ(unit, L3_DEFIP_128m, index, hw_entry);
    637         if (BCM_FAILURE(rv)) {
    638             break;
    639         }
    640 
    641         /* Make sure entry is valid.  */
    642         if ((!soc_mem_field32_get(unit, L3_DEFIP_128m, hw_entry, VALID_0f)) ||
    643             (!soc_mem_field32_get(unit, L3_DEFIP_128m, hw_entry, VALID_1f))) {
    644             /* Too bad sw image doesn't match hardware. */
    645             continue;
    646         }
    647 
    648         /* Extract entry address vrf */
    649         rv =  _trx_defip_128_get_key(unit, hw_entry, &candidate);
    650         if (BCM_FAILURE(rv)) {
    651             break;
    652         }
    653 
    654 
    655         /* Address & Vrf comparison. */
    656         if (lpm_cfg->defip_vrf != candidate.defip_vrf) {
    657             continue;
    658         }
    659 
    660         /* Subnet mask comparison. */
    661         if (lpm_cfg->defip_sub_len != candidate.defip_sub_len) {
    662             continue;
    663         }
    664 
    665 
    666         if (sal_memcmp(lpm_cfg->defip_ip6_addr, candidate.defip_ip6_addr,
    667                        sizeof(bcm_ip6_t))) {
    668             continue;
    669         }
    670 
    671 
    672         /* Matching entry found. */
    673         break;
    674 
    675     }
    676 
    677     BCM_IF_ERROR_RETURN(rv);
    678 
    679     if (index > BCM_TRX_DEFIP128_IDX_MAX(unit))  {
    680         return (BCM_E_NOT_FOUND);
    681     }
    682 
    683 #ifdef BCM_TRIDENT_SUPPORT
    684     if (SOC_IS_TRIDENT(unit)) {
    685         uint32 hit_x, hit_y;
    686         BCM_IF_ERROR_RETURN
    687             (BCM_XGS3_MEM_READ(unit, L3_DEFIP_128_HIT_ONLY_Ym, index, &hit_y));
    688         hit_x = soc_mem_field32_get(unit, L3_DEFIP_128m, hw_entry, HITf);
    689         hit_x |= hit_y;
    690         soc_mem_field32_set(unit, L3_DEFIP_128m, hw_entry, HITf, hit_x);
    691     }
    692 #endif /* BCM_TRIDENT_SUPPORT */
    693 
    694     *hw_index = index;
    695     return (BCM_E_NONE);
    696 }
    697 
    698 /*
    699  * Function:
    700  *      _trx_defip_128_entry_clear
    701  * Purpose:
    702  *      Clear/Reset a single route entry. 
    703  * Parameters:
    704  *      unit      - (IN)SOC unit number.
    705  *      hw_index  - (IN)Entry index in the tcam. 
    706  * Returns:
    707  *      BCM_E_XXX
    708  */
    709 STATIC int 
    710 _trx_defip_128_entry_clear(int unit, int hw_index)  
    711 {
    712 
    713     /* Reset hw entry. */
    714     BCM_IF_ERROR_RETURN
    715         (BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, hw_index,
    716                             soc_mem_entry_null(unit, L3_DEFIP_128m)));
    717 
    718     /* Reset sw entry. */
    719     BCM_TRX_DEFIP128_ENTRY_SET(unit, hw_index, 0, 0);
    720 
    721     /* Reset urpf source lookup entry. */
    722     if (SOC_URPF_STATUS_GET(unit)) {
    723         BCM_IF_ERROR_RETURN
    724             (BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, 
    725                                 (hw_index + BCM_TRX_DEFIP128_URPF_OFFSET(unit)),
    726                                 soc_mem_entry_null(unit, L3_DEFIP_128m)));
    727     }
    728     return (BCM_E_NONE);
    729 }
    730 /*
    731  * Function:
    732  *      _trx_defip_128_shift
    733  * Purpose:
    734  *      Shift entries in the tcam. 
    735  * Parameters:
    736  *      unit    - (IN)SOC unit number.
    737  *      idx_src     - (IN)Entry source. 
    738  *      idx_dest    - (IN)Entry destination.
    739  * Returns:
    740  *      BCM_E_XXX
    741  */
    742 STATIC int 
    743 _trx_defip_128_shift(int unit, int idx_src, int idx_dest)  
    744 {
    745     uint32 hw_entry[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */
    746 
    747     /* Don't copy uninstalled entries. */
    748     if (0 != BCM_TRX_DEFIP128_ARR(unit)[idx_src].prefix_len) {
    749         /* Read entry from source index. */
    750         BCM_IF_ERROR_RETURN
    751             (BCM_XGS3_MEM_READ(unit, L3_DEFIP_128m, idx_src, hw_entry));
    752 
    753         /* Write entry to the destination index. */
    754         BCM_IF_ERROR_RETURN
    755             (BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, idx_dest, hw_entry));
    756 
    757         /* Shift corresponding  URPF/source lookup entries. */
    758         if (SOC_URPF_STATUS_GET(unit)) {
    759             /* Read entry from source index + half tcam. */
    760             BCM_IF_ERROR_RETURN
    761                 (BCM_XGS3_MEM_READ(unit, L3_DEFIP_128m, 
    762                                    idx_src + BCM_TRX_DEFIP128_URPF_OFFSET(unit),
    763                                    hw_entry));
    764 
    765             /* Write entry to the destination index + half tcam. */
    766             BCM_IF_ERROR_RETURN
    767                 (BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, 
    768                                     idx_dest +  BCM_TRX_DEFIP128_URPF_OFFSET(unit),
    769                                     hw_entry));
    770         }
    771     }
    772     /* Copy software portion of the entry. */ 
    773     sal_memcpy (&BCM_TRX_DEFIP128_ARR(unit)[idx_dest],
    774                 &BCM_TRX_DEFIP128_ARR(unit)[idx_src], 
    775                 sizeof(_bcm_l3_defip_128_entry_t));
    776 
    777     return (BCM_E_NONE);
    778 }
    779 
    780 /*
    781  * Function:
    782  *      _trx_defip_128_shift_range
    783  * Purpose:
    784  *      Shift entries in the tcam. 
    785  * Parameters:
    786  *      unit        - (IN)SOC unit number.
    787  *      idx_start   - (IN)Start index
    788  *      idx_end     - (IN)End index
    789  * Returns:
    790  *      BCM_E_XXX
    791  */
    792 STATIC int 
    793 _trx_defip_128_shift_range(int unit, int idx_start, int idx_end)  
    794 {
    795     int idx;     /* Iteration index. */
    796     int rv = BCM_E_NONE;   /* Operaton status. */ 
    797 
    798     /* Shift entries down (1 index up) */
    799     if (idx_end > idx_start) {
    800         for (idx = idx_end - 1; idx >= idx_start; idx--) {
    801             rv = _trx_defip_128_shift(unit, idx, idx + 1);  
    802             if (BCM_FAILURE(rv)) { 
    803                 break;
    804             }
    805         }
    806         /* Delete last entry from hardware & software. */
    807         rv = _trx_defip_128_entry_clear(unit, idx_start);
    808     }
    809 
    810     /* Shift entries up (1 index down) */
    811     if (idx_end < idx_start) {
    812         for (idx = idx_end + 1; idx <= idx_start; idx++) {
    813             rv = _trx_defip_128_shift(unit, idx, idx - 1);  
    814             if (BCM_FAILURE(rv)) { 
    815                 break;
    816             }
    817         }
    818         /* Delete last entry from hardware & software. */
    819         rv = _trx_defip_128_entry_clear(unit, idx_start);
    820     }
    821 
    822     return (rv);
    823 }
    824 /*
    825  * Function:
    826  *      _trx_defip_128_idx_alloc
    827  * Purpose:
    828  *      Shuffle the tcam in order to insert a new entry 
    829  *      based on vrf weighted prefix length.
    830  * Parameters:
    831  *      unit        - (IN)SOC unit number.
    832  *      lpm_cfg     - (IN)Route info 
    833  *      hw_index    - (OUT)Allocated hw index. 
    834  * Returns:
    835  *      BCM_E_XXX
    836  */
    837 STATIC int 
    838 _trx_defip_128_idx_alloc(int unit, _bcm_defip_cfg_t *lpm_cfg, int *hw_index) 
    839 {
    840     int  lkup_plen;                   /* Vrf weighted lookup prefix.    */
    841     uint8 hash;                       /* Entry hash value.              */
    842     int  idx;                         /* Table iteration index.         */
    843     int  rv;                          /* Operation return status.       */
    844     int  shift_min = 0;               /* Minimum entry shift required.  */
    845     int  range_start = 0;             /* First valid location for pfx.  */
    846     int  range_end = BCM_TRX_DEFIP128_IDX_MAX(unit);  
    847                                       /* Last valid location for pfx.   */
    848     int  free_idx_before = -1;        /* Free index before range_start. */
    849     int  free_idx_after  = -1;        /* Free index after range_end.    */
    850 
    851     /* Input parameters check. */
    852     if ((NULL == lpm_cfg) || (NULL == hw_index)) {
    853         return (BCM_E_PARAM);
    854     }
    855 
    856     /* Calculate vrf weighted prefix length. */
    857     lkup_plen = lpm_cfg->defip_sub_len * 
    858         ((BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) ? 2 : 1);
    859 
    860     /* Calculate entry hash. */
    861     BCM_IF_ERROR_RETURN(_trx_defip_128_hash(unit, lpm_cfg, &hash));
    862 
    863     /* Make sure at least one slot is available. */
    864     if (BCM_TRX_DEFIP128_USED_COUNT(unit) == BCM_TRX_DEFIP128_TOTAL(unit)) {
    865         return (BCM_E_FULL);
    866     }
    867 
    868     /* 
    869      *  Find first valid index for the prefix;
    870      */ 
    871     for (idx = 0; idx <= BCM_TRX_DEFIP128_IDX_MAX(unit); idx++) {
    872 
    873         /* Remeber free entry before installation location. */
    874         if (0 == BCM_TRX_DEFIP128_ARR(unit)[idx].prefix_len) {
    875             free_idx_before = idx;
    876             continue;
    877         }
    878         /* Route prefix length comparison. */
    879         if (lkup_plen < BCM_TRX_DEFIP128_ARR(unit)[idx].prefix_len) {
    880             range_start = idx + 1;
    881             continue;
    882         }
    883         break;
    884     }
    885 
    886     /* 
    887      *  Find last valid index for the prefix;
    888      */ 
    889     for (idx = BCM_TRX_DEFIP128_IDX_MAX(unit); idx >= 0; idx--) {
    890 
    891         /* Remeber free entry after installation location. */
    892         if (0 == BCM_TRX_DEFIP128_ARR(unit)[idx].prefix_len) {
    893             free_idx_after = idx;
    894             continue;
    895         }
    896         /* Route prefix length comparison. */
    897         if (lkup_plen >  BCM_TRX_DEFIP128_ARR(unit)[idx].prefix_len) {
    898             range_end = idx;
    899             continue;
    900         }
    901         break;
    902     }
    903 
    904     /* Check if entry should be inserted at the end. */
    905     if (range_start > BCM_TRX_DEFIP128_IDX_MAX(unit)) {
    906     /*    coverity[negative_returns : FALSE]    */
    907         /* Shift all entries from free_idx_before till the end 1 up. */
    908     /* coverity[negative_returns] */
    909         rv = _trx_defip_128_shift_range(unit, BCM_TRX_DEFIP128_IDX_MAX(unit),
    910                                         free_idx_before);
    911 
    912         if (BCM_SUCCESS(rv)) { 
    913             /* Allocated index is last TCAM entry. */
    914             *hw_index = BCM_TRX_DEFIP128_IDX_MAX(unit);
    915             BCM_TRX_DEFIP128_ENTRY_SET(unit, *hw_index, lkup_plen, hash);
    916         }
    917         return (rv);
    918     }
    919 
    920     /* Check if entry should be inserted at the beginning. */
    921     if (range_end < 0) {
    922         /* Shift all entries from 0 till free_idx_after 1 down. */
    923         rv = _trx_defip_128_shift_range(unit, 0, free_idx_after);
    924 
    925         if (BCM_SUCCESS(rv)) {
    926             /* Allocated index is first TCAM entry. */
    927             *hw_index = 0;
    928             BCM_TRX_DEFIP128_ENTRY_SET(unit, 0, lkup_plen, hash);
    929         }
    930         return (rv);
    931     }
    932 
    933     /* Find if there is any free index in range. */
    934     for (idx = range_start; idx <= range_end; idx++) {
    935         if (0 == BCM_TRX_DEFIP128_ARR(unit)[idx].prefix_len) {
    936             *hw_index = idx;
    937             BCM_TRX_DEFIP128_ENTRY_SET(unit, idx, lkup_plen, hash);
    938             return (BCM_E_NONE);
    939         }
    940     }
    941 
    942     /* Check if entry should be inserted at the end of range. */
    943     if ((free_idx_after > range_end) && (free_idx_after != -1))  {
    944         shift_min = free_idx_after - range_end;
    945     } 
    946 
    947     /* Check if entry should be inserted in the beginning. */
    948     if ((free_idx_before < range_start) && (free_idx_before != -1))  {
    949         if(shift_min > (range_start - free_idx_before)) {
    950             shift_min = -1;
    951         }
    952     /*    coverity[negative_returns : FALSE]    */
    953     }
    954 
    955     /* coverity[negative_returns] */
    956     if (shift_min <= 0) {
    957         rv = _trx_defip_128_shift_range(unit, range_start, free_idx_before);
    958     /*    coverity[negative_returns : FALSE]    */
    959         if (BCM_SUCCESS(rv)) {
    960             *hw_index= range_start;
    961     /*    coverity[negative_returns : FALSE]    */
    962             BCM_TRX_DEFIP128_ENTRY_SET(unit, range_start, lkup_plen, hash);
    963     /* coverity[negative_returns] */
    964     /* coverity[negative_returns] */
    965         }
    966     } else {
    967     /* coverity[negative_returns] */
    968     /* coverity[negative_returns] */
    969         rv = _trx_defip_128_shift_range(unit, range_end, free_idx_after);
    970         if (BCM_SUCCESS(rv)) {
    971             *hw_index = range_end;
    972             BCM_TRX_DEFIP128_ENTRY_SET(unit, range_end, lkup_plen, hash);
    973         }
    974     }
    975     return (rv);
    976 }
    977 /*
    978  * Function:
    979  *      _bcm_trx_defip_128_get
    980  * Purpose:
    981  *      Get an entry from L3_DEFIP_128 table.
    982  * Parameters:
    983  *      unit        - (IN)SOC unit number.
    984  *      lpm_cfg     - (IN)Buffer to fill defip information. 
    985  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
    986  * Returns:
    987  *      BCM_E_XXX
    988  */
    989 int 
    990 _bcm_trx_defip_128_get(int unit, _bcm_defip_cfg_t *lpm_cfg, 
    991                        int *nh_ecmp_idx) 
    992 {
    993     uint32 hw_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.          */
    994     bcm_ip6_t mask;                          /* Subnet mask.              */
    995     int clear_hit;                           /* Clear entry hit bit flag. */
    996     int hw_index = 0;                            /* Entry offset in the TCAM. */ 
    997     int rv;                                  /* Internal operation status.*/
    998 
    999     /* Input parameters check. */
   1000     if (NULL == lpm_cfg) {
   1001         return (BCM_E_PARAM);
   1002     }
   1003 
   1004     /* Check if clear hit bit required. */
   1005     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
   1006 
   1007     /* Create mask from prefix length. */
   1008     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   1009 
   1010     /* Apply mask on address. */
   1011     bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr);
   1012 
   1013 
   1014     /* Search for matching entry in the cam. */
   1015     rv =  _trx_defip_128_match(unit, lpm_cfg, hw_entry, &hw_index);
   1016     BCM_IF_ERROR_RETURN(rv);
   1017 
   1018     lpm_cfg->defip_index = hw_index;
   1019 
   1020     /* Parse matched entry. */
   1021     rv = _trx_defip_128_parse(unit, hw_entry, lpm_cfg, nh_ecmp_idx);
   1022     BCM_IF_ERROR_RETURN(rv);
   1023 
   1024     /* Clear the HIT bit */
   1025     if (clear_hit) {
   1026         soc_mem_field32_set(unit, L3_DEFIP_128m, hw_entry, HITf, 0);
   1027 
   1028         rv = BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, hw_index, hw_entry);
   1029     }
   1030 
   1031     return (rv);
   1032 }
   1033 
   1034 /*
   1035  * Function:
   1036  *      _bcm_trx_defip_128_add
   1037  * Purpose:
   1038  *      Add an entry to internal L3_DEFIP_128 table.
   1039  * Parameters:
   1040  *      unit        - (IN)SOC unit number.
   1041  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   1042  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
   1043  * Returns:
   1044  *      BCM_E_XXX
   1045  */
   1046 int 
   1047 _bcm_trx_defip_128_add(int unit, _bcm_defip_cfg_t *lpm_cfg,
   1048                        int nh_ecmp_idx) 
   1049 {
   1050     uint32 hw_entry[SOC_MAX_MEM_FIELD_WORDS];   /* New entry hw buffer.      */
   1051     bcm_ip6_t mask;                             /* Subnet mask.              */
   1052     int hw_index = 0;                           /* Entry offset in the TCAM. */ 
   1053     int rv;                                     /* Operation return status.  */
   1054     soc_mem_t mem = L3_DEFIP_128m;              /* Route table memory.       */ 
   1055 
   1056     /* Input parameters check. */
   1057     if (NULL == lpm_cfg) {
   1058         return (BCM_E_PARAM);
   1059     }
   1060 
   1061     /* No support for routes matchin AFTER vrf specific. */
   1062     if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   1063         return (BCM_E_UNAVAIL);
   1064     }
   1065 
   1066     /* Zero buffers. */
   1067     sal_memset(hw_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS));
   1068 
   1069     /* Create mask from prefix length. */
   1070     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   1071 
   1072     /* Apply mask on address. */
   1073     bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr);
   1074 
   1075     /* Allocate a new index for inserted entry. */
   1076     if (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index) {
   1077         rv = _trx_defip_128_idx_alloc(unit, lpm_cfg, &hw_index);
   1078         BCM_IF_ERROR_RETURN(rv);
   1079     } else {
   1080         hw_index = lpm_cfg->defip_index;
   1081     }
   1082 
   1083     /* Set hit bit. */
   1084     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
   1085         soc_mem_field32_set(unit, mem, hw_entry, HITf, 1);
   1086     }
   1087 
   1088     /* Set priority override bit. */
   1089     if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   1090         soc_mem_field32_set(unit, mem, hw_entry, RPEf, 1);
   1091     }
   1092 
   1093     /* Set classification group id. */
   1094     soc_mem_field32_set(unit, mem, hw_entry, CLASS_IDf, 
   1095                         lpm_cfg->defip_lookup_class);
   1096 
   1097 
   1098     /* Write priority field. */
   1099     soc_mem_field32_set(unit, mem, hw_entry, PRIf, lpm_cfg->defip_prio);
   1100 
   1101 
   1102     /* Fill next hop information. */
   1103     if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   1104         soc_mem_field32_set(unit, mem, hw_entry, ECMP_PTRf, nh_ecmp_idx);
   1105         soc_mem_field32_set(unit, mem, hw_entry, ECMPf, 1);
   1106     } else {
   1107         soc_mem_field32_set(unit, mem, hw_entry, NEXT_HOP_INDEXf, nh_ecmp_idx);
   1108     }
   1109 
   1110     /* Set destination discard flag. */
   1111     if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   1112         soc_mem_field32_set(unit, mem, hw_entry, DST_DISCARDf, 1);
   1113     }
   1114 
   1115     /* Set valid bits. */
   1116     soc_mem_field32_set(unit, mem, hw_entry, VALID_0f, 1);
   1117     soc_mem_field32_set(unit, mem, hw_entry, VALID_1f, 1);
   1118 
   1119 
   1120     /* Set destination/source ip address. */
   1121     soc_mem_ip6_addr_set(unit, mem, hw_entry, IP_ADDRf, lpm_cfg->defip_ip6_addr,
   1122                          SOC_MEM_IP6_FULL_ADDR);
   1123 
   1124     /* Set ip mask. */
   1125     soc_mem_ip6_addr_set(unit, mem, hw_entry, IP_ADDR_MASKf, mask,
   1126                          SOC_MEM_IP6_FULL_ADDR);
   1127 
   1128     /* Set vrf id & vrf mask. */
   1129     if (BCM_L3_VRF_OVERRIDE != lpm_cfg->defip_vrf) {
   1130         soc_mem_field32_set(unit, mem, hw_entry, VRF_IDf, lpm_cfg->defip_vrf);
   1131         soc_mem_field32_set(unit, mem, hw_entry, VRF_ID_MASKf,
   1132                             (1 << soc_mem_field_length(unit, mem,
   1133                                                        VRF_ID_MASKf)) - 1);
   1134         if (SOC_MEM_FIELD_VALID(unit, mem, GLOBAL_ROUTEf)) {
   1135             soc_mem_field32_set(unit, mem, hw_entry, GLOBAL_ROUTEf, 0);
   1136         }
   1137     } else {
   1138         soc_mem_field32_set(unit, mem, hw_entry, VRF_IDf, 0);
   1139         soc_mem_field32_set(unit, mem, hw_entry, VRF_ID_MASKf, 0);
   1140     }
   1141 
   1142     /* Write buffer to hw. */
   1143     rv = BCM_XGS3_MEM_WRITE(unit, mem, hw_index, hw_entry);
   1144     if (BCM_FAILURE(rv)) {
   1145         BCM_TRX_DEFIP128_ENTRY_SET(unit, hw_index, 0, 0);
   1146         return (rv);
   1147     }
   1148 
   1149     /* Write source lookup portion of the entry. */
   1150     if (SOC_URPF_STATUS_GET(unit)) {
   1151         soc_mem_field32_set(unit, mem, hw_entry, SRC_DISCARDf, 0);
   1152         rv = BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_128m, 
   1153                                 (hw_index + BCM_TRX_DEFIP128_URPF_OFFSET(unit)),
   1154                                 hw_entry);
   1155         if (BCM_FAILURE(rv)) {
   1156             _trx_defip_128_entry_clear(unit, hw_index);
   1157             return (rv);
   1158         }
   1159     }
   1160 
   1161     /* If new route added increment total number of routes.  */
   1162     /* Lack of index indicates a new route. */
   1163     if (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index) {
   1164         BCM_XGS3_L3_DEFIP_CNT_INC(unit, TRUE);
   1165         BCM_TRX_DEFIP128_USED_COUNT(unit)++;
   1166     }
   1167 
   1168     return rv;
   1169 }
   1170 
   1171 
   1172 /*
   1173  * Function:
   1174  *      _bcm_trx_defip_128_delete
   1175  * Purpose:
   1176  *      Delete an entry from L3_DEFIP_128 table.
   1177  * Parameters:
   1178  *      unit    - (IN)SOC unit number.
   1179  *      lpm_cfg - (IN)Buffer to fill defip information. 
   1180  * Returns:
   1181  *      BCM_E_XXX
   1182  */
   1183 int 
   1184 _bcm_trx_defip_128_delete(int unit, _bcm_defip_cfg_t *lpm_cfg) 
   1185 {
   1186     uint32 hw_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.          */
   1187     bcm_ip6_t mask;                          /* Subnet mask.              */
   1188     int hw_index;                            /* Entry offset in the TCAM. */ 
   1189     int rv;                                  /* Internal operation status.*/
   1190     /* Input parameters check. */
   1191     if (NULL == lpm_cfg) {
   1192         return (BCM_E_PARAM);
   1193     }
   1194 
   1195     /* Create mask from prefix length. */
   1196     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   1197 
   1198     /* Apply mask on address. */
   1199     bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr);
   1200 
   1201     /* Search for matching entry in the cam. */
   1202     rv =  _trx_defip_128_match(unit, lpm_cfg, hw_entry, &hw_index);
   1203     if (BCM_FAILURE(rv)) {
   1204         return (rv);
   1205     }
   1206     /* Delete entry from hardware & software. */
   1207     rv = _trx_defip_128_entry_clear(unit, hw_index);
   1208     if (BCM_SUCCESS(rv)) {
   1209         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, TRUE);
   1210         BCM_TRX_DEFIP128_USED_COUNT(unit)--;
   1211     }
   1212 
   1213     return (rv);
   1214 }
   1215 
   1216 
   1217 /*
   1218  * Function:
   1219  *      _bcm_trx_defip_128_update_match
   1220  * Purpose:
   1221  *      Update/Delete all entries in defip table matching a certain rule.
   1222  * Parameters:
   1223  *      unit     - (IN)SOC unit number.
   1224  *      trv_data - (IN)Delete pattern + compare,act,notify routines.  
   1225  * Returns:
   1226  *      BCM_E_XXX
   1227  */
   1228 int
   1229 _bcm_trx_defip_128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   1230 {
   1231     int idx;                                 /* Iteration index.           */
   1232     int rv;                                  /* Operation return status.   */
   1233     int cmp_result;                          /* Test routine result.       */
   1234     int nh_ecmp_idx;                         /* Next hop/Ecmp group index. */
   1235     uint32 *hw_entry;                        /* Hw entry buffer.           */
   1236     char *lpm_tbl_ptr;                       /* Dma table pointer.         */
   1237     int defip_table_size;                    /* Defip table size.          */
   1238     _bcm_defip_cfg_t lpm_cfg;                /* Buffer to fill route info. */
   1239     soc_mem_t mem = L3_DEFIP_128m;           /* Route table memory.        */ 
   1240 
   1241     /* Table DMA the LPM table to software copy */
   1242     BCM_IF_ERROR_RETURN
   1243         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_L3_MEM_ENT_SIZE(unit, mem),
   1244                              "lpm_tbl", &lpm_tbl_ptr, &defip_table_size));
   1245 
   1246     if (SOC_URPF_STATUS_GET(unit)) {
   1247         defip_table_size >>= 1;
   1248     } 
   1249 
   1250     for (idx = 0; idx < defip_table_size; idx++) {
   1251         /* Calculate entry ofset. */
   1252         hw_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
   1253                                                 lpm_tbl_ptr, idx);
   1254 
   1255         /* Make sure entry is valid. */
   1256         if (!soc_mem_field32_get (unit, mem, hw_entry, VALID_0f)) {
   1257             continue;
   1258         }
   1259 
   1260 #ifdef BCM_TRIDENT_SUPPORT
   1261         if (SOC_IS_TRIDENT(unit)) {
   1262             uint32 hit_x, hit_y;
   1263             BCM_IF_ERROR_RETURN
   1264                 (BCM_XGS3_MEM_READ(unit, L3_DEFIP_128_HIT_ONLY_Ym, idx,
   1265                                    &hit_y));
   1266             hit_x = soc_mem_field32_get(unit, L3_DEFIP_128m, hw_entry, HITf);
   1267             hit_x |= hit_y;
   1268             soc_mem_field32_set(unit, L3_DEFIP_128m, hw_entry, HITf, hit_x);
   1269         }
   1270 #endif /* BCM_TRIDENT_SUPPORT */
   1271 
   1272         /* Zero destination buffer first. */
   1273         sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   1274 
   1275         /* Parse  the entry. */
   1276         _trx_defip_128_parse(unit, hw_entry, &lpm_cfg, &nh_ecmp_idx);
   1277         lpm_cfg.defip_index = idx;
   1278 
   1279         /* Fill entry ip address &  subnet mask. */
   1280         _trx_defip_128_get_key(unit, hw_entry, &lpm_cfg);
   1281 
   1282         /* Execute operation routine if any. */
   1283         if (trv_data->op_cb) {
   1284             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   1285                                      (void *)&lpm_cfg,
   1286                                      (void *)&nh_ecmp_idx, &cmp_result);
   1287             if (BCM_FAILURE(rv)) {
   1288                 soc_cm_sfree(unit, lpm_tbl_ptr);
   1289                 return rv;
   1290             }
   1291         }
   1292 #ifdef BCM_WARM_BOOT_SUPPORT
   1293         if (SOC_WARM_BOOT(unit)) {
   1294             rv = _trx_defip_128_reinit(unit, idx, &lpm_cfg);
   1295             if (BCM_FAILURE(rv)) {
   1296                 soc_cm_sfree(unit, lpm_tbl_ptr);
   1297                 return rv;
   1298             }
   1299         }
   1300 #endif /* BCM_WARM_BOOT_SUPPORT */
   1301     }
   1302 
   1303 #ifdef BCM_WARM_BOOT_SUPPORT
   1304     if (SOC_WARM_BOOT(unit)) {
   1305         SOC_IF_ERROR_RETURN(soc_fb_lpm_reinit_done(unit, 1));
   1306     }
   1307 #endif /* BCM_WARM_BOOT_SUPPORT */
   1308     soc_cm_sfree(unit, lpm_tbl_ptr);
   1309     return (BCM_E_NONE);
   1310 }
   1311 
   1312 /*
   1313  * Function:
   1314  *      _bcm_trx_l3_defip_mem_get
   1315  * Purpose:
   1316  *      Resolve route table memory for a given route entry.
   1317  * Parameters:
   1318  *      unit       - (IN)SOC unit number.
   1319  *      flags      - (IN)IPv6/IPv4 route.
   1320  *      plen       - (IN)Prefix length.
   1321  *      mem        - (OUT)Route table memory.
   1322  * Returns:
   1323  *      BCM_E_XXX
   1324  */
   1325 int
   1326 _bcm_trx_l3_defip_mem_get(int unit, uint32 flags, int plen, soc_mem_t *mem)
   1327 {
   1328     /* Input parameters check. */
   1329     if (NULL == mem) {
   1330         return (BCM_E_PARAM);
   1331     }
   1332 
   1333 #if defined(BCM_TRIUMPH_SUPPORT)
   1334     if (SOC_IS_TR_VL(unit)) {
   1335         BCM_IF_ERROR_RETURN
   1336             (_bcm_tr_l3_defip_mem_get(unit, flags, plen, mem));
   1337     }
   1338 #endif /* BCM_TRIUMPH_SUPPORT */
   1339 #if defined(BCM_SCORPION_SUPPORT)
   1340     if (SOC_IS_SCORPION(unit)) {
   1341         if ((flags & BCM_L3_IP6) && (plen > 64)) {
   1342             *mem = L3_DEFIP_128m;
   1343         } else {
   1344             *mem = L3_DEFIPm;
   1345         }
   1346     }
   1347 #endif /* BCM_SCORPION_SUPPORT */
   1348     return (BCM_E_NONE);
   1349 }
   1350 
   1351 #if defined(BCM_TRIUMPH_SUPPORT)
   1352 /*
   1353  * Function:
   1354  *      _bcm_trx_l3_defip_verify_internal_mem_usage
   1355  * Purpose:
   1356  *      Verify if entries are present within INT-DEFIP table
   1357  * Parameters:
   1358  *      unit  - (IN)SOC unit number.
   1359  * Returns:
   1360  *      BCM_E_XXX
   1361  */
   1362 
   1363 int
   1364 _bcm_trx_l3_defip_verify_internal_mem_usage(int unit)
   1365 {
   1366     if (soc_feature(unit, soc_feature_esm_support)) {
   1367         if (SOC_MEM_IS_VALID(unit, L3_DEFIP_128m)) {
   1368             if (soc_mem_index_count(unit, L3_DEFIP_128m)) {
   1369                 if (BCM_TRX_DEFIP128(unit) != NULL) {
   1370                     if (BCM_TRX_DEFIP128_USED_COUNT(unit)) {
   1371                         return BCM_E_DISABLED;
   1372                     }
   1373                 }
   1374             }
   1375         }
   1376     }
   1377     return BCM_E_NONE;
   1378 }
   1379 #endif
   1380 
   1381 
   1382 int
   1383 _bcm_trx_defip128_used_count_get(int unit)
   1384 {
   1385     return BCM_TRX_DEFIP128_USED_COUNT(unit);
   1386 }
   1387 
   1388 int
   1389 _bcm_trx_defip128_idx_max_get(int unit)
   1390 {
   1391     return BCM_TRX_DEFIP128_IDX_MAX(unit);
   1392 }
   1393 
   1394 int
   1395 _bcm_trx_defip128_array_idx_prefix_len_get(int unit, int arr_idx)
   1396 {
   1397     return BCM_TRX_DEFIP128_ARR(unit)[arr_idx].prefix_len;
   1398 }
   1399 
   1400 #else /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   1401 int bcm_trx_l3_not_empty;
   1402 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */