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

wlan.c (128978B)


      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:    wlan.c
      8  * Purpose: Manages WLAN functions
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 #include <shared/bsl.h>
     14 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/drv.h>
     17 #include <soc/scache.h>
     18 #include <soc/hash.h>
     19 #include <soc/util.h>
     20 #include <soc/triumph.h>
     21 
     22 #include <bcm/error.h>
     23 #include <bcm/wlan.h>
     24 
     25 #include <bcm_int/esw/mbcm.h>
     26 #include <bcm_int/esw/l3.h>
     27 #include <bcm_int/esw/firebolt.h>
     28 #include <bcm_int/esw/triumph.h>
     29 #include <bcm_int/esw/triumph2.h>
     30 #include <bcm_int/esw/xgs3.h>
     31 #include <bcm_int/common/multicast.h>
     32 #include <bcm_int/esw/virtual.h>
     33 #include <bcm_int/esw/trx.h>
     34 #include <bcm_int/esw/stack.h>
     35 
     36 #include <bcm_int/esw_dispatch.h>
     37 #include <bcm_int/api_xlate_port.h>
     38 
     39 /*
     40  * WLAN port state - need to remember where to find the port.
     41  * Flags indicate the type of the port and hence the tables where the data is.
     42  * The match attributes are the keys for the EGR_VLAN_XLATE table.
     43  */
     44 #define _BCM_WLAN_PORT_MATCH_BSSID                    (1 << 0)
     45 #define _BCM_WLAN_PORT_MATCH_BSSID_RADIO              (1 << 1)
     46 #define _BCM_WLAN_PORT_MATCH_TUNNEL                   (1 << 2)
     47 typedef struct _bcm_tr2_wlan_port_info_s {
     48     uint32 flags;
     49     bcm_trunk_t tgid; /* Trunk group ID */
     50     bcm_module_t modid; /* Module id */
     51     bcm_port_t port; /* Port */
     52     bcm_mac_t match_bssid;         /* Match BSSID */
     53     int match_radio;               /* Match radio */      
     54     bcm_gport_t match_tunnel;      /* Match tunnel */
     55     bcm_gport_t egress_tunnel;     /* Egress tunnel */
     56 } _bcm_tr2_wlan_port_info_t;
     57 
     58 /*
     59  * Software book keeping for WLAN related information
     60  */
     61 typedef struct _bcm_tr2_wlan_bookkeeping_s {
     62     _bcm_tr2_wlan_port_info_t *port_info;   /* VP state */
     63     int capwap_frag_profile_created; /* Flag to check profile creation */
     64     soc_profile_reg_t *capwap_frag_profile; /* CAPWAP fragment profile */
     65     bcm_vlan_t *tunnel_vlan; /* Tunnel VLAN cache */
     66     SHR_BITDCL *intf_bitmap; /* L3 interfaces used */
     67     SHR_BITDCL *ip_tnl_bitmap; /* EGR_IP_TUNNEL index bitmap */
     68     SHR_BITDCL *ip_tnl_is_v6_bitmap; /* Set if above used entry is actually 
     69                                      double-wide (IPv6) */
     70     uint8 **vlan_grp_bmp_use_cnt; /* Vlan group bitmap use count per VLAN */
     71 } _bcm_tr2_wlan_bookkeeping_t;
     72 
     73 STATIC _bcm_tr2_wlan_bookkeeping_t  _bcm_tr2_wlan_bk_info[BCM_MAX_NUM_UNITS];
     74 
     75 /* Flag to check initialized status */
     76 STATIC int wlan_initialized[BCM_MAX_NUM_UNITS];
     77 
     78 STATIC sal_mutex_t _wlan_mutex[BCM_MAX_NUM_UNITS] = {NULL};
     79 
     80 #define L3_INFO(unit)    (&_bcm_l3_bk_info[unit])
     81 #define WLAN_INFO(_unit_) (&_bcm_tr2_wlan_bk_info[_unit_])
     82 #define CAPWAP_FRAG_PROFILE(_unit_) \
     83     (_bcm_tr2_wlan_bk_info[_unit_].capwap_frag_profile)
     84 #define TUNNEL_VLAN(_unit_, _tnl_idx_) \
     85         (_bcm_tr2_wlan_bk_info[_unit_].tunnel_vlan[_tnl_idx_])
     86 
     87 #define WLAN_INIT(unit)                                   \
     88     do {                                                  \
     89         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) {  \
     90             return BCM_E_UNIT;                            \
     91         }                                                 \
     92         if (!wlan_initialized[unit]) {                    \
     93             return BCM_E_INIT;                            \
     94         }                                                 \
     95     } while (0)
     96 
     97 /* 
     98  * WLAN module lock
     99  */
    100 #define WLAN_LOCK(unit) \
    101         sal_mutex_take(_wlan_mutex[unit], sal_mutex_FOREVER);
    102 
    103 #define WLAN_UNLOCK(unit) \
    104         sal_mutex_give(_wlan_mutex[unit]); 
    105 
    106 /*
    107  * EGR_IP_TUNNEL table usage bitmap operations
    108  */
    109 #define _BCM_WLAN_IP_TNL_USED_GET(_u_, _tnl_) \
    110         SHR_BITGET(WLAN_INFO(_u_)->ip_tnl_bitmap, (_tnl_))
    111 #define _BCM_WLAN_IP_TNL_USED_SET(_u_, _tnl_) \
    112         SHR_BITSET(WLAN_INFO((_u_))->ip_tnl_bitmap, (_tnl_))
    113 #define _BCM_WLAN_IP_TNL_USED_CLR(_u_, _tnl_) \
    114         SHR_BITCLR(WLAN_INFO((_u_))->ip_tnl_bitmap, (_tnl_))
    115 
    116 /*
    117  * EGR_IP_TUNNEL table index is v6 bitmap operations
    118  */
    119 #define _BCM_WLAN_IP_TNL_IS_V6_GET(_u_, _tnl_) \
    120         SHR_BITGET(WLAN_INFO(_u_)->ip_tnl_is_v6_bitmap, (_tnl_))
    121 #define _BCM_WLAN_IP_TNL_IS_V6_SET(_u_, _tnl_) \
    122         SHR_BITSET(WLAN_INFO((_u_))->ip_tnl_is_v6_bitmap, (_tnl_))
    123 #define _BCM_WLAN_IP_TNL_IS_V6_CLR(_u_, _tnl_) \
    124         SHR_BITCLR(WLAN_INFO((_u_))->ip_tnl_is_v6_bitmap, (_tnl_))
    125 
    126 /*
    127  * L3 interface usage bitmap operations
    128  */
    129 #define _BCM_WLAN_INTF_USED_GET(_u_, _intf_) \
    130         SHR_BITGET(WLAN_INFO(_u_)->intf_bitmap, (_intf_))
    131 #define _BCM_WLAN_INTF_USED_SET(_u_, _intf_) \
    132         SHR_BITSET(WLAN_INFO((_u_))->intf_bitmap, (_intf_))
    133 #define _BCM_WLAN_INTF_USED_CLR(_u_, _intf_) \
    134         SHR_BITCLR(WLAN_INFO((_u_))->intf_bitmap, (_intf_))
    135 
    136 /*
    137  * Function:
    138  *      _bcm_tr2_wlan_free_resources
    139  * Purpose:
    140  *      Free all allocated tables and memory
    141  * Parameters:
    142  *      unit - SOC unit number
    143  * Returns:
    144  *      Nothing
    145  */
    146 STATIC void
    147 _bcm_tr2_wlan_free_resources(int unit)
    148 {
    149     _bcm_tr2_wlan_bookkeeping_t *wlan_info = WLAN_INFO(unit);
    150     int i;
    151 
    152     /* Destroy WLAN mutex */
    153     if (_wlan_mutex[unit]) {
    154         sal_mutex_destroy(_wlan_mutex[unit]);
    155         _wlan_mutex[unit] = NULL;
    156     }
    157 
    158     /* Destroy the VLAN group bitmap use count */
    159     if (wlan_info->vlan_grp_bmp_use_cnt) {
    160         for (i = 0; i < BCM_VLAN_COUNT; i++) {
    161             if (wlan_info->vlan_grp_bmp_use_cnt[i]) {
    162                 sal_free((uint8 *)(wlan_info->vlan_grp_bmp_use_cnt[i]));
    163                 wlan_info->vlan_grp_bmp_use_cnt[i] = NULL;
    164             }
    165         }
    166         sal_free(wlan_info->vlan_grp_bmp_use_cnt);
    167         wlan_info->vlan_grp_bmp_use_cnt = NULL;
    168     }
    169 
    170     /* Destroy EGR_IP_TUNNEL is V6 bitmap */
    171     if (wlan_info->ip_tnl_is_v6_bitmap) {
    172         sal_free(wlan_info->ip_tnl_is_v6_bitmap);
    173         wlan_info->ip_tnl_is_v6_bitmap = NULL;
    174     }
    175 
    176     /* Destroy EGR_IP_TUNNEL usage bitmap */
    177     if (wlan_info->ip_tnl_bitmap) {
    178         sal_free(wlan_info->ip_tnl_bitmap);
    179         wlan_info->ip_tnl_bitmap = NULL;
    180     }
    181 
    182     /* Destroy EGR_L3_INTF usage bitmap */
    183     if (wlan_info->intf_bitmap) {
    184         sal_free(wlan_info->intf_bitmap);
    185         wlan_info->intf_bitmap = NULL;
    186     }
    187 
    188     /* Destroy tunnel VLAN cache */
    189     if (wlan_info->tunnel_vlan) {
    190         sal_free(wlan_info->tunnel_vlan);
    191         wlan_info->tunnel_vlan = NULL;
    192     }
    193 
    194     /* Destroy CAPWAP_FRAG profile */
    195     if (wlan_info->capwap_frag_profile) {
    196         if (wlan_info->capwap_frag_profile_created) {
    197             (void) soc_profile_reg_destroy(unit, wlan_info->capwap_frag_profile);
    198         }
    199         sal_free(wlan_info->capwap_frag_profile);
    200         wlan_info->capwap_frag_profile = NULL;
    201     }
    202 
    203     /* Destroy WLAN port usage bitmap */ 
    204     if (wlan_info->port_info) {
    205         sal_free(wlan_info->port_info);
    206         wlan_info->port_info = NULL;
    207     }
    208 }
    209 
    210 #ifdef BCM_WARM_BOOT_SUPPORT
    211 STATIC void
    212 _bcm_tr2_wlan_port_flex_stat_recover(int unit, source_vp_entry_t *source_vp, 
    213                                      int index)
    214 {
    215     int fs_idx;
    216     if (soc_feature(unit, soc_feature_gport_service_counters)) {
    217         if (soc_mem_field_valid(unit, SOURCE_VPm, VINTF_CTR_IDXf)) {
    218             fs_idx = soc_mem_field32_get(unit, SOURCE_VPm, source_vp,
    219                                          VINTF_CTR_IDXf);
    220             if (fs_idx) {
    221                 BCM_GPORT_WLAN_PORT_ID_SET(index, index);
    222                 _bcm_esw_flex_stat_reinit_add(unit, _bcmFlexStatTypeGport,
    223                                               fs_idx, index);
    224             }
    225         }
    226     }
    227     return;
    228 }
    229 
    230 STATIC int
    231 _bcm_tr2_wlan_lport_tpid_recover(int unit, lport_tab_entry_t *lport_tab)
    232 {
    233     int tpid_enable, index, rv = BCM_E_NONE;
    234     tpid_enable = soc_LPORT_TABm_field32_get(unit, lport_tab,
    235                                              OUTER_TPID_ENABLEf);
    236     for (index = 0; index < 4; index++) {
    237         if (tpid_enable & (1 << index)) {
    238             rv = _bcm_fb2_outer_tpid_tab_ref_count_add(unit, index, 1);
    239             break;
    240         }
    241     }
    242     return rv;
    243 }
    244 
    245 STATIC int
    246 _bcm_tr2_wlan_port_associated_data_recover(int unit, int vp, int stable_size)
    247 {
    248     int idx, nh_index, intf_num, rv = BCM_E_NONE;
    249     uint32 nh_flags;
    250     ing_l3_next_hop_entry_t ing_nh_entry;
    251     egr_l3_next_hop_entry_t egr_nh_entry;
    252     ing_dvp_table_entry_t ing_dvp_entry;
    253     bcm_module_t mod_in, mod_out;
    254     bcm_port_t port_in, port_out, phys_port;
    255     bcm_trunk_t trunk_id;
    256     bcm_l3_egress_t nh_info;
    257     _bcm_port_info_t *info;
    258     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
    259     int local_member_count;
    260     uint32 port_flags;
    261 
    262     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_DVP_TABLEm, MEM_BLOCK_ANY, 
    263                                      vp, &ing_dvp_entry));
    264     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 
    265                                               NEXT_HOP_INDEXf);
    266     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
    267                                      nh_index, &ing_nh_entry));
    268     BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
    269                                      nh_index, &egr_nh_entry));
    270 
    271     bcm_l3_egress_t_init(&nh_info);
    272 
    273     nh_flags = _BCM_L3_SHR_UPDATE | _BCM_L3_SHR_WRITE_DISABLE | 
    274                _BCM_L3_SHR_WITH_ID;
    275     rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
    276     BCM_IF_ERROR_RETURN(rv);
    277 
    278     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 
    279                                          ENTRY_TYPEf) == 0x2) {
    280         /* Type is SVP */
    281         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
    282             trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, 
    283                                                         &ing_nh_entry, TGIDf);
    284             WLAN_INFO(unit)->port_info[vp].modid = -1;
    285             WLAN_INFO(unit)->port_info[vp].port = -1;
    286             WLAN_INFO(unit)->port_info[vp].tgid = trunk_id;
    287             /* Update each local physical port's SW state */
    288             if (stable_size == 0) {
    289                 /* When persistent storage is available, this state is recovered
    290                    in the port module */
    291                 rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
    292                         SOC_MAX_NUM_PORTS, local_member_array, &local_member_count);
    293                 BCM_IF_ERROR_RETURN(rv);
    294                 for (idx = 0; idx < local_member_count; idx++) {
    295                     _bcm_port_info_access(unit, local_member_array[idx], &info);
    296                     info->vp_count++;
    297                     BCM_IF_ERROR_RETURN(
    298                         bcm_esw_port_vlan_member_get(
    299                             unit, local_member_array[idx], &port_flags));
    300                     BCM_IF_ERROR_RETURN(
    301                         bcm_esw_port_vlan_member_set(
    302                             unit, local_member_array[idx], port_flags));
    303                 }
    304             }
    305         } else {
    306             mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 
    307                                                       MODULE_IDf);
    308             port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 
    309                                                        PORT_NUMf);
    310             rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    311                                         mod_in, port_in, &mod_out, &port_out);
    312             WLAN_INFO(unit)->port_info[vp].modid = mod_out;
    313             WLAN_INFO(unit)->port_info[vp].port = port_out;
    314             WLAN_INFO(unit)->port_info[vp].tgid = -1;
    315             /* Update the physical port's SW state */
    316             if (stable_size == 0) {
    317                 /* When persistent storage is available, this state is recovered
    318                    in the port module */
    319                 phys_port = WLAN_INFO(unit)->port_info[vp].port; 
    320                 if (soc_feature(unit, soc_feature_sysport_remap)) { 
    321                     BCM_XLATE_SYSPORT_S2P(unit, &phys_port); 
    322                 }
    323                 _bcm_port_info_access(unit, phys_port, &info);
    324                 info->vp_count++;
    325                 BCM_IF_ERROR_RETURN(
    326                     bcm_esw_port_vlan_member_get(
    327                         unit, phys_port, &port_flags));
    328                 BCM_IF_ERROR_RETURN(
    329                     bcm_esw_port_vlan_member_set(
    330                         unit, phys_port, port_flags));
    331             }
    332         }
    333     } else {
    334         return BCM_E_INTERNAL; /* Should never happen */
    335     }
    336     intf_num = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry,
    337                                                 WLAN__INTF_NUMf);
    338     _BCM_WLAN_INTF_USED_SET(unit, intf_num);
    339     BCM_L3_INTF_USED_SET(unit, intf_num);
    340     return rv;
    341 }
    342 
    343 /*
    344  * Function:
    345  *      _bcm_tr2_wlan_reinit
    346  * Purpose:
    347  *      Warm boot recovery for the WLAN software module
    348  * Parameters:
    349  *      unit     - Device Number
    350  * Returns:
    351  *      BCM_E_XXX
    352  */
    353 STATIC int 
    354 _bcm_tr2_wlan_reinit(int unit)
    355 {
    356     int rv, i, j, index_min, index_max, mtu_sel, lport_profile_ptr;
    357     int tpid_index, tnl_idx, stable_size, vvp, vp = 0;
    358     uint32 entry_type, tunnel_type, flags, grp_bmp, rval;
    359     uint32 tnl_entry[SOC_MAX_MEM_FIELD_WORDS];
    360     uint64 rval64, *rval64s[1];
    361     uint8 *wlan_svp_table_buf = NULL; /* WLAN_SVP_TABLE DMA buffer */
    362     wlan_svp_table_entry_t *wlan_svp_table;
    363     uint8 *egr_vlan_xlate_buf = NULL; /* EGR_VLAN_XLATE DMA buffer */
    364     egr_vlan_xlate_entry_t *egr_vlan_xlate;
    365     uint8 *egr_ip_tunnel_buf = NULL; /* EGR_IP_TUNNEL DMA buffer */
    366     egr_ip_tunnel_entry_t *egr_ip_tunnel;
    367     uint8 *egr_ip_tunnel_ipv6_buf = NULL; /* EGR_IP_TUNNEL_IPV6 DMA buffer */
    368     egr_ip_tunnel_ipv6_entry_t *egr_ip_tunnel_ipv6;
    369     uint8 *vbuf = NULL; /* VLAN_TABLE DMA buffer */
    370     vlan_tab_entry_t *vtab;
    371     egr_wlan_dvp_entry_t egr_wlan_dvp;
    372     lport_tab_entry_t lport_profile;
    373     source_vp_entry_t source_vp;
    374     bcm_tunnel_initiator_t info;
    375     _bcm_vp_info_t vp_info;
    376 
    377     _bcm_vp_info_init(&vp_info);
    378     vp_info.vp_type = _bcmVpTypeWlan;
    379 
    380     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    381 
    382     /* DMA various tables */
    383     wlan_svp_table_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    384                                  (unit, WLAN_SVP_TABLEm), 
    385                                  "WLAN_SVP_TABLE buffer");
    386     if (NULL == wlan_svp_table_buf) {
    387         rv = BCM_E_MEMORY;
    388         goto cleanup;
    389     }
    390     index_min = soc_mem_index_min(unit, WLAN_SVP_TABLEm);
    391     index_max = soc_mem_index_max(unit, WLAN_SVP_TABLEm);
    392     if ((rv = soc_mem_read_range(unit, WLAN_SVP_TABLEm, MEM_BLOCK_ANY,
    393                                  index_min, index_max, 
    394                                  wlan_svp_table_buf)) < 0 ) {
    395         goto cleanup;
    396     }
    397     egr_vlan_xlate_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    398                                        (unit, EGR_VLAN_XLATEm), 
    399                                        "EGR_VLAN_XLATE buffer");
    400     if (NULL == egr_vlan_xlate_buf) {
    401         rv = BCM_E_MEMORY;
    402         goto cleanup;
    403     }
    404     index_min = soc_mem_index_min(unit, EGR_VLAN_XLATEm);
    405     index_max = soc_mem_index_max(unit, EGR_VLAN_XLATEm);
    406     if ((rv = soc_mem_read_range(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ANY,
    407                                  index_min, index_max, 
    408                                  egr_vlan_xlate_buf)) < 0 ) {
    409         goto cleanup;
    410     }
    411     egr_ip_tunnel_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    412                                        (unit, EGR_IP_TUNNELm), 
    413                                        "EGR_IP_TUNNEL buffer");
    414     if (NULL == egr_ip_tunnel_buf) {
    415         rv = BCM_E_MEMORY;
    416         goto cleanup;
    417     }
    418     index_min = soc_mem_index_min(unit, EGR_IP_TUNNELm);
    419     index_max = soc_mem_index_max(unit, EGR_IP_TUNNELm);
    420     if ((rv = soc_mem_read_range(unit, EGR_IP_TUNNELm, MEM_BLOCK_ANY,
    421                                  index_min, index_max, 
    422                                  egr_ip_tunnel_buf)) < 0 ) {
    423         goto cleanup;
    424     }
    425     egr_ip_tunnel_ipv6_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    426                                        (unit, EGR_IP_TUNNEL_IPV6m), 
    427                                        "EGR_IP_TUNNEL_IPV6 buffer");
    428     if (NULL == egr_ip_tunnel_ipv6_buf) {
    429         rv = BCM_E_MEMORY;
    430         goto cleanup;
    431     }
    432     index_min = soc_mem_index_min(unit, EGR_IP_TUNNEL_IPV6m);
    433     index_max = soc_mem_index_max(unit, EGR_IP_TUNNEL_IPV6m);
    434     if ((rv = soc_mem_read_range(unit, EGR_IP_TUNNEL_IPV6m, MEM_BLOCK_ANY,
    435                                  index_min, index_max, 
    436                                  egr_ip_tunnel_ipv6_buf)) < 0 ) {
    437         goto cleanup;
    438     }
    439     vbuf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABm), 
    440                          "VLAN_TAB buffer");
    441     if (NULL == vbuf) {
    442         rv = BCM_E_MEMORY;
    443         goto cleanup;
    444     }
    445     index_min = soc_mem_index_min(unit, VLAN_TABm);
    446     index_max = soc_mem_index_max(unit, VLAN_TABm);
    447     if ((rv = soc_mem_read_range(unit, VLAN_TABm, MEM_BLOCK_ANY,
    448                                  index_min, index_max, vbuf)) < 0 ) {
    449         goto cleanup;
    450     }
    451 
    452     flags = 0;
    453 
    454     /* Get the VPs */
    455     index_min = soc_mem_index_min(unit, EGR_VLAN_XLATEm);
    456     index_max = soc_mem_index_max(unit, EGR_VLAN_XLATEm);
    457     for (i = index_min; i <= index_max; i++) {
    458         egr_vlan_xlate = soc_mem_table_idx_to_pointer
    459                          (unit, EGR_VLAN_XLATEm, egr_vlan_xlate_entry_t *, 
    460                          egr_vlan_xlate_buf, i);
    461         if (soc_EGR_VLAN_XLATEm_field32_get(unit, 
    462                                             egr_vlan_xlate, VALIDf) == 0) {
    463             continue;
    464         }
    465         entry_type = soc_EGR_VLAN_XLATEm_field32_get(unit, egr_vlan_xlate, 
    466                                                      ENTRY_TYPEf);
    467         if ((entry_type != 5) && (entry_type != 6) && (entry_type != 7)) {
    468             continue; /* Not WLAN_SVP */
    469         }
    470         vp = soc_EGR_VLAN_XLATEm_field32_get(unit, egr_vlan_xlate, 
    471                                              WLAN_SVP__SVPf);
    472         wlan_svp_table = soc_mem_table_idx_to_pointer
    473                          (unit, WLAN_SVP_TABLEm, wlan_svp_table_entry_t *, 
    474                          wlan_svp_table_buf, vp);
    475         if (soc_WLAN_SVP_TABLEm_field32_get(unit, 
    476                                             wlan_svp_table, VALIDf) == 0) {
    477             rv = BCM_E_INTERNAL; /* Should never happen */
    478             goto cleanup;
    479         }
    480         rv = _bcm_vp_used_set(unit, vp, vp_info);
    481         if (BCM_FAILURE(rv)) {
    482             goto cleanup;
    483         }
    484         switch (entry_type) {
    485         case 5:
    486             BCM_GPORT_TUNNEL_ID_SET(WLAN_INFO(unit)->port_info[vp].match_tunnel,
    487                                     soc_EGR_VLAN_XLATEm_field32_get(unit, 
    488                                     egr_vlan_xlate, WLAN_SVP__TUNNEL_IDf));
    489             WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_TUNNEL;
    490             break;
    491         case 6:
    492             soc_mem_mac_addr_get(unit, EGR_VLAN_XLATEm, egr_vlan_xlate, 
    493                                  WLAN_SVP__BSSIDf, 
    494                                  WLAN_INFO(unit)->port_info[vp].match_bssid);
    495             BCM_GPORT_TUNNEL_ID_SET(WLAN_INFO(unit)->port_info[vp].match_tunnel,
    496                                     soc_EGR_VLAN_XLATEm_field32_get(unit, 
    497                                     egr_vlan_xlate, WLAN_SVP__EXP_TUNNEL_IDf));
    498             WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID;
    499             break;
    500         case 7:
    501             WLAN_INFO(unit)->port_info[vp].match_radio = 
    502                 soc_EGR_VLAN_XLATEm_field32_get(unit, egr_vlan_xlate, 
    503                                                 WLAN_SVP__RIDf);
    504             soc_mem_mac_addr_get(unit, EGR_VLAN_XLATEm, egr_vlan_xlate, 
    505                                  WLAN_SVP__BSSIDf, 
    506                                  WLAN_INFO(unit)->port_info[vp].match_bssid);
    507             BCM_GPORT_TUNNEL_ID_SET(WLAN_INFO(unit)->port_info[vp].match_tunnel,
    508                                     soc_EGR_VLAN_XLATEm_field32_get(unit, 
    509                                     egr_vlan_xlate, WLAN_SVP__EXP_TUNNEL_IDf));
    510             WLAN_INFO(unit)->port_info[vp].flags |= 
    511                                                _BCM_WLAN_PORT_MATCH_BSSID_RADIO;
    512             break;
    513         /*
    514          * COVERITY
    515          *
    516          * This default is unreachable. It is kept intentionally as a defensive 
    517          * default for future development. 
    518          */ 
    519         /* coverity[dead_error_begin] */
    520         default:
    521             rv = BCM_E_INTERNAL;
    522             goto cleanup;
    523             break;
    524         }
    525         /* Update LPORT profile entry refererence count */
    526         lport_profile_ptr = soc_WLAN_SVP_TABLEm_field32_get
    527                                 (unit, wlan_svp_table, LPORT_PROFILE_IDXf);
    528         rv = _bcm_lport_profile_mem_reference(unit, lport_profile_ptr, 1);
    529         if (BCM_FAILURE(rv)) {
    530             goto cleanup;
    531         }
    532         rv = READ_LPORT_TABm(unit, MEM_BLOCK_ANY, lport_profile_ptr, 
    533                              &lport_profile);
    534         if (BCM_FAILURE(rv)) {
    535             goto cleanup;
    536         }
    537         /* Get TPID reference count from the LPORT entry */
    538         rv = _bcm_tr2_wlan_lport_tpid_recover(unit, &lport_profile);
    539         if (BCM_FAILURE(rv)) {
    540             goto cleanup;
    541         }
    542         /* Recover flex stats from the SOURCE_VP table */
    543         rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &source_vp); 
    544         if (BCM_FAILURE(rv)) {
    545             goto cleanup;
    546         }
    547         _bcm_tr2_wlan_port_flex_stat_recover(unit, &source_vp, vp);
    548         /* Get the TUNNEL_VLAN from the EGR_WLAN_DVP table */
    549         rv = READ_EGR_WLAN_DVPm(unit, MEM_BLOCK_ANY, vp, &egr_wlan_dvp); 
    550         if (BCM_FAILURE(rv)) {
    551             goto cleanup;
    552         }
    553         tnl_idx = soc_EGR_WLAN_DVPm_field32_get(unit, &egr_wlan_dvp, 
    554                                                 TUNNEL_INDEXf);
    555         sal_memset(tnl_entry, 0, sizeof(tnl_entry));
    556         rv = READ_EGR_IP_TUNNELm(unit, MEM_BLOCK_ANY, tnl_idx, tnl_entry);
    557         if (BCM_FAILURE(rv)) {
    558             goto cleanup;
    559         }
    560         entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, tnl_entry, 
    561                                                     ENTRY_TYPEf);
    562         if (entry_type == BCM_XGS3_TUNNEL_INIT_V6) {
    563             tnl_idx *= 2;
    564         }
    565         TUNNEL_VLAN(unit, tnl_idx) = soc_EGR_WLAN_DVPm_field32_get(unit, 
    566                                          &egr_wlan_dvp, TUNNEL_VLAN_IDf);
    567         /* Get the VLAN validation state from TUNNEL VPs */
    568         if (WLAN_INFO(unit)->port_info[vp].flags & 
    569             _BCM_WLAN_PORT_MATCH_TUNNEL) {
    570             vvp = soc_WLAN_SVP_TABLEm_field32_get(unit, &source_vp, 
    571                                                   VLAN_VALIDATION_PTRf);
    572             for (j = BCM_VLAN_MIN; j < BCM_VLAN_MAX; j++) {
    573                 vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABm, 
    574                                                    vlan_tab_entry_t *, vbuf, j);
    575                 grp_bmp = soc_mem_field32_get(unit, VLAN_TABm, vtab, 
    576                                               VLAN_GROUP_BITMAPf);
    577                 if (grp_bmp & (1 << vvp)) {
    578                     /* Increase use-count for this bit for this VLAN */
    579                     WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[j][vvp]++;
    580                 }
    581             }
    582         }
    583         /* Recover other port data */
    584         rv = _bcm_tr2_wlan_port_associated_data_recover(unit, vp, stable_size);
    585         if (BCM_FAILURE(rv)) {
    586             goto cleanup;
    587         }
    588     }
    589 
    590     /* Get the IPV4 tunnel initiators */
    591     index_min = soc_mem_index_min(unit, EGR_IP_TUNNELm);
    592     index_max = soc_mem_index_max(unit, EGR_IP_TUNNELm);
    593     for (i = index_min; i <= index_max; i++) {
    594         egr_ip_tunnel = soc_mem_table_idx_to_pointer
    595                          (unit, EGR_IP_TUNNELm, egr_ip_tunnel_entry_t *, 
    596                          egr_ip_tunnel_buf, i);
    597         entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    598                                                     ENTRY_TYPEf);
    599         tunnel_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    600                                                      TUNNEL_TYPEf);
    601         if (entry_type != BCM_XGS3_TUNNEL_INIT_V4) {
    602             continue; /* Not IPv4 */
    603         }
    604         if ((tunnel_type != 8) && (tunnel_type != 9)) {
    605             continue; /* Not CAPWAP */
    606         }
    607         bcm_tunnel_initiator_t_init(&info);
    608         /* Get the CAPWAP fragment profile */
    609         mtu_sel = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    610                                                  CAPWAP_MTU_SELf);
    611         rv = READ_EGR_CAPWAP_FRAG_CONTROLr(unit, mtu_sel, &rval);
    612         if (BCM_FAILURE(rv)) {
    613             goto cleanup;
    614         }
    615         COMPILER_64_ZERO(rval64);
    616         COMPILER_64_SET(rval64, 0, rval);
    617         rval64s[0] = &rval64;
    618         rv = soc_profile_reg_add(unit, CAPWAP_FRAG_PROFILE(unit), rval64s, 1, 
    619                                  (uint32 *)&mtu_sel);
    620         /* Mark tunnel initiator entry as used in the L3 module */
    621         flags |= _BCM_L3_SHR_UPDATE | _BCM_L3_SHR_WRITE_DISABLE |
    622                  _BCM_L3_SHR_WITH_ID;
    623         tnl_idx = i;
    624         info.type = (tunnel_type == 8) ? bcmTunnelTypeWlanAcToAc : 
    625                                          bcmTunnelTypeWlanWtpToAc;
    626         soc_mem_field_get(unit, EGR_IP_TUNNELm, (uint32 *)egr_ip_tunnel, 
    627                           DIPf, &info.dip);
    628         soc_mem_field_get(unit, EGR_IP_TUNNELm, (uint32 *)egr_ip_tunnel, 
    629                           SIPf, &info.sip);
    630         if (soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    631                                            VLAN_ASSIGN_POLICYf)) {
    632             info.flags |= BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED;
    633             /* Get the TPID state */
    634             tpid_index = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    635                                                         TUNNEL_TPID_INDEXf);
    636             rv = _bcm_fb2_outer_tpid_tab_ref_count_add(unit, tpid_index, 1);
    637             if (BCM_FAILURE(rv)) {
    638                 goto cleanup;
    639             }
    640             rv = _bcm_fb2_outer_tpid_entry_get(unit, &info.tpid, tpid_index);
    641             if (BCM_FAILURE(rv)) {
    642                 goto cleanup;
    643             }
    644             info.pkt_pri = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    645                                                           NEW_PRIf);
    646             info.pkt_cfi = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    647                                                           NEW_CFIf);
    648 
    649         }
    650         if (soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    651                                            IPV4_DF_SELf) == 2) {
    652             info.flags |= BCM_TUNNEL_INIT_USE_INNER_DF;
    653         } else if (soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    654                                            IPV4_DF_SELf) == 1) {
    655             info.flags |= BCM_TUNNEL_INIT_IPV4_SET_DF;
    656         }
    657         info.dscp = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, DSCPf);
    658         info.dscp_sel = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    659                                                        DSCP_SELf);
    660         info.ttl = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, TTLf);
    661         soc_mem_mac_addr_get(unit, EGR_IP_TUNNELm, egr_ip_tunnel, 
    662                              DEST_ADDRf, info.dmac);
    663         info.udp_src_port = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    664                                                            L4_SRC_PORTf);
    665         info.udp_dst_port = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 
    666                                                            L4_DEST_PORTf);
    667         info.mtu = soc_reg_field_get(unit, EGR_CAPWAP_FRAG_CONTROLr, 
    668                                      rval, MTUf);
    669         info.flags |= BCM_TUNNEL_INIT_WLAN_MTU;
    670         rv = bcm_xgs3_tnl_init_add(unit, flags, &info, &tnl_idx);
    671         if (tnl_idx != i) {
    672             rv = BCM_E_INTERNAL;
    673             goto cleanup;
    674         }
    675         _BCM_WLAN_IP_TNL_USED_SET(unit, i);
    676     }
    677 
    678     /* Get the IPV6 tunnel initiators */
    679     index_min = soc_mem_index_min(unit, EGR_IP_TUNNEL_IPV6m);
    680     index_max = soc_mem_index_max(unit, EGR_IP_TUNNEL_IPV6m);
    681     for (i = index_min; i <= index_max; i++) {
    682         egr_ip_tunnel_ipv6 = soc_mem_table_idx_to_pointer
    683                       (unit, EGR_IP_TUNNEL_IPV6m, egr_ip_tunnel_ipv6_entry_t *, 
    684                       egr_ip_tunnel_ipv6_buf, i);
    685         entry_type = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    686                                               egr_ip_tunnel_ipv6, ENTRY_TYPEf);
    687         tunnel_type = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    688                                              egr_ip_tunnel_ipv6, TUNNEL_TYPEf);
    689         if (entry_type != BCM_XGS3_TUNNEL_INIT_V6) {
    690             continue; /* Not IPv6 */
    691         }
    692         if ((tunnel_type != 8) && (tunnel_type != 9)) {
    693             continue; /* Not CAPWAP */
    694         }
    695         bcm_tunnel_initiator_t_init(&info);
    696         /* Get the CAPWAP fragment profile */
    697         mtu_sel = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, egr_ip_tunnel_ipv6, 
    698                                                  CAPWAP_MTU_SELf);
    699         rv = READ_EGR_CAPWAP_FRAG_CONTROLr(unit, mtu_sel, &rval);
    700         if (BCM_FAILURE(rv)) {
    701             goto cleanup;
    702         }
    703         COMPILER_64_ZERO(rval64);
    704         COMPILER_64_SET(rval64, 0, rval);
    705         rval64s[0] = &rval64;
    706         rv = soc_profile_reg_add(unit, CAPWAP_FRAG_PROFILE(unit), rval64s, 1, 
    707                                  (uint32 *)&mtu_sel);
    708         /* Mark tunnel initiator entry as used in the L3 module */
    709         flags |= _BCM_L3_SHR_UPDATE | _BCM_L3_SHR_WRITE_DISABLE |
    710                  _BCM_L3_SHR_WITH_ID;
    711         tnl_idx = i;
    712         info.type = (tunnel_type == 8) ? bcmTunnelTypeWlanAcToAc6 : 
    713                                          bcmTunnelTypeWlanWtpToAc6;
    714         soc_mem_ip6_addr_get(unit, EGR_IP_TUNNEL_IPV6m, (uint32 *)
    715                              egr_ip_tunnel_ipv6, DIPf, info.dip6, 0);
    716         soc_mem_ip6_addr_get(unit, EGR_IP_TUNNEL_IPV6m, (uint32 *)
    717                              egr_ip_tunnel_ipv6, SIPf, info.sip6, 0);
    718         if (soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel_ipv6, 
    719                                            VLAN_ASSIGN_POLICYf)) {
    720             info.flags |= BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED;
    721             /* Get the TPID state */
    722             tpid_index = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    723                              egr_ip_tunnel_ipv6, TUNNEL_TPID_INDEXf);
    724             rv = _bcm_fb2_outer_tpid_tab_ref_count_add(unit, tpid_index, 1);
    725             if (BCM_FAILURE(rv)) {
    726                 goto cleanup;
    727             }
    728             rv = _bcm_fb2_outer_tpid_entry_get(unit, &info.tpid, tpid_index);
    729             if (BCM_FAILURE(rv)) {
    730                 goto cleanup;
    731             }
    732             info.pkt_pri = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    733                                egr_ip_tunnel_ipv6, NEW_PRIf);
    734             info.pkt_cfi = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    735                                egr_ip_tunnel_ipv6, NEW_CFIf);
    736         }
    737         if (soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, egr_ip_tunnel_ipv6, 
    738                                                 IPV6_DF_SELf) == 1) {
    739             info.flags |= BCM_TUNNEL_INIT_IPV6_SET_DF;
    740         }
    741         info.dscp = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    742                         egr_ip_tunnel_ipv6, DSCPf);
    743         info.dscp_sel = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    744                             egr_ip_tunnel_ipv6, DSCP_SELf);
    745         info.flow_label = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    746                               egr_ip_tunnel_ipv6, FLOW_LABELf);
    747         info.ttl = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, egr_ip_tunnel_ipv6,
    748                                                        TTLf);
    749         soc_mem_mac_addr_get(unit, EGR_IP_TUNNEL_IPV6m, egr_ip_tunnel_ipv6, 
    750                              DEST_ADDRf, info.dmac);
    751         info.udp_src_port = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    752                                 egr_ip_tunnel_ipv6, L4_SRC_PORTf);
    753         info.udp_dst_port = soc_EGR_IP_TUNNEL_IPV6m_field32_get(unit, 
    754                                 egr_ip_tunnel_ipv6, L4_DEST_PORTf);
    755         info.mtu = soc_reg_field_get(unit, EGR_CAPWAP_FRAG_CONTROLr, 
    756                                      rval, MTUf);
    757         info.flags |= BCM_TUNNEL_INIT_WLAN_MTU;
    758         rv = bcm_xgs3_tnl_init_add(unit, flags, &info, &tnl_idx);
    759         if (tnl_idx != i) {
    760             rv = BCM_E_INTERNAL;
    761             goto cleanup;
    762         }
    763         _BCM_WLAN_IP_TNL_USED_SET(unit, i * 2);
    764         _BCM_WLAN_IP_TNL_IS_V6_SET(unit, i * 2);
    765     }
    766 
    767 cleanup:
    768     if (wlan_svp_table_buf) {
    769         soc_cm_sfree(unit, wlan_svp_table_buf);
    770     }
    771     if (egr_vlan_xlate_buf) {
    772         soc_cm_sfree(unit, egr_vlan_xlate_buf);
    773     }
    774     if (egr_ip_tunnel_buf) {
    775         soc_cm_sfree(unit, egr_ip_tunnel_buf);
    776     }
    777     if (egr_ip_tunnel_ipv6_buf) {
    778         soc_cm_sfree(unit, egr_ip_tunnel_ipv6_buf);
    779     }
    780     if (vbuf) {
    781         soc_cm_sfree(unit, vbuf);
    782     }
    783     return rv;
    784 }
    785 #endif /* BCM_WARM_BOOT_SUPPORT */
    786 
    787 /*
    788  * Function:
    789  *      bcm_wlan_init
    790  * Purpose:
    791  *      Initialize the WLAN software module
    792  * Parameters:
    793  *      unit     - Device Number
    794  * Returns:
    795  *      BCM_E_XXX
    796  */
    797 int 
    798 bcm_tr2_wlan_init(int unit)
    799 {
    800     int i, num_vp, num_tnl, num_intf, rv = BCM_E_NONE;
    801     _bcm_tr2_wlan_bookkeeping_t *wlan_info = WLAN_INFO(unit);
    802     soc_reg_t reg;
    803     uint64 rval64, *rval64s[1];
    804     uint32 capwap_frag_profile;
    805 
    806     if (!L3_INFO(unit)->l3_initialized) {
    807         LOG_INFO(BSL_LS_BCM_L3,
    808                  (BSL_META_U(unit,
    809                              "L3 module must be initialized first\n")));
    810         return BCM_E_NONE;
    811     }
    812     if (wlan_initialized[unit]) {
    813         BCM_IF_ERROR_RETURN(bcm_tr2_wlan_detach(unit));
    814     }
    815     num_vp = soc_mem_index_count(unit, WLAN_SVP_TABLEm);
    816 
    817     sal_memset(wlan_info, 0, sizeof(_bcm_tr2_wlan_bookkeeping_t));
    818 
    819     /* Create WLAN port usage bitmap */
    820     if (wlan_info->port_info == NULL) {
    821         wlan_info->port_info = sal_alloc(sizeof(_bcm_tr2_wlan_port_info_t) 
    822                                        * num_vp, "wlan_port_info");
    823         if (wlan_info->port_info == NULL) {
    824             _bcm_tr2_wlan_free_resources(unit);
    825             return BCM_E_MEMORY;
    826         }
    827     }
    828     sal_memset(wlan_info->port_info, 0, sizeof(_bcm_tr2_wlan_port_info_t) 
    829                * num_vp);
    830 
    831     /* Create profile register cache for EGR_CAPWAP_FRAG_CONTROL */
    832     reg = EGR_CAPWAP_FRAG_CONTROLr;
    833     if (NULL == wlan_info->capwap_frag_profile) {
    834         wlan_info->capwap_frag_profile = sal_alloc(sizeof(soc_profile_reg_t),
    835                                          "CAPWAP Frag Ctrl Profile Reg");
    836         if (wlan_info->capwap_frag_profile == NULL) {
    837             _bcm_tr2_wlan_free_resources(unit);
    838             return BCM_E_MEMORY;
    839         }
    840         soc_profile_reg_t_init(wlan_info->capwap_frag_profile);
    841 
    842         rv = soc_profile_reg_create(unit, &reg, 1, wlan_info->capwap_frag_profile);
    843         wlan_info->capwap_frag_profile_created = TRUE;
    844         if (rv < 0) {
    845             _bcm_tr2_wlan_free_resources(unit);
    846             return rv;
    847         }
    848         COMPILER_64_ZERO(rval64);
    849         rval64s[0] = &rval64;
    850         rv = soc_profile_reg_add(unit, CAPWAP_FRAG_PROFILE(unit), rval64s, 1,
    851                             &capwap_frag_profile);
    852         if (BCM_FAILURE(rv)) {
    853             _bcm_tr2_wlan_free_resources(unit);
    854             return rv;
    855         }
    856     }
    857 
    858     /* Allocate tunnel VLAN cache */
    859     num_tnl = soc_mem_index_count(unit, EGR_IP_TUNNELm);
    860     if (NULL == wlan_info->tunnel_vlan) {
    861         wlan_info->tunnel_vlan =
    862                 sal_alloc(sizeof(bcm_vlan_t) * num_tnl, "tunnel vlan cache");
    863         if (wlan_info->tunnel_vlan == NULL) {
    864             _bcm_tr2_wlan_free_resources(unit);
    865             return BCM_E_MEMORY;
    866         }
    867     }
    868     sal_memset(wlan_info->tunnel_vlan, 0, sizeof(bcm_vlan_t) * num_tnl);
    869 
    870     /* Allocate L3 interface usage bitmap */
    871     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
    872     if (NULL == wlan_info->intf_bitmap) {
    873         wlan_info->intf_bitmap =
    874             sal_alloc(SHR_BITALLOCSIZE(num_intf), "intf_bitmap");
    875         if (wlan_info->intf_bitmap == NULL) {
    876             _bcm_tr2_wlan_free_resources(unit);
    877             return BCM_E_MEMORY;
    878         }
    879     }
    880     sal_memset(wlan_info->intf_bitmap, 0, SHR_BITALLOCSIZE(num_intf));    
    881 
    882     /* Create EGR_IP_TUNNEL usage bitmap */
    883     wlan_info->ip_tnl_bitmap =
    884         sal_alloc(SHR_BITALLOCSIZE(num_tnl), "wlan ip_tnl_bitmap");
    885     if (wlan_info->ip_tnl_bitmap == NULL) {
    886         _bcm_tr2_wlan_free_resources(unit);
    887 	return BCM_E_MEMORY;
    888     }
    889     sal_memset(wlan_info->ip_tnl_bitmap, 0, SHR_BITALLOCSIZE(num_tnl));
    890 
    891     /* Create EGR_IP_TUNNEL is V6 usage bitmap */
    892     wlan_info->ip_tnl_is_v6_bitmap =
    893         sal_alloc(SHR_BITALLOCSIZE(num_tnl), "wlan ip_tnl_bitmap");
    894     if (wlan_info->ip_tnl_is_v6_bitmap == NULL) {
    895         _bcm_tr2_wlan_free_resources(unit);
    896 	return BCM_E_MEMORY;
    897     }
    898     sal_memset(wlan_info->ip_tnl_is_v6_bitmap, 0, SHR_BITALLOCSIZE(num_tnl));
    899 
    900     /* Allocate the VLAN group bitmap use count per VLAN */
    901     wlan_info->vlan_grp_bmp_use_cnt = (uint8 **)sal_alloc(BCM_VLAN_COUNT * 
    902                              sizeof(uint8 *), "VLAN group bitmap pointer list");
    903     if (wlan_info->vlan_grp_bmp_use_cnt == NULL) {
    904         _bcm_tr2_wlan_free_resources(unit);
    905 	return BCM_E_MEMORY;
    906     }
    907     for (i = 0; i < BCM_VLAN_COUNT; i++) {
    908         wlan_info->vlan_grp_bmp_use_cnt[i] = (uint8 *)sal_alloc(32 * 
    909                                             sizeof(uint8), "VLAN group bitmap");
    910         if (wlan_info->vlan_grp_bmp_use_cnt[i] == NULL) {
    911             _bcm_tr2_wlan_free_resources(unit);
    912             return BCM_E_MEMORY;
    913         }
    914         sal_memset(wlan_info->vlan_grp_bmp_use_cnt[i], 0, 32 * sizeof(uint8));
    915     }
    916 
    917     /* Create WLAN mutex */
    918     if (_wlan_mutex[unit] == NULL) {
    919         _wlan_mutex[unit] = sal_mutex_create("wlan mutex");
    920         if (_wlan_mutex[unit] == NULL) {
    921             _bcm_tr2_wlan_free_resources(unit);
    922             return BCM_E_MEMORY;
    923         }
    924     }
    925 
    926 #ifdef BCM_WARM_BOOT_SUPPORT
    927     if (SOC_WARM_BOOT(unit)) {
    928         /* Warm Boot recovery */
    929         rv = _bcm_tr2_wlan_reinit(unit); 
    930     } 
    931 #endif
    932 
    933     /* Enable egress VXLT lookup on the loopback port */
    934     BCM_IF_ERROR_RETURN(bcm_esw_vlan_control_port_set
    935                         (unit, 54, bcmVlanTranslateEgressEnable, 1));
    936 
    937     wlan_initialized[unit] = TRUE;
    938     return rv;
    939 }
    940 
    941 /*
    942  * Function:
    943  *      _bcm_tr2_wlan_hw_clear
    944  * Purpose:
    945  *     Perform HW tables clean up for WLAN module.
    946  * Parameters:
    947  *      unit     - Device Number
    948  * Returns:
    949  *      BCM_E_XXX
    950  */
    951 STATIC int
    952 _bcm_tr2_wlan_hw_clear(int unit)
    953 {
    954     int rv, rv_error = BCM_E_NONE;
    955 
    956     /* Delete all ports */
    957     rv = bcm_tr2_wlan_port_delete_all(unit);
    958     if (BCM_FAILURE(rv) && (BCM_E_NONE == rv_error)) {
    959         rv_error = rv;
    960     }
    961 
    962     /* Delete all clients */
    963     rv = bcm_tr2_wlan_client_delete_all(unit);
    964     if (BCM_FAILURE(rv) && (BCM_E_NONE == rv_error)) {
    965         rv_error = rv;
    966     }
    967 
    968     return rv_error;
    969 }
    970 
    971 /*
    972  * Function:
    973  *      bcm_wlan_detach
    974  * Purpose:
    975  *      Detach the WLAN software module
    976  * Parameters:
    977  *      unit     - Device Number
    978  * Returns:
    979  *      BCM_E_XXX
    980  */
    981 int 
    982 bcm_tr2_wlan_detach(int unit)
    983 {
    984     int rv = BCM_E_NONE;
    985 
    986     if (wlan_initialized[unit])
    987     {
    988         if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
    989             rv = _bcm_tr2_wlan_hw_clear(unit);
    990         }
    991 
    992         _bcm_tr2_wlan_free_resources(unit);
    993         wlan_initialized[unit] = FALSE;
    994     }
    995 
    996     return rv;
    997 }
    998 
    999 /*
   1000  * Function:
   1001  *      _bcm_tr2_wlan_client_api_to_hw
   1002  * Purpose:
   1003  *      Convert a hardware-independent WLAN client entry to a TR2 HW entry
   1004  * Parameters:
   1005  *      unit - Unit number
   1006  *      hw_entry - (OUT) Triumph 2 HW entry
   1007  *      info - Hardware-independent WLAN client entry
   1008  */
   1009 STATIC int
   1010 _bcm_tr2_wlan_client_api_to_hw(int unit, mpls_entry_entry_t *hw_entry, 
   1011                                bcm_wlan_client_t *info)
   1012 {
   1013     sal_memset(hw_entry, 0, sizeof(mpls_entry_entry_t));
   1014     if ((info->flags & BCM_WLAN_CLIENT_ROAMED_IN) && 
   1015         (info->flags & BCM_WLAN_CLIENT_ROAMED_OUT)) {
   1016         return BCM_E_PARAM;
   1017     }
   1018     if (BCM_MAC_IS_MCAST(info->mac)) {
   1019         return BCM_E_PARAM;
   1020     }
   1021     soc_MPLS_ENTRYm_field32_set(unit, hw_entry, VALIDf, 1);
   1022     soc_MPLS_ENTRYm_field32_set(unit, hw_entry, KEY_TYPEf, 4); /* WLAN MAC */
   1023     soc_mem_mac_addr_set(unit, MPLS_ENTRYm, hw_entry, WLAN_MAC__MAC_ADDRf, 
   1024                          info->mac);
   1025     if (info->flags & BCM_WLAN_CLIENT_ROAMED_IN) {
   1026         int vp;
   1027         if (!BCM_GPORT_IS_WLAN_PORT(info->home_agent) || 
   1028             !BCM_GPORT_IS_WLAN_PORT(info->wtp)) {
   1029             return BCM_E_PARAM;
   1030         } 
   1031         soc_MPLS_ENTRYm_field32_set(unit, hw_entry, WLAN_MAC__RICf, 1);
   1032         vp = BCM_GPORT_WLAN_PORT_ID_GET(info->home_agent);
   1033         soc_MPLS_ENTRYm_field32_set(unit, hw_entry, WLAN_MAC__RIC_HA_VPf, vp);
   1034         vp = BCM_GPORT_WLAN_PORT_ID_GET(info->wtp);
   1035         soc_MPLS_ENTRYm_field32_set(unit, hw_entry, WLAN_MAC__RIC_WTP_VPf, vp);
   1036     }
   1037     if (info->flags & BCM_WLAN_CLIENT_ROAMED_OUT) {
   1038         soc_MPLS_ENTRYm_field32_set(unit, hw_entry, WLAN_MAC__ROCf, 1);
   1039     }
   1040     if (info->flags & BCM_WLAN_CLIENT_AUTHORIZED) {
   1041         soc_MPLS_ENTRYm_field32_set(unit, hw_entry, WLAN_MAC__DOT1X_STATEf, 1);
   1042     }
   1043     return BCM_E_NONE;
   1044 }
   1045 
   1046 /*
   1047  * Function:
   1048  *      _bcm_tr2_wlan_client_api_from_hw
   1049  * Purpose:
   1050  *      Convert a TR2 HW entry to a hardware-independent WLAN client entry 
   1051  * Parameters:
   1052  *      unit - Unit number
   1053  *      hw_entry - Triumph 2 HW entry
   1054  *      info - (OUT) Hardware-independent WLAN client entry
   1055  */
   1056 STATIC int
   1057 _bcm_tr2_wlan_client_api_from_hw(int unit, bcm_wlan_client_t *info, 
   1058                                  mpls_entry_entry_t *hw_entry)
   1059 {
   1060     int vp;
   1061     sal_memset(info, 0, sizeof (bcm_wlan_client_t));
   1062     soc_mem_mac_addr_get(unit, MPLS_ENTRYm, hw_entry, WLAN_MAC__MAC_ADDRf, 
   1063                          info->mac);
   1064     if (soc_MPLS_ENTRYm_field32_get(unit, hw_entry, WLAN_MAC__RICf)) {
   1065         info->flags |= BCM_WLAN_CLIENT_ROAMED_IN;
   1066         vp = soc_MPLS_ENTRYm_field32_get(unit, hw_entry, 
   1067                                          WLAN_MAC__RIC_HA_VPf);
   1068         BCM_GPORT_WLAN_PORT_ID_SET(info->home_agent, vp);
   1069         vp = soc_MPLS_ENTRYm_field32_get(unit, hw_entry, 
   1070                                          WLAN_MAC__RIC_WTP_VPf);
   1071         BCM_GPORT_WLAN_PORT_ID_SET(info->wtp, vp);
   1072     }
   1073     if (soc_MPLS_ENTRYm_field32_get(unit, hw_entry, WLAN_MAC__ROCf)) {
   1074         info->flags |= BCM_WLAN_CLIENT_ROAMED_OUT;
   1075     }
   1076     if (soc_MPLS_ENTRYm_field32_get(unit, hw_entry, WLAN_MAC__DOT1X_STATEf)) {
   1077         info->flags |= BCM_WLAN_CLIENT_AUTHORIZED;
   1078     }
   1079     return BCM_E_NONE;
   1080 }
   1081 
   1082 /*
   1083  * Function:
   1084  *      bcm_wlan_client_add
   1085  * Purpose:
   1086  *      Add a wireless client to the database
   1087  * Parameters:
   1088  *      unit     - Device Number
   1089  *      info     - (IN/OUT) Wireless Client structure
   1090  * Returns:
   1091  *      BCM_E_XXX
   1092  */
   1093 int 
   1094 bcm_tr2_wlan_client_add(int unit, bcm_wlan_client_t *info)
   1095 {
   1096     int index, rv = BCM_E_UNAVAIL;
   1097     mpls_entry_entry_t client_entry_key, client_entry_lookup;
   1098 
   1099     WLAN_INIT(unit);
   1100 
   1101     BCM_IF_ERROR_RETURN
   1102         (_bcm_tr2_wlan_client_api_to_hw(unit, &client_entry_key, info));
   1103 
   1104     WLAN_LOCK(unit);
   1105     rv = soc_mem_search(unit, MPLS_ENTRYm, MEM_BLOCK_ANY, &index, 
   1106                         (void *)&client_entry_key, 
   1107                         (void *)&client_entry_lookup, 0);
   1108 
   1109     if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   1110         WLAN_UNLOCK(unit);
   1111         return rv;
   1112     } else if ((rv == BCM_E_NONE) && 
   1113                !(info->flags & BCM_WLAN_CLIENT_REPLACE)) {
   1114         WLAN_UNLOCK(unit);
   1115         return BCM_E_EXISTS;
   1116     }
   1117 
   1118     rv = soc_mem_insert(unit, MPLS_ENTRYm, MEM_BLOCK_ALL, 
   1119                                        (void *)&client_entry_key); 
   1120     WLAN_UNLOCK(unit);
   1121     return rv;
   1122 }
   1123 
   1124 /*
   1125  * Function:
   1126  *      bcm_wlan_client_delete
   1127  * Purpose:
   1128  *      Delete a wireless client from the database
   1129  * Parameters:
   1130  *      unit     - Device Number
   1131  *      mac      - MAC address of client (lookup key)
   1132  * Returns:
   1133  *      BCM_E_XXX
   1134  */
   1135 int 
   1136 bcm_tr2_wlan_client_delete(int unit, bcm_mac_t mac)
   1137 {
   1138     int index, rv = BCM_E_UNAVAIL;
   1139     mpls_entry_entry_t client_entry_key, client_entry_lookup;
   1140 
   1141     WLAN_INIT(unit);
   1142 
   1143     sal_memset(&client_entry_key, 0, sizeof(mpls_entry_entry_t));
   1144     sal_memset(&client_entry_lookup, 0, sizeof(mpls_entry_entry_t));
   1145 
   1146     soc_MPLS_ENTRYm_field32_set(unit, &client_entry_key, VALIDf, 1);
   1147     soc_MPLS_ENTRYm_field32_set(unit, &client_entry_key, KEY_TYPEf, 4); 
   1148     soc_mem_mac_addr_set(unit, MPLS_ENTRYm, &client_entry_key, 
   1149                          WLAN_MAC__MAC_ADDRf, mac); 
   1150     WLAN_LOCK(unit);
   1151     rv = soc_mem_search(unit, MPLS_ENTRYm, MEM_BLOCK_ANY, &index, 
   1152                         (void *)&client_entry_key, 
   1153                         (void *)&client_entry_lookup, 0);
   1154     if (BCM_FAILURE(rv)) {
   1155         WLAN_UNLOCK(unit);
   1156         return rv;
   1157     }
   1158     rv = soc_mem_delete(unit, MPLS_ENTRYm, MEM_BLOCK_ALL, 
   1159                         (void *)&client_entry_key);
   1160     WLAN_UNLOCK(unit);
   1161     return rv;
   1162 }
   1163 
   1164 /*
   1165  * Function:
   1166  *      bcm_wlan_client_delete_all
   1167  * Purpose:
   1168  *      Delete all wireless clients from the database
   1169  * Parameters:
   1170  *      unit     - Device Number
   1171  * Returns:
   1172  *      BCM_E_XXX
   1173  */
   1174 int 
   1175 bcm_tr2_wlan_client_delete_all(int unit)
   1176 {
   1177     int i, valid, key_type, index_min, index_max, rv = BCM_E_NONE;
   1178     mpls_entry_entry_t hw_entry;
   1179 
   1180     WLAN_INIT(unit);
   1181 
   1182     index_min = soc_mem_index_min(unit, MPLS_ENTRYm);
   1183     index_max = soc_mem_index_max(unit, MPLS_ENTRYm);
   1184     WLAN_LOCK(unit);
   1185     for (i = index_min; i <= index_max; i++) {
   1186         rv = soc_mem_read(unit, MPLS_ENTRYm, MEM_BLOCK_ANY, i, 
   1187                           (void *)&hw_entry);
   1188         if (BCM_FAILURE(rv)) {
   1189             break;
   1190         }
   1191         valid = soc_MPLS_ENTRYm_field32_get(unit, &hw_entry, VALIDf);
   1192         key_type = soc_MPLS_ENTRYm_field32_get(unit, &hw_entry, KEY_TYPEf);
   1193         if (!valid || (key_type != 0x4)) {
   1194             continue;
   1195         }
   1196         soc_MPLS_ENTRYm_field32_set(unit, &hw_entry, VALIDf, 0);
   1197         rv = soc_mem_write(unit, MPLS_ENTRYm, MEM_BLOCK_ALL, i, 
   1198                            (void *)&hw_entry);
   1199         if (BCM_FAILURE(rv)) {
   1200             break;
   1201         }
   1202     }
   1203     WLAN_UNLOCK(unit);
   1204     return rv;
   1205 }
   1206 
   1207 /*
   1208  * Function:
   1209  *      bcm_wlan_client_get
   1210  * Purpose:
   1211  *      Get a wireless client from the database
   1212  * Parameters:
   1213  *      unit     - Device Number
   1214  *      mac      - MAC address of client (lookup key)
   1215  *      info     - (IN/OUT) Wireless Client structure
   1216  * Returns:
   1217  *      BCM_E_XXX
   1218  */
   1219 int 
   1220 bcm_tr2_wlan_client_get(int unit, bcm_mac_t mac, bcm_wlan_client_t *info)
   1221 {
   1222     int index, rv = BCM_E_UNAVAIL;
   1223     mpls_entry_entry_t client_entry_key, client_entry_lookup;
   1224 
   1225     WLAN_INIT(unit);
   1226 
   1227     sal_memset(&client_entry_key, 0, sizeof(mpls_entry_entry_t));
   1228     sal_memset(&client_entry_lookup, 0, sizeof(mpls_entry_entry_t));
   1229 
   1230     soc_MPLS_ENTRYm_field32_set(unit, &client_entry_key, VALIDf, 1);
   1231     soc_MPLS_ENTRYm_field32_set(unit, &client_entry_key, KEY_TYPEf, 4);
   1232     soc_mem_mac_addr_set(unit, MPLS_ENTRYm, &client_entry_key, 
   1233                          WLAN_MAC__MAC_ADDRf, mac); 
   1234     rv = soc_mem_search(unit, MPLS_ENTRYm, MEM_BLOCK_ANY, &index, 
   1235                         (void *)&client_entry_key, 
   1236                         (void *)&client_entry_lookup, 0);
   1237     BCM_IF_ERROR_RETURN(rv);
   1238     bcm_wlan_client_t_init(info);
   1239     rv = _bcm_tr2_wlan_client_api_from_hw(unit, info, &client_entry_lookup);
   1240     return rv; 
   1241 }
   1242 
   1243 /*
   1244  * Function:
   1245  *      bcm_wlan_client_traverse
   1246  * Purpose:
   1247  *      Walks through the valid WLAN client entries and calls
   1248  *      the user supplied callback function for each entry.
   1249  * Parameters:
   1250  *      unit       - (IN) bcm device.
   1251  *      trav_fn    - (IN) Callback function.
   1252  *      user_data  - (IN) User data to be passed to callback function.
   1253  * Returns:
   1254  *      BCM_E_NONE - Success.
   1255  *      BCM_E_XXX
   1256  */
   1257 int
   1258 bcm_tr2_wlan_client_traverse(int unit,
   1259                              bcm_wlan_client_traverse_cb cb,
   1260                              void *user_data)
   1261 {
   1262     int i, index_min, index_max, rv = BCM_E_NONE;
   1263     int valid, key_type, *buffer = NULL;
   1264     mpls_entry_entry_t *hw_entry;
   1265     bcm_wlan_client_t info;
   1266 
   1267     WLAN_INIT(unit);
   1268 
   1269     index_min = soc_mem_index_min(unit, MPLS_ENTRYm);
   1270     index_max = soc_mem_index_max(unit, MPLS_ENTRYm);
   1271 
   1272     WLAN_LOCK(unit);
   1273     buffer = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, MPLS_ENTRYm), 
   1274                            "wlan client traverse");
   1275     if (NULL == buffer) {
   1276         WLAN_UNLOCK(unit);
   1277         return BCM_E_MEMORY;
   1278     }
   1279     if ((rv = soc_mem_read_range(unit, MPLS_ENTRYm, MEM_BLOCK_ALL,
   1280                                  index_min, index_max, buffer)) < 0 ) {
   1281         soc_cm_sfree(unit, buffer);
   1282         WLAN_UNLOCK(unit);
   1283         return rv;
   1284     }
   1285     for (i = index_min; i <= index_max; i++) {
   1286         hw_entry = soc_mem_table_idx_to_pointer(unit, MPLS_ENTRYm,
   1287                                          mpls_entry_entry_t *, buffer, i);
   1288         valid = soc_MPLS_ENTRYm_field32_get(unit, hw_entry, VALIDf);
   1289         key_type = soc_MPLS_ENTRYm_field32_get(unit, hw_entry, KEY_TYPEf);
   1290         if (!valid || (key_type != 0x4)) {
   1291             continue;
   1292         }
   1293         bcm_wlan_client_t_init(&info);
   1294         rv = _bcm_tr2_wlan_client_api_from_hw(unit, &info, hw_entry);
   1295         if (BCM_FAILURE(rv)) {
   1296             soc_cm_sfree(unit, buffer);
   1297             WLAN_UNLOCK(unit);
   1298             return rv;
   1299         }
   1300         rv = cb(unit, &info, user_data);
   1301         if (BCM_FAILURE(rv)) {
   1302             soc_cm_sfree(unit, buffer);
   1303             WLAN_UNLOCK(unit); 
   1304             return rv;
   1305         }
   1306     }
   1307     soc_cm_sfree(unit, buffer);
   1308     WLAN_UNLOCK(unit);
   1309     return rv;
   1310 }
   1311 
   1312 /*
   1313  * Function:
   1314  *      _bcm_tr2_wlan_port_resolve
   1315  * Purpose:
   1316  *      Get the modid, port, trunk values for a WLAN port
   1317  * Returns:
   1318  *      BCM_E_XXX
   1319  */
   1320 int
   1321 _bcm_tr2_wlan_port_resolve(int unit, bcm_gport_t wlan_port_id,
   1322                           bcm_module_t *modid, bcm_port_t *port,
   1323                           bcm_trunk_t *trunk_id, int *id)
   1324 
   1325 {
   1326     int rv = BCM_E_NONE, nh_index, vp;
   1327     ing_l3_next_hop_entry_t ing_nh;
   1328     ing_dvp_table_entry_t dvp;
   1329 
   1330     WLAN_INIT(unit);
   1331 
   1332     if (!BCM_GPORT_IS_WLAN_PORT(wlan_port_id)) {
   1333         return (BCM_E_BADID);
   1334     }
   1335 
   1336     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1337     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   1338         return BCM_E_NOT_FOUND;
   1339     }
   1340     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   1341     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   1342                                               NEXT_HOP_INDEXf);
   1343     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1344                                       nh_index, &ing_nh));
   1345 
   1346     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x2) {
   1347         /* Entry type is not L2 DVP */
   1348         return BCM_E_NOT_FOUND;
   1349     }
   1350     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1351         *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1352     } else {
   1353         /* Only add this to replication set if destination is local */
   1354         *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1355         *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1356     }
   1357     *id = vp;
   1358     return rv;
   1359 }
   1360 
   1361 /*
   1362  * Function:
   1363  *      bcm_tr2_wlan_port_learn_get
   1364  * Purpose:
   1365  *      Get the CML bits for an wlan port
   1366  * Returns:
   1367  *      BCM_E_XXX
   1368  */
   1369 int
   1370 bcm_tr2_wlan_port_learn_get(int unit, bcm_gport_t wlan_port_id, uint32 *flags)
   1371 {
   1372     int rv, cml = 0;
   1373     uint32 vp;
   1374     source_vp_entry_t svp;
   1375     int lport_ptr = 0;
   1376     lport_tab_entry_t lport_profile;
   1377     rtag7_port_based_hash_entry_t rtag7_entry;
   1378     void *entries[2];
   1379 
   1380     WLAN_INIT(unit);
   1381 
   1382     /* Get the VP index from the gport */
   1383     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1384 
   1385     /* Be sure the entry is used and is set for VPLS */
   1386     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeAny)) {
   1387         return BCM_E_NOT_FOUND;
   1388     }
   1389     rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp);
   1390     BCM_IF_ERROR_RETURN(rv);
   1391 
   1392     /* Get lport_profile */
   1393     lport_ptr = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, 
   1394                                                 LPORT_PROFILE_IDXf);
   1395     entries[0] = &lport_profile;
   1396     entries[1] = &rtag7_entry;
   1397     rv = _bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries);
   1398     BCM_IF_ERROR_RETURN(rv);
   1399     cml = soc_LPORT_TABm_field32_get(unit, &lport_profile, CML_FLAGS_NEWf);
   1400 
   1401     *flags = 0;
   1402     if (!(cml & (1 << 0))) {
   1403        *flags |= BCM_PORT_LEARN_FWD;
   1404     }
   1405     if (cml & (1 << 1)) {
   1406        *flags |= BCM_PORT_LEARN_CPU;
   1407     }
   1408     if (cml & (1 << 2)) {
   1409        *flags |= BCM_PORT_LEARN_PENDING;
   1410     }
   1411     if (cml & (1 << 3)) {
   1412        *flags |= BCM_PORT_LEARN_ARL;
   1413     }
   1414     return BCM_E_NONE;
   1415 }
   1416 
   1417 /*
   1418  * Function:
   1419  *      bcm_tr2_wlan_port_learn_set
   1420  * Purpose:
   1421  *      Set the CML bits for an wlan port.
   1422  * Returns:
   1423  *      BCM_E_XXX
   1424  */
   1425 int
   1426 bcm_tr2_wlan_port_learn_set(int unit, bcm_gport_t wlan_port_id, uint32 flags)
   1427 {
   1428     int cml_old = 0, cml = 0, rv = BCM_E_NONE;
   1429     uint32 vp;
   1430     wlan_svp_table_entry_t svp;
   1431     lport_tab_entry_t lport_profile;
   1432     rtag7_port_based_hash_entry_t rtag7_entry;
   1433     int lport_ptr, old_lport_ptr = -1;
   1434     void *entries[2];
   1435 
   1436     WLAN_INIT(unit);
   1437 
   1438     cml = 0;
   1439     if (!(flags & BCM_PORT_LEARN_FWD)) {
   1440        cml |= (1 << 0);
   1441     }
   1442     if (flags & BCM_PORT_LEARN_CPU) {
   1443        cml |= (1 << 1);
   1444     }
   1445     if (flags & BCM_PORT_LEARN_PENDING) {
   1446        cml |= (1 << 2);
   1447     }
   1448     if (flags & BCM_PORT_LEARN_ARL) {
   1449        cml |= (1 << 3);
   1450     }
   1451 
   1452     /* Get the VP index from the gport */
   1453     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1454 
   1455     WLAN_LOCK(unit);
   1456     /* Be sure the entry is used and is set for WLAN */
   1457     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   1458         WLAN_UNLOCK(unit);
   1459         return BCM_E_NOT_FOUND;
   1460     }
   1461     rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp);
   1462     if (rv < 0) {
   1463         WLAN_UNLOCK(unit);
   1464         return rv;
   1465     }
   1466     /* Get old lport_profile */
   1467     old_lport_ptr = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, 
   1468                                                     LPORT_PROFILE_IDXf);
   1469     entries[0] = &lport_profile;
   1470     entries[1] = &rtag7_entry;
   1471     rv = _bcm_lport_profile_entry_get(unit, old_lport_ptr, 1, entries);
   1472     if (rv < 0) {
   1473         WLAN_UNLOCK(unit);
   1474         return rv;
   1475     }
   1476     cml_old = soc_LPORT_TABm_field32_get(unit, &lport_profile, CML_FLAGS_NEWf);
   1477     if (cml != cml_old) {
   1478         soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, cml);
   1479         soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, cml);
   1480         rv = _bcm_lport_profile_entry_add(unit, entries, 1, 
   1481                                           (uint32 *) &lport_ptr);
   1482         if (rv < 0) {
   1483             WLAN_UNLOCK(unit);
   1484             return rv;
   1485         }
   1486         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, LPORT_PROFILE_IDXf, 
   1487                                         lport_ptr);
   1488         /* coverity[negative_returns : FALSE] */
   1489         rv = WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp);
   1490         if (BCM_FAILURE(rv)) {
   1491             WLAN_UNLOCK(unit);
   1492             return rv;
   1493         }
   1494         rv = _bcm_lport_profile_entry_delete(unit, old_lport_ptr);
   1495     }
   1496     WLAN_UNLOCK(unit);
   1497     return rv;
   1498 }
   1499 
   1500 STATIC int
   1501 _bcm_tr2_wlan_l3_intf_add(int unit, _bcm_l3_intf_cfg_t *if_info)
   1502 {
   1503     int i, num_intf;
   1504     egr_l3_intf_entry_t egr_intf;
   1505     bcm_mac_t hw_mac;
   1506     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1507     for (i = 0; i < num_intf; i++) {
   1508         if (_BCM_WLAN_INTF_USED_GET(unit, i)) {
   1509             BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm,  
   1510                                              MEM_BLOCK_ANY, i, &egr_intf));
   1511             soc_mem_mac_addr_get(unit, EGR_L3_INTFm, &egr_intf, 
   1512                                  MAC_ADDRESSf, hw_mac);
   1513             if (SAL_MAC_ADDR_EQUAL(hw_mac, if_info->l3i_mac_addr)) {
   1514                 if_info->l3i_index = i;
   1515                 return BCM_E_NONE;
   1516             }
   1517         }
   1518     }
   1519     /* Create an interface */
   1520     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_intf_create(unit, if_info));
   1521     _BCM_WLAN_INTF_USED_SET(unit, if_info->l3i_index);
   1522     return BCM_E_NONE;
   1523 }
   1524 
   1525 typedef struct _bcm_tr2_ing_nh_info_s {
   1526     int      port;
   1527     int      module;
   1528     int      trunk;
   1529     uint32   mtu;
   1530 } _bcm_tr2_ing_nh_info_t;
   1531 
   1532 typedef struct _bcm_tr2_egr_nh_info_s {
   1533     uint8     entry_type;
   1534     uint16    capwap_mc_bitmap;
   1535     int       dvp;
   1536     int       intf_num;
   1537     bcm_mac_t macda;
   1538 } _bcm_tr2_egr_nh_info_t;
   1539 
   1540 STATIC int
   1541 _bcm_tr2_wlan_nh_info_add(int unit, bcm_wlan_port_t *wlan_port, int vp, int drop,
   1542                            int *nh_index, bcm_port_t *local_port, int *is_local) 
   1543 {
   1544     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   1545     ing_l3_next_hop_entry_t ing_nh;
   1546     egr_l3_next_hop_entry_t egr_nh;
   1547     _bcm_tr2_ing_nh_info_t ing_nh_info;
   1548     _bcm_tr2_egr_nh_info_t egr_nh_info;
   1549     bcm_l3_egress_t nh_info;
   1550     _bcm_l3_intf_cfg_t if_info;
   1551     uint32 nh_flags;
   1552     int gport_id, rv;
   1553     bcm_module_t mod_out;
   1554     bcm_port_t port_out;
   1555     bcm_trunk_t trunk_id;
   1556     _bcm_port_info_t *info;
   1557     uint32 port_flags;
   1558 
   1559     /* Initialize values */
   1560     sal_memset(&ing_nh_info, 0, sizeof(_bcm_tr2_ing_nh_info_t));
   1561     sal_memset(&egr_nh_info, 0, sizeof(_bcm_tr2_egr_nh_info_t));
   1562     *local_port = 0;
   1563     *is_local = 0;
   1564     ing_nh_info.mtu = 0x3fff; 
   1565     ing_nh_info.port = -1;
   1566     ing_nh_info.module = -1;
   1567     ing_nh_info.trunk = -1;
   1568 
   1569     egr_nh_info.dvp = vp;
   1570     egr_nh_info.intf_num = -1;
   1571     egr_nh_info.capwap_mc_bitmap = 0;
   1572     egr_nh_info.entry_type = 0x4;
   1573 
   1574     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   1575         if ((*nh_index > soc_mem_index_max(unit, EGR_L3_NEXT_HOPm)) ||
   1576             (*nh_index < soc_mem_index_min(unit, EGR_L3_NEXT_HOPm)))  {
   1577             return BCM_E_PARAM;
   1578         }
   1579         /* Read the existing egress next_hop entry */
   1580         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
   1581                           *nh_index, &egr_nh);
   1582         BCM_IF_ERROR_RETURN(rv);
   1583     } else {
   1584         /*
   1585          * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
   1586          * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
   1587          * allocated but nothing is written to hardware. The "nh_info"
   1588          * in this case is not used, so just set to all zeros.
   1589          */
   1590         bcm_l3_egress_t_init(&nh_info);
   1591 
   1592         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
   1593         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, nh_index);
   1594         BCM_IF_ERROR_RETURN(rv);
   1595     }
   1596 
   1597     /* Resolve the gport */
   1598     rv = _bcm_esw_gport_resolve(unit, wlan_port->port, &mod_out, 
   1599                                 &port_out, &trunk_id, &gport_id);
   1600     BCM_IF_ERROR_RETURN(rv);
   1601 
   1602     if (BCM_GPORT_IS_TRUNK(wlan_port->port)) {
   1603         ing_nh_info.module = -1;
   1604         ing_nh_info.port = -1;
   1605         ing_nh_info.trunk = trunk_id;
   1606         WLAN_INFO(unit)->port_info[vp].modid = -1;
   1607         WLAN_INFO(unit)->port_info[vp].port = -1;
   1608         WLAN_INFO(unit)->port_info[vp].tgid = trunk_id;
   1609     } else {
   1610         ing_nh_info.module = mod_out;
   1611         ing_nh_info.port = port_out;
   1612         ing_nh_info.trunk = -1;
   1613         BCM_IF_ERROR_RETURN(
   1614             _bcm_esw_modid_is_local(unit, mod_out, is_local));
   1615         if (TRUE == *is_local) {
   1616             /* Indicated to calling function that this is a local port */
   1617             *is_local = 1;
   1618             *local_port = ing_nh_info.port;
   1619         }
   1620         WLAN_INFO(unit)->port_info[vp].modid = mod_out;
   1621         WLAN_INFO(unit)->port_info[vp].port = port_out;
   1622         WLAN_INFO(unit)->port_info[vp].tgid = -1;
   1623     }
   1624 
   1625     if (wlan_port->flags & BCM_WLAN_PORT_EGRESS_CLIENT_MULTICAST) {
   1626         /* CAPWAP_WLAN_MC_BITMAP and MAC_ADDRESS are overlays */
   1627         egr_nh_info.capwap_mc_bitmap = wlan_port->client_multicast;
   1628     }
   1629 
   1630     /* Write INITIAL_ING_L3_NEXT_HOP entry */
   1631     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   1632     if (ing_nh_info.trunk == -1) {
   1633         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   1634                             &initial_ing_nh, PORT_NUMf, ing_nh_info.port);
   1635         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   1636                             &initial_ing_nh, MODULE_IDf, ing_nh_info.module);
   1637     } else {
   1638         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   1639                             &initial_ing_nh, Tf, 1);
   1640         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   1641                             &initial_ing_nh, TGIDf, ing_nh_info.trunk);
   1642         BCM_GPORT_TRUNK_SET(*local_port, ing_nh_info.trunk);
   1643     }
   1644     rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   1645                        MEM_BLOCK_ALL, *nh_index, &initial_ing_nh);
   1646     if (rv < 0) {
   1647         goto cleanup;
   1648     }
   1649 
   1650     /* Add an L3 interface entry with L2_SWITCH=1 - ref count if exists */
   1651     sal_memset(&if_info, 0, sizeof(_bcm_l3_intf_cfg_t));
   1652     if_info.l3i_flags |= BCM_L3_L2ONLY | BCM_L3_SECONDARY;
   1653     rv = _bcm_tr2_wlan_l3_intf_add(unit, &if_info);
   1654     if (BCM_FAILURE(rv)) {
   1655         goto cleanup;
   1656     }
   1657 
   1658     /* Populate the fields of WLAN::EGR_l3_NEXT_HOP */
   1659     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   1660     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1661                         ENTRY_TYPEf, egr_nh_info.entry_type);
   1662     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1663                         WLAN__DVPf, egr_nh_info.dvp);
   1664     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1665                         WLAN__INTF_NUMf, if_info.l3i_index);
   1666 
   1667     if (egr_nh_info.capwap_mc_bitmap != 0) {
   1668         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1669                             WLAN__CAPWAP_WLAN_MC_BITMAPf, 
   1670                             egr_nh_info.capwap_mc_bitmap);
   1671     }
   1672 
   1673     /* Write EGR_L3_NEXT_HOP entry */
   1674     rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   1675                        MEM_BLOCK_ALL, *nh_index, &egr_nh);
   1676     if (rv < 0) {
   1677         goto cleanup;
   1678     }
   1679 
   1680     /* Write ING_L3_NEXT_HOP entry */
   1681     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   1682     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, drop);
   1683     if (ing_nh_info.trunk == -1) {
   1684         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1685                             &ing_nh, PORT_NUMf, ing_nh_info.port);
   1686         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1687                             &ing_nh, MODULE_IDf, ing_nh_info.module);
   1688     } else {    
   1689         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1690                             &ing_nh, Tf, 1);
   1691         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1692                             &ing_nh, TGIDf, ing_nh_info.trunk);
   1693     }
   1694     if (drop) {
   1695         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, drop);
   1696     }
   1697     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1698                        &ing_nh, ENTRY_TYPEf, 0x2); /* L2 DVP */
   1699     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   1700                        &ing_nh, MTU_SIZEf, ing_nh_info.mtu);
   1701     rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
   1702                        MEM_BLOCK_ALL, *nh_index, &ing_nh);
   1703     if (rv < 0) {
   1704         goto cleanup;
   1705     }
   1706 
   1707     /* Update the physical port's SW state */
   1708     if (*is_local) {
   1709         bcm_port_t phys_port = WLAN_INFO(unit)->port_info[vp].port; 
   1710         if (soc_feature(unit, soc_feature_sysport_remap)) { 
   1711             BCM_XLATE_SYSPORT_S2P(unit, &phys_port); 
   1712         }
   1713         _bcm_port_info_access(unit, phys_port, &info);
   1714         info->vp_count++;
   1715         BCM_IF_ERROR_RETURN(
   1716             bcm_esw_port_vlan_member_get(
   1717                 unit, phys_port, &port_flags));
   1718         BCM_IF_ERROR_RETURN(
   1719             bcm_esw_port_vlan_member_set(
   1720                 unit, phys_port, port_flags));
   1721     }
   1722 
   1723     /* If associated with a trunk, update each local physical port's SW state */
   1724     if (ing_nh_info.trunk != -1) {
   1725         int idx;
   1726         bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   1727         int local_member_count;
   1728 
   1729         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
   1730                 SOC_MAX_NUM_PORTS, local_member_array, &local_member_count);
   1731         if (rv < 0) {
   1732             goto cleanup;
   1733         }
   1734         for (idx = 0; idx < local_member_count; idx++) {
   1735             _bcm_port_info_access(unit, local_member_array[idx], &info);
   1736             info->vp_count++;
   1737             BCM_IF_ERROR_RETURN(
   1738                 bcm_esw_port_vlan_member_get(
   1739                     unit, local_member_array[idx], &port_flags));
   1740             BCM_IF_ERROR_RETURN(
   1741                 bcm_esw_port_vlan_member_set(
   1742                     unit, local_member_array[idx], port_flags));
   1743         }
   1744     }
   1745 
   1746     return rv;
   1747 
   1748 cleanup:
   1749     if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   1750         (void) bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, *nh_index);
   1751     }
   1752     return rv;
   1753 }
   1754 
   1755 STATIC int
   1756 _bcm_tr2_wlan_nh_info_delete(int unit, int nh_index)
   1757 {
   1758     int rv;
   1759     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   1760     ing_l3_next_hop_entry_t ing_nh;
   1761     egr_l3_next_hop_entry_t egr_nh;
   1762 
   1763     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, 
   1764                                   MEM_BLOCK_ANY, nh_index, &egr_nh));
   1765 
   1766     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, 
   1767                                                 ENTRY_TYPEf) != 0x4) {
   1768         /* Not a WLAN VP */
   1769         return BCM_E_NOT_FOUND;
   1770     }
   1771 
   1772     /* Clear EGR_L3_NEXT_HOP entry */
   1773     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   1774     BCM_IF_ERROR_RETURN (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   1775                                    MEM_BLOCK_ALL, nh_index, &egr_nh));
   1776 
   1777     /* Clear ING_L3_NEXT_HOP entry */
   1778     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   1779     BCM_IF_ERROR_RETURN (soc_mem_write (unit, ING_L3_NEXT_HOPm,
   1780                                    MEM_BLOCK_ALL, nh_index, &ing_nh));
   1781 
   1782     /* Clear INITIAL_ING_L3_NEXT_HOP entry */
   1783     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   1784     BCM_IF_ERROR_RETURN (soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   1785                                    MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
   1786 
   1787     /* Free the next-hop entry. */
   1788     rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
   1789     return rv;
   1790 }
   1791 
   1792 STATIC int
   1793 _bcm_tr2_wlan_nh_info_get(int unit, bcm_wlan_port_t *wlan_port, int nh_index)
   1794 {
   1795     ing_l3_next_hop_entry_t ing_nh;
   1796     bcm_module_t mod_out, mod_in;
   1797     bcm_port_t port_out, port_in;
   1798     bcm_trunk_t trunk_id;
   1799 
   1800     /* Read the HW entries */
   1801     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
   1802                                       nh_index, &ing_nh));
   1803 
   1804     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, 
   1805                                                 ENTRY_TYPEf) == 0x2) {
   1806         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1807             trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1808             BCM_GPORT_TRUNK_SET(wlan_port->port, trunk_id);
   1809         } else {
   1810             mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1811             port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1812 
   1813             SOC_IF_ERROR_RETURN
   1814                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1815                                          mod_in, port_in, &mod_out, &port_out));
   1816             BCM_GPORT_MODPORT_SET(wlan_port->port, mod_out, port_out);
   1817         }
   1818     } else {
   1819         return BCM_E_NOT_FOUND;
   1820     }
   1821 
   1822     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, DROPf)) {
   1823         wlan_port->flags |= BCM_WLAN_PORT_DROP;
   1824     }
   1825 	
   1826     return BCM_E_NONE;
   1827 }
   1828 
   1829 STATIC int
   1830 _bcm_tr2_wlan_match_get(int unit, bcm_wlan_port_t *wlan_port, int vp)
   1831 {
   1832     int rv = BCM_E_NONE;
   1833     uint64 temp;
   1834 
   1835     if (WLAN_INFO(unit)->port_info[vp].flags & 
   1836          _BCM_WLAN_PORT_MATCH_TUNNEL) {
   1837 
   1838         wlan_port->flags |= BCM_WLAN_PORT_MATCH_TUNNEL;
   1839         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   1840 
   1841     } else if (WLAN_INFO(unit)->port_info[vp].flags & 
   1842                _BCM_WLAN_PORT_MATCH_BSSID_RADIO) {
   1843         wlan_port->flags |= BCM_WLAN_PORT_BSSID_RADIO;
   1844 
   1845         SAL_MAC_ADDR_TO_UINT64
   1846            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   1847         SAL_MAC_ADDR_FROM_UINT64(wlan_port->bssid, temp);
   1848         wlan_port->radio = WLAN_INFO(unit)->port_info[vp].match_radio;
   1849         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   1850 
   1851     } else if (WLAN_INFO(unit)->port_info[vp].flags & 
   1852                _BCM_WLAN_PORT_MATCH_BSSID) {
   1853         wlan_port->flags |= BCM_WLAN_PORT_BSSID;
   1854 
   1855         SAL_MAC_ADDR_TO_UINT64
   1856            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   1857         SAL_MAC_ADDR_FROM_UINT64(wlan_port->bssid, temp);
   1858         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   1859     }
   1860     return rv;
   1861 }
   1862 
   1863 STATIC int
   1864 _bcm_tr2_wlan_match_delete(int unit, int vp)
   1865 {
   1866     int rv = BCM_E_NONE;
   1867     egr_vlan_xlate_entry_t vent;
   1868     uint32 tunnel;
   1869 
   1870     sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1871 
   1872     if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_BSSID) {
   1873         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x6);
   1874         soc_mem_mac_addr_set(unit, EGR_VLAN_XLATEm, &vent, WLAN_SVP__BSSIDf, 
   1875                              WLAN_INFO(unit)->port_info[vp].match_bssid);
   1876 
   1877     } else if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_BSSID_RADIO) {
   1878         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x7);
   1879         soc_mem_mac_addr_set(unit, EGR_VLAN_XLATEm, &vent, WLAN_SVP__BSSIDf, 
   1880                              WLAN_INFO(unit)->port_info[vp].match_bssid);
   1881         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__RIDf, 
   1882                                         WLAN_INFO(unit)->port_info[vp].match_radio);
   1883 
   1884     } else if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_TUNNEL) {
   1885         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x5);
   1886         tunnel = BCM_GPORT_TUNNEL_ID_GET(WLAN_INFO(unit)->port_info[vp].match_tunnel);
   1887         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__TUNNEL_IDf, 
   1888                                         tunnel);
   1889     }
   1890     rv = soc_mem_delete(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &vent);
   1891     return rv;
   1892 }
   1893 
   1894 STATIC int
   1895 _bcm_tr2_wlan_match_add(int unit, bcm_wlan_port_t *wlan_port, int vp)
   1896 {
   1897     int rv = BCM_E_NONE;
   1898     egr_vlan_xlate_entry_t vent;
   1899     uint32 tunnel;
   1900     uint64 temp;
   1901 
   1902     sal_memset(&vent, 0, sizeof(egr_vlan_xlate_entry_t));
   1903     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, VALIDf, 1);
   1904     soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__SVPf, vp);
   1905 
   1906     if (wlan_port->flags & BCM_WLAN_PORT_BSSID) {
   1907         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x6);
   1908         soc_mem_mac_addr_set(unit, EGR_VLAN_XLATEm, &vent, WLAN_SVP__BSSIDf, 
   1909                              wlan_port->bssid);
   1910         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   1911         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__EXP_TUNNEL_IDf, 
   1912                                         tunnel);
   1913         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID;
   1914         SAL_MAC_ADDR_TO_UINT64(wlan_port->bssid, temp);
   1915         SAL_MAC_ADDR_FROM_UINT64
   1916            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp); 
   1917         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   1918 
   1919     } else if (wlan_port->flags & BCM_WLAN_PORT_BSSID_RADIO) {
   1920         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x7);
   1921         soc_mem_mac_addr_set(unit, EGR_VLAN_XLATEm, &vent, WLAN_SVP__BSSIDf, 
   1922                              wlan_port->bssid);
   1923         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__RIDf, 
   1924                                         wlan_port->radio);
   1925         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   1926         if (tunnel > (1 << soc_mem_field_length(unit, EGR_VLAN_XLATEm, 
   1927                                                WLAN_SVP__EXP_TUNNEL_IDf)) - 1) {
   1928             return BCM_E_PARAM;
   1929         }
   1930         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__EXP_TUNNEL_IDf, 
   1931                                         tunnel);
   1932         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID_RADIO;
   1933         SAL_MAC_ADDR_TO_UINT64(wlan_port->bssid, temp);
   1934         SAL_MAC_ADDR_FROM_UINT64
   1935            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   1936         WLAN_INFO(unit)->port_info[vp].match_radio = wlan_port->radio;
   1937         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   1938 
   1939     } else if (wlan_port->flags & BCM_WLAN_PORT_MATCH_TUNNEL) {
   1940         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, ENTRY_TYPEf, 0x5);
   1941         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   1942         soc_EGR_VLAN_XLATEm_field32_set(unit, &vent, WLAN_SVP__TUNNEL_IDf, 
   1943                                         tunnel);
   1944         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_TUNNEL;
   1945         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   1946     }
   1947     rv = soc_mem_insert(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &vent);
   1948     return rv;
   1949 }
   1950 
   1951 /*
   1952  * Function:
   1953  *      bcm_wlan_port_add
   1954  * Purpose:
   1955  *      Create or replace a WLAN port
   1956  * Parameters:
   1957  *      unit  - (IN)  Device Number
   1958  *      wlan_port  - (IN/OUT) WLAN port configuration info
   1959  * Returns:
   1960  *      BCM_E_XXX
   1961  * Notes:
   1962  *      For AC-to-AC VPs, the match_tunnel and egress_tunnel must have the same
   1963  *      ID. That way we can use a single VP for both directions. This constrains
   1964  *      the application to use the lower half of the tunnel initiators.
   1965  */
   1966 int 
   1967 bcm_tr2_wlan_port_add(int unit, bcm_wlan_port_t *wlan_port)
   1968 {
   1969     int drop, mode, is_local = 0, rv = BCM_E_PARAM, nh_index = 0;
   1970     bcm_port_t local_port;
   1971     bcm_module_t my_modid;
   1972     int vp, num_vp, lport_ptr = -1;
   1973     int tpid_enable = 0, tpid_index;
   1974     wlan_svp_table_entry_t svp;
   1975     ing_dvp_table_entry_t dvp;
   1976     egr_wlan_dvp_entry_t wlan_dvp;
   1977     lport_tab_entry_t lport_profile;
   1978     rtag7_port_based_hash_entry_t rtag7_entry;
   1979     void *entries[2];
   1980     uint32 tunnel;
   1981     int cml_default_enable=0, cml_default_new=0, cml_default_move=0;
   1982     _bcm_vp_info_t vp_info;
   1983 
   1984     _bcm_vp_info_init(&vp_info);
   1985     vp_info.vp_type = _bcmVpTypeWlan;
   1986 
   1987     WLAN_INIT(unit);
   1988 
   1989     rv = bcm_xgs3_l3_egress_mode_get(unit, &mode);
   1990     BCM_IF_ERROR_RETURN(rv);
   1991     if (!mode) {
   1992         LOG_INFO(BSL_LS_BCM_L3,
   1993                  (BSL_META_U(unit,
   1994                              "L3 egress mode must be set first\n")));
   1995         return BCM_E_DISABLED;
   1996     }
   1997 
   1998     if (!BCM_GPORT_IS_TUNNEL(wlan_port->match_tunnel)) {
   1999         return BCM_E_BADID;
   2000     }
   2001 
   2002     WLAN_LOCK(unit);
   2003     /* Allocate a new VP or use provided one */
   2004     if (wlan_port->flags & BCM_WLAN_PORT_WITH_ID) {
   2005         if (!BCM_GPORT_IS_WLAN_PORT((wlan_port->wlan_port_id))) {
   2006             WLAN_UNLOCK(unit);
   2007             return BCM_E_PARAM;
   2008         }
   2009         vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port->wlan_port_id);
   2010         if (vp >= soc_mem_index_count(unit, WLAN_SVP_TABLEm)) {
   2011             WLAN_UNLOCK(unit);
   2012             return BCM_E_PARAM;
   2013         }
   2014         if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   2015             if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   2016                 WLAN_UNLOCK(unit);
   2017                 return BCM_E_EXISTS;
   2018             }
   2019         } else {
   2020             rv = _bcm_vp_used_set(unit, vp, vp_info);
   2021             if (rv < 0) {
   2022                 WLAN_UNLOCK(unit);
   2023                 return rv;
   2024             }
   2025         }
   2026     } else {
   2027         /* allocate a new VP index */
   2028         num_vp = soc_mem_index_count(unit, WLAN_SVP_TABLEm);
   2029         rv = _bcm_vp_alloc(unit, 0, (num_vp - 1), 1, WLAN_SVP_TABLEm, 
   2030                            vp_info, &vp);
   2031         if (rv < 0) {
   2032             WLAN_UNLOCK(unit);
   2033             return rv;
   2034         }
   2035     }
   2036 
   2037     /* Program, the next hop, matching and egress tables */
   2038     sal_memset(&lport_profile, 0, sizeof(lport_tab_entry_t));
   2039     sal_memset(&rtag7_entry, 0, sizeof(rtag7_port_based_hash_entry_t));
   2040 
   2041     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   2042         /* For existing ports, NH entry already exists */
   2043         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp);
   2044         if (rv < 0) {
   2045             WLAN_UNLOCK(unit);
   2046             return rv;
   2047         }
   2048         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   2049                                                   NEXT_HOP_INDEXf);
   2050         /* Read the existing SVP entry for potential modifications */
   2051         rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp);
   2052         if (rv < 0) {
   2053             WLAN_UNLOCK(unit);
   2054             return rv;
   2055         }
   2056     } else {
   2057         sal_memset(&svp, 0, sizeof(wlan_svp_table_entry_t));
   2058         sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
   2059         sal_memset(&wlan_dvp, 0, sizeof(egr_wlan_dvp_entry_t));
   2060         /* Allocate a default profile entry for SVPs */
   2061         rv = _bcm_fb2_outer_tpid_entry_add(unit, 0x8100, &tpid_index);
   2062         if (rv < 0) {
   2063             WLAN_UNLOCK(unit);
   2064             goto port_cleanup;
   2065         }
   2066         tpid_enable = (1 << tpid_index);
   2067         soc_LPORT_TABm_field32_set(unit, &lport_profile, PORT_VIDf, 0x1);
   2068         soc_LPORT_TABm_field32_set(unit, &lport_profile,  
   2069                                    TRUST_INCOMING_VIDf, 0x1);
   2070         soc_LPORT_TABm_field32_set(unit, &lport_profile,  
   2071                                    TRUST_OUTER_DOT1Pf, 0x1);
   2072         soc_LPORT_TABm_field32_set(unit, &lport_profile,  
   2073                                    OUTER_TPID_ENABLEf, tpid_enable);
   2074         soc_LPORT_TABm_field32_set(unit, &lport_profile,  
   2075                                    MAC_BASED_VID_ENABLEf, 0x1);
   2076         if (!(wlan_port->flags & BCM_WLAN_PORT_NETWORK)) {
   2077             soc_LPORT_TABm_field32_set(unit, &lport_profile,  
   2078                                        PORT_BRIDGEf, 0x1);
   2079         }
   2080         soc_LPORT_TABm_field32_set(unit, &lport_profile, 
   2081                                    SUBNET_BASED_VID_ENABLEf, 0x1);
   2082         /* Set the CML */
   2083         rv = _bcm_vp_default_cml_mode_get (unit, 
   2084                            &cml_default_enable, &cml_default_new, 
   2085                            &cml_default_move);
   2086          if (rv < 0) {
   2087             WLAN_UNLOCK(unit);
   2088             goto port_cleanup;
   2089          }
   2090 
   2091         if (cml_default_enable) {
   2092             /* Set the CML to default values */
   2093            soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, cml_default_new);
   2094            soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, cml_default_move);
   2095         } else {
   2096             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
   2097             soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, 0x8);
   2098             soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, 0x8);
   2099         }
   2100 
   2101         soc_LPORT_TABm_field32_set(unit, &lport_profile, PRI_MAPPINGf, 
   2102                                    0xfac688);
   2103         soc_LPORT_TABm_field32_set(unit, &lport_profile, CFI_0_MAPPINGf, 0);
   2104         soc_LPORT_TABm_field32_set(unit, &lport_profile, CFI_1_MAPPINGf, 1);
   2105         soc_LPORT_TABm_field32_set(unit, &lport_profile, V4L3_ENABLEf, 0x1);
   2106         soc_LPORT_TABm_field32_set(unit, &lport_profile, V6L3_ENABLEf, 0x1);
   2107         soc_LPORT_TABm_field32_set(unit, &lport_profile, V4IPMC_ENABLEf, 0x1);
   2108         soc_LPORT_TABm_field32_set(unit, &lport_profile, V6IPMC_ENABLEf, 0x1);
   2109         soc_LPORT_TABm_field32_set(unit, &lport_profile, IPMC_DO_VLANf, 0x1);
   2110         soc_LPORT_TABm_field32_set(unit, &lport_profile, FILTER_ENABLEf, 0x1);
   2111         soc_LPORT_TABm_field32_set(unit, &lport_profile, VFP_ENABLEf, 0x1);
   2112         /* Allocate a fixed high index for the PORT_FIELD_SEL */
   2113         soc_LPORT_TABm_field32_set(unit, &lport_profile, 
   2114                                    FP_PORT_FIELD_SEL_INDEXf, 
   2115                                    soc_mem_index_max(unit, FP_PORT_FIELD_SELm));
   2116         /* The vt_key_types must be set to 0x3 or 0x7 for WLAN */
   2117         soc_LPORT_TABm_field32_set(unit, &lport_profile, VT_KEY_TYPEf,
   2118                                    TR_VLXLT_HASH_KEY_TYPE_VLAN_MAC);
   2119         soc_LPORT_TABm_field32_set(unit, &lport_profile, VT_KEY_TYPE_2f,
   2120                                    TR_VLXLT_HASH_KEY_TYPE_VLAN_MAC); 
   2121         /* Program MY_MODID for the LPORT entry */
   2122         rv = bcm_esw_stk_my_modid_get(unit, &my_modid);
   2123         if (rv < 0) {
   2124             WLAN_UNLOCK(unit);
   2125             goto port_cleanup;
   2126         }
   2127         soc_LPORT_TABm_field32_set(unit, &lport_profile, MY_MODIDf, my_modid);
   2128         entries[0] = &lport_profile;
   2129         entries[1] = &rtag7_entry;
   2130         rv = _bcm_lport_profile_entry_add(unit, entries, 1, 
   2131                                           (uint32 *) &lport_ptr);
   2132         if (rv < 0) {
   2133             WLAN_UNLOCK(unit);
   2134             goto port_cleanup;
   2135         }
   2136         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, LPORT_PROFILE_IDXf, 
   2137                                         lport_ptr);
   2138     }
   2139 
   2140     /* Program next hop entry using existing or new index */
   2141     drop = (wlan_port->flags & BCM_WLAN_PORT_DROP) ? 1 : 0;
   2142     rv = _bcm_tr2_wlan_nh_info_add(unit, wlan_port, vp, drop,
   2143                                    &nh_index, &local_port, &is_local);
   2144     if (rv < 0) {
   2145         WLAN_UNLOCK(unit);
   2146         goto port_cleanup;
   2147     }
   2148 
   2149     /* Program the VP tables */
   2150     if (wlan_port->flags & BCM_WLAN_PORT_NETWORK) {
   2151         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, SH_PRUNE_ENABLEf, 1);
   2152         soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, SH_PRUNE_ENABLEf, 1);
   2153     }
   2154 
   2155     /* Select HG2 PPD2 header for remote egress */
   2156     soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, HG_HDR_SELf, 1);
   2157     
   2158     /* Program the matching criteria */
   2159     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   2160         rv = WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp);
   2161         if (rv < 0) {
   2162             WLAN_UNLOCK(unit);
   2163             goto port_cleanup;
   2164         }
   2165     } else {
   2166         /* Link in the newly allocated next-hop entry */
   2167         soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NEXT_HOP_INDEXf,
   2168                                        nh_index);
   2169         rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   2170         if (rv < 0) {
   2171             WLAN_UNLOCK(unit);
   2172             goto port_cleanup;
   2173         }
   2174 
   2175         if ((wlan_port->flags & BCM_WLAN_PORT_BSSID) || 
   2176             (wlan_port->flags & BCM_WLAN_PORT_BSSID_RADIO)) {
   2177             soc_mem_mac_addr_set(unit, EGR_WLAN_DVPm, &wlan_dvp, BSSIDf, 
   2178                                  wlan_port->bssid);
   2179             if ((wlan_port->flags & BCM_WLAN_PORT_EGRESS_BSSID)) {
   2180                 soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, 
   2181                                               CAPWAP_BSSID_ENf, 1);
   2182             }
   2183         }
   2184         if (wlan_port->flags & BCM_WLAN_PORT_BSSID_RADIO) {
   2185             if (wlan_port->radio > 
   2186                 (1 << soc_mem_field_length(unit, EGR_WLAN_DVPm, RIDf)) - 1) {
   2187                 WLAN_UNLOCK(unit);
   2188                 rv = BCM_E_PARAM;
   2189                 goto port_cleanup;
   2190             } 
   2191             soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, RIDf, 
   2192                                           wlan_port->radio);
   2193         }
   2194         if (!BCM_GPORT_IS_TUNNEL(wlan_port->egress_tunnel)) {
   2195             WLAN_UNLOCK(unit);
   2196             rv = BCM_E_BADID;
   2197             goto port_cleanup;
   2198         }
   2199         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->egress_tunnel);
   2200         /* Program the tunnel VLAN from the cached state */
   2201         soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, TUNNEL_VLAN_IDf, 
   2202                                       TUNNEL_VLAN(unit, tunnel));
   2203         if (_BCM_WLAN_IP_TNL_IS_V6_GET(unit, tunnel)) {
   2204             tunnel >>= 1;
   2205         }
   2206         soc_EGR_WLAN_DVPm_field32_set(unit, &wlan_dvp, TUNNEL_INDEXf, tunnel); 
   2207         rv = WRITE_EGR_WLAN_DVPm(unit, MEM_BLOCK_ALL, vp, &wlan_dvp);
   2208         if (rv < 0) {
   2209             WLAN_UNLOCK(unit);
   2210             goto port_cleanup;
   2211         }
   2212 
   2213         /* Initialize the SVP parameters */
   2214         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, VLAN_IDf, 0x1);
   2215         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, VALIDf, 0x1);
   2216         rv = WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp);
   2217         if (rv < 0) {
   2218             WLAN_UNLOCK(unit);
   2219             goto port_cleanup;
   2220         }
   2221 
   2222         /*
   2223          * Match entries cannot be replaced, instead, callers
   2224          * need to delete the existing entry and re-add with the
   2225          * new match parameters.
   2226          */
   2227         rv = _bcm_tr2_wlan_match_add(unit, wlan_port, vp);
   2228         if (rv < 0) {
   2229             WLAN_UNLOCK(unit);
   2230             goto port_cleanup;
   2231         } else {
   2232             /* Set the WLAN port ID */
   2233             BCM_GPORT_WLAN_PORT_ID_SET(wlan_port->wlan_port_id, vp);
   2234             wlan_port->encap_id = nh_index;
   2235         }
   2236     }
   2237     WLAN_UNLOCK(unit);
   2238 port_cleanup:
   2239     if (rv < 0) {
   2240         if (tpid_enable) {
   2241             (void) _bcm_fb2_outer_tpid_entry_delete(unit, tpid_index);
   2242         }
   2243         if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   2244             (void) _bcm_vp_free(unit, _bcmVpTypeWlan, 1, vp);
   2245             _bcm_tr2_wlan_nh_info_delete(unit, nh_index);
   2246         }
   2247         if (lport_ptr != -1) {
   2248             (void) _bcm_lport_profile_entry_delete(unit, lport_ptr);
   2249         }
   2250     }
   2251     return rv;
   2252 }
   2253 
   2254 STATIC int
   2255 _bcm_tr2_wlan_port_delete(int unit, int vp)
   2256 {
   2257     int rv = BCM_E_NONE;
   2258     int nh_index = 0;
   2259     int lport_ptr = -1;
   2260     int is_local, i, tpid_enable = 0;
   2261     wlan_svp_table_entry_t svp;
   2262     ing_dvp_table_entry_t dvp;
   2263     egr_wlan_dvp_entry_t wlan_dvp;
   2264     lport_tab_entry_t lport_profile;
   2265     rtag7_port_based_hash_entry_t rtag7_entry;
   2266     _bcm_port_info_t *info;
   2267     void *entries[2];
   2268 
   2269     rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp);
   2270     BCM_IF_ERROR_RETURN(rv);
   2271     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2272 
   2273     rv = _bcm_tr2_wlan_match_delete(unit, vp);
   2274     BCM_IF_ERROR_RETURN(rv);
   2275 
   2276     /* Delete LPORT profile and its associated TPID entry */
   2277     rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp);
   2278     BCM_IF_ERROR_RETURN(rv);
   2279     lport_ptr = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, LPORT_PROFILE_IDXf);
   2280     entries[0] = &lport_profile;
   2281     entries[1] = &rtag7_entry;
   2282     rv = _bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries);
   2283     BCM_IF_ERROR_RETURN(rv);
   2284     tpid_enable = soc_LPORT_TABm_field32_get(unit, &lport_profile, 
   2285                                              OUTER_TPID_ENABLEf);
   2286     if (tpid_enable) {
   2287         for (i = 0; i < 4; i++) {
   2288             if (tpid_enable & (1 << i)) {
   2289                 (void) _bcm_fb2_outer_tpid_entry_delete(unit, i);
   2290                 break;
   2291             }
   2292         }
   2293     }
   2294     rv = _bcm_lport_profile_entry_delete(unit, lport_ptr);
   2295     BCM_IF_ERROR_RETURN(rv);
   2296 
   2297     /* Clear the SVP and DVP table entries */
   2298     sal_memset(&svp, 0, sizeof(wlan_svp_table_entry_t));
   2299     rv = WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp);
   2300     BCM_IF_ERROR_RETURN(rv);
   2301 
   2302     sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
   2303     rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   2304     BCM_IF_ERROR_RETURN(rv);
   2305 
   2306     sal_memset(&wlan_dvp, 0, sizeof(egr_wlan_dvp_entry_t));
   2307     rv = WRITE_EGR_WLAN_DVPm(unit, MEM_BLOCK_ALL, vp, &wlan_dvp);
   2308     BCM_IF_ERROR_RETURN(rv);
   2309 
   2310     /* Clear the next-hop table entries */
   2311     rv = _bcm_tr2_wlan_nh_info_delete(unit, nh_index);
   2312     BCM_IF_ERROR_RETURN(rv);
   2313 
   2314     /* Update the physical port's SW state */
   2315     BCM_IF_ERROR_RETURN(
   2316         _bcm_esw_modid_is_local(unit, WLAN_INFO(unit)->port_info[vp].modid, 
   2317                                 &is_local));
   2318     if (is_local && (WLAN_INFO(unit)->port_info[vp].tgid == -1)) {
   2319         bcm_port_t phys_port = WLAN_INFO(unit)->port_info[vp].port; 
   2320         if (soc_feature(unit, soc_feature_sysport_remap)) { 
   2321             BCM_XLATE_SYSPORT_S2P(unit, &phys_port); 
   2322         }
   2323         _bcm_port_info_access(unit, phys_port, &info);
   2324         info->vp_count--;
   2325     }
   2326 
   2327     /* If associated with a trunk, update each local physical port's SW state */
   2328     if (WLAN_INFO(unit)->port_info[vp].tgid != -1) {
   2329         int idx;
   2330         bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   2331        int local_member_count;
   2332 
   2333         bcm_trunk_t trunk_id = WLAN_INFO(unit)->port_info[vp].tgid;
   2334 
   2335         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, trunk_id,
   2336                     SOC_MAX_NUM_PORTS, local_member_array, &local_member_count));
   2337         for (idx = 0; idx < local_member_count; idx++) {
   2338             _bcm_port_info_access(unit, local_member_array[idx], &info);
   2339             info->vp_count--;
   2340         }
   2341     }
   2342 
   2343     /* Clear the SW state */
   2344     sal_memset(&(WLAN_INFO(unit)->port_info[vp]), 0, 
   2345                sizeof(_bcm_tr2_wlan_port_info_t));
   2346 
   2347     /* Release Service counter, if any */
   2348     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   2349         bcm_gport_t gport;
   2350 
   2351         BCM_GPORT_WLAN_PORT_ID_SET(gport, vp);
   2352         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
   2353     }
   2354 
   2355     /* Free the VP */
   2356     (void) _bcm_vp_free(unit, _bcmVpTypeWlan, 1, vp);
   2357     return rv;
   2358 }
   2359 
   2360 /*
   2361  * Function:
   2362  *      bcm_wlan_port_delete
   2363  * Purpose:
   2364  *      Delete a wlan port
   2365  * Parameters:
   2366  *      unit       - (IN) Device Number
   2367  *      wlan_port_id - (IN) wlan port information
   2368  * Returns:
   2369  *      BCM_E_XXX
   2370  */
   2371 int
   2372 bcm_tr2_wlan_port_delete(int unit, bcm_gport_t wlan_port_id)
   2373 {
   2374     int vp, rv;
   2375 
   2376     WLAN_INIT(unit);
   2377 
   2378     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   2379     if (vp == -1) {
   2380         return BCM_E_PARAM;
   2381     }
   2382 
   2383     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   2384         return BCM_E_NOT_FOUND;
   2385     }
   2386     WLAN_LOCK(unit);
   2387     rv = _bcm_tr2_wlan_port_delete(unit, vp);
   2388     WLAN_UNLOCK(unit);
   2389     return rv;
   2390 }
   2391 
   2392 /*
   2393  * Function:
   2394  *      bcm_wlan_port_delete_all
   2395  * Purpose:
   2396  *      Delete all wlan ports
   2397  * Parameters:
   2398  *      unit       - (IN) Device Number
   2399  * Returns:
   2400  *      BCM_E_XXX
   2401  */
   2402 int
   2403 bcm_tr2_wlan_port_delete_all(int unit)
   2404 {
   2405     int rv = BCM_E_NONE;
   2406     uint32 vp, num_vp;
   2407     source_vp_entry_t svp;
   2408 
   2409     WLAN_INIT(unit);
   2410 
   2411     num_vp = soc_mem_index_count(unit, WLAN_SVP_TABLEm);
   2412     for (vp = 0; vp < num_vp; vp++) {
   2413         rv = READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp);
   2414         if (rv < 0) {
   2415             goto done;
   2416         }
   2417         if (soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, VALIDf) != 0) {
   2418             WLAN_LOCK(unit);
   2419             rv = _bcm_tr2_wlan_port_delete(unit, vp);
   2420             WLAN_UNLOCK(unit);
   2421             if (rv < 0) {
   2422                 goto done;
   2423             }
   2424         }
   2425     }
   2426 done:
   2427     return rv;
   2428 }
   2429 
   2430 STATIC int
   2431 _bcm_tr2_wlan_port_get(int unit, int vp, bcm_wlan_port_t *wlan_port)
   2432 {
   2433     int egress_tunnel, nh_index, rv = BCM_E_NONE;
   2434     ing_dvp_table_entry_t dvp;
   2435     egr_wlan_dvp_entry_t wlan_dvp;
   2436 
   2437     /* Initialize the structure */
   2438     bcm_wlan_port_t_init(wlan_port);
   2439     BCM_GPORT_WLAN_PORT_ID_SET(wlan_port->wlan_port_id, vp);
   2440 
   2441     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   2442     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2443 
   2444     /* Fill the encap ID */
   2445     wlan_port->encap_id = nh_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   2446 
   2447     /* Get the match parameters */
   2448     rv = _bcm_tr2_wlan_match_get(unit, wlan_port, vp);
   2449     BCM_IF_ERROR_RETURN(rv);
   2450 
   2451     /* Get the next-hop parameters */
   2452     rv = _bcm_tr2_wlan_nh_info_get(unit, wlan_port, nh_index);
   2453     BCM_IF_ERROR_RETURN(rv);
   2454 
   2455     /* Fill in egress parameters */
   2456     BCM_IF_ERROR_RETURN(READ_EGR_WLAN_DVPm(unit, MEM_BLOCK_ANY, vp, &wlan_dvp));
   2457     egress_tunnel = soc_EGR_WLAN_DVPm_field32_get(unit, &wlan_dvp, 
   2458                                                   TUNNEL_INDEXf);
   2459     BCM_GPORT_TUNNEL_ID_SET(wlan_port->egress_tunnel, egress_tunnel);
   2460     if (soc_EGR_WLAN_DVPm_field32_get(unit, &wlan_dvp, SH_PRUNE_ENABLEf)) {
   2461         wlan_port->flags |= BCM_WLAN_PORT_NETWORK;
   2462     }
   2463     if (soc_EGR_WLAN_DVPm_field32_get(unit, &wlan_dvp, CAPWAP_BSSID_ENf)) {
   2464         wlan_port->flags |= BCM_WLAN_PORT_EGRESS_BSSID;
   2465     }
   2466     return rv;
   2467 }
   2468 
   2469 /*
   2470  * Function:
   2471  *      bcm_wlan_port_get
   2472  * Purpose:
   2473  *      Get a wlan port
   2474  * Parameters:
   2475  *      unit       - (IN) Device Number
   2476  *      wlan_port  - (IN/OUT) wlan port information
   2477  */
   2478 int
   2479 bcm_tr2_wlan_port_get(int unit, bcm_gport_t wlan_port_id, bcm_wlan_port_t *wlan_port)
   2480 {
   2481     int vp;
   2482 
   2483     WLAN_INIT(unit);
   2484 
   2485     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   2486     if (vp == -1) {
   2487         return BCM_E_PARAM;
   2488     }
   2489 
   2490     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   2491         return BCM_E_NOT_FOUND;
   2492     }
   2493     return _bcm_tr2_wlan_port_get(unit, vp, wlan_port);
   2494 }
   2495 
   2496 /*
   2497  * Function:
   2498  *      bcm_wlan_port_traverse
   2499  * Purpose:
   2500  *      Walks through the valid WLAN port entries and calls
   2501  *      the user supplied callback function for each entry.
   2502  * Parameters:
   2503  *      unit       - (IN) bcm device.
   2504  *      trav_fn    - (IN) Callback function.
   2505  *      user_data  - (IN) User data to be passed to callback function.
   2506  * Returns:
   2507  *      BCM_E_NONE - Success.
   2508  *      BCM_E_XXX
   2509  */
   2510 int
   2511 bcm_tr2_wlan_port_traverse(int unit,
   2512                            bcm_wlan_port_traverse_cb cb,
   2513                            void *user_data)
   2514 {
   2515     int i, index_min, index_max, rv = BCM_E_NONE;
   2516     int valid, wlan_port_id, *buffer = NULL;
   2517     wlan_svp_table_entry_t *hw_entry;
   2518     bcm_wlan_port_t info;
   2519 
   2520     WLAN_INIT(unit);
   2521 
   2522     index_min = soc_mem_index_min(unit, WLAN_SVP_TABLEm);
   2523     index_max = soc_mem_index_max(unit, WLAN_SVP_TABLEm);
   2524 
   2525     WLAN_LOCK(unit);
   2526     buffer = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, WLAN_SVP_TABLEm),
   2527                            "wlan port traverse");
   2528     if (NULL == buffer) {
   2529         WLAN_UNLOCK(unit);
   2530         return BCM_E_MEMORY;
   2531     }
   2532     if ((rv = soc_mem_read_range(unit, WLAN_SVP_TABLEm, MEM_BLOCK_ALL,
   2533                                  index_min, index_max, buffer)) < 0 ) {
   2534         soc_cm_sfree(unit, buffer);
   2535         WLAN_UNLOCK(unit);
   2536         return rv;
   2537     }
   2538     for (i = index_min; i <= index_max; i++) {
   2539         hw_entry = soc_mem_table_idx_to_pointer(unit, WLAN_SVP_TABLEm,
   2540                                          wlan_svp_table_entry_t *, buffer, i);
   2541         valid = soc_WLAN_SVP_TABLEm_field32_get(unit, hw_entry, VALIDf);
   2542         if (!valid) {
   2543             continue;
   2544         }
   2545         bcm_wlan_port_t_init(&info);
   2546         BCM_GPORT_WLAN_PORT_ID_SET(wlan_port_id, i);
   2547         rv = bcm_tr2_wlan_port_get(unit, wlan_port_id, &info);
   2548         if (BCM_FAILURE(rv)) {
   2549             soc_cm_sfree(unit, buffer);
   2550             WLAN_UNLOCK(unit);
   2551             return rv;
   2552         }
   2553         rv = cb(unit, &info, user_data);
   2554         if (BCM_FAILURE(rv)) {
   2555             soc_cm_sfree(unit, buffer);
   2556             WLAN_UNLOCK(unit); 
   2557             return rv;
   2558         }
   2559     }
   2560     soc_cm_sfree(unit, buffer);
   2561     WLAN_UNLOCK(unit);
   2562     return rv;
   2563 }
   2564 
   2565 
   2566 int
   2567 _bcm_esw_wlan_flex_stat_index_set(int unit, bcm_gport_t port, int fs_idx,uint32 flags)
   2568 {
   2569     int rv, nh_index;
   2570     ing_dvp_table_entry_t dvp;
   2571     uint32 vp;
   2572 
   2573     vp = BCM_GPORT_WLAN_PORT_ID_GET(port);
   2574 
   2575     WLAN_LOCK(unit);
   2576     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   2577         WLAN_UNLOCK(unit);
   2578         return BCM_E_NOT_FOUND;
   2579     } else {
   2580         rv = BCM_E_NONE;
   2581         /* Ingress side */
   2582         if (flags & _BCM_FLEX_STAT_HW_INGRESS) {
   2583             rv = soc_mem_field32_modify(unit, SOURCE_VPm, vp, VINTF_CTR_IDXf, 
   2584                                     fs_idx);
   2585         }
   2586         if (flags & _BCM_FLEX_STAT_HW_EGRESS) {
   2587             if (BCM_SUCCESS(rv)) {
   2588                 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp);
   2589                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   2590                                                 NEXT_HOP_INDEXf);
   2591                 /* Egress side */
   2592                 if (BCM_SUCCESS(rv)) {
   2593                     rv = soc_mem_field32_modify(unit, EGR_L3_NEXT_HOPm, 
   2594                                             nh_index,
   2595                                             VINTF_CTR_IDXf, fs_idx);
   2596                 }
   2597             }
   2598         }
   2599     }
   2600 
   2601     WLAN_UNLOCK(unit);
   2602     return rv;
   2603 }
   2604 
   2605 /*
   2606  * Function:
   2607  *      _bcm_tr2_wlan_tunnel_init_add
   2608  * Purpose:
   2609  *      Add tunnel initiator entry to hw. 
   2610  * Parameters:
   2611  *      unit     - (IN)SOC unit number.
   2612  *      idx      - (IN)Index to insert tunnel initiator.
   2613  *      info     - (IN)Tunnel initiator entry info.
   2614  * Returns:
   2615  *      BCM_E_XXX
   2616  */
   2617 STATIC int
   2618 _bcm_tr2_wlan_tunnel_init_add(int unit, int idx, bcm_tunnel_initiator_t *info)
   2619 {
   2620     uint32 tnl_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to write hw entry */
   2621     soc_mem_t mem;                        /* Tunnel initiator table memory */  
   2622     int df_val;                           /* Don't fragment encoding       */
   2623     int ipv6;                             /* IPv6 tunnel initiator         */
   2624     int entry_type = 0;                   /* HW entry type IPv4/IPv6/MPLS  */
   2625     int hw_type_code = 0;                 /* Tunnel type.                  */
   2626     int old_capwap_frag_profile = 0;      /* Old profile pointer           */
   2627     int capwap_frag_profile = -1;         /* New profile pointer           */
   2628     int old_tpid_index = -1;              /* Old TPID index                */
   2629     int tpid_index = -1;                  /* TPID index                    */
   2630     int rv = BCM_E_NONE;                  /* Return value                  */
   2631     uint64 rval64, *rval64s[1];           /* For the profile register      */
   2632     uint32 rval = 0;                      /* Register value                */
   2633 
   2634     ipv6 = _BCM_TUNNEL_OUTER_HEADER_IPV6(info->type);
   2635 
   2636     /* Tunnel VLAN needs to be programmed in the EGR_WLAN_DVP table. 
   2637      * We need to cache it so that the bcm_wlan_port_add API can
   2638      * program it in the correct location. It is always cached against
   2639      * the index to EGR_IP_TUNNEL for both V4 and V6 for simplicity. */
   2640     TUNNEL_VLAN(unit, idx) = info->vlan;
   2641 
   2642     /* Get table memory. */
   2643     if (ipv6) {
   2644         idx >>= 1;
   2645         mem = EGR_IP_TUNNEL_IPV6m;
   2646     } else {
   2647         mem = EGR_IP_TUNNELm; 
   2648     }
   2649 
   2650     /* Zero write buffer. */
   2651     sal_memset(tnl_entry, 0, sizeof(tnl_entry));
   2652 
   2653     /* If replacing existing entry, first read the entry to get old 
   2654        profile pointer and TPID */
   2655     if (info->flags & BCM_TUNNEL_REPLACE) {
   2656         rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, tnl_entry);
   2657         BCM_IF_ERROR_RETURN(rv);
   2658         old_capwap_frag_profile = soc_mem_field32_get(unit, mem, tnl_entry, 
   2659                                                       CAPWAP_MTU_SELf);
   2660         old_tpid_index = soc_mem_field32_get(unit, mem, tnl_entry, 
   2661                                              TUNNEL_TPID_INDEXf);
   2662         if (!(info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED)) {
   2663             soc_mem_field32_set(unit, mem, tnl_entry, VLAN_ASSIGN_POLICYf, 0);
   2664         }
   2665     }
   2666 
   2667     /* Set destination address. */
   2668     soc_mem_field_set(unit, mem, tnl_entry, DIPf, 
   2669                 ((ipv6) ? (uint32 *)info->dip6 : (uint32 *)&info->dip));
   2670 
   2671     /* Set source address. */
   2672     soc_mem_field_set(unit, mem, tnl_entry, SIPf,
   2673                 ((ipv6) ? (uint32 *)info->sip6 : (uint32 *)&info->sip));
   2674 
   2675     if (!ipv6) {
   2676         /* IP tunnel hdr DF bit for IPv4. */
   2677         df_val = 0;
   2678         if (info->flags & BCM_TUNNEL_INIT_USE_INNER_DF) {
   2679             df_val |= 0x2;
   2680         } else if (info->flags & BCM_TUNNEL_INIT_IPV4_SET_DF) {
   2681             df_val |= 0x1;
   2682         }
   2683         soc_mem_field32_set(unit, mem, tnl_entry, IPV4_DF_SELf, df_val);
   2684     }
   2685 
   2686     if (ipv6) {
   2687         /* IP tunnel hdr DF bit for IPv6. */
   2688         df_val = (info->flags & BCM_TUNNEL_INIT_IPV6_SET_DF) ? 0x1 : 0;
   2689         soc_mem_field32_set(unit, mem, tnl_entry, IPV6_DF_SELf, df_val);
   2690     }
   2691 
   2692     /* Set DSCP value.  */
   2693     soc_mem_field32_set(unit, mem, tnl_entry, DSCPf, info->dscp);
   2694 
   2695     /* Tunnel header DSCP select. */
   2696     soc_mem_field32_set(unit, mem, tnl_entry, DSCP_SELf, info->dscp_sel);
   2697 
   2698     /* Set TTL. */
   2699     soc_mem_field32_set(unit, mem, tnl_entry, TTLf, info->ttl);
   2700 
   2701     /* Set tunnel type. */
   2702     BCM_IF_ERROR_RETURN (_bcm_trx_tnl_type_to_hw_code(unit, info->type,
   2703                                                       &hw_type_code,
   2704                                                       &entry_type));
   2705 
   2706     soc_mem_field32_set(unit, mem, tnl_entry, TUNNEL_TYPEf, hw_type_code);
   2707 
   2708     /* Set flow label. */
   2709     if (ipv6) {
   2710         soc_mem_field32_set(unit, mem, tnl_entry, FLOW_LABELf,
   2711                             info->flow_label);
   2712     }
   2713 
   2714     /* Set entry type. */
   2715     soc_mem_field32_set(unit, mem, tnl_entry, ENTRY_TYPEf, entry_type);
   2716 
   2717     /* Set destination mac address. */
   2718     soc_mem_mac_addr_set(unit, mem, &tnl_entry, DEST_ADDRf, info->dmac);
   2719 
   2720     /* L4 fields */
   2721     soc_mem_field32_set(unit, mem, tnl_entry, L4_SRC_PORTf,
   2722                         info->udp_src_port);
   2723     soc_mem_field32_set(unit, mem, tnl_entry, L4_DEST_PORTf,
   2724                         info->udp_dst_port);
   2725 
   2726     /* L2 fields */
   2727     soc_mem_mac_addr_set(unit, mem, &tnl_entry, MACSAf, info->smac);
   2728     if (info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   2729         soc_mem_field32_set(unit, mem, tnl_entry, VLAN_ASSIGN_POLICYf, 1);
   2730         soc_mem_field32_set(unit, mem, tnl_entry, NEW_PRIf, info->pkt_pri);
   2731         soc_mem_field32_set(unit, mem, tnl_entry, NEW_CFIf, info->pkt_cfi);
   2732         rv = _bcm_fb2_outer_tpid_entry_add(unit, info->tpid, &tpid_index);
   2733         soc_mem_field32_set(unit, mem, tnl_entry, TUNNEL_TPID_INDEXf, 
   2734                             tpid_index);
   2735         if (BCM_FAILURE(rv)) {
   2736             goto tnl_cleanup;
   2737         }
   2738     }
   2739 
   2740     /* CAPWAP MTU */
   2741     if (info->flags & BCM_TUNNEL_INIT_WLAN_MTU && info->mtu > 0) {
   2742         uint32 first = (((info->mtu - 128) / 128) > 15) ? 15 : 
   2743                         ((info->mtu - 128) / 128);
   2744         soc_reg_field_set(unit, EGR_CAPWAP_FRAG_CONTROLr, &rval, MTUf, 
   2745                           info->mtu);
   2746         soc_reg_field_set(unit, EGR_CAPWAP_FRAG_CONTROLr, &rval,  
   2747                           FIRST_FRAG_SIZEf, first);
   2748         COMPILER_64_ZERO(rval64);
   2749         COMPILER_64_SET(rval64, 0, rval);
   2750         rval64s[0] = &rval64;
   2751         rv = soc_profile_reg_add(unit, CAPWAP_FRAG_PROFILE(unit), rval64s, 1, 
   2752                                  (uint32 *)&capwap_frag_profile);
   2753         if (BCM_FAILURE(rv)) {
   2754             goto tnl_cleanup;
   2755         }
   2756         soc_mem_field32_set(unit, mem, tnl_entry, CAPWAP_MTU_SELf,
   2757                             capwap_frag_profile);
   2758     }
   2759 
   2760     /* Write buffer to hw. */
   2761     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, tnl_entry);
   2762 
   2763     if (BCM_FAILURE(rv)) {
   2764         goto tnl_cleanup;
   2765     }
   2766     if (old_tpid_index != -1) {
   2767         (void)_bcm_fb2_outer_tpid_entry_delete(unit, old_tpid_index);
   2768     }
   2769     if (old_capwap_frag_profile != 0) {
   2770         rv = soc_profile_reg_delete(unit, CAPWAP_FRAG_PROFILE(unit), 
   2771                                     old_capwap_frag_profile);
   2772     }
   2773 tnl_cleanup:
   2774     if (BCM_FAILURE(rv)) {
   2775         if (tpid_index != -1) {
   2776             (void) _bcm_fb2_outer_tpid_entry_delete(unit, tpid_index);
   2777         }
   2778         if (capwap_frag_profile != -1) {
   2779             (void)soc_profile_reg_delete(unit, CAPWAP_FRAG_PROFILE(unit), 
   2780                                         capwap_frag_profile);
   2781         }
   2782     }
   2783     return rv;
   2784 }
   2785 
   2786 /*
   2787  * Function:
   2788  *      bcm_wlan_tunnel_initiator_create
   2789  * Purpose:
   2790  *      Create an outgong CAPWAP tunnel
   2791  * Parameters:
   2792  *      unit    - (IN) Device Number
   2793  *      info    - (IN/OUT) Tunnel initiator structure
   2794  */
   2795 int
   2796 bcm_tr2_wlan_tunnel_initiator_create(int unit, bcm_tunnel_initiator_t *info)
   2797 {
   2798     int tnl_idx, rv = BCM_E_NONE;
   2799     uint32 flags = 0;
   2800 
   2801     WLAN_INIT(unit);
   2802 
   2803     /* Input parameters check. */
   2804     if (NULL == info) {
   2805         return (BCM_E_PARAM);
   2806     }   
   2807     if ((info->type != bcmTunnelTypeWlanWtpToAc) && 
   2808         (info->type != bcmTunnelTypeWlanAcToAc) && 
   2809         (info->type != bcmTunnelTypeWlanWtpToAc6) && 
   2810         (info->type != bcmTunnelTypeWlanAcToAc6)) {
   2811         return BCM_E_PARAM;
   2812     }
   2813     if (!BCM_TTL_VALID(info->ttl)) {
   2814         return BCM_E_PARAM;
   2815     }
   2816     if (info->dscp_sel > 2 || info->dscp_sel < 0) {
   2817         return BCM_E_PARAM;
   2818     }
   2819     if (info->dscp > 63 || info->dscp < 0) {
   2820         return BCM_E_PARAM;
   2821     }
   2822     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(info->type)) {
   2823         if (info->flow_label > (1 << 20)) {
   2824             return BCM_E_PARAM;
   2825         }
   2826     }
   2827     if (!BCM_VLAN_VALID(info->vlan)) {
   2828         return BCM_E_PARAM;
   2829     }
   2830     if (BCM_MAC_IS_MCAST(info->smac) || BCM_MAC_IS_ZERO(info->smac)) {
   2831         return BCM_E_PARAM;
   2832     }
   2833     if (info->flags & BCM_TUNNEL_INIT_WLAN_TUNNEL_WITH_ID) {
   2834         if (!BCM_GPORT_IS_TUNNEL(info->tunnel_id)) {
   2835             return BCM_E_PARAM;
   2836         }
   2837         flags |= _BCM_L3_SHR_WITH_ID;
   2838         tnl_idx = BCM_GPORT_TUNNEL_ID_GET(info->tunnel_id);
   2839         if (info->flags & BCM_TUNNEL_REPLACE) {
   2840             if (!_BCM_WLAN_IP_TNL_USED_GET(unit, tnl_idx)) {
   2841                 return BCM_E_PARAM;
   2842             }
   2843             flags |= _BCM_L3_SHR_UPDATE;
   2844         }
   2845     }
   2846     if (info->flags & BCM_TUNNEL_INIT_WLAN_MTU) {
   2847         if (info->mtu < 0) {
   2848             return BCM_E_PARAM;
   2849         }
   2850     }
   2851     
   2852     WLAN_LOCK(unit);
   2853     /* Allocate either existing or new tunnel initiator entry */
   2854     flags |= _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE |
   2855              _BCM_L3_SHR_SKIP_INDEX_ZERO;
   2856     rv = bcm_xgs3_tnl_init_add(unit, flags, info, &tnl_idx);
   2857     if (BCM_FAILURE(rv)) {
   2858         WLAN_UNLOCK(unit);
   2859         return rv;
   2860     }
   2861     if (!(info->flags & BCM_TUNNEL_INIT_WLAN_TUNNEL_WITH_ID)) {
   2862         BCM_GPORT_TUNNEL_ID_SET(info->tunnel_id, tnl_idx);
   2863     }
   2864 
   2865     /* Write the entry to HW */
   2866     rv = _bcm_tr2_wlan_tunnel_init_add(unit, tnl_idx, info);
   2867     if (BCM_FAILURE(rv)) {
   2868         flags = _BCM_L3_SHR_WRITE_DISABLE;
   2869         (void) bcm_xgs3_tnl_init_del(unit, flags, tnl_idx);
   2870         WLAN_UNLOCK(unit);
   2871         return rv;
   2872     }
   2873 
   2874     /* Update usage bitmaps appropriately */
   2875     /* tnl_idx is always the index to EGR_IP_TUNNEL */
   2876     /* If writing to EGR_IP_TUNNEL_IPV6, need to divide by 2 */
   2877     _BCM_WLAN_IP_TNL_USED_SET(unit, tnl_idx);
   2878     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(info->type)) {
   2879         _BCM_WLAN_IP_TNL_IS_V6_SET(unit, tnl_idx);
   2880    }
   2881     WLAN_UNLOCK(unit);
   2882     return rv;
   2883 }
   2884 
   2885 /*
   2886  * Function:
   2887  *      _bcm_tr2_wlan_tunnel_init_get
   2888  * Purpose:
   2889  *      Get a tunnel initiator entry from hw. 
   2890  * Parameters:
   2891  *      unit     - (IN)SOC unit number.
   2892  *      idx      - (IN)Index to read tunnel initiator.
   2893  *      info     - (OUT)Tunnel initiator entry info.
   2894  * Returns:
   2895  *      BCM_E_XXX
   2896  */
   2897 STATIC int
   2898 _bcm_tr2_wlan_tunnel_init_get(int unit, int idx, bcm_tunnel_initiator_t *info,
   2899                               int *capwap_frag_profile, int *tpid_index)
   2900 {
   2901     uint32 tnl_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to read hw entry.  */
   2902     soc_mem_t mem;                         /* Tunnel initiator table memory.*/  
   2903     int df_val;                            /* Don't fragment encoded value. */
   2904     int tnl_type;                          /* Tunnel type.                  */
   2905     uint32 entry_type = BCM_XGS3_TUNNEL_INIT_V4;/* Entry type (IPv4/IPv6/MPLS)*/
   2906     uint32 rval;                           /* Generic register value */
   2907 
   2908     /* Get table memory. */
   2909     mem = EGR_IP_TUNNELm; 
   2910 
   2911     /* Initialize the buffer. */
   2912     sal_memset(tnl_entry, 0, sizeof(tnl_entry));
   2913 
   2914     /* Get tunnel VLAN from cache */
   2915     if (TUNNEL_VLAN(unit, idx) != 0) {
   2916         info->vlan = TUNNEL_VLAN(unit, idx);
   2917     }
   2918     
   2919     /* First read the entry to get the type */
   2920     BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, tnl_entry));
   2921 
   2922     /* Get entry_type. */
   2923     entry_type = soc_mem_field32_get(unit, mem, tnl_entry, ENTRY_TYPEf); 
   2924 
   2925     /* VLAN tag added or not */
   2926     if (soc_mem_field32_get(unit, mem, tnl_entry, VLAN_ASSIGN_POLICYf)) {
   2927         info->flags |= BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED;
   2928     }
   2929 
   2930     if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
   2931         mem = EGR_IP_TUNNEL_IPV6m; 
   2932         idx >>= 1;    /* Each record takes two slots. */
   2933         BCM_IF_ERROR_RETURN
   2934             (soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, tnl_entry)); 
   2935     }
   2936 
   2937     /* Get profiled data */
   2938     *capwap_frag_profile = soc_mem_field32_get(unit, mem, tnl_entry, 
   2939                                                CAPWAP_MTU_SELf);
   2940     *tpid_index = soc_mem_field32_get(unit, mem, tnl_entry, 
   2941                                       TUNNEL_TPID_INDEXf);
   2942 
   2943     /* Parse hw buffer. */
   2944     if (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) {
   2945         /* Get destination ip. */
   2946         info->dip = soc_mem_field32_get(unit, mem, tnl_entry, DIPf); 
   2947 
   2948         /* Get source ip. */
   2949         info->sip = soc_mem_field32_get(unit, mem, tnl_entry, SIPf);
   2950     } else if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
   2951         /* Get destination ip. */
   2952         soc_mem_field_get(unit, mem, tnl_entry, DIPf, (uint32 *)info->dip6);
   2953 
   2954         /* Get source ip. */
   2955         soc_mem_field_get(unit, mem, tnl_entry, SIPf, (uint32 *)info->sip6);
   2956     }
   2957 
   2958     /* Tunnel header DSCP select. */
   2959     info->dscp_sel = soc_mem_field32_get(unit, mem, tnl_entry, DSCP_SELf);
   2960 
   2961     /* Tunnel header DSCP value. */
   2962     info->dscp = soc_mem_field32_get(unit, mem, tnl_entry, DSCPf);
   2963 
   2964     /* IP tunnel hdr DF bit for IPv4 */
   2965     df_val = soc_mem_field32_get(unit, mem, tnl_entry, IPV4_DF_SELf);
   2966     if (0x2 <= df_val) {
   2967         info->flags |= BCM_TUNNEL_INIT_USE_INNER_DF;  
   2968     } else if (0x1 == df_val) {
   2969         info->flags |= BCM_TUNNEL_INIT_IPV4_SET_DF;  
   2970     }
   2971 
   2972     /* IP tunnel hdr DF bit for IPv6 */
   2973     if (soc_mem_field32_get(unit, mem, tnl_entry, IPV6_DF_SELf)) {
   2974         info->flags |= BCM_TUNNEL_INIT_IPV6_SET_DF;  
   2975     }
   2976 
   2977     /* Get TTL. */
   2978     info->ttl = soc_mem_field32_get(unit, mem, tnl_entry, TTLf);
   2979 
   2980     /* Get tunnel type. */
   2981     tnl_type = soc_mem_field32_get(unit, mem, tnl_entry, TUNNEL_TYPEf);
   2982 
   2983     /* Translate hw tunnel type into API encoding. */
   2984     BCM_IF_ERROR_RETURN(_bcm_trx_tnl_hw_code_to_type(unit, tnl_type,
   2985                                                      entry_type,
   2986                                                      &info->type));
   2987 
   2988     /* Get flow label for IPv6 */
   2989     if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
   2990         info->flow_label = 
   2991             soc_mem_field32_get(unit, mem, tnl_entry, FLOW_LABELf);
   2992     }
   2993 
   2994     /* Get L4 fields */
   2995     info->udp_dst_port = soc_mem_field32_get(unit, mem, tnl_entry, 
   2996                                                  L4_DEST_PORTf);
   2997     info->udp_src_port = soc_mem_field32_get(unit, mem, tnl_entry, 
   2998                                                  L4_SRC_PORTf);
   2999 
   3000     /* Get mac addresses */
   3001     soc_mem_mac_addr_get(unit, mem, tnl_entry, DEST_ADDRf, info->dmac);
   3002     soc_mem_mac_addr_get(unit, mem, tnl_entry, MACSAf, info->smac);
   3003 
   3004     /* Get other L2 fields */
   3005     if (info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   3006         info->pkt_pri = soc_mem_field32_get(unit, mem, tnl_entry, NEW_PRIf);
   3007         info->pkt_cfi = soc_mem_field32_get(unit, mem, tnl_entry, NEW_CFIf);
   3008         BCM_IF_ERROR_RETURN(READ_EGR_OUTER_TPIDr(unit, *tpid_index, &rval));
   3009         info->tpid = soc_reg_field_get(unit, EGR_OUTER_TPIDr, rval, TPIDf);    
   3010     }
   3011 
   3012     /* Get the MTU */
   3013     BCM_IF_ERROR_RETURN
   3014         (READ_EGR_CAPWAP_FRAG_CONTROLr(unit, *capwap_frag_profile, &rval));
   3015     info->mtu = soc_reg_field_get(unit, EGR_CAPWAP_FRAG_CONTROLr, rval, MTUf); 
   3016     info->flags |= BCM_TUNNEL_INIT_WLAN_MTU;
   3017 
   3018     return BCM_E_NONE;
   3019 }
   3020 
   3021 /*
   3022  * Function:
   3023  *      bcm_wlan_tunnel_initiator_destroy
   3024  * Purpose:
   3025  *      Destroy an outgong CAPWAP tunnel
   3026  * Parameters:
   3027  *      unit           - (IN) Device Number
   3028  *      wlan_tunnel_id - (IN) Tunnel ID (Gport)
   3029  */
   3030 int
   3031 bcm_tr2_wlan_tunnel_initiator_destroy(int unit, bcm_gport_t wlan_tunnel_id) 
   3032 {
   3033     int tnl_idx, rv = BCM_E_NONE;
   3034     uint32 flags = 0;
   3035     int capwap_frag_profile;               /* CAPWAP frag profile pointer */
   3036     int tpid_index;                        /* TPID index */
   3037     bcm_tunnel_initiator_t info;           /* Tunnel initiator structure */
   3038 
   3039     WLAN_INIT(unit);
   3040 
   3041     /* Input parameters check. */
   3042     if (!BCM_GPORT_IS_TUNNEL(wlan_tunnel_id)) {
   3043         return BCM_E_PARAM;
   3044     }
   3045     tnl_idx = BCM_GPORT_TUNNEL_ID_GET(wlan_tunnel_id);
   3046     if (!_BCM_WLAN_IP_TNL_USED_GET(unit, tnl_idx)) {
   3047         return BCM_E_PARAM;
   3048     }
   3049 
   3050     bcm_tunnel_initiator_t_init(&info);
   3051 
   3052     WLAN_LOCK(unit);
   3053     /* Get the entry first */
   3054     rv = _bcm_tr2_wlan_tunnel_init_get(unit, tnl_idx, &info, 
   3055                                        &capwap_frag_profile, &tpid_index);
   3056     if (BCM_FAILURE(rv)) {
   3057         WLAN_UNLOCK(unit);
   3058         return rv;
   3059     }
   3060 
   3061     /* Destroy the profiles */
   3062     (void)_bcm_fb2_outer_tpid_entry_delete(unit, tpid_index);
   3063     if (capwap_frag_profile != 0) {
   3064         rv = soc_profile_reg_delete(unit, CAPWAP_FRAG_PROFILE(unit), 
   3065                                     capwap_frag_profile);
   3066         if (BCM_FAILURE(rv)) {
   3067             WLAN_UNLOCK(unit);
   3068             return rv;
   3069         }
   3070     }
   3071 
   3072     /* Destroy the tunnel entry */
   3073     (void) bcm_xgs3_tnl_init_del(unit, flags, tnl_idx);
   3074 
   3075     /* Update usage bitmaps appropriately */
   3076     /* tnl_idx is always the index to EGR_IP_TUNNEL */
   3077     /* If writing to EGR_IP_TUNNEL_IPV6, need to divide by 2 */
   3078     _BCM_WLAN_IP_TNL_USED_CLR(unit, tnl_idx);
   3079     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(info.type)) {
   3080         _BCM_WLAN_IP_TNL_IS_V6_CLR(unit, tnl_idx);
   3081     }
   3082     TUNNEL_VLAN(unit, tnl_idx) = 0;
   3083     WLAN_UNLOCK(unit);
   3084     return rv;
   3085 }
   3086 
   3087 /*
   3088  * Function:
   3089  *      bcm_wlan_tunnel_initiator_get
   3090  * Purpose:
   3091  *      Get an outgong CAPWAP tunnel
   3092  * Parameters:
   3093  *      unit    - (IN) Device Number
   3094  *      info    - (IN/OUT) Tunnel initiator structure
   3095  */
   3096 int
   3097 bcm_tr2_wlan_tunnel_initiator_get(int unit, bcm_tunnel_initiator_t *info)
   3098 {
   3099     int tnl_idx, rv = BCM_E_NONE;
   3100     int capwap_frag_profile;               /* CAPWAP frag profile pointer */
   3101     int tpid_index;                        /* TPID index */
   3102 
   3103     WLAN_INIT(unit);
   3104 
   3105     /* Input parameters check. */
   3106     if (info == NULL) {
   3107         return BCM_E_PARAM;
   3108     }
   3109     if (!BCM_GPORT_IS_TUNNEL(info->tunnel_id)) {
   3110         return BCM_E_PARAM;
   3111     }
   3112     tnl_idx = BCM_GPORT_TUNNEL_ID_GET(info->tunnel_id);
   3113     if (!_BCM_WLAN_IP_TNL_USED_GET(unit, tnl_idx)) {
   3114         return BCM_E_NOT_FOUND;
   3115     }
   3116 
   3117     /* Get the entry */
   3118     rv = _bcm_tr2_wlan_tunnel_init_get(unit, tnl_idx, info, 
   3119                                        &capwap_frag_profile, &tpid_index);
   3120     return rv;
   3121 }
   3122 
   3123 /*
   3124  * Function:
   3125  *      bcm_tunnel_terminator_vlan_set 
   3126  * Purpose:
   3127  *      Set the allowed VLANs for a WLAN tunnel (AC2AC only)
   3128  * Parameters:
   3129  *      unit    - (IN)SOC unit number. 
   3130  *      tunnel  - (IN)Tunnel ID.
   3131  *      vlan_vec - (IN)VLAN vector
   3132  * Returns:
   3133  *      BCM_E_XXX
   3134  */
   3135 int
   3136 bcm_tr2_tunnel_terminator_vlan_set(int unit, bcm_gport_t tunnel, 
   3137                                    bcm_vlan_vector_t vlan_vec)
   3138 {
   3139     int i, tnl_idx, rv = BCM_E_NONE;
   3140     uint32 grp_bmp = 0, grp_bmp_union = 0, count = 0, diff = 0;
   3141     uint32 *buf;
   3142     vlan_tab_entry_t *vtab;    
   3143     bcm_vlan_vector_t vlan_vec_old;
   3144     int num_vp = 0, vp = -1, vvp = -1;
   3145     wlan_svp_table_entry_t svp;
   3146 
   3147     WLAN_INIT(unit);
   3148 
   3149     /* Input parameters check. */
   3150     if (!BCM_GPORT_IS_TUNNEL(tunnel)) {
   3151         return BCM_E_PARAM;
   3152     }
   3153     tnl_idx = BCM_GPORT_TUNNEL_ID_GET(tunnel);
   3154     if (!_BCM_WLAN_IP_TNL_USED_GET(unit, tnl_idx)) {
   3155         return BCM_E_PARAM;
   3156     }
   3157     if (BCM_VLAN_VEC_GET(vlan_vec, BCM_VLAN_MAX) || 
   3158         BCM_VLAN_VEC_GET(vlan_vec, BCM_VLAN_MIN)) {
   3159         return BCM_E_PARAM;
   3160     }
   3161 
   3162     WLAN_LOCK(unit);
   3163 
   3164     /* First get existing VLAN vector */
   3165     BCM_VLAN_VEC_ZERO(vlan_vec_old);
   3166     rv = bcm_tr2_tunnel_terminator_vlan_get(unit, tunnel, &vlan_vec_old);
   3167     if (BCM_FAILURE(rv)) {
   3168         WLAN_UNLOCK(unit);
   3169         return rv;
   3170     }
   3171 
   3172     /* Check if old == new and if old vector is empty */
   3173     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3174         if (BCM_VLAN_VEC_GET(vlan_vec_old, i) != 
   3175             BCM_VLAN_VEC_GET(vlan_vec, i)) {
   3176             diff = 1;
   3177             if (BCM_VLAN_VEC_GET(vlan_vec_old, i)) {
   3178                 count++;
   3179                 break;
   3180             }
   3181         }
   3182     }
   3183     if (!diff) {
   3184         WLAN_UNLOCK(unit);
   3185         return rv;
   3186     }
   3187 
   3188     /* Find the SVP corresponding to this tunnel */
   3189     num_vp = soc_mem_index_count(unit, WLAN_SVP_TABLEm);
   3190     for (i = 0; i < num_vp; i++) {
   3191         if ((WLAN_INFO(unit)->port_info[i].match_tunnel == tunnel) && 
   3192             (WLAN_INFO(unit)->port_info[i].flags & 
   3193              _BCM_WLAN_PORT_MATCH_TUNNEL)) {
   3194             /* Found the matching VP  - get the VLAN_VALIDATION_PTR */
   3195             BCM_IF_ERROR_RETURN
   3196                 (soc_mem_read(unit, WLAN_SVP_TABLEm, MEM_BLOCK_ANY, i, &svp));
   3197             if (!soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, VALIDf)) {
   3198                 WLAN_UNLOCK(unit);
   3199                 return BCM_E_INTERNAL;
   3200             }
   3201             vp = i;
   3202             vvp = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, 
   3203                                                   VLAN_VALIDATION_PTRf);
   3204             break;
   3205         }
   3206     }
   3207     if (vp == -1) {
   3208         WLAN_UNLOCK(unit);
   3209         return BCM_E_NOT_FOUND;
   3210     }
   3211 
   3212     /* DMA the VLAN table */
   3213     buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABm), 
   3214                         "vlan_table");
   3215     if (buf == NULL) {
   3216         WLAN_UNLOCK(unit);
   3217         return BCM_E_MEMORY;
   3218     }
   3219     soc_mem_lock(unit, VLAN_TABm);
   3220     if ((rv = soc_mem_read_range(unit, VLAN_TABm, MEM_BLOCK_ANY,
   3221                                  BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   3222         goto vlan_set_end;
   3223     }
   3224 
   3225     if (count == 0) {
   3226         /* Old vector is empty, allocate a new bit in VLAN_GROUP_BITMAP */
   3227         /* Otherwise use the existing VLAN_VALIDATION_PTR from the SVP */
   3228         for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3229             vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABm, 
   3230                                                 vlan_tab_entry_t *, buf, i);
   3231             if (!soc_mem_field32_get(unit, VLAN_TABm, vtab, VALIDf)) {
   3232                 if (BCM_VLAN_VEC_GET(vlan_vec, i)) {
   3233                     rv = BCM_E_NOT_FOUND;
   3234                     goto vlan_set_end;
   3235                 } else {
   3236                     continue;                                    
   3237                 } 
   3238             }
   3239             grp_bmp = soc_mem_field32_get(unit, VLAN_TABm, vtab, 
   3240                                           VLAN_GROUP_BITMAPf);
   3241             grp_bmp_union |= grp_bmp;
   3242         }
   3243         if (grp_bmp_union == 0xFFFFFFFF) {
   3244             rv = BCM_E_RESOURCE;
   3245             goto vlan_set_end;
   3246         }
   3247         /* Use the first available zero bit - skip vvp == 0 */
   3248         for (i = 1; i < soc_mem_field_length(unit, VLAN_TABm, 
   3249                                              VLAN_GROUP_BITMAPf); i++) {
   3250             if (((grp_bmp_union >> i) & 0x1) == 0) {
   3251                 vvp = i;
   3252                 break;
   3253             }
   3254         }
   3255     } 
   3256  
   3257     /* Write the VLAN_GROUP_BITMAP for all applicable VLANs */
   3258     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3259         vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABm, vlan_tab_entry_t *,
   3260                                             buf, i);
   3261         grp_bmp = soc_mem_field32_get(unit, VLAN_TABm, vtab, 
   3262                                       VLAN_GROUP_BITMAPf);
   3263         if (BCM_VLAN_VEC_GET(vlan_vec, i)) {
   3264             grp_bmp |= (1 << vvp);
   3265             /* Increase use-count for this bit for this VLAN */
   3266             WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp]++;
   3267         } else {
   3268             /* Decrease use-count for this bit for this VLAN */
   3269             if (BCM_VLAN_VEC_GET(vlan_vec_old, i)) {
   3270                 WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp]--;
   3271             }
   3272             if (WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp] == 0) {
   3273                 grp_bmp &= ~(1 << vvp);
   3274             }
   3275         }
   3276         soc_VLAN_TABm_field32_set(unit, vtab, VLAN_GROUP_BITMAPf, grp_bmp);
   3277     }
   3278     if ((rv = soc_mem_write_range(unit, VLAN_TABm, MEM_BLOCK_ALL,
   3279                                   BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   3280         goto vlan_set_end;
   3281     }
   3282     soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, VLAN_VALIDATION_PTRf, vvp);
   3283     rv = WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp);
   3284 vlan_set_end:
   3285     soc_mem_unlock(unit, VLAN_TABm);
   3286     WLAN_UNLOCK(unit);
   3287     soc_cm_sfree(unit, buf);
   3288     return rv;
   3289 }
   3290 
   3291 /*
   3292  * Function:
   3293  *      bcm_tunnel_terminator_vlan_get 
   3294  * Purpose:
   3295  *      Get the allowed VLANs for a WLAN tunnel (AC2AC only)
   3296  * Parameters:
   3297  *      unit    - (IN)SOC unit number. 
   3298  *      tunnel  - (IN)Tunnel ID.
   3299  *      vlan_vec - (OUT)VLAN vector
   3300  * Returns:
   3301  *      BCM_E_XXX
   3302  */
   3303 int
   3304 bcm_tr2_tunnel_terminator_vlan_get(int unit, bcm_gport_t tunnel, 
   3305                                    bcm_vlan_vector_t *vlan_vec)
   3306 {
   3307     int i, tnl_id, rv = BCM_E_NONE;
   3308     uint32 grp_bmp = 0;
   3309     vlan_tab_entry_t *vtab;    
   3310     uint32 *buf;
   3311     int num_vp = 0, vp = -1, vvp = -1;
   3312     wlan_svp_table_entry_t svp;
   3313 
   3314     WLAN_INIT(unit);
   3315 
   3316     /* Input parameters check. */
   3317     if (!BCM_GPORT_IS_TUNNEL(tunnel)) {
   3318         return BCM_E_PARAM;
   3319     }
   3320     tnl_id = BCM_GPORT_TUNNEL_ID_GET(tunnel);
   3321     if (!_BCM_WLAN_IP_TNL_USED_GET(unit, tnl_id)) {
   3322         return BCM_E_PARAM;
   3323     }
   3324     if (vlan_vec == NULL) {
   3325         return BCM_E_PARAM;
   3326     }
   3327 
   3328     /* Search the VP that corresponds to this tunnel */
   3329     num_vp = soc_mem_index_count(unit, WLAN_SVP_TABLEm);
   3330     for (i = 0; i < num_vp; i++) {
   3331         if ((WLAN_INFO(unit)->port_info[i].match_tunnel == tunnel) && 
   3332             (WLAN_INFO(unit)->port_info[i].flags & 
   3333              _BCM_WLAN_PORT_MATCH_TUNNEL)) {
   3334             /* Found the matching VP  - get the VLAN_VALIDATION_PTR */
   3335             BCM_IF_ERROR_RETURN
   3336                 (soc_mem_read(unit, WLAN_SVP_TABLEm, MEM_BLOCK_ANY, i, &svp));
   3337             if (!soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, VALIDf)) {
   3338                 return BCM_E_INTERNAL;
   3339             }
   3340             vp = i;
   3341             vvp = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, 
   3342                                                   VLAN_VALIDATION_PTRf);
   3343             break;
   3344         }
   3345     }
   3346     if (vp == -1) {
   3347         return BCM_E_NOT_FOUND;
   3348     }
   3349  
   3350     /* Compare against the VLAN_GROUP_BITMAP */
   3351     buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABm), 
   3352                         "vlan_table");
   3353     if (buf == NULL) {
   3354         return BCM_E_MEMORY;
   3355     }
   3356     if ((rv = soc_mem_read_range(unit, VLAN_TABm, MEM_BLOCK_ANY,
   3357                                  BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   3358         soc_cm_sfree(unit, buf);
   3359         return rv;
   3360     }
   3361     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3362         vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABm, vlan_tab_entry_t *,
   3363                                             buf, i);
   3364         if (!soc_mem_field32_get(unit, VLAN_TABm, vtab, VALIDf)) {
   3365             continue;                                     
   3366         }
   3367         grp_bmp = soc_mem_field32_get(unit, VLAN_TABm, vtab, 
   3368                                       VLAN_GROUP_BITMAPf);
   3369         if ((grp_bmp >> vvp) & 0x1) {
   3370             /* VLAN is allowed to come in on this AC 2 AC tunnel */
   3371             BCM_VLAN_VEC_SET((*vlan_vec), i);
   3372         }
   3373     }
   3374     soc_cm_sfree(unit, buf);
   3375     return rv;
   3376 }
   3377 
   3378 
   3379 /*
   3380  * Helper functions for setting/getting a field in the LPORT table and
   3381  * update corresponding reference in the WLAN_SVP_TABLE.
   3382  * Assumes locks are taken outside.
   3383  */
   3384 int
   3385 bcm_tr2_wlan_lport_field_set(int unit, bcm_gport_t wlan_port_id,
   3386                              soc_field_t field, int value)
   3387 {
   3388     int value_old = 0, rv = BCM_E_NONE;
   3389     uint32 vp;
   3390     wlan_svp_table_entry_t svp;
   3391     lport_tab_entry_t lport_profile;
   3392     rtag7_port_based_hash_entry_t rtag7_entry;
   3393     int lport_ptr, old_lport_ptr = -1;
   3394     void *entries[2];
   3395 
   3396     /* Check valid LPORT field */
   3397     if (!SOC_MEM_FIELD_VALID(unit, LPORT_TABm, field)) {
   3398         return BCM_E_UNAVAIL;
   3399     }
   3400 
   3401     /* Get the VP index from the gport */
   3402     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   3403 
   3404     /* Be sure the entry is used and is set for WLAN */
   3405     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   3406         return BCM_E_BADID;
   3407     }
   3408     BCM_IF_ERROR_RETURN(READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp));
   3409 
   3410     /* Get old lport_profile */
   3411     old_lport_ptr = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, 
   3412                                                     LPORT_PROFILE_IDXf);
   3413     entries[0] = &lport_profile;
   3414     entries[1] = &rtag7_entry;
   3415     BCM_IF_ERROR_RETURN
   3416         (_bcm_lport_profile_entry_get(unit, old_lport_ptr, 1, entries));
   3417     value_old = soc_LPORT_TABm_field32_get(unit, &lport_profile, field);
   3418     if (value != value_old) {
   3419         soc_LPORT_TABm_field32_set(unit, &lport_profile, field, value);
   3420         BCM_IF_ERROR_RETURN(_bcm_lport_profile_entry_add(unit, entries, 1, 
   3421                                                         (uint32 *) &lport_ptr));
   3422         soc_WLAN_SVP_TABLEm_field32_set(unit, &svp, LPORT_PROFILE_IDXf, 
   3423                                         lport_ptr);
   3424         /* coverity[negative_returns : FALSE] */
   3425         BCM_IF_ERROR_RETURN
   3426             (WRITE_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &svp));
   3427         BCM_IF_ERROR_RETURN
   3428             (_bcm_lport_profile_entry_delete(unit, old_lport_ptr));
   3429     }
   3430     return rv;
   3431 }
   3432 
   3433 int
   3434 bcm_tr2_wlan_lport_field_get(int unit, bcm_gport_t wlan_port_id, 
   3435                              soc_field_t field, int *value)
   3436 {
   3437     int rv = BCM_E_NONE;
   3438     uint32 vp;
   3439     wlan_svp_table_entry_t svp;
   3440     lport_tab_entry_t lport_profile;
   3441     rtag7_port_based_hash_entry_t rtag7_entry;
   3442     int lport_ptr;
   3443     void *entries[2];
   3444 
   3445     /* Check valid LPORT field */
   3446     if (!SOC_MEM_FIELD_VALID(unit, LPORT_TABm, field)) {
   3447         return BCM_E_UNAVAIL;
   3448     }
   3449 
   3450     /* Get the VP index from the gport */
   3451     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   3452 
   3453     /* Be sure the entry is used and is set for WLAN */
   3454     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   3455         return BCM_E_BADID;
   3456     }
   3457     BCM_IF_ERROR_RETURN(READ_WLAN_SVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &svp));
   3458 
   3459     /* Get old lport_profile */
   3460     lport_ptr = soc_WLAN_SVP_TABLEm_field32_get(unit, &svp, LPORT_PROFILE_IDXf);
   3461     entries[0] = &lport_profile;
   3462     entries[1] = &rtag7_entry;
   3463     BCM_IF_ERROR_RETURN
   3464         (_bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries));
   3465     *value = soc_LPORT_TABm_field32_get(unit, &lport_profile, field);
   3466     return rv;
   3467 }
   3468 
   3469 int
   3470 _bcm_tr2_wlan_port_set(int unit, bcm_gport_t wlan_port_id, soc_field_t field,
   3471                        uint32 value)
   3472 {
   3473     int rv = BCM_E_NONE;
   3474     WLAN_LOCK(unit);
   3475     rv = bcm_tr2_wlan_lport_field_set(unit, wlan_port_id, field, value);
   3476     WLAN_UNLOCK(unit);
   3477     return rv;
   3478 }
   3479 
   3480 int
   3481 bcm_tr2_wlan_port_untagged_vlan_set(int unit, bcm_gport_t port, bcm_vlan_t vid)
   3482 {
   3483     int old_profile, profile, rv = BCM_E_NONE;
   3484     bcm_vlan_action_set_t action;
   3485     WLAN_LOCK(unit);
   3486     /* Get current default tag action entry */
   3487     rv = bcm_tr2_wlan_lport_field_get(unit, port, TAG_ACTION_PROFILE_PTRf, 
   3488                                       &old_profile);
   3489     if (rv < 0) {
   3490         WLAN_UNLOCK(unit);
   3491         return rv;
   3492     }
   3493     bcm_vlan_action_set_t_init(&action);
   3494     _bcm_trx_vlan_action_profile_entry_get(unit, &action, old_profile);
   3495 
   3496     /* Add new tag action entry */
   3497     action.new_outer_vlan = vid;
   3498     rv = bcm_tr2_wlan_lport_field_get(unit, port,
   3499                                       PORT_PRIf, &(action.priority));
   3500     if (rv < 0) {
   3501         WLAN_UNLOCK(unit);
   3502         return rv;
   3503     }
   3504     rv = _bcm_trx_vlan_action_profile_entry_add(unit, &action, (uint32*) &profile);
   3505     if (rv < 0) {
   3506         WLAN_UNLOCK(unit);
   3507         return rv;
   3508     }
   3509     /* Set the port VID value */
   3510     rv = bcm_tr2_wlan_lport_field_set(unit, port, PORT_VIDf, vid);
   3511     if (rv < 0) {
   3512         WLAN_UNLOCK(unit);
   3513         return rv;
   3514     }
   3515     /* Point to the new profile */
   3516     rv = bcm_tr2_wlan_lport_field_set(unit, port, TAG_ACTION_PROFILE_PTRf,
   3517                                       profile);
   3518     if (rv < 0) {
   3519         WLAN_UNLOCK(unit);
   3520         return rv;
   3521     }
   3522     /* Delete the old profile */
   3523     rv = _bcm_trx_vlan_action_profile_entry_delete(unit, old_profile);
   3524     WLAN_UNLOCK(unit);
   3525     return rv;
   3526 }
   3527 
   3528 int
   3529 bcm_tr2_wlan_port_untagged_vlan_get(int unit, bcm_gport_t port, 
   3530                                     bcm_vlan_t *vid_ptr)
   3531 {
   3532     int value, rv = BCM_E_NONE;
   3533     rv = bcm_tr2_wlan_lport_field_get(unit, port, PORT_VIDf, &value);
   3534     *vid_ptr = (bcm_vlan_t)value;
   3535     return rv;
   3536 }
   3537 
   3538 int
   3539 bcm_tr2_wlan_port_untagged_prio_set(int unit, bcm_gport_t port, int prio)
   3540 {
   3541     int rv = BCM_E_NONE;
   3542     if (prio > 7) {
   3543         return BCM_E_PARAM;
   3544     }
   3545     rv = _bcm_tr2_wlan_port_set(unit, port, PORT_PRIf, prio);
   3546     return rv;
   3547 }
   3548 
   3549 int
   3550 bcm_tr2_wlan_port_untagged_prio_get(int unit, bcm_gport_t port, 
   3551                                     int *prio_ptr)
   3552 {
   3553     int value, rv = BCM_E_NONE;
   3554     rv = bcm_tr2_wlan_lport_field_get(unit, port, PORT_PRIf, &value);
   3555     *prio_ptr = value;
   3556     return rv;
   3557 }
   3558 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */