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

l2cache.c (23267B)


      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  * L2 Cache - Layer 2 BPDU and overflow address cache
      8  */
      9 
     10 #include <sal/core/libc.h>
     11 
     12 #include <soc/mem.h>
     13 #include <soc/debug.h>
     14 #include <soc/drv.h>
     15 #include <soc/l2u.h>
     16 
     17 #include <bcm/l2.h>
     18 #include <bcm/error.h>
     19 #include <bcm_int/common/multicast.h>
     20 
     21 #include <bcm_int/esw/port.h>
     22 #include <bcm_int/esw/trunk.h>
     23 #include <bcm_int/esw/vlan.h>
     24 #include <bcm_int/esw/vpn.h>
     25 #include <bcm_int/esw/virtual.h>
     26 #include <bcm_int/esw/l2.h>
     27 #include <bcm_int/esw/stack.h>
     28 #ifdef BCM_TRIDENT_SUPPORT
     29 #include <bcm_int/esw/trident.h>
     30 #endif
     31 #if defined(BCM_TRIUMPH3_SUPPORT)
     32 #include <bcm_int/esw/triumph3.h>
     33 #endif /* BCM_TRIUMPH3_SUPPORT */
     34 
     35 #include <bcm_int/esw_dispatch.h>
     36 #if defined(BCM_TOMAHAWK3_SUPPORT)
     37 #include <include/bcm_int/esw/tomahawk3.h>
     38 #ifdef BCM_XGS3_SWITCH_SUPPORT
     39 
     40 /*
     41  * Function:
     42  *      _bcm_th3_cache_gport_resolve
     43  * Purpose:
     44  *      Convert destination in a GPORT format to modid port pair or trunk id
     45  * Parameters:
     46  *      unit - Unit number
     47  *      l2caddr - (IN/OUT) Hardware-independent L2 entry
     48  * Returns:
     49  *      BCM_E_XXX
     50  */
     51 STATIC int 
     52 _bcm_th3_cache_gport_resolve(int unit, bcm_l2_cache_addr_t *l2caddr)
     53 {
     54     bcm_port_t      port;
     55     bcm_module_t    modid;
     56     bcm_trunk_t     tgid;
     57     int             id;
     58 
     59 
     60     if (BCM_GPORT_IS_SET(l2caddr->dest_port)) {
     61         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, l2caddr->dest_port, 
     62                                                    &modid, &port, &tgid, &id));
     63 
     64         if (-1 != id) {
     65             return (BCM_E_UNAVAIL);
     66         }
     67 
     68         /* Trunk GPORT */
     69         if (BCM_TRUNK_INVALID != tgid) {
     70             l2caddr->flags |= BCM_L2_CACHE_TRUNK;
     71             l2caddr->dest_trunk = tgid;
     72         } else {    /* MODPORT GPORT */
     73             l2caddr->dest_port = port;
     74             l2caddr->dest_modid = modid; /* This may be set to 0 - check */
     75         }
     76     }
     77     if (BCM_GPORT_IS_SET(l2caddr->src_port)) {
     78         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, l2caddr->src_port, 
     79                                                    &port));
     80         l2caddr->src_port = port;
     81     }
     82 
     83     return BCM_E_NONE;
     84 }
     85 
     86 /*
     87  * Function:
     88  *      _bcm_th3_cache_gport_construct
     89  * Purpose:
     90  *      Constract a GPORT destination format from modid port pair or trunk id
     91  * Parameters:
     92  *      unit - Unit number
     93  *      l2caddr - (IN/OUT) Hardware-independent L2 entry
     94  * Returns:
     95  *      BCM_E_XXX
     96  */
     97 STATIC int 
     98 _bcm_th3_cache_gport_construct(int unit, bcm_l2_cache_addr_t *l2caddr)
     99 {
    100     bcm_gport_t         gport;
    101     _bcm_gport_dest_t   gport_dst;
    102 
    103      _bcm_gport_dest_t_init(&gport_dst);
    104 
    105      if (l2caddr->flags & BCM_L2_CACHE_TRUNK) {
    106          gport_dst.gport_type = BCM_GPORT_TYPE_TRUNK;
    107          gport_dst.tgid = l2caddr->dest_trunk;
    108      } else {
    109          gport_dst.gport_type = BCM_GPORT_TYPE_MODPORT;
    110          gport_dst.modid = l2caddr->dest_modid;
    111          gport_dst.port = l2caddr->dest_port;
    112      }
    113 
    114     
    115     BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &gport_dst, &gport));
    116 
    117     l2caddr->dest_port = gport;
    118 
    119     gport_dst.gport_type = BCM_GPORT_TYPE_MODPORT;
    120     gport_dst.port = l2caddr->src_port;
    121     gport_dst.modid = SOC_BASE_MODID(unit);
    122     if (gport_dst.modid < 0) {
    123         return BCM_E_UNAVAIL;
    124     }
    125 
    126     
    127     BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &gport_dst, &gport));
    128 
    129     l2caddr->src_port = gport;
    130 
    131     return BCM_E_NONE;
    132 }
    133 
    134 /*
    135  * Function:
    136  *      _bcm_th3_l2_cache_from_l2u
    137  * Purpose:
    138  *      Convert L2 User table entry to a hardware-independent L2 cache entry.
    139  * Parameters:
    140  *      unit - Unit number
    141  *      l2caddr - (OUT) Hardware-independent L2 entry
    142  *      l2u_entry - Firebolt L2 User entry
    143  * Returns:
    144  *      BCM_E_XXX
    145  */
    146 STATIC int
    147 _bcm_th3_l2_cache_from_l2u(int unit, 
    148                        bcm_l2_cache_addr_t *l2caddr, l2u_entry_t *l2u_entry)
    149 {
    150     l2u_entry_t     l2u_mask_entry;
    151     bcm_module_t    mod_in = 0;
    152     bcm_port_t      port_in = 0, port_out;
    153     uint32          mask[SOC_MAX_MEM_WORDS];
    154     int             skip_l2u, isGport, port_field_len, rval;
    155     bcm_vlan_t      vlan;
    156     soc_field_t     port_field = 0;
    157 
    158     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    159 
    160     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    161 
    162         if (!_l2u_field32_get(unit, l2u_entry, VALIDf)) {
    163             return BCM_E_NOT_FOUND;
    164         }
    165 
    166         sal_memset(l2caddr, 0, sizeof (*l2caddr));
    167         sal_memset(&l2u_mask_entry, 0, sizeof (l2u_mask_entry));
    168 
    169         _l2u_field_get(unit, l2u_entry, MASKf, mask);
    170         _l2u_field_set(unit, &l2u_mask_entry, KEYf, mask);
    171 
    172         _l2u_mac_addr_get(unit, l2u_entry, MAC_ADDRf, l2caddr->mac);
    173         _l2u_mac_addr_get(unit, &l2u_mask_entry, MAC_ADDRf, l2caddr->mac_mask);
    174 
    175         vlan = _l2u_field32_get(unit, l2u_entry, VLAN_IDf);
    176         l2caddr->vlan_mask = _l2u_field32_get(unit, &l2u_mask_entry, VLAN_IDf);
    177 
    178 #if defined(INCLUDE_L3)
    179         _l2u_field32_get(unit, l2u_entry, KEY_TYPEf);
    180 #endif
    181 
    182         l2caddr->vlan = vlan;
    183 
    184         l2caddr->prio = _l2u_field32_get(unit, l2u_entry, PRIf);
    185 
    186         if (_l2u_field32_get(unit, l2u_entry, RPEf)) {
    187             l2caddr->flags |= BCM_L2_CACHE_SETPRI;
    188         }
    189 
    190         if (_l2u_field32_get(unit, l2u_entry, DO_NOT_LEARN_MACSAf)) {
    191             l2caddr->flags |= BCM_L2_CACHE_LEARN_DISABLE;
    192         }
    193 
    194         if (_l2u_field32_get(unit, l2u_entry, CPUf)) {
    195             l2caddr->flags |= BCM_L2_CACHE_CPU;
    196         }
    197 
    198         if (_l2u_field32_get(unit, l2u_entry, BPDUf)) {
    199             l2caddr->flags |= BCM_L2_CACHE_BPDU;
    200         }
    201 
    202         if (_l2u_field32_get(unit, l2u_entry, L2_PROTOCOL_PKTf)) {
    203             l2caddr->flags |= BCM_L2_CACHE_PROTO_PKT;
    204         }
    205 
    206         if (_l2u_field32_get(unit, l2u_entry, DST_DISCARDf)) {
    207             l2caddr->flags |= BCM_L2_CACHE_DISCARD;
    208         }
    209 
    210         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    211             if (_l2u_field32_get(unit, l2u_entry, Tf)) {
    212                 l2caddr->flags |= BCM_L2_CACHE_TRUNK;
    213                 l2caddr->dest_trunk = _l2u_field32_get(unit, l2u_entry, TGIDf);
    214             } else {
    215                 mod_in = 0;
    216                 port_in = _l2u_field32_get(unit, l2u_entry, PORT_NUMf);
    217                 port_field = PORT_NUMf;
    218             }
    219         }
    220 
    221         
    222         if (BCM_MAC_IS_MCAST(l2caddr->mac)) {
    223             l2caddr->flags |= BCM_L2_CACHE_MULTICAST;
    224             l2caddr->dest_modid = mod_in;
    225             l2caddr->dest_port = port_in;
    226             port_field_len = soc_mem_field_length(unit, L2_USER_ENTRYm,
    227                                                   port_field);
    228 
    229             /* If MACDA is MC, HW interprets value encoded in MODULE_IDf
    230                and PORT_FIELD as L2MC_INDEX */
    231             l2caddr->group = (port_in & ((1 << port_field_len) - 1));
    232             /* Translate l2mc index */
    233             BCM_IF_ERROR_RETURN(
    234                 bcm_esw_switch_control_get(unit, bcmSwitchL2McIdxRetType,
    235                                            &rval));
    236             if (rval) {
    237                 _BCM_MULTICAST_GROUP_SET(l2caddr->group, _BCM_MULTICAST_TYPE_L2,
    238                                          l2caddr->group);
    239             }
    240         }
    241 
    242         if (!((l2caddr->flags & BCM_L2_CACHE_TRUNK) ||
    243             (l2caddr->flags & BCM_L2_CACHE_MULTICAST))) {
    244             port_out = port_in;
    245             l2caddr->dest_modid = 0;
    246             l2caddr->dest_port = port_out;
    247         }
    248         BCM_IF_ERROR_RETURN(
    249             bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport));
    250 
    251         if (isGport) {
    252             BCM_IF_ERROR_RETURN(_bcm_th3_cache_gport_construct(unit, l2caddr));
    253         }
    254 
    255         l2caddr->lookup_class = _l2u_field32_get(unit, l2u_entry, CLASS_IDf);
    256 
    257         return BCM_E_NONE;
    258     }
    259 
    260     return BCM_E_UNAVAIL;
    261 }
    262 
    263 /*
    264  * Function:
    265  *      _bcm_th3_l2_cache_to_l2u
    266  * Purpose:
    267  *      Convert a hardware-independent L2 cache entry to a L2 User table entry.
    268  * Parameters:
    269  *      unit - Unit number
    270  *      l2u_entry - (OUT) Firebolt L2 User entry
    271  *      l2caddr - Hardware-independent L2 entry
    272  * Returns:
    273  *      BCM_E_XXX
    274  * Note:
    275  * BCM_L2_CACHE_L3, BCM_L2_CACHE_MIRROR are not supported
    276  */
    277 STATIC int
    278 _bcm_th3_l2_cache_to_l2u(int unit, 
    279                          l2u_entry_t *l2u_entry, bcm_l2_cache_addr_t *l2caddr)
    280 {
    281     l2u_entry_t     l2u_mask_entry;
    282     bcm_module_t    mod_in;
    283     bcm_port_t      port_in, port_out;
    284     uint32          mask[SOC_MAX_MEM_WORDS];
    285     soc_field_t     port_field = 0;
    286     int             skip_l2u, isGport;
    287     bcm_vlan_t      vlan;
    288     int             port_field_len;
    289 
    290     int valid_bit = 0;
    291     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    292     
    293     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    294 
    295         if (l2caddr->flags & BCM_L2_CACHE_SETPRI) {
    296             if (l2caddr->prio < 0 || l2caddr->prio > 15) {
    297                 return BCM_E_PARAM;
    298             }
    299         }
    300 
    301         if (BCM_GPORT_IS_SET(l2caddr->dest_port) ||
    302             BCM_GPORT_IS_SET(l2caddr->src_port)) {
    303             BCM_IF_ERROR_RETURN(_bcm_th3_cache_gport_resolve(unit, l2caddr));
    304             isGport = 1;
    305         } else {
    306             isGport = 0;
    307         }
    308 
    309         sal_memset(l2u_entry, 0, sizeof (*l2u_entry));
    310         sal_memset(&l2u_mask_entry, 0, sizeof (l2u_mask_entry));
    311 
    312         valid_bit = 1 <<  soc_mem_field_length(unit, L2_USER_ENTRYm, VALIDf);
    313         valid_bit -= 1;
    314         _l2u_field32_set(unit, l2u_entry, VALIDf, valid_bit);
    315 
    316         vlan = l2caddr->vlan;
    317 
    318         _l2u_field32_set(unit, l2u_entry, KEY_TYPEf, 0);
    319         _l2u_field32_set(unit, &l2u_mask_entry, KEY_TYPEf, 0);
    320 
    321         if (l2caddr->flags & BCM_L2_CACHE_PROTO_PKT) {
    322             _l2u_field32_set(unit, l2u_entry, L2_PROTOCOL_PKTf, 1);
    323         }
    324 
    325         _l2u_field32_set(unit, l2u_entry, VLAN_IDf, vlan);
    326         _l2u_field32_set(unit, &l2u_mask_entry, VLAN_IDf, l2caddr->vlan_mask);
    327 
    328         _l2u_mac_addr_set(unit, l2u_entry, MAC_ADDRf, l2caddr->mac);
    329         _l2u_mac_addr_set(unit, &l2u_mask_entry, MAC_ADDRf, l2caddr->mac_mask);
    330 
    331         _l2u_field_get(unit, &l2u_mask_entry, KEYf, mask);
    332 
    333         _l2u_field_set(unit, l2u_entry, MASKf, mask);
    334 
    335         if (l2caddr->flags & BCM_L2_CACHE_SETPRI) {
    336             _l2u_field32_set(unit, l2u_entry, PRIf, l2caddr->prio);
    337             _l2u_field32_set(unit, l2u_entry, RPEf, 1);
    338         }
    339 
    340         if (l2caddr->flags & BCM_L2_CACHE_LEARN_DISABLE) {
    341             _l2u_field32_set(unit, l2u_entry, DO_NOT_LEARN_MACSAf, 1);
    342         }
    343 
    344         if (l2caddr->flags & BCM_L2_CACHE_CPU) {
    345             _l2u_field32_set(unit, l2u_entry, CPUf, 1);
    346         }
    347 
    348         if (l2caddr->flags & BCM_L2_CACHE_BPDU) {
    349             _l2u_field32_set(unit, l2u_entry, BPDUf, 1);
    350         }
    351 
    352         if (l2caddr->flags & BCM_L2_CACHE_DISCARD) {
    353             _l2u_field32_set(unit, l2u_entry, DST_DISCARDf, 1);
    354         }
    355 
    356         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    357             if (l2caddr->flags & BCM_L2_CACHE_TRUNK) {
    358                 _l2u_field32_set(unit, l2u_entry, Tf, 1);
    359                 _l2u_field32_set(unit, l2u_entry, TGIDf, l2caddr->dest_trunk);
    360             } else {
    361                 port_field = PORT_NUMf;
    362             }
    363         }
    364 
    365         if (!((l2caddr->flags & BCM_L2_CACHE_TRUNK) ||
    366             (l2caddr->flags & BCM_L2_CACHE_MULTICAST))) {
    367             mod_in = l2caddr->dest_modid;
    368             port_in = l2caddr->dest_port;
    369             if (!isGport) {
    370                 PORT_DUALMODID_VALID(unit, port_in);
    371             }
    372 
    373             if (!SOC_MODID_ADDRESSABLE(unit, mod_in)) {
    374                 return BCM_E_BADID;
    375             }
    376 
    377             if (!SOC_PORT_ADDRESSABLE(unit, port_in)) {
    378                 return BCM_E_PORT;
    379             }
    380 
    381             port_out = port_in;
    382 
    383             _l2u_field32_set(unit, l2u_entry, port_field, port_out);
    384         }
    385 
    386         
    387         if (l2caddr->flags & BCM_L2_CACHE_MULTICAST) {
    388             if (_BCM_MULTICAST_IS_SET(l2caddr->group)) {
    389                 if (_BCM_MULTICAST_IS_L2(l2caddr->group)) {
    390                     port_field_len = soc_mem_field_length(unit, L2_USER_ENTRYm,
    391                                                           port_field);
    392                     /* If MACDA is MC, HW interprets value encoded in 
    393                      * PORT_FIELD as L2MC_INDEX
    394                      */
    395                     _l2u_field32_set(unit, l2u_entry, port_field,
    396                                      (_BCM_MULTICAST_ID_GET(l2caddr->group) &
    397                                      ((1 << port_field_len) - 1)));
    398                 } else {
    399                     return BCM_E_PARAM;
    400                 }
    401             }
    402         }
    403 
    404         _l2u_field32_set(unit, l2u_entry, CLASS_IDf, l2caddr->lookup_class);
    405 
    406         return BCM_E_NONE;
    407     }
    408 
    409     return BCM_E_UNAVAIL;
    410 }
    411 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    412 
    413 /*
    414  * Function:
    415  *      bcm_th3_l2_cache_init
    416  * Purpose:
    417  *      Initialize the L2 cache
    418  * Parameters:
    419  *      unit - device number
    420  * Returns:
    421  *      BCM_E_XXX
    422  * Notes:
    423  *      Clears all entries and preloads a few BCM_L2_CACHE_BPDU
    424  *      entries to match previous generation of devices.
    425  */
    426 int
    427 bcm_th3_l2_cache_init(int unit)
    428 {
    429 #ifdef BCM_XGS3_SWITCH_SUPPORT
    430     int     skip_l2u;
    431 
    432     if (!SOC_UNIT_VALID(unit)) {
    433         return BCM_E_UNIT;
    434     }
    435 
    436     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    437 
    438     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    439         bcm_l2_cache_addr_t addr;
    440         l2u_entry_t entry;
    441         int index;
    442 
    443         if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) {
    444             SOC_IF_ERROR_RETURN
    445                 (soc_mem_clear(unit, L2_USER_ENTRYm, COPYNO_ALL, TRUE));
    446         }
    447 
    448         bcm_l2_cache_addr_t_init(&addr);
    449         addr.flags = BCM_L2_CACHE_CPU | BCM_L2_CACHE_BPDU;
    450         /* Set default BPDU addresses (01:80:c2:00:00:00) */
    451         ENET_SET_MACADDR(addr.mac, _soc_mac_spanning_tree);
    452         ENET_SET_MACADDR(addr.mac_mask, _soc_mac_all_ones);
    453         addr.dest_modid = 0;
    454         addr.dest_port = CMIC_PORT(unit);
    455         BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_to_l2u(unit, &entry, &addr));
    456         SOC_IF_ERROR_RETURN(soc_l2u_insert(unit, &entry, -1, &index));
    457 
    458         soc_mem_field32_set(unit, L2_USER_ENTRYm, &entry, L2_PROTOCOL_PKTf, 1);
    459         soc_mem_field32_set(unit, L2_USER_ENTRYm, &entry, KEY_TYPEf, 0);
    460         SOC_IF_ERROR_RETURN(soc_l2u_insert(unit, &entry, -1, &index));
    461 
    462         if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) {
    463             /* Set 01:80:c2:00:00:10 */
    464             addr.mac[5] = 0x10;
    465             BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_to_l2u(unit, &entry, &addr));
    466             SOC_IF_ERROR_RETURN(soc_l2u_insert(unit, &entry, -1, &index));
    467             /* Set 01:80:c2:00:00:0x */
    468             addr.mac[5] = 0x00;
    469             addr.mac_mask[5] = 0xf0;
    470             BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_to_l2u(unit, &entry, &addr));
    471             SOC_IF_ERROR_RETURN(soc_l2u_insert(unit, &entry, -1, &index));
    472             /* Set 01:80:c2:00:00:2x */
    473             addr.mac[5] = 0x20;
    474             BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_to_l2u(unit, &entry, &addr));
    475             SOC_IF_ERROR_RETURN(soc_l2u_insert(unit, &entry, -1, &index));
    476         }
    477 
    478         return BCM_E_NONE;
    479     }
    480 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    481     return BCM_E_UNAVAIL;
    482 }
    483 
    484 /*
    485  * Function:
    486  *      bcm_tomahawk3_l2_cache_set
    487  * Purpose:
    488  *      Set an L2 cache entry
    489  * Parameters:
    490  *      unit - device number
    491  *      index - l2 cache entry number (or -1)
    492  *              If -1 is given then the entry used will be the first
    493  *              available entry if the l2 cache address mac_mask
    494  *              field is all ones, or the last available entry if
    495  *              the mac_mask field has some zeros.  Cache entries
    496  *              are matched from lowest entry to highest entry.
    497  *      addr - l2 cache address
    498  *      index_used - (OUT) l2 cache entry number actually used
    499  * Returns:
    500  *      BCM_E_XXX
    501  */
    502 int
    503 bcm_tomahawk3_l2_cache_set(int unit, int index, bcm_l2_cache_addr_t *addr,
    504                            int *index_used)
    505 {
    506 #ifdef BCM_XGS3_SWITCH_SUPPORT
    507     int skip_l2u;
    508     l2u_entry_t l2u_entry;
    509     bcm_l2_cache_addr_t l2_addr;
    510 
    511     if (!SOC_UNIT_VALID(unit)) {
    512         return BCM_E_UNIT;
    513     }
    514 
    515     TH3_L2_INIT(unit);
    516 
    517     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    518 
    519     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    520         if (index < -1 || index > soc_mem_index_max(unit, L2_USER_ENTRYm)) {
    521             return BCM_E_PARAM;
    522         }
    523 
    524         sal_memcpy(&l2_addr, addr, sizeof(bcm_l2_cache_addr_t));
    525 
    526         if (soc_feature(unit, soc_feature_overlaid_address_class)) {
    527             if ((l2_addr.lookup_class > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
    528                 (l2_addr.lookup_class < 0)) {
    529                 return (BCM_E_PARAM);
    530             }
    531         } else if ((l2_addr.lookup_class > SOC_ADDR_CLASS_MAX(unit)) || 
    532                    (l2_addr.lookup_class < 0)) {
    533             return (BCM_E_PARAM);
    534         }
    535 
    536         /* ESW architecture can't support multiple destinations */
    537         if (BCM_PBMP_NOT_NULL(l2_addr.dest_ports)) {
    538             return BCM_E_PARAM;
    539         }
    540 
    541         BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_to_l2u(unit, &l2u_entry,
    542                                                      &l2_addr));
    543         
    544 #if defined(BCM_TRIDENT_SUPPORT)
    545         if (addr->flags & BCM_L2_CACHE_L3) {
    546             int rv;
    547             if (index == -1) {
    548                 rv = bcm_td_l2cache_myStation_lookup(unit, &l2_addr, &index);
    549                 if (BCM_FAILURE(rv)) {
    550                     /* Find the first free index in L2_USER_ENTRY */
    551                     BCM_IF_ERROR_RETURN
    552                         (soc_l2u_find_free_entry(unit, &l2u_entry, &index));
    553                 }
    554             }
    555 
    556             rv = bcm_td_l2cache_myStation_set(unit, index, &l2_addr);
    557         }
    558 #endif /* BCM_TRIDENT_SUPPORT*/
    559 
    560         SOC_IF_ERROR_RETURN
    561             (soc_l2u_insert(unit, &l2u_entry, index, index_used));
    562 
    563         return BCM_E_NONE;
    564     }
    565 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    566     return BCM_E_UNAVAIL;
    567 }
    568 
    569 /*
    570  * Function:
    571  *      bcm_tomahawk3_l2_cache_get
    572  * Purpose:
    573  *      Get an L2 cache entry
    574  * Parameters:
    575  *      unit - device number
    576  *      index - l2 cache entry index
    577  *      size - (OUT) l2 cache address
    578  * Returns:
    579  *      BCM_E_XXX
    580  */
    581 int
    582 bcm_tomahawk3_l2_cache_get(int unit, int index, bcm_l2_cache_addr_t *addr)
    583 {
    584 #ifdef BCM_XGS3_SWITCH_SUPPORT
    585     int skip_l2u;
    586     l2u_entry_t l2u_entry;
    587 
    588     if (!SOC_UNIT_VALID(unit)) {
    589         return BCM_E_UNIT;
    590     }
    591 
    592     TH3_L2_INIT(unit)
    593 
    594     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    595 
    596     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    597         if (index < 0 || index > soc_mem_index_max(unit, L2_USER_ENTRYm)) {
    598             return BCM_E_PARAM;
    599         }
    600 
    601         SOC_IF_ERROR_RETURN(soc_l2u_get(unit, &l2u_entry, index));
    602 
    603         BCM_IF_ERROR_RETURN(_bcm_th3_l2_cache_from_l2u(unit, addr, &l2u_entry));
    604 
    605 #if defined(BCM_TRIDENT_SUPPORT)
    606         if (addr->flags & BCM_L2_CACHE_L3) {
    607             BCM_IF_ERROR_RETURN(bcm_td_l2cache_myStation_get(unit, index,
    608                                                              addr));
    609         }
    610 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
    611 
    612         return BCM_E_NONE;
    613     }
    614 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    615     return BCM_E_UNAVAIL;
    616 }
    617 
    618 /*
    619  * Function:
    620  *      bcm_tomahawk3_l2_cache_size_get
    621  * Purpose:
    622  *      Get number of L2 cache entries
    623  * Parameters:
    624  *      unit - device number
    625  *      size - (OUT) number of entries in cache
    626  * Returns:
    627  *      BCM_E_XXX
    628  */
    629 int
    630 bcm_tomahawk3_l2_cache_size_get(int unit, int *size)
    631 {
    632 #ifdef BCM_XGS3_SWITCH_SUPPORT
    633     int skip_l2u;
    634 
    635     if (!SOC_UNIT_VALID(unit)) {
    636         return BCM_E_UNIT;
    637     }
    638 
    639     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    640 
    641     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    642         *size = soc_mem_index_count(unit, L2_USER_ENTRYm);
    643 
    644         return 0;
    645     }
    646 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    647     return BCM_E_UNAVAIL;
    648 }
    649 
    650 int
    651 bcm_tomahawk3_l2_cache_init(int unit)
    652 {
    653     return bcm_th3_l2_cache_init(unit);
    654 }
    655 
    656 /*
    657  * Function:
    658  *      bcm_tomahawk3_l2_cache_delete
    659  * Purpose:
    660  *      Clear an L2 cache entry
    661  * Parameters:
    662  *      unit - device number
    663  *      index - l2 cache entry index
    664  * Returns:
    665  *      BCM_E_XXX
    666  */
    667 int
    668 bcm_tomahawk3_l2_cache_delete(int unit, int index)
    669 {
    670 #ifdef BCM_XGS3_SWITCH_SUPPORT
    671     int skip_l2u, rv;
    672 
    673     if (!SOC_UNIT_VALID(unit)) {
    674         return BCM_E_UNIT;
    675     }
    676 
    677     TH3_L2_INIT(unit);
    678 
    679     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    680 
    681     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    682         l2u_entry_t l2u_entry;
    683 
    684         if (index < 0 || index > soc_mem_index_max(unit, L2_USER_ENTRYm)) {
    685             return BCM_E_PARAM;
    686         }
    687 
    688         rv = BCM_E_NONE;
    689         soc_mem_lock(unit, L2_USER_ENTRYm);
    690 
    691 #if defined(BCM_TRIDENT_SUPPORT)
    692         rv = soc_l2u_get(unit, &l2u_entry, index);
    693         if (BCM_SUCCESS(rv))  {
    694             /* TH3 doesn't have L3,RESERVED_0 fields, ignoring return value,
    695              * as done in legacy code
    696              */
    697             bcm_td_l2cache_myStation_delete(unit, index);
    698         }
    699 #endif /* BCM_TRIDENT_SUPPORT */
    700 
    701         if (BCM_SUCCESS(rv)) {
    702             rv = soc_l2u_delete(unit, NULL, index, &index);
    703         }
    704 
    705         soc_mem_unlock(unit, L2_USER_ENTRYm);
    706         return rv;
    707     }
    708 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    709     return BCM_E_UNAVAIL;
    710 }
    711 
    712 /*
    713  * Function:
    714  *      bcm_tomahawk3_l2_cache_delete_all
    715  * Purpose:
    716  *      Clear all L2 cache entries
    717  * Parameters:
    718  *      unit - device number
    719  * Returns:
    720  *      BCM_E_XXX
    721  */
    722 int
    723 bcm_tomahawk3_l2_cache_delete_all(int unit)
    724 {
    725 #ifdef BCM_XGS3_SWITCH_SUPPORT
    726     int skip_l2u, rv, index, index_max;
    727     l2u_entry_t entry;
    728 
    729     if (!SOC_UNIT_VALID(unit)) {
    730         return BCM_E_UNIT;
    731     }
    732 
    733     TH3_L2_INIT(unit);
    734 
    735     skip_l2u = soc_property_get(unit, spn_SKIP_L2_USER_ENTRY, 0);
    736 
    737     if (soc_feature(unit, soc_feature_l2_user_table) && !skip_l2u) {
    738         index_max = soc_mem_index_max(unit, L2_USER_ENTRYm);
    739 
    740         rv = BCM_E_NONE;
    741         soc_mem_lock(unit, L2_USER_ENTRYm);
    742         for (index = 0; index <= index_max; index++) {
    743 #if defined(BCM_TRIDENT_SUPPORT)
    744                 rv = READ_L2_USER_ENTRYm(unit, MEM_BLOCK_ALL, index, &entry);
    745                 if (BCM_SUCCESS(rv)) {
    746                     rv = bcm_td_l2cache_myStation_delete(unit, index);
    747                     /* Ignore entry not found case
    748                      * (same action as legacy code)
    749                      */
    750                     if (rv == BCM_E_NOT_FOUND) {
    751                         rv = BCM_E_NONE;
    752                     }
    753                 }
    754 #endif /* BCM_TRIDENT_SUPPORT */
    755             if (BCM_SUCCESS(rv)) {
    756                 sal_memset(&entry, 0, sizeof(entry));
    757                 rv = WRITE_L2_USER_ENTRYm(unit, MEM_BLOCK_ALL, index, &entry);
    758             }
    759             if (BCM_FAILURE(rv)) {
    760                 break;
    761             }
    762         }
    763         soc_mem_unlock(unit, L2_USER_ENTRYm);
    764         return rv;
    765     }
    766 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    767     return BCM_E_UNAVAIL;
    768 }
    769 #endif /* BCM_TOMAHAWK3_SUPPORT */