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

extender.c (24738B)


      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:    extender.c
      8  * Purpose: Implements bcm_extender_forward_* APIs for Trident2.
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 #include <soc/katana2.h>
     14 
     15 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_PE_SUPPORT)
     16 #if defined(INCLUDE_L3)
     17 
     18 #include <soc/mem.h>
     19 #include <soc/ism_hash.h>
     20 
     21 #include <bcm/error.h>
     22 
     23 #include <bcm_int/common/multicast.h>
     24 #include <bcm_int/esw/trident2.h>
     25 
     26 /*
     27  * Purpose:
     28  *	Add a downstream forwarding entry
     29  * Parameters:
     30  *	unit - (IN) Device Number
     31  *	forward_entry - (IN) Forwarding entry
     32  */
     33 int
     34 bcm_td2_extender_forward_add(int unit, bcm_extender_forward_t *forward_entry)
     35 {
     36     int rv = BCM_E_NONE;
     37     bcm_module_t mod_out;
     38     bcm_port_t port_out;
     39     bcm_trunk_t tgid_out;
     40     int id_out;
     41     l2x_entry_t l2x_entry;
     42     int lower_th, higher_th;
     43 
     44     if (forward_entry->name_space > 0xfff) {
     45         return BCM_E_PARAM;
     46     }
     47 
     48     BCM_IF_ERROR_RETURN(
     49         bcm_esw_switch_control_get(unit,
     50                                    bcmSwitchExtenderMulticastLowerThreshold,
     51                                    &lower_th));
     52     BCM_IF_ERROR_RETURN(
     53         bcm_esw_switch_control_get(unit,
     54                                    bcmSwitchExtenderMulticastHigherThreshold, 
     55                                    &higher_th));
     56 
     57     if ((forward_entry->extended_port_vid >=
     58          (1 << soc_mem_field_length(unit, L2Xm, PE_VID__ETAG_VIDf))) ||
     59         (forward_entry->class_id >=
     60          (1 << soc_mem_field_length(unit, L2Xm, PE_VID__CLASS_IDf)))) {
     61         return BCM_E_PARAM;
     62     }
     63 
     64     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
     65         if ((forward_entry->extended_port_vid >= lower_th) &&
     66             (forward_entry->extended_port_vid <= higher_th)) {
     67             return BCM_E_PARAM;
     68         }
     69 
     70         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit,
     71                     forward_entry->dest_port,
     72                     &mod_out, &port_out, &tgid_out, &id_out));
     73         if (-1 != id_out) {
     74             return BCM_E_PARAM;
     75         }
     76 
     77         sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
     78         soc_L2Xm_field32_set(unit, &l2x_entry,
     79             soc_feature(unit, soc_feature_base_valid) ? BASE_VALIDf : VALIDf, 1);
     80 #ifdef BCM_PE_SUPPORT
     81         if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
     82             soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
     83                     KT2_L2_HASH_KEY_TYPE_PE_VID);
     84         } else
     85 #endif /* BCM_PE_SUPPORT */
     86         {
     87             soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
     88                     TR_L2_HASH_KEY_TYPE_PE_VID);
     89         }
     90         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
     91                 forward_entry->name_space);
     92         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
     93                 forward_entry->extended_port_vid);
     94         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__CLASS_IDf,
     95                 forward_entry->class_id);
     96         if (-1 != tgid_out) {
     97             BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, tgid_out));
     98             if (soc_feature(unit, soc_feature_generic_dest)) {
     99                 soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
    100                     PE_VID__DESTINATIONf, SOC_MEM_FIF_DEST_LAG, tgid_out);
    101             } else {
    102                 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__DEST_TYPEf, 1);
    103                 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__TGIDf, tgid_out);
    104             }
    105         } else {
    106             if (soc_feature(unit, soc_feature_generic_dest)) {
    107                 soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
    108                     PE_VID__DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
    109                     mod_out << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | port_out);
    110             } else {
    111                 soc_L2Xm_field32_set(unit, &l2x_entry,
    112                                      PE_VID__MODULE_IDf, mod_out);
    113                 soc_L2Xm_field32_set(unit, &l2x_entry,
    114                                      PE_VID__PORT_NUMf, port_out);
    115             }
    116         }
    117         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1);
    118 
    119     } else { /* Multicast forward entry */
    120         if ((forward_entry->extended_port_vid < lower_th) ||
    121                (forward_entry->extended_port_vid > higher_th)) {
    122             return BCM_E_PARAM;
    123         }
    124         if (!_BCM_MULTICAST_IS_L2(forward_entry->dest_multicast)) {
    125             return BCM_E_PARAM;
    126         }
    127 
    128         sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
    129         soc_L2Xm_field32_set(unit, &l2x_entry,
    130             soc_feature(unit, soc_feature_base_valid) ? BASE_VALIDf : VALIDf, 1);
    131 #ifdef BCM_PE_SUPPORT
    132         if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
    133             soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    134                     KT2_L2_HASH_KEY_TYPE_PE_VID);
    135         } else
    136 #endif /* BCM_PE_SUPPORT */
    137         {
    138             soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    139                     TR_L2_HASH_KEY_TYPE_PE_VID);
    140         }
    141         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
    142                 forward_entry->name_space);
    143         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
    144                 forward_entry->extended_port_vid);
    145         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__CLASS_IDf,
    146                 forward_entry->class_id);
    147         if (soc_feature(unit, soc_feature_generic_dest)) {
    148             soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
    149                 PE_VID__DESTINATIONf, SOC_MEM_FIF_DEST_L2MC,
    150                 _BCM_MULTICAST_ID_GET(forward_entry->dest_multicast));
    151         } else {
    152             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__L2MC_PTRf,
    153                     _BCM_MULTICAST_ID_GET(forward_entry->dest_multicast));
    154         }
    155         soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1);
    156     }
    157 
    158     if (forward_entry->flags & BCM_EXTENDER_FORWARD_COPY_TO_CPU) {
    159         if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__DST_CPUf)) {
    160             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__DST_CPUf, 1);
    161         } else if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) {
    162             soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__CPUf, 1);
    163         }
    164     }
    165 
    166     soc_mem_lock(unit, L2Xm);
    167 
    168     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_REPLACE)) {
    169         l2x_entry_t  l2x_lookup;
    170         int          l2_index;
    171 
    172         /* See if the entry already exists */
    173         rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
    174                                     &l2x_lookup, &l2_index);
    175         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
    176             soc_mem_unlock(unit, L2Xm);
    177             return rv;
    178         }
    179         if (BCM_SUCCESS(rv)) {
    180             soc_mem_unlock(unit, L2Xm);
    181             return BCM_E_EXISTS;
    182         }
    183 
    184         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    185         if (SOC_FAILURE(rv)) {
    186             soc_mem_unlock(unit, L2Xm);
    187             return rv;
    188         }
    189     } else { /* Replace existing entry */
    190         rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    191         if (SOC_FAILURE(rv)) {
    192             soc_mem_unlock(unit, L2Xm);
    193             return rv;
    194         }
    195         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    196         if (SOC_FAILURE(rv)) {
    197             soc_mem_unlock(unit, L2Xm);
    198             return rv;
    199         }
    200     }
    201 
    202     soc_mem_unlock(unit, L2Xm);
    203 
    204     return rv;
    205 }
    206 
    207 /*
    208  * Purpose:
    209  *	Delete a downstream forwarding entry
    210  * Parameters:
    211  *      unit - (IN) Device Number
    212  *      forward_entry - (IN) Forwarding entry
    213  */
    214 int
    215 bcm_td2_extender_forward_delete(int unit, bcm_extender_forward_t *forward_entry)
    216 {
    217     int rv = BCM_E_NONE;
    218     l2x_entry_t l2x_entry;
    219     int lower_th, higher_th;
    220 
    221     if (forward_entry->name_space > 0xfff) {
    222         return BCM_E_PARAM;
    223     }
    224     
    225     BCM_IF_ERROR_RETURN(
    226         bcm_esw_switch_control_get(unit,
    227                                    bcmSwitchExtenderMulticastLowerThreshold,
    228                                    &lower_th));
    229     BCM_IF_ERROR_RETURN(
    230         bcm_esw_switch_control_get(unit,
    231                                    bcmSwitchExtenderMulticastHigherThreshold, 
    232                                    &higher_th));
    233     
    234     if (forward_entry->extended_port_vid >=
    235          (1 << soc_mem_field_length(unit, L2Xm, PE_VID__ETAG_VIDf))) {
    236         return BCM_E_PARAM;
    237     }
    238 
    239     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    240         if ((forward_entry->extended_port_vid >= lower_th) &&
    241             (forward_entry->extended_port_vid <= higher_th)) {
    242             return BCM_E_PARAM;
    243         }
    244     } else { /* Multicast forward entry */
    245         if ((forward_entry->extended_port_vid < lower_th) ||
    246                (forward_entry->extended_port_vid > higher_th)) {
    247             return BCM_E_PARAM;
    248         }
    249     }
    250 
    251     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
    252 #ifdef BCM_PE_SUPPORT
    253     if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
    254         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    255                 KT2_L2_HASH_KEY_TYPE_PE_VID);
    256     } else
    257 #endif /* BCM_PE_SUPPORT */
    258     {
    259         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    260                 TR_L2_HASH_KEY_TYPE_PE_VID);
    261     }
    262     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
    263             forward_entry->name_space);
    264     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
    265             forward_entry->extended_port_vid);
    266     soc_mem_lock(unit, L2Xm);
    267     rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
    268     soc_mem_unlock(unit, L2Xm);
    269 
    270     return rv;
    271 }
    272 
    273 /*
    274  * Purpose:
    275  *	Delete all downstream forwarding entries
    276  * Parameters:
    277  *	unit - Device Number
    278  */
    279 int
    280 bcm_td2_extender_forward_delete_all(int unit)
    281 {
    282     int rv = BCM_E_NONE;
    283     int field_len;
    284 
    285 #ifdef BCM_TOMAHAWK_SUPPORT
    286     if (soc_feature(unit, soc_feature_l2_bulk_unified_table)) {
    287         l2_bulk_entry_t match_mask, match_data;
    288 
    289         sal_memset(&match_mask, 0, sizeof(match_mask));
    290         sal_memset(&match_data, 0, sizeof(match_data));
    291 
    292         if (soc_feature(unit, soc_feature_base_valid)) {
    293             soc_mem_field32_set(unit, L2_BULKm, &match_mask, BASE_VALIDf, 1);
    294             soc_mem_field32_set(unit, L2_BULKm, &match_data, BASE_VALIDf, 1);
    295         } else {
    296             soc_mem_field32_set(unit, L2_BULKm, &match_mask, VALIDf, 1);
    297             soc_mem_field32_set(unit, L2_BULKm, &match_data, VALIDf, 1);
    298         }
    299 
    300         field_len = soc_mem_field_length(unit, L2_BULKm, KEY_TYPEf);
    301         soc_mem_field32_set(unit, L2_BULKm, &match_mask, KEY_TYPEf,
    302                             (1 << field_len) - 1);
    303         soc_mem_field32_set(unit, L2_BULKm, &match_data, KEY_TYPEf,
    304                             TR_L2_HASH_KEY_TYPE_PE_VID);
    305         soc_mem_lock(unit, L2Xm);
    306         rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, _BCM_L2_BULK_MATCH_MASK_INX,
    307                             &match_mask);
    308         if (BCM_SUCCESS(rv)) {
    309             rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL,
    310                                 _BCM_L2_BULK_MATCH_DATA_INX,
    311                                 &match_data);
    312         }
    313         if (BCM_SUCCESS(rv)) {
    314             rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
    315                                         NUM_ENTRIESf, 
    316                                         soc_mem_index_count(unit, L2Xm));
    317         }
    318     } else
    319 #endif /* BCM_TOMAHAWK_SUPPORT */
    320     {
    321         l2_bulk_match_mask_entry_t match_mask;
    322         l2_bulk_match_data_entry_t match_data;
    323 
    324         sal_memset(&match_mask, 0, sizeof(match_mask));
    325         sal_memset(&match_data, 0, sizeof(match_data));
    326 
    327         soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, VALIDf, 1);
    328         soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, VALIDf, 1);
    329 
    330         field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm, KEY_TYPEf);
    331         soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, KEY_TYPEf,
    332                             (1 << field_len) - 1);
    333 #ifdef BCM_PE_SUPPORT
    334         if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
    335             soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf,
    336                     KT2_L2_HASH_KEY_TYPE_PE_VID);
    337         } else
    338 #endif /* BCM_PE_SUPPORT */
    339         {
    340             soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf,
    341                     TR_L2_HASH_KEY_TYPE_PE_VID);
    342         }
    343        soc_mem_lock(unit, L2Xm);
    344         rv = WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0,
    345                                        &match_mask);
    346         if (BCM_SUCCESS(rv)) {
    347             rv = WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0,
    348                                            &match_data);
    349         }
    350     }
    351     if (BCM_SUCCESS(rv)) {
    352         rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
    353                                     ACTIONf, 1);
    354     }
    355     if (BCM_SUCCESS(rv)) {
    356         rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr);
    357     }
    358     soc_mem_unlock(unit, L2Xm);
    359     return rv;
    360 }
    361 
    362 /*
    363  * Purpose:
    364  *      Get a downstream forwarding entry
    365  * Parameters:
    366  *      unit - (IN) Device Number
    367  *      forward_entry - (IN/OUT) Forwarding entry
    368  */
    369 int
    370 bcm_td2_extender_forward_get(int unit, bcm_extender_forward_t *forward_entry)
    371 {
    372     int rv = BCM_E_NONE;
    373     l2x_entry_t l2x_entry, l2x_entry_out;
    374     int idx;
    375     _bcm_gport_dest_t dest;
    376     int l2mc_index;
    377     int lower_th, higher_th;
    378 
    379     if (forward_entry->name_space > 0xfff) {
    380         return BCM_E_PARAM;
    381     }
    382 
    383     BCM_IF_ERROR_RETURN(
    384         bcm_esw_switch_control_get(unit,
    385                                    bcmSwitchExtenderMulticastLowerThreshold,
    386                                    &lower_th));
    387     BCM_IF_ERROR_RETURN(
    388         bcm_esw_switch_control_get(unit,
    389                                    bcmSwitchExtenderMulticastHigherThreshold, 
    390                                    &higher_th));
    391    
    392     if (forward_entry->extended_port_vid >=
    393         (1 << soc_mem_field_length(unit, L2Xm, PE_VID__ETAG_VIDf))) {
    394         return BCM_E_PARAM;
    395     }
    396 
    397     if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    398         if ((forward_entry->extended_port_vid >= lower_th) &&
    399             (forward_entry->extended_port_vid <= higher_th)) {
    400             return BCM_E_PARAM;
    401         }
    402     } else { /* Multicast forward entry */
    403         if ((forward_entry->extended_port_vid < lower_th) ||
    404                (forward_entry->extended_port_vid > higher_th)) {
    405             return BCM_E_PARAM;
    406         }
    407     }
    408 
    409     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
    410 #ifdef BCM_PE_SUPPORT
    411     if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
    412         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    413                 KT2_L2_HASH_KEY_TYPE_PE_VID);
    414     } else
    415 #endif /* BCM_PE_SUPPORT */
    416     {
    417         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
    418                 TR_L2_HASH_KEY_TYPE_PE_VID);
    419     }
    420     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf,
    421             forward_entry->name_space);
    422     soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf,
    423             forward_entry->extended_port_vid);
    424     soc_mem_lock(unit, L2Xm);
    425     rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ALL, &idx, &l2x_entry,
    426             &l2x_entry_out, 0);
    427     soc_mem_unlock(unit, L2Xm);
    428 
    429     if (SOC_SUCCESS(rv)) {
    430         uint32 dv, dt = SOC_MEM_FIF_DEST_INVALID;
    431         if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) {
    432             if (soc_feature(unit, soc_feature_generic_dest)) {
    433                 dv = soc_mem_field32_dest_get(unit, L2Xm, &l2x_entry_out,
    434                                               PE_VID__DESTINATIONf, &dt);
    435                 if (dt == SOC_MEM_FIF_DEST_LAG) {
    436                     dest.tgid = dv;
    437                     dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    438                 } else {
    439                     dest.port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
    440                     dest.modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
    441                                     SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
    442                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    443                 }
    444             } else {
    445                 if (soc_L2Xm_field32_get(unit, &l2x_entry_out,
    446                             PE_VID__DEST_TYPEf)) {
    447                     dest.tgid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    448                         PE_VID__TGIDf);
    449                     dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    450                 } else {
    451                     dest.modid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    452                             PE_VID__MODULE_IDf);
    453                     dest.port = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    454                             PE_VID__PORT_NUMf);
    455                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    456                 }
    457             }
    458             BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest,
    459                         &(forward_entry->dest_port)));
    460         } else {
    461             if (soc_feature(unit, soc_feature_generic_dest)) {
    462                 dv = soc_mem_field32_dest_get(unit, L2Xm, &l2x_entry_out,
    463                                               PE_VID__DESTINATIONf, &dt);
    464                 l2mc_index = (dt == SOC_MEM_FIF_DEST_L2MC) ? dv : 0;
    465             } else {
    466                 l2mc_index = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    467                                                   PE_VID__L2MC_PTRf);
    468             }
    469             _BCM_MULTICAST_GROUP_SET(forward_entry->dest_multicast,
    470                     _BCM_MULTICAST_TYPE_L2, l2mc_index);
    471         }
    472         forward_entry->class_id = soc_L2Xm_field32_get(unit, &l2x_entry_out,
    473                                                        PE_VID__CLASS_IDf);
    474     }
    475 
    476     return rv;
    477 }
    478 
    479 /*
    480  * Purpose:
    481  *      Traverse all valid downstream forwarding entries and call the
    482  *      supplied callback routine.
    483  * Parameters:
    484  *      unit      - Device Number
    485  *      cb        - User callback function, called once per forwarding entry.
    486  *      user_data - cookie
    487  * Returns:
    488  *      BCM_E_XXX
    489  */
    490 int
    491 bcm_td2_extender_forward_traverse(int unit,
    492                              bcm_extender_forward_traverse_cb cb,
    493                              void *user_data)
    494 {
    495     int rv = BCM_E_NONE;
    496     int chunk_entries, chunk_bytes;
    497     uint8 *l2_tbl_chunk = NULL;
    498     int chunk_idx_min, chunk_idx_max;
    499     int ent_idx;
    500     l2x_entry_t *l2x_entry;
    501     bcm_extender_forward_t forward_entry;
    502     int l2mc_index;
    503     _bcm_gport_dest_t dest;
    504     int lower_th, higher_th;
    505     int key_val = 0;
    506 
    507     /* Get ETAG VID multicast range */
    508     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    509                 bcmSwitchExtenderMulticastLowerThreshold, &lower_th));
    510     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
    511                 bcmSwitchExtenderMulticastHigherThreshold, &higher_th));
    512 
    513     chunk_entries = soc_property_get(unit, spn_L2DELETE_CHUNKS,
    514                                  L2_MEM_CHUNKS_DEFAULT);
    515     chunk_bytes = 4 * SOC_MEM_WORDS(unit, L2Xm) * chunk_entries;
    516     l2_tbl_chunk = soc_cm_salloc(unit, chunk_bytes, "extender forward traverse");
    517     if (NULL == l2_tbl_chunk) {
    518         return BCM_E_MEMORY;
    519     }
    520     for (chunk_idx_min = soc_mem_index_min(unit, L2Xm); 
    521          chunk_idx_min <= soc_mem_index_max(unit, L2Xm); 
    522          chunk_idx_min += chunk_entries) {
    523 
    524         /* Read a chunk of L2 table */
    525         sal_memset(l2_tbl_chunk, 0, chunk_bytes);
    526         chunk_idx_max = chunk_idx_min + chunk_entries - 1;
    527         if (chunk_idx_max > soc_mem_index_max(unit, L2Xm)) {
    528             chunk_idx_max = soc_mem_index_max(unit, L2Xm);
    529         }
    530         rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
    531                                 chunk_idx_min, chunk_idx_max, l2_tbl_chunk);
    532         if (SOC_FAILURE(rv)) {
    533             break;
    534         }
    535         for (ent_idx = 0;
    536              ent_idx <= (chunk_idx_max - chunk_idx_min);
    537              ent_idx++) {
    538             uint32 dv, dt = SOC_MEM_FIF_DEST_INVALID;
    539             l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, l2x_entry_t *,
    540                                              l2_tbl_chunk, ent_idx);
    541             if (soc_L2Xm_field32_get(unit, l2x_entry,
    542                                      soc_feature(unit, soc_feature_base_valid) ?
    543                                      BASE_VALIDf :
    544                                      VALIDf) == 0) {
    545                 continue;
    546             }
    547 #ifdef BCM_PE_SUPPORT
    548             if (soc_feature(unit, soc_feature_port_extension_kt2_key_type)) {
    549                 key_val = (int)KT2_L2_HASH_KEY_TYPE_PE_VID;
    550             } else
    551 #endif /* BCM_PE_SUPPORT */
    552             {
    553                 key_val = (int)TR_L2_HASH_KEY_TYPE_PE_VID;
    554             }
    555             if (soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf) != key_val) {
    556                 continue;
    557             }
    558 
    559             /* Get fields of forwarding entry */
    560             bcm_extender_forward_t_init(&forward_entry);
    561             forward_entry.name_space = soc_L2Xm_field32_get(unit, l2x_entry,
    562                     PE_VID__NAMESPACEf);
    563             forward_entry.extended_port_vid = soc_L2Xm_field32_get(unit,
    564                     l2x_entry, PE_VID__ETAG_VIDf);
    565             forward_entry.class_id = soc_L2Xm_field32_get(unit,
    566                     l2x_entry, PE_VID__CLASS_IDf);
    567             if ((forward_entry.extended_port_vid >= lower_th) &&
    568                 (forward_entry.extended_port_vid <= higher_th)) {
    569                 /* Multicast forward entry */
    570                 forward_entry.flags |= BCM_EXTENDER_FORWARD_MULTICAST;
    571                 if (soc_feature(unit, soc_feature_generic_dest)) {
    572                     dv = soc_mem_field32_dest_get(unit, L2Xm, l2x_entry,
    573                                                   PE_VID__DESTINATIONf, &dt);
    574                     l2mc_index = (dt == SOC_MEM_FIF_DEST_L2MC) ? dv : 0;
    575                 } else {
    576                     l2mc_index = soc_L2Xm_field32_get(unit, l2x_entry,
    577                                                       PE_VID__L2MC_PTRf);
    578                 }
    579                 _BCM_MULTICAST_GROUP_SET(forward_entry.dest_multicast,
    580                         _BCM_MULTICAST_TYPE_L2, l2mc_index);
    581             } else {
    582                 if (soc_feature(unit, soc_feature_generic_dest)) {
    583                     dv = soc_mem_field32_dest_get(unit, L2Xm, l2x_entry,
    584                                                   PE_VID__DESTINATIONf, &dt);
    585                     if (dt == SOC_MEM_FIF_DEST_LAG) {
    586                         dest.tgid = dv;
    587                         dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    588                     } else {
    589                         dest.port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
    590                         dest.modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
    591                                         SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
    592                         dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    593                     }
    594                 } else {
    595                     if (soc_L2Xm_field32_get(unit, l2x_entry,
    596                                 PE_VID__DEST_TYPEf)) {
    597                         dest.tgid = soc_L2Xm_field32_get(unit, l2x_entry,
    598                                 PE_VID__TGIDf);
    599                         dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
    600                     } else {
    601                         dest.modid = soc_L2Xm_field32_get(unit, l2x_entry,
    602                                 PE_VID__MODULE_IDf);
    603                         dest.port = soc_L2Xm_field32_get(unit, l2x_entry,
    604                                 PE_VID__PORT_NUMf);
    605                         dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
    606                     }
    607                 }
    608                 rv = _bcm_esw_gport_construct(unit, &dest,
    609                         &(forward_entry.dest_port));
    610                 if (BCM_FAILURE(rv)) {
    611                     break;
    612                 }
    613             }
    614 
    615             if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__DST_CPUf)) {
    616                 if (soc_L2Xm_field32_get(unit, l2x_entry,
    617                             PE_VID__DST_CPUf)) {
    618                     forward_entry.flags |= BCM_EXTENDER_FORWARD_COPY_TO_CPU;
    619                 }
    620             } else if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) {
    621                 if (soc_L2Xm_field32_get(unit, l2x_entry,
    622                             PE_VID__CPUf)) {
    623                     forward_entry.flags |= BCM_EXTENDER_FORWARD_COPY_TO_CPU;
    624                 }
    625             }
    626 
    627             rv = cb(unit, &forward_entry, user_data);
    628             if (BCM_FAILURE(rv)) {
    629                 break;
    630             }
    631         }
    632         if (BCM_FAILURE(rv)) {
    633             break;
    634         }
    635     }
    636     soc_cm_sfree(unit, l2_tbl_chunk);
    637 
    638     return rv;
    639 }
    640 #endif
    641 #endif /* BCM_TRIDENT2_SUPPORT || BCM_PE_SUPPORT && INCLUDE_L3 */