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 (23531B)


      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  * Hurricane2 LPM implementation
      8  */
      9 
     10 #include <bcm/types.h>
     11 #include <soc/hurricane2.h>
     12 #if defined(INCLUDE_L3)
     13 #include <bcm_int/esw/hurricane2.h>
     14 #include <shared/l3.h>
     15 #if defined(BCM_HURRICANE3_SUPPORT)
     16 #include <soc/hurricane3.h>
     17 #endif  /* BCM_HURRICANE3_SUPPORT */
     18 
     19 #define SOC_HU2_L3_VRF_DEFAULT   _SHR_L3_VRF_DEFAULT  /* Default vrf id.    */
     20 
     21 /*
     22  * Function:	
     23  *     _bcm_hu2_mem_ip6_defip_set
     24  * Purpose:
     25  *    Set an IP6 address field in L3_DEFIPm
     26  * Parameters: 
     27  *    unit    - (IN) SOC unit number; 
     28  *    lpm_key - (OUT) Buffer to fill. 
     29  *    lpm_cfg - (IN) Route information. 
     30  * Note:
     31  *    See soc_mem_ip6_addr_set()
     32  */
     33 STATIC void
     34 _bcm_hu2_mem_ip6_defip_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg)
     35 {
     36     uint8 *ip6;                 /* Ip6 address.       */
     37     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
     38     uint32 ip6_word;            /* Temp storage.      */
     39     int idx;                    /* Iteration index .  */
     40 
     41     /* Just to keep variable name short. */
     42     ip6 = lpm_cfg->defip_ip6_addr;
     43 
     44     /* Create mask from prefix length. */
     45     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
     46 
     47     /* Apply subnet mask */
     48     idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
     49     ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
     50     for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
     51         ip6[idx] = 0;           /* Reset rest of bytes.     */
     52     }
     53 
     54 
     55     ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
     56     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_Uf, (void *)&ip6_word);
     57 
     58     ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
     59     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_Lf, (void *)&ip6_word);
     60 
     61     ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3]));
     62     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_U_MASKf,
     63                             (void *)&ip6_word);
     64 
     65     ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7]));
     66     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_L_MASKf,
     67                             (void *)&ip6_word);
     68 }
     69 
     70 /*
     71  * Function:
     72  *     _bcm_hu2_mem_ip6_defip_get
     73  * Purpose:
     74  *    Set an IP6 address field in L3_DEFIPm
     75  * Note:
     76  *    See soc_mem_ip6_addr_set()
     77  */
     78 STATIC void
     79 _bcm_hu2_mem_ip6_defip_get(int unit, const void *lpm_key,
     80                           _bcm_defip_cfg_t *lpm_cfg)
     81 {
     82     uint8 *ip6;                 /* Ip6 address.       */
     83     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
     84     uint32 ip6_word;            /* Temp storage.      */
     85 
     86     sal_memset(mask, 0, sizeof (bcm_ip6_t));
     87 
     88     /* Just to keep variable name short. */
     89     ip6 = lpm_cfg->defip_ip6_addr;
     90     sal_memset(ip6, 0, sizeof (bcm_ip6_t));
     91 
     92     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_Uf, &ip6_word);
     93     ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
     94     ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
     95     ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
     96     ip6[3] = (uint8) (ip6_word & 0xff);
     97 
     98     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_Lf, &ip6_word);
     99     ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
    100     ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
    101     ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
    102     ip6[7] = (uint8) (ip6_word & 0xff);
    103 
    104     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_U_MASKf, &ip6_word);
    105     mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
    106     mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
    107     mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
    108     mask[3] = (uint8) (ip6_word & 0xff);
    109 
    110     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_L_MASKf, &ip6_word);
    111     mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
    112     mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
    113     mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
    114     mask[7] = (uint8) (ip6_word & 0xff);
    115 
    116     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
    117 }
    118 
    119 /*
    120  * Function:
    121  *      _bcm_hu2_lpm_clear_hit
    122  * Purpose:
    123  *      Clear prefix entry hit bit.
    124  * Parameters:
    125  *      unit      - (IN)SOC unit number.
    126  *      lpm_cfg   - (IN)Route info.  
    127  *      lpm_entry - (IN)Buffer to write to hw. 
    128  * Returns:
    129  *      BCM_E_XXX
    130  */
    131 STATIC int
    132 _bcm_hu2_lpm_clear_hit(int unit, _bcm_defip_cfg_t *lpm_cfg,
    133                       uint32 *lpm_entry)
    134 {
    135     int rv;                        /* Operation return status. */
    136     int tbl_idx;                   /* Defip table index.       */
    137     soc_field_t hit_field = HITf; /* HIT bit field id.        */
    138 
    139     /* Input parameters check */
    140     if ((NULL == lpm_cfg) || (NULL == lpm_entry)) {
    141         return (BCM_E_PARAM);
    142     }
    143 
    144     /* If entry was not hit  clear "clear hit" and return */
    145     if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) {
    146         return (BCM_E_NONE);
    147     }
    148 
    149     /* Reset entry hit bit in buffer. */
    150     tbl_idx = lpm_cfg->defip_index;
    151     soc_L3_DEFIPm_field32_set(unit, lpm_entry, hit_field, 0);
    152 
    153     /* Write lpm buffer to hardware. */
    154     rv = soc_mem_write(unit, L3_DEFIPm, MEM_BLOCK_ALL, tbl_idx, lpm_entry);
    155     return rv;
    156 }
    157 
    158 /*
    159  * Function:
    160  *      _bcm_hu2_lpm_ent_init
    161  * Purpose:
    162  *      Service routine used to initialize lkup key for lpm entry.
    163  * Parameters:
    164  *      unit      - (IN)SOC unit number.
    165  *      lpm_cfg   - (IN)Prefix info.
    166  *      lpm_entry - (OUT)Hw buffer to fill.
    167  * Returns:
    168  *      BCM_E_XXX
    169  */
    170 STATIC int
    171 _bcm_hu2_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
    172                      uint32 *lpm_entry)
    173 {
    174     bcm_ip_t ip4_mask;
    175     int vrf_id;
    176     int vrf_mask;
    177 
    178     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
    179 
    180     /* 
    181      * Extract entry  vrf id  & vrf mask. 
    182      *  - HR2/HR3/GH : vrf_id = 0 is expected (no VRF feature is supported)
    183      *    >> VRF=0 as the key for L3 host/route table hit operation.
    184      *  - GH2 : support 16 VRF_IDs
    185      *  
    186      *  Note : E_PARAM is returened once vrf_id is out of valid range.
    187      */
    188     BCM_IF_ERROR_RETURN
    189         (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask));
    190 
    191     /* Set prefix ip address & mask. */
    192     if (ipv6) {
    193         _bcm_hu2_mem_ip6_defip_set(unit, lpm_entry, lpm_cfg);
    194     } else {
    195         ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len);
    196         /* Apply subnet mask. */
    197         lpm_cfg->defip_ip_addr &= ip4_mask;
    198 
    199         /* Set address to the buffer. */
    200         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_Lf,
    201                                   lpm_cfg->defip_ip_addr);
    202         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_L_MASKf, ip4_mask);
    203         /* For IPv4 set the IP_ADDR_Uf to 0 */
    204         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_Uf, 0);
    205         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_U_MASKf, 0);
    206     }
    207 
    208     /* Set Virtual Router id if supported. */
    209     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_IDf)) {
    210         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_IDf, vrf_id);
    211         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASKf, vrf_mask);
    212     } else {
    213         if (vrf_id != BCM_L3_VRF_DEFAULT) {
    214             LOG_CLI((BSL_META_U(unit,
    215                     "LPM entry init with vrf_id=%d on device."
    216                     "(will be treated as vrf_id=0)\n"), vrf_id));
    217         }
    218     }
    219 
    220     /* Set valid bit. */
    221     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALIDf, 1);
    222     soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODEf, (ipv6) ? 1 : 0);
    223 
    224     if (soc_mem_field_valid(unit,L3_DEFIPm, MODE_MASKf)) {
    225         soc_mem_field32_set(unit,L3_DEFIPm, lpm_entry,
    226             MODE_MASKf, (1 << soc_mem_field_length(unit,
    227                         L3_DEFIPm, MODE_MASKf)) - 1);
    228     }
    229 
    230     if (soc_mem_field_valid(unit,L3_DEFIPm,
    231                             RESERVED_MASKf)) {
    232         soc_mem_field32_set(unit,L3_DEFIPm, 
    233                             lpm_entry, RESERVED_MASKf, 0);
    234     }
    235 
    236     /* 
    237      * Set the Global route :
    238      *  - Global Route is meanful on device can support VRF_ID != 0
    239      */
    240     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_IDf)) {
    241         if (SOC_MEM_FIELD_VALID(unit, 
    242                 BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) {
    243             if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
    244                 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip),
    245                                     lpm_entry, GLOBAL_ROUTE0f, 0x1);
    246             }
    247         }
    248     }
    249 
    250     return (BCM_E_NONE);
    251 }
    252 
    253 /*
    254  * Function:
    255  *      _bcm_hu2_lpm_ent_get_key
    256  * Purpose:
    257  *      Parse entry key from DEFIP table.
    258  * Parameters:
    259  *      unit        - (IN)SOC unit number.
    260  *      lpm_cfg     - (OUT)Buffer to fill defip information. 
    261  *      lpm_entry   - (IN) Buffer read from hw. 
    262  * Returns:
    263  *      void
    264  */
    265 STATIC void
    266 _bcm_hu2_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg,
    267                         uint32 *lpm_entry)
    268 {
    269     bcm_ip_t v4_mask;
    270     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
    271 
    272     /* Set prefix ip address & mask. */
    273     if (ipv6) {
    274         _bcm_hu2_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg);
    275     } else {
    276         /* Get ipv4 address. */
    277         lpm_cfg->defip_ip_addr =
    278             soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_Lf);
    279 
    280         /* Get subnet mask. */
    281         v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_L_MASKf);
    282 
    283         /* Fill mask length. */
    284         lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask);
    285     }
    286 
    287     /* Get Virtual Router id */
    288     if ((SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, VRF_ID_MASKf)) && 
    289             (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, VRF_IDf))) {
    290         int vrf_id;
    291 
    292         vrf_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry, VRF_IDf);
    293 
    294         /* Special vrf's handling. */
    295         if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VRF_ID_MASKf)) {
    296             lpm_cfg->defip_vrf = vrf_id;
    297         } else if (SOC_VRF_MAX(unit) == vrf_id) {
    298             lpm_cfg->defip_vrf = BCM_L3_VRF_GLOBAL;
    299         } else {
    300             lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE;
    301             if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) {
    302                 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, GLOBAL_ROUTE0f)) {
    303                     lpm_cfg->defip_vrf = BCM_L3_VRF_GLOBAL; 
    304                 }
    305             }
    306         }
    307     } else {
    308         /* No vrf support on this device. */
    309         lpm_cfg->defip_vrf = BCM_L3_VRF_DEFAULT;
    310     }
    311 
    312     return;
    313 }
    314 
    315 /*
    316  * Function:
    317  *      _bcm_hu2_lpm_ent_parse
    318  * Purpose:
    319  *      Parse an entry from DEFIP table.
    320  * Parameters:
    321  *      unit        - (IN)SOC unit number.
    322  *      lpm_cfg     - (OUT)Buffer to fill defip information. 
    323  *      nh_ecmp_idx - (OUT)Next hop index or ecmp group id.  
    324  *      lpm_entry   - (IN) Buffer read from hw. 
    325  * Returns:
    326  *      void
    327  */
    328 STATIC INLINE void
    329 _bcm_hu2_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx,
    330                       uint32 *lpm_entry)
    331 {
    332     /* Reset entry flags first. */
    333     lpm_cfg->defip_flags = 0;
    334 
    335     if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, MODEf)) {
    336         lpm_cfg->defip_flags |= BCM_L3_IP6;
    337     }
    338 
    339     /* Check if entry points to ecmp group. */
    340     if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f)) {
    341         /* Mark entry as ecmp */
    342         lpm_cfg->defip_ecmp = 1;
    343         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
    344 
    345         /* Get ecmp group id. */
    346         if (nh_ecmp_idx) {
    347             *nh_ecmp_idx =
    348                 soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f);
    349         }
    350     } else {
    351         /* Mark entry as non-ecmp. */
    352         lpm_cfg->defip_ecmp = 0;
    353 
    354         /* Reset ecmp group next hop count. */
    355         lpm_cfg->defip_ecmp_count = 0;
    356 
    357         /* Get next hop index. */
    358         if (nh_ecmp_idx) {
    359             *nh_ecmp_idx =
    360                 soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f);
    361         }
    362     }
    363     /* Get entry priority. */
    364     lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f);
    365 
    366     /* Get hit bit. */
    367     if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, HITf)) {
    368         lpm_cfg->defip_flags |= BCM_L3_HIT;
    369     }
    370 
    371     /* Get priority override bit. */
    372     if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE0f)) {
    373         lpm_cfg->defip_flags |= BCM_L3_RPE;
    374     }
    375 
    376     /* Get destination discard flag. */
    377     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) {
    378         if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) {
    379             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
    380         }
    381     }
    382 
    383     /* Set classification group id. */
    384     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) {
    385         lpm_cfg->defip_lookup_class = 
    386             soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f);
    387     }
    388 
    389     return;
    390 }
    391 
    392 /*
    393  * Function:
    394  *      _bcm_hu2_lpm_get
    395  * Purpose:
    396  *      Get an entry from DEFIP table.
    397  * Parameters:
    398  *      unit        - (IN)SOC unit number.
    399  *      lpm_cfg     - (IN)Buffer to fill defip information. 
    400  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
    401  * Returns:
    402  *      BCM_E_XXX
    403  */
    404 int
    405 _bcm_hu2_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
    406 {
    407     uint32 lpm_key[SOC_MAX_MEM_FIELD_WORDS];/* Route lookup key.        */
    408     uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Search result buffer.    */
    409     int clear_hit;              /* Clear hit indicator.     */
    410     int rv;                     /* Operation return status. */
    411 
    412     /* Input parameters check */
    413     if (NULL == lpm_cfg) {
    414         return (BCM_E_PARAM);
    415     }
    416 
    417     /* Zero buffers. */
    418     sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS));
    419     sal_memset(lpm_key, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS));
    420 
    421     /* Check if clear hit bit required. */
    422     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
    423 
    424     /* Initialize lkup key. */
    425     BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_key));
    426 
    427     /* Perform hw lookup. */
    428     rv = soc_hu2_lpm_match(unit, lpm_key, lpm_entry, &lpm_cfg->defip_index);
    429     BCM_IF_ERROR_RETURN(rv);
    430 
    431     /* Parse hw buffer to defip entry. */
    432     _bcm_hu2_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, lpm_entry);
    433 
    434     /* Clear the HIT bit */
    435     if (clear_hit) {
    436         BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_clear_hit(unit, lpm_cfg, lpm_entry));
    437     }
    438     return (BCM_E_NONE);
    439 }
    440 
    441 /*
    442  * Function:
    443  *      _bcm_hu2_lpm_add
    444  * Purpose:
    445  *      Add an entry to DEFIP table.
    446  * Parameters:
    447  *      unit        - (IN)SOC unit number.
    448  *      lpm_cfg     - (IN)Buffer to fill defip information. 
    449  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
    450  * Returns:
    451  *      BCM_E_XXX
    452  */
    453 int
    454 _bcm_hu2_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
    455 {
    456     uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.*/
    457     int rv;                                   /* Operation return status. */
    458     int pri_field_len;
    459     int max_pri;
    460 
    461     /* Input parameters check */
    462     if (NULL == lpm_cfg) {
    463         return (BCM_E_PARAM);
    464     }
    465 
    466     /* check if priority is over valid value */
    467     pri_field_len = soc_mem_field_length(unit, L3_DEFIPm, PRI0f);
    468     max_pri = (1 << pri_field_len) - 1;
    469     if (lpm_cfg->defip_prio > max_pri) {
    470         return BCM_E_PARAM;
    471     }
    472 
    473     /* Zero buffers. */
    474     sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS));
    475 
    476     /* Set hit bit. */
    477     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
    478         soc_L3_DEFIPm_field32_set(unit, lpm_entry, HITf, 1);
    479     }
    480 
    481     /* Set priority override bit. */
    482     if (lpm_cfg->defip_flags & BCM_L3_RPE) {
    483         soc_L3_DEFIPm_field32_set(unit, lpm_entry, RPE0f, 1);
    484     }
    485 
    486     /* Write priority field. */
    487     soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio);
    488 
    489     /* Fill next hop information. */
    490     if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
    491         soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1);
    492         /* NOTE: Order is important set next hop index before ECMP_COUNT.
    493                 * If device doesn't have ECMP_COUNT:  ECMP_PTR field is shorter than 
    494                 * next hop -> we must ensure that write resets high bits of next hop
    495                 * field.
    496                 */
    497         soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, nh_ecmp_idx);
    498         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ECMP_COUNT0f)) {
    499             soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT0f,
    500                                       lpm_cfg->defip_ecmp_count);
    501         }
    502     } else {
    503         soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f,
    504                                   nh_ecmp_idx);
    505     }
    506 
    507     /* Set destination discard flag. */
    508     if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
    509         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) {
    510             soc_L3_DEFIPm_field32_set(unit, lpm_entry, DST_DISCARD0f, 1);
    511         } else {
    512             return (BCM_E_UNAVAIL);
    513         }
    514     }
    515 
    516     /* Set classification group id. */
    517     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) {
    518         soc_L3_DEFIPm_field32_set(unit, lpm_entry, CLASS_ID0f, 
    519                                   lpm_cfg->defip_lookup_class);
    520     }
    521 
    522     /* Set Global route flag. */
    523     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) {
    524         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
    525             soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, 
    526                                 GLOBAL_ROUTE0f, 0x1);
    527         }
    528     }
    529 
    530     /* 
    531          * Initialize hw buffer from lpm configuration. 
    532          * NOTE: DON'T MOVE _bcm_hu2_defip_ent_init CALL UP, 
    533          * We want to copy flags & nh info, avoid  ipv6 mask & address corruption. 
    534          */
    535     BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_entry));
    536 
    537     /* Write buffer to hw. */
    538     rv = soc_hu2_lpm_insert(unit, lpm_entry);
    539 
    540     /* If new route added increment total number of routes.  */
    541     /* Lack of index indicates a new route. */
    542     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index)) {
    543         BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
    544     }
    545     return rv;
    546 }
    547 
    548 /*
    549  * Function:
    550  *      _bcm_hu2_lpm_del
    551  * Purpose:
    552  *      Delete an entry from DEFIP table.
    553  * Parameters:
    554  *      unit    - (IN)SOC unit number.
    555  *      lpm_cfg - (IN)Buffer to fill defip information. 
    556  * Returns:
    557  *      BCM_E_XXX
    558  */
    559 int
    560 _bcm_hu2_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
    561 {
    562     int rv;                     /* Operation return status. */
    563     uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.*/
    564 
    565     /* Input parameters check */
    566     if (NULL == lpm_cfg) {
    567         return (BCM_E_PARAM);
    568     }
    569 
    570     /* Zero buffers. */
    571     sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS));
    572 
    573     /* Initialize hw buffer deletion key. */
    574     BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_entry));
    575 
    576     /* Write buffer to hw. */
    577     rv = soc_hu2_lpm_delete(unit, lpm_entry);
    578 
    579     /* If new route added increment total number of routes.  */
    580     if (rv >= 0) {
    581         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6);
    582     }
    583     return rv;
    584 }
    585 
    586 /*
    587  * Function:
    588  *      _bcm_hu2_lpm_update_match
    589  * Purpose:
    590  *      Update/Delete all entries in defip table matching a certain rule.
    591  * Parameters:
    592  *      unit     - (IN)SOC unit number.
    593  *      trv_data - (IN)Delete pattern + compare,act,notify routines.  
    594  * Returns:
    595  *      BCM_E_XXX
    596  */
    597 int
    598 _bcm_hu2_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
    599 {
    600     uint32 ipv6;                /* Iterate over ipv6 only flag. */
    601     int idx;                    /* Iteration index.             */
    602     char *lpm_tbl_ptr;          /* Dma table pointer.           */
    603     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
    604     int cmp_result;             /* Test routine result.         */
    605     uint32 *lpm_entry;          /* Hw entry buffer.             */
    606     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
    607     int defip_table_size;       /* Defip table size.            */
    608     int rv;                     /* Operation return status.     */
    609     int idx_start = 0;
    610     int idx_end = 0;
    611     soc_mem_t mem = L3_DEFIPm;  /* Route table memory.        */ 
    612 
    613     ipv6 = (trv_data->flags & BCM_L3_IP6);
    614 
    615     /* Table DMA the LPM table to software copy */
    616     BCM_IF_ERROR_RETURN
    617         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, defip),
    618                              "lpm_tbl", &lpm_tbl_ptr, &defip_table_size));
    619 
    620     idx_start = 0;
    621     if (soc_feature(unit, soc_feature_urpf) && SOC_URPF_STATUS_GET(unit)) {
    622         /* only HR3 in HRx devices support uRPF feature
    623          *  - LPM table will be halved while uPRF enabled. And the lower 
    624          *      LPM is for DIP lookup.
    625          */
    626         idx_end = defip_table_size / 2;
    627     } else {
    628         idx_end = defip_table_size;
    629     }
    630 
    631     for (idx = idx_start; idx < idx_end; idx++) {
    632         /* Calculate entry ofset. */
    633         lpm_entry =
    634             soc_mem_table_idx_to_pointer(unit, mem, uint32 *, lpm_tbl_ptr, idx);
    635 
    636         /* Each lpm entry contains either 1 ipv4 or 1 ipv6 entry
    637                 * Make sure entry is valid. */
    638         if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALIDf)) {
    639             continue;
    640         }
    641 
    642 #if defined(BCM_HURRICANE3_SUPPORT)
    643         /* 
    644          * HR3-Lite : LPM WAR to sync-up HIT bit on correct LPM location 
    645          *  >> HIT operation for LPM-DATA entries 32~63 will occrred on 
    646          *      LPM-DATA internally. This behavior causes the HIT status
    647          *      need additional sync-up from LPM 512~543 entries.
    648  */
    649         if (soc_feature(unit, soc_feature_hr3_lite_lpm_shadow_hit) && idx >= 32) {
    650             defip_hit_only_entry_t lpm_hit_entry;
    651             uint32 real_hit = 0;
    652 
    653             BCM_IF_ERROR_RETURN(soc_mem_read(unit, 
    654                     L3_DEFIP_HIT_ONLYm, MEM_BLOCK_ANY, idx, &lpm_hit_entry));
    655             real_hit = soc_L3_DEFIP_HIT_ONLYm_field32_get(unit, 
    656                     &lpm_hit_entry, HITf);
    657             LOG_INFO(BSL_LS_SOC_LPM, (BSL_META_U(unit,
    658                     "HR3-Lite LPM_WAR :LPM entry(%d) real_hit=%d!\n"),
    659                     idx, real_hit));
    660 
    661             /* sync-up the HIT field */
    662             soc_L3_DEFIPm_field32_set(unit, lpm_entry, HITf, real_hit);
    663         }
    664 #endif
    665 
    666         /* Zero destination buffer first. */
    667         sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
    668 
    669         /* Parse  the entry. */
    670         _bcm_hu2_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry);
    671         lpm_cfg.defip_index = idx;
    672          
    673         /* If protocol doesn't match skip the entry. */
    674         if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
    675             continue;
    676         }
    677 
    678         /* Fill entry ip address &  subnet mask. */
    679         _bcm_hu2_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry);
    680 
    681         /* Execute operation routine if any. */
    682         if (trv_data->op_cb) {
    683             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
    684                                      (void *)&lpm_cfg,
    685                                      (void *)&nh_ecmp_idx, &cmp_result);
    686             if (rv < 0) {
    687                 soc_cm_sfree(unit, lpm_tbl_ptr);
    688                 return rv;
    689             }
    690         }
    691 #ifdef BCM_WARM_BOOT_SUPPORT
    692         if (SOC_WARM_BOOT(unit)) {
    693             rv = soc_hu2_lpm_reinit(unit, idx, lpm_entry);
    694             if (rv < 0) {
    695                 soc_cm_sfree(unit, lpm_tbl_ptr);
    696                 return rv;
    697             }
    698         }
    699 #endif /* BCM_WARM_BOOT_SUPPORT */
    700         
    701     }
    702 
    703 #ifdef BCM_WARM_BOOT_SUPPORT
    704     SOC_IF_ERROR_RETURN(soc_hu2_lpm_reinit_done(unit));
    705 #endif /* BCM_WARM_BOOT_SUPPORT */
    706     soc_cm_sfree(unit, lpm_tbl_ptr);
    707     return (BCM_E_NONE);
    708 }
    709 
    710 #endif /* INCLUDE_L3 */
    711