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


      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_TRIUMPH3_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/drv.h>
     17 #include <soc/hash.h>
     18 #include <soc/mem.h>
     19 #include <soc/scache.h>
     20 #include <soc/util.h>
     21 #include <soc/debug.h>
     22 #include <soc/triumph3.h>
     23 
     24 #include <bcm/error.h>
     25 #include <bcm/wlan.h>
     26 
     27 #include <bcm_int/esw/mbcm.h>
     28 #include <bcm_int/esw/l3.h>
     29 #include <bcm_int/esw/firebolt.h>
     30 #include <bcm_int/esw/triumph.h>
     31 #include <bcm_int/esw/triumph2.h>
     32 #include <bcm_int/esw/triumph3.h>
     33 #include <bcm_int/esw/xgs3.h>
     34 #include <bcm_int/common/multicast.h>
     35 #include <bcm_int/esw/virtual.h>
     36 #include <bcm_int/esw/trx.h>
     37 #include <bcm_int/esw/stack.h>
     38 
     39 #include <bcm_int/esw_dispatch.h>
     40 #include <bcm_int/api_xlate_port.h>
     41 
     42 /*
     43  * WLAN port state - need to remember where to find the port.
     44  * Flags indicate the type of the port and hence the tables where the data is.
     45  * The match attributes are the keys for the AXP_WRX_SVP table.
     46  */
     47 #define _BCM_WLAN_PORT_MATCH_BSSID                    (1 << 0)
     48 #define _BCM_WLAN_PORT_MATCH_BSSID_RADIO              (1 << 1)
     49 #define _BCM_WLAN_PORT_MATCH_TUNNEL                   (1 << 2)
     50 typedef struct _bcm_tr3_wlan_port_info_s {
     51     uint32 flags;
     52     bcm_trunk_t tgid; /* Trunk group ID */
     53     bcm_module_t modid; /* Module id */
     54     bcm_port_t port; /* Port */
     55     bcm_mac_t match_bssid;         /* Match BSSID */
     56     int match_radio;               /* Match radio */
     57     bcm_gport_t match_tunnel;      /* Match tunnel */
     58     bcm_gport_t egress_tunnel;     /* Egress tunnel */
     59 } _bcm_tr3_wlan_port_info_t;
     60 
     61 /*
     62  * Software book keeping for WLAN related information
     63  */
     64 typedef struct _bcm_tr3_wlan_bookkeeping_s {
     65     _bcm_tr3_wlan_port_info_t *port_info;   /* VP state                       */
     66     soc_profile_reg_t *wlan_tpid_profile;   /* WLAN TUNNEL TPID Profile       */
     67     soc_profile_mem_t *wlan_dvp_profile;    /* WLAN DVP Profile               */
     68     soc_profile_mem_t *wlan_frag_profile;   /* WLAN Fragment Id profile       */
     69     bcm_vlan_t  *tunnel_vlan;               /* Tunnel VLAN cache              */
     70     uint8       *tunnel_pri;                /* Tunnel VLAN priority           */
     71     uint8       *tunnel_cfi;                /* Tunnel VLAN CFI                */
     72     SHR_BITDCL  *intf_bitmap;               /* L3 interfaces used             */
     73     SHR_BITDCL  *wlan_tnl_bitmap;           /* WTX_TUNNEL index bitmap        */
     74     uint8       **vlan_grp_bmp_use_cnt;     /* Vlan group bitmap use count per VLAN */
     75 } _bcm_tr3_wlan_bookkeeping_t;
     76 
     77 static _bcm_tr3_wlan_bookkeeping_t  _bcm_tr3_wlan_bk_info[BCM_MAX_NUM_UNITS];
     78 
     79 /* initialized state machine */
     80 static int _tr3_wlan_initialized[BCM_MAX_NUM_UNITS];
     81 
     82 /* wlan module lock */
     83 static sal_mutex_t _tr3_wlan_mutex[BCM_MAX_NUM_UNITS] = {NULL};
     84 
     85 #define L3_INFO(unit)    (&_bcm_l3_bk_info[unit])
     86 #define WLAN_INFO(_unit_) (&_bcm_tr3_wlan_bk_info[_unit_])
     87 #define WLAN_TPID_PROFILE(_unit_) \
     88     (_bcm_tr3_wlan_bk_info[_unit_].wlan_tpid_profile)
     89 #define TUNNEL_VLAN(_unit_, _tnl_idx_) \
     90         (_bcm_tr3_wlan_bk_info[_unit_].tunnel_vlan[_tnl_idx_])
     91 #define TUNNEL_PRI(_unit_, _tnl_idx_) \
     92         (_bcm_tr3_wlan_bk_info[_unit_].tunnel_pri[_tnl_idx_])
     93 #define TUNNEL_CFI(_unit_, _tnl_idx_) \
     94         (_bcm_tr3_wlan_bk_info[_unit_].tunnel_cfi[_tnl_idx_])
     95 #define WLAN_DVP_PROFILE(_unit_) \
     96     (_bcm_tr3_wlan_bk_info[_unit_].wlan_dvp_profile)
     97 #define WLAN_FRAG_PROFILE(_unit_) \
     98     (_bcm_tr3_wlan_bk_info[_unit_].wlan_frag_profile)
     99 
    100 
    101 #define WLAN_INIT(unit)                                   \
    102     do {                                                  \
    103         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) {  \
    104             return BCM_E_UNIT;                            \
    105         }                                                 \
    106         if (!_tr3_wlan_initialized[unit]) {               \
    107             return BCM_E_INIT;                            \
    108         }                                                 \
    109     } while (0)
    110 
    111 /*
    112  * WLAN module lock
    113  */
    114 #define WLAN_LOCK(unit) \
    115         sal_mutex_take(_tr3_wlan_mutex[unit], sal_mutex_FOREVER);
    116 
    117 #define WLAN_UNLOCK(unit) \
    118         sal_mutex_give(_tr3_wlan_mutex[unit]);
    119 
    120 /*
    121  * WTX_TUNNEL table usage bitmap operations
    122  */
    123 #define _BCM_WLAN_TNL_USED_GET(_u_, _tnl_) \
    124         SHR_BITGET(WLAN_INFO(_u_)->wlan_tnl_bitmap, (_tnl_))
    125 #define _BCM_WLAN_TNL_USED_SET(_u_, _tnl_) \
    126         SHR_BITSET(WLAN_INFO((_u_))->wlan_tnl_bitmap, (_tnl_))
    127 #define _BCM_WLAN_TNL_USED_CLR(_u_, _tnl_) \
    128         SHR_BITCLR(WLAN_INFO((_u_))->wlan_tnl_bitmap, (_tnl_))
    129 
    130 /*
    131  * L3 interface usage bitmap operations
    132  */
    133 #define _BCM_WLAN_INTF_USED_GET(_u_, _intf_) \
    134         SHR_BITGET(WLAN_INFO(_u_)->intf_bitmap, (_intf_))
    135 #define _BCM_WLAN_INTF_USED_SET(_u_, _intf_) \
    136         SHR_BITSET(WLAN_INFO((_u_))->intf_bitmap, (_intf_))
    137 #define _BCM_WLAN_INTF_USED_CLR(_u_, _intf_) \
    138         SHR_BITCLR(WLAN_INFO((_u_))->intf_bitmap, (_intf_))
    139 
    140 /* WLAN TUNNEL IP TYPES */
    141 #define WLAN_TUNNEL_TYPE_V4       (0x0)
    142 #define WLAN_TUNNEL_TYPE_V6       (0x1)
    143 #define WLAN_TUNNEL_TYPE_AC2AC    (0x0)
    144 #define WLAN_TUNNEL_TYPE_WTP2AC   (0x1)
    145 
    146 /* Wlan tunnel entry width */
    147 #define _BCM_WLAN_TNL_ENTRY_WIDTH 4
    148 #define TNL_ENTRY_0 0
    149 #define TNL_ENTRY_1 1
    150 #define TNL_ENTRY_2 2
    151 #define TNL_ENTRY_3 3
    152 
    153 /* WLAN get tunnel index to/from tunnel id */
    154 #define WLAN_TNL_INDEX_TO_ID(idx) (idx / _BCM_WLAN_TNL_ENTRY_WIDTH)
    155 #define WLAN_TNL_ID_TO_INDEX(id)  (id * _BCM_WLAN_TNL_ENTRY_WIDTH)
    156 
    157 /* capwap encap sizes */
    158 #define IP_HDR_FIXED_LEN           20
    159 #define IP6_HDR_FIXED_LEN          40
    160 /*dmac(6)+smac(6)+8100(2)+vlan/Qos(2)+etype(2)+crc(4) */
    161 #define ETHER_SGL_TAG_FIXED_LEN    22
    162 /*Source port(2) + Destination port(2) + len(2) + cksum(2) */
    163 #define UDP_HDR_LEN                8
    164 /*
    165         0                   1                   2                   3
    166         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    167        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    168        |CAPWAP Preamble|  HLEN   |   RID   | WBID    |T|F|L|W|M|K|Flags|
    169        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    170        |          Fragment ID          |     Frag Offset         |Rsvd |
    171        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    172        |                 (optional) Radio MAC Address (8 bytes)        |
    173        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    174        |            (optional) Wireless Specific Information (8 bytes) |
    175        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    176 */
    177 #define CAPWAP_HDR_MAX_LEN         24
    178 #define CAPWAP_IPV4_ENCAP_LEN      (IP_HDR_FIXED_LEN + ETHER_SGL_TAG_FIXED_LEN + \
    179                                    UDP_HDR_LEN + CAPWAP_HDR_MAX_LEN)
    180 #define CAPWAP_IPV6_ENCAP_LEN      (IP6_HDR_FIXED_LEN + ETHER_SGL_TAG_FIXED_LEN + \
    181                                    UDP_HDR_LEN + CAPWAP_HDR_MAX_LEN)
    182 
    183 #define GET_CAPWAP_ENCAP_LEN(t)    (_BCM_TUNNEL_OUTER_HEADER_IPV6(t) ?  \
    184                                    CAPWAP_IPV6_ENCAP_LEN : CAPWAP_IPV4_ENCAP_LEN)
    185 
    186 /* AXP WTX priority map chunk size */
    187 #define _BCM_AXP_PRI_MAP_CHUNK 64
    188 
    189 /*
    190  * Function:
    191  *      _bcm_tr3_wlan_tnl_create
    192  * Purpose: 
    193  *      Function creates tunnel initiator unused index.
    194  *
    195  * Parameters: 
    196  *      unit        - (IN) bcm device
    197  *      tnl_id_p    - (OUT)tunnel id
    198  * Returns:
    199  *      BCM_E_NONE - Success
    200  *      BCM_E_XXX
    201  * Notes:
    202  */
    203 
    204 STATIC int
    205 _bcm_tr3_wlan_tnl_create(int unit, int *tnl_id_p)
    206 {
    207     int idx_cnt, max_idx;
    208     int         rv  = BCM_E_NONE;
    209     soc_mem_t   mem = AXP_WTX_TUNNELm;
    210    
    211     /* Validate Args */
    212     if ((NULL == tnl_id_p)) {
    213         return BCM_E_PARAM;
    214     }
    215          
    216     max_idx = (soc_mem_index_count(unit, mem) / _BCM_WLAN_TNL_ENTRY_WIDTH);
    217     
    218     /* Get First free index */
    219     for (idx_cnt = 0; idx_cnt < max_idx; idx_cnt++) {
    220         if (!_BCM_WLAN_TNL_USED_GET(unit, idx_cnt)) {
    221             *tnl_id_p = idx_cnt; /* free index */
    222             break;
    223        }
    224     }
    225    
    226     /* Check if all tunnel index is used */
    227     if (idx_cnt == max_idx) {
    228         *tnl_id_p = -1;
    229         return BCM_E_FULL; 
    230     }
    231 
    232     /* Set Tunnel index usage bitmap */
    233     _BCM_WLAN_TNL_USED_SET(unit, *tnl_id_p);
    234 
    235     return rv;
    236 }
    237 
    238 /*
    239  * Function:
    240  *      _bcm_tr3_wlan_tnl_delete
    241  * Purpose: 
    242  *      Function deletes tunnel entry for tunnel id
    243  *
    244  * Parameters: 
    245  *      unit       - (IN) bcm device
    246  *      tnl    - (IN) Tunnel index
    247  * Returns:
    248  *      BCM_E_NONE - Success
    249  *      BCM_E_XXX
    250  * Notes:
    251  */
    252 STATIC int
    253 _bcm_tr3_wlan_tnl_delete(int unit, int tnl_id) 
    254 {
    255     int idx_cnt, tnl_idx;
    256     axp_wtx_tunnel_entry_t axp_wtx_tunnel[4]; 
    257     int rv = BCM_E_NONE;
    258 
    259     tnl_idx =  WLAN_TNL_ID_TO_INDEX(tnl_id);
    260   
    261     /* Validate Args */
    262     if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_id)) {
    263         return BCM_E_PARAM;
    264     }
    265   
    266 
    267     sal_memset((void*)&axp_wtx_tunnel, 0, sizeof(axp_wtx_tunnel));
    268     /* clear tunnel entry for tunnel index */
    269     for (idx_cnt =0; idx_cnt < _BCM_WLAN_TNL_ENTRY_WIDTH; idx_cnt++) {
    270         rv = soc_mem_write(unit, AXP_WTX_TUNNELm, MEM_BLOCK_ALL, (tnl_idx + idx_cnt),
    271                            (void *)&axp_wtx_tunnel[idx_cnt]);
    272         if (BCM_FAILURE(rv)) {
    273             return rv;
    274         }
    275     }
    276 
    277     /* Clear tunnel bitmap usage */
    278     _BCM_WLAN_TNL_USED_CLR(unit, tnl_id);
    279     
    280     return rv;
    281 }
    282 
    283 /*
    284  * Function:
    285  *      _bcm_tr3_wlan_tnl_write
    286  * Purpose: 
    287  *      Function to write tunnel entries for tnl_id
    288  *
    289  * Parameters: 
    290  *      unit       - (IN) bcm device
    291  *      tnl_id     - (IN) Tunnel index
    292  *      tnl_entry_p- (OUT) tunnel entry
    293  * Returns:
    294  *      BCM_E_NONE - Success
    295  *      BCM_E_XXX
    296  * Notes:
    297  */
    298 STATIC int
    299 _bcm_tr3_wlan_tnl_write(int unit, int tnl_id, 
    300                                             axp_wtx_tunnel_entry_t *tnl_entries_p) 
    301 {
    302     int idx_cnt, tnl_idx;
    303     int rv = BCM_E_NONE;
    304     
    305 
    306     /* Validate Args */
    307     if (NULL == tnl_entries_p) {
    308         return BCM_E_PARAM;
    309     }
    310 
    311     tnl_idx = WLAN_TNL_ID_TO_INDEX(tnl_id);
    312     for (idx_cnt =0; idx_cnt < _BCM_WLAN_TNL_ENTRY_WIDTH; idx_cnt++) {
    313         /* Get Tunnel entries from wlan tunnel table */
    314         rv = soc_mem_write(unit, AXP_WTX_TUNNELm, MEM_BLOCK_ALL, (tnl_idx + idx_cnt),
    315                            (void *)&tnl_entries_p[idx_cnt]);
    316         if (BCM_FAILURE(rv)) {
    317             return rv;
    318         }
    319     }
    320 
    321     return rv;
    322 }
    323 
    324 /*
    325  * Function:
    326  *      _bcm_tr3_wlan_tnl_read
    327  * Purpose: 
    328  *      Function to read tunnel entries for tunnel id
    329  *
    330  * Parameters: 
    331  *      unit       - (IN) bcm device
    332  *      tnl_id     - (IN) Tunnel index
    333  *      tnl_entry_p- (OUT) tunnel entry
    334  * Returns:
    335  *      BCM_E_NONE - Success
    336  *      BCM_E_XXX
    337  * Notes:
    338  */
    339 STATIC int
    340 _bcm_tr3_wlan_tnl_read(int unit, int tnl_id, axp_wtx_tunnel_entry_t *tnl_entries_p) 
    341 {
    342     int idx_cnt, tnl_idx;
    343     int rv = BCM_E_NONE;
    344     
    345 
    346     /* Validate Args */
    347     if (NULL == tnl_entries_p) {
    348         return BCM_E_PARAM;
    349     }
    350 
    351     tnl_idx = WLAN_TNL_ID_TO_INDEX(tnl_id);
    352     for (idx_cnt =0; idx_cnt < _BCM_WLAN_TNL_ENTRY_WIDTH; idx_cnt++) {
    353         /* Get Tunnel entries from wlan tunnel table */
    354         rv = soc_mem_read(unit, AXP_WTX_TUNNELm, MEM_BLOCK_ALL, (tnl_idx + idx_cnt),
    355                            (void *)&tnl_entries_p[idx_cnt]);
    356         if (BCM_FAILURE(rv)) {
    357             return rv;
    358         }
    359     }
    360     return rv;
    361 }
    362 
    363 /*
    364  * Function:
    365  *      _bcm_tr3_wlan_profile_init
    366  * Purpose:
    367  *      Internal function to create profile for WLAN profile tables
    368  * Parameters:
    369  *      unit    -  (IN) Device number.
    370  * Returns:
    371  *      BCM_E_NONE - Success
    372  *      BCM_E_XXX
    373  */
    374 STATIC int
    375 _bcm_tr3_wlan_profile_init (int unit)
    376 {
    377     soc_mem_t   mem;
    378     soc_reg_t   reg;
    379     int         entry_words, alloc_size;
    380     void *entry;
    381     int rv = BCM_E_NONE;
    382     uint32 base_index, tpid_index;
    383     uint64 rval64, *rval64s[1];
    384 
    385     /*
    386      * Initialize WLAN dvp (AXP_WTX_DVP_PROFILE) profile
    387      * 2k entries with 1 entry per set
    388      */
    389     if (WLAN_DVP_PROFILE(unit) == NULL) {
    390         WLAN_DVP_PROFILE(unit) = sal_alloc (sizeof(soc_profile_mem_t),
    391                                                      "Axp wtx dvp profile mem");
    392         if (WLAN_DVP_PROFILE(unit) == NULL) {
    393             return BCM_E_MEMORY;
    394         }
    395         soc_profile_mem_t_init(WLAN_DVP_PROFILE(unit));
    396     } else {
    397         soc_profile_mem_destroy(unit, WLAN_DVP_PROFILE(unit));
    398     }
    399 
    400     mem = AXP_WTX_DVP_PROFILEm;
    401     entry_words = sizeof(axp_wtx_dvp_profile_entry_t) / sizeof(uint32);
    402     SOC_IF_ERROR_RETURN
    403         (soc_profile_mem_create(unit, &mem, &entry_words, 1,
    404                                 WLAN_DVP_PROFILE(unit)));
    405 
    406     /* Add wlan dvp default entry */
    407     alloc_size = sizeof(axp_wtx_dvp_profile_entry_t);
    408     entry = sal_alloc(alloc_size, "axp wtx dvp profile");
    409     if (entry == NULL) {
    410         return BCM_E_MEMORY;
    411     }
    412     sal_memset(entry, 0, alloc_size);
    413     rv = soc_profile_mem_add(unit, WLAN_DVP_PROFILE(unit), &entry, 1,
    414                              &base_index);
    415     sal_free(entry);
    416     if (BCM_FAILURE(rv)) {
    417         return rv;
    418     }
    419 
    420     /*
    421      * Initialize WLAN TPID (AXP_WTX_TUNNEL_TPID) profile
    422      */
    423     if (WLAN_TPID_PROFILE(unit) == NULL) {
    424         WLAN_TPID_PROFILE(unit) = sal_alloc(sizeof(soc_profile_reg_t),
    425                                          "Axp wtx tunnel tpid");
    426         if (WLAN_TPID_PROFILE(unit) == NULL) {
    427             return BCM_E_MEMORY;
    428         }
    429         soc_profile_reg_t_init(WLAN_TPID_PROFILE(unit));
    430     } else {
    431         soc_profile_reg_destroy(unit, WLAN_TPID_PROFILE(unit));
    432     }
    433 
    434     reg = AXP_WTX_TUNNEL_TPIDr;
    435     SOC_IF_ERROR_RETURN
    436         (soc_profile_reg_create(unit, &reg, 1, WLAN_TPID_PROFILE(unit)));
    437 
    438     /* Add default tpid entry */
    439     COMPILER_64_ZERO(rval64);
    440     rval64s[0] = &rval64;
    441     rv = soc_profile_reg_add(unit, WLAN_TPID_PROFILE(unit), rval64s, 1,
    442                             &tpid_index);
    443     if (BCM_FAILURE(rv)) {
    444         return rv;
    445     }
    446 
    447     /*
    448      * Initialize WLAN frag id table (AXP_WTX_FRAG_ID_PROFILE) profile
    449      * 1K entries of fragment id entries with 1 entry per set
    450      */
    451     if (WLAN_FRAG_PROFILE(unit) == NULL) {
    452         WLAN_FRAG_PROFILE(unit) = sal_alloc (sizeof(soc_profile_mem_t),
    453                                                      "Axp Wtx Frag Id mem");
    454         if (WLAN_FRAG_PROFILE(unit) == NULL) {
    455             return BCM_E_MEMORY;
    456         }
    457         soc_profile_mem_t_init(WLAN_FRAG_PROFILE(unit));
    458     } else {
    459         soc_profile_mem_destroy(unit, WLAN_FRAG_PROFILE(unit));
    460     }
    461 
    462     mem = AXP_WTX_FRAG_IDm;
    463     entry_words = sizeof(axp_wtx_frag_id_entry_t) / sizeof(uint32);
    464     SOC_IF_ERROR_RETURN
    465         (soc_profile_mem_create(unit, &mem, &entry_words, 1,
    466                                 WLAN_FRAG_PROFILE(unit)));
    467     /* Add wlan frag id default entry */
    468     alloc_size = sizeof(axp_wtx_frag_id_entry_t);
    469     entry = sal_alloc(alloc_size, "axp wtx frag id profile");
    470     if (entry == NULL) {
    471         return BCM_E_MEMORY;
    472     }
    473     sal_memset(entry, 0, alloc_size);
    474     rv = soc_profile_mem_add(unit, WLAN_FRAG_PROFILE(unit), &entry, 1,
    475                              &base_index);
    476     sal_free(entry);
    477     if (BCM_FAILURE(rv)) {
    478         return rv;
    479     }
    480 
    481     return BCM_E_NONE;
    482 }
    483 
    484 /*
    485  * Function:
    486  *      _bcm_tr3_wlan_profile_delete
    487  * Purpose:
    488  *      Internal function to delete all wlan profile tables
    489  * Parameters:
    490  *      unit    -  (IN) Device number.
    491  * Returns:
    492  *      BCM_E_NONE - Success
    493  *      BCM_E_XXX
    494  */
    495 STATIC int
    496 _bcm_tr3_wlan_profile_delete (int unit)
    497 {
    498     /* Destroy wlan frag profile */
    499     if (WLAN_FRAG_PROFILE(unit)) {
    500         BCM_IF_ERROR_RETURN(
    501             soc_profile_mem_destroy(unit, WLAN_FRAG_PROFILE(unit)));
    502         sal_free(WLAN_FRAG_PROFILE(unit));
    503         WLAN_FRAG_PROFILE(unit) = NULL;
    504     }
    505 
    506     /* Destroy wlan tpid profile */
    507     if (WLAN_TPID_PROFILE(unit)) {
    508         BCM_IF_ERROR_RETURN(
    509             soc_profile_reg_destroy(unit, WLAN_TPID_PROFILE(unit)));
    510         sal_free(WLAN_TPID_PROFILE(unit));
    511         WLAN_TPID_PROFILE(unit) = NULL;
    512     }
    513 
    514     /* Destroy wlan dvp profile */
    515     if (WLAN_DVP_PROFILE(unit)) {
    516         BCM_IF_ERROR_RETURN(
    517             soc_profile_mem_destroy(unit, WLAN_DVP_PROFILE(unit)));
    518         sal_free(WLAN_DVP_PROFILE(unit));
    519         WLAN_DVP_PROFILE(unit) = NULL;
    520     }
    521 
    522     return BCM_E_NONE;
    523 }
    524 
    525 /*
    526  * Function:
    527  *      _bcm_tr3_wlan_free_resources
    528  * Purpose:
    529  *      Free all allocated tables and memory
    530  * Parameters:
    531  *      unit - SOC unit number
    532  * Returns:
    533  *      Nothing
    534  */
    535 STATIC void
    536 _bcm_tr3_wlan_free_resources(int unit)
    537 {
    538     _bcm_tr3_wlan_bookkeeping_t *wlan_info = WLAN_INFO(unit);
    539     int i;
    540 
    541     /* Delete wlan table profiles */
    542     _bcm_tr3_wlan_profile_delete(unit);
    543 
    544     /* Destroy WLAN mutex */
    545     if (_tr3_wlan_mutex[unit]) {
    546         sal_mutex_destroy(_tr3_wlan_mutex[unit]);
    547         _tr3_wlan_mutex[unit] = NULL;
    548     }
    549 
    550     /* Destroy the VLAN group bitmap use count */
    551     if (wlan_info->vlan_grp_bmp_use_cnt) {
    552         for (i = 0; i < BCM_VLAN_COUNT; i++) {
    553             if (wlan_info->vlan_grp_bmp_use_cnt[i]) {
    554                 sal_free((uint8 *)(wlan_info->vlan_grp_bmp_use_cnt[i]));
    555                 wlan_info->vlan_grp_bmp_use_cnt[i] = NULL;
    556             }
    557         }
    558         sal_free(wlan_info->vlan_grp_bmp_use_cnt);
    559         wlan_info->vlan_grp_bmp_use_cnt = NULL;
    560     }
    561 
    562 
    563     /* Destroy EGR_L3_INTF usage bitmap */
    564     if (wlan_info->intf_bitmap) {
    565         sal_free(wlan_info->intf_bitmap);
    566         wlan_info->intf_bitmap = NULL;
    567     }
    568 
    569     /* Destroy tunnel VLAN cache */
    570     if (wlan_info->tunnel_vlan) {
    571         sal_free(wlan_info->tunnel_vlan);
    572         wlan_info->tunnel_vlan = NULL;
    573     }
    574 
    575     /* Destroy tunnel VLAN pri cache */
    576     if (wlan_info->tunnel_pri) {
    577         sal_free(wlan_info->tunnel_pri);
    578         wlan_info->tunnel_pri = NULL;
    579     }
    580 
    581     /* Destroy tunnel VLAN cfi cache */
    582     if (wlan_info->tunnel_cfi) {
    583         sal_free(wlan_info->tunnel_cfi);
    584         wlan_info->tunnel_cfi = NULL;
    585     }
    586 
    587 
    588 
    589     /* Destroy WTX_TUNNEL usage bitmap */
    590     if (wlan_info->wlan_tnl_bitmap) {
    591         sal_free(wlan_info->wlan_tnl_bitmap);
    592         wlan_info->wlan_tnl_bitmap = NULL;
    593     }
    594 
    595     /* Destroy WLAN port usage bitmap */
    596     if (wlan_info->port_info) {
    597         sal_free(wlan_info->port_info);
    598         wlan_info->port_info = NULL;
    599     }
    600 }
    601 
    602 #ifdef BCM_WARM_BOOT_SUPPORT
    603 
    604 /*
    605  * Function:
    606  *      _bcm_tr3_wlan_port_flex_stat_recover
    607  * Purpose: 
    608  *      This function retrieves flex stats from source vp table
    609  * Parameters: 
    610  *      unit       - (IN) bcm device
    611  *      source_vp  - (IN/OUT) source vp table
    612  *      index      - (IN) Source vp
    613  * Returns:
    614  *      BCM_E_NONE - Success
    615  *      BCM_E_XXX
    616  * Notes:
    617  */
    618 STATIC void
    619 _bcm_tr3_wlan_port_flex_stat_recover(int unit, source_vp_entry_t *source_vp,
    620                                      int index)
    621 {
    622     int fs_idx;
    623     if (soc_feature(unit, soc_feature_gport_service_counters)) {
    624         /* vp index into ING_VINTF_COUNTER_TABLE */
    625         if (soc_mem_field_valid(unit, SOURCE_VPm, VINTF_CTR_IDXf)) {
    626             fs_idx = soc_mem_field32_get(unit, SOURCE_VPm, source_vp,
    627                                          VINTF_CTR_IDXf);
    628             if (fs_idx) {
    629                 BCM_GPORT_WLAN_PORT_ID_SET(index, index);
    630                 _bcm_esw_flex_stat_reinit_add(unit, _bcmFlexStatTypeGport,
    631                                               fs_idx, index);
    632             }
    633         }
    634     }
    635     return;
    636 }
    637 /*
    638  * Function:
    639  *      _bcm_tr3_wlan_lport_tpid_recover
    640  * Purpose: 
    641  *      This function gets tpid reference from lport table
    642  * Parameters: 
    643  *      unit       - (IN) bcm device
    644  *      lport_tab  - (IN) LPORT Table
    645  * Returns:
    646  *      BCM_E_NONE - Success
    647  *      BCM_E_XXX
    648  * Notes:
    649  */
    650 STATIC int
    651 _bcm_tr3_wlan_lport_tpid_recover(int unit, lport_tab_entry_t *lport_tab)
    652 {
    653     int tpid_enable, index, rv = BCM_E_NONE;
    654     tpid_enable = soc_LPORT_TABm_field32_get(unit, lport_tab,
    655                                              OUTER_TPID_ENABLEf);
    656     for (index = 0; index < 4; index++) {
    657         if (tpid_enable & (1 << index)) {
    658             rv = _bcm_fb2_outer_tpid_tab_ref_count_add(unit, index, 1);
    659             break;
    660         }
    661     }
    662     return rv;
    663 }
    664 /*
    665  * Function:
    666  *      _bcm_tr3_wlan_port_associated_data_recover
    667  * Purpose: 
    668  *      This function recovers wlan port data
    669  * Parameters: 
    670  *      unit       - (IN) bcm device
    671  *      vp         - (IN) wlan virtual port
    672  *      stable_size- (IN) shared table size
    673  * Returns:
    674  *      BCM_E_NONE - Success
    675  *      BCM_E_XXX
    676  * Notes:
    677  */
    678 STATIC int
    679 _bcm_tr3_wlan_port_associated_data_recover(int unit, int vp, int stable_size)
    680 {
    681     int idx, nh_index, intf_num, rv = BCM_E_NONE;
    682     uint32                      nh_flags;
    683     ing_l3_next_hop_entry_t     ing_nh_entry;
    684     egr_l3_next_hop_entry_t     egr_nh_entry;
    685     ing_dvp_table_entry_t       ing_dvp_entry;
    686     bcm_module_t                mod_in, mod_out;
    687     bcm_port_t                  port_in, port_out, phys_port;
    688     bcm_trunk_t                 trunk_id;
    689     bcm_l3_egress_t             nh_info;
    690     _bcm_port_info_t            *info;
    691     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
    692     int local_member_count;
    693     uint32 port_flags;
    694 
    695     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_DVP_TABLEm, MEM_BLOCK_ANY,
    696                                      vp, &ing_dvp_entry));
    697     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
    698                                               NEXT_HOP_INDEXf);
    699     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    700                                      nh_index, &ing_nh_entry));
    701     BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    702                                      nh_index, &egr_nh_entry));
    703 
    704     bcm_l3_egress_t_init(&nh_info);
    705 
    706     nh_flags = _BCM_L3_SHR_UPDATE | _BCM_L3_SHR_WRITE_DISABLE |
    707                _BCM_L3_SHR_WITH_ID;
    708     rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
    709     BCM_IF_ERROR_RETURN(rv);
    710 
    711     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
    712                                          ENTRY_TYPEf) == 0x2) {
    713         /* Type is SVP */
    714         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
    715             trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit,
    716                                                         &ing_nh_entry, TGIDf);
    717             WLAN_INFO(unit)->port_info[vp].modid = -1;
    718             WLAN_INFO(unit)->port_info[vp].port = -1;
    719             WLAN_INFO(unit)->port_info[vp].tgid = trunk_id;
    720             /* Update each local physical port's SW state */
    721             if (stable_size == 0) {
    722                 /* When persistent storage is available, this state is recovered
    723                    in the port module */
    724                 rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
    725                         SOC_MAX_NUM_PORTS, local_member_array, &local_member_count);
    726                 BCM_IF_ERROR_RETURN(rv);
    727                 for (idx = 0; idx < local_member_count; idx++) {
    728                     _bcm_port_info_access(unit, local_member_array[idx], &info);
    729                     info->vp_count++;
    730                     BCM_IF_ERROR_RETURN(
    731                         bcm_esw_port_vlan_member_get(
    732                             unit, local_member_array[idx], &port_flags));
    733                     BCM_IF_ERROR_RETURN(
    734                         bcm_esw_port_vlan_member_set(
    735                             unit, local_member_array[idx], port_flags));
    736                 }
    737             }
    738         } else {
    739             mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
    740                                                       MODULE_IDf);
    741             port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
    742                                                        PORT_NUMf);
    743             rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    744                                         mod_in, port_in, &mod_out, &port_out);
    745             WLAN_INFO(unit)->port_info[vp].modid = mod_out;
    746             WLAN_INFO(unit)->port_info[vp].port = port_out;
    747             WLAN_INFO(unit)->port_info[vp].tgid = -1;
    748             /* Update the physical port's SW state */
    749             if (stable_size == 0) {
    750                 /* When persistent storage is available, this state is recovered
    751                    in the port module */
    752                 phys_port = WLAN_INFO(unit)->port_info[vp].port;
    753                 if (soc_feature(unit, soc_feature_sysport_remap)) {
    754                     BCM_XLATE_SYSPORT_S2P(unit, &phys_port);
    755                 }
    756                 _bcm_port_info_access(unit, phys_port, &info);
    757                 info->vp_count++;
    758                 BCM_IF_ERROR_RETURN(
    759                     bcm_esw_port_vlan_member_get(
    760                         unit, phys_port, &port_flags));
    761                 BCM_IF_ERROR_RETURN(
    762                     bcm_esw_port_vlan_member_set(
    763                         unit, phys_port, port_flags));
    764             }
    765         }
    766     } else {
    767         return BCM_E_INTERNAL; /* Should never happen */
    768     }
    769     intf_num = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh_entry,
    770                                                 WLAN__INTF_NUMf);
    771     _BCM_WLAN_INTF_USED_SET(unit, intf_num);
    772     BCM_L3_INTF_USED_SET(unit, intf_num);
    773     return rv;
    774 }
    775 
    776 /*
    777  * Function:
    778  *      _bcm_tr3_wlan_reinit
    779  * Purpose:
    780  *      Warm boot recovery for the WLAN software module
    781  * Parameters:
    782  *      unit     - Device Number
    783  * Returns:
    784  *      BCM_E_XXX
    785  */
    786 STATIC int
    787 _bcm_tr3_wlan_reinit(int unit)
    788 {
    789     int         rv, i, j, index_min, index_max, lport_profile_ptr;
    790     int         stable_size, vvp, vp = 0;
    791     int         tnl_idx, wlan_dvp_index;
    792     uint64      grp_bmp;
    793     uint32      grp_vec[2];
    794     uint32      entry_type;
    795     vlan_tab_entry_t                *vtab;
    796     source_vp_entry_t               source_vp;
    797     lport_tab_entry_t               lport_profile;
    798     axp_wrx_svp_assignment_entry_t  *axp_wrx_svp;
    799     source_vp_attributes_2_entry_t  *source_vp_attributes_2;
    800     egr_dvp_attribute_entry_t       egr_dvp_attribute;
    801     axp_wtx_dvp_profile_entry_t     axp_wtx_dvp;
    802     uint8  *source_vp_attributes_2_buf = NULL; /* source vp DMA buffer      */
    803     uint8  *axp_wtx_svp_buf            = NULL; /* axp_wrx_svp DMA buffer    */
    804     uint8  *vbuf                       = NULL; /* VLAN_TABLE DMA buffer     */
    805     void        *entries[1];                   /* for profile memories      */ 
    806     _bcm_vp_info_t vp_info;
    807 
    808     _bcm_vp_info_init(&vp_info);
    809     vp_info.vp_type = _bcmVpTypeWlan;
    810 
    811     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    812 
    813     /* DMA various tables */
    814     source_vp_attributes_2_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    815                                  (unit, SOURCE_VP_ATTRIBUTES_2m),
    816                                  "source_vp_attributes_2 buffer");
    817     if (NULL == source_vp_attributes_2_buf) {
    818         rv = BCM_E_MEMORY;
    819         goto cleanup;
    820     }
    821     index_min = soc_mem_index_min(unit, SOURCE_VP_ATTRIBUTES_2m);
    822     index_max = soc_mem_index_max(unit, SOURCE_VP_ATTRIBUTES_2m);
    823     if ((rv = soc_mem_read_range(unit, SOURCE_VP_ATTRIBUTES_2m, MEM_BLOCK_ANY,
    824                                  index_min, index_max,
    825                                  source_vp_attributes_2_buf)) < 0 ) {
    826         goto cleanup;
    827     }
    828     axp_wtx_svp_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
    829                                        (unit, AXP_WRX_SVP_ASSIGNMENTm),
    830                                        "axp_wrx_svp buffer");
    831     if (NULL == axp_wtx_svp_buf) {
    832         rv = BCM_E_MEMORY;
    833         goto cleanup;
    834     }
    835     index_min = soc_mem_index_min(unit, AXP_WRX_SVP_ASSIGNMENTm);
    836     index_max = soc_mem_index_max(unit, AXP_WRX_SVP_ASSIGNMENTm);
    837     if ((rv = soc_mem_read_range(unit, AXP_WRX_SVP_ASSIGNMENTm, MEM_BLOCK_ANY,
    838                                  index_min, index_max,
    839                                  axp_wtx_svp_buf)) < 0 ) {
    840         goto cleanup;
    841     }
    842 
    843     vbuf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABLE(unit)),
    844                          "VLAN_TAB buffer");
    845     if (NULL == vbuf) {
    846         rv = BCM_E_MEMORY;
    847         goto cleanup;
    848     }
    849     index_min = soc_mem_index_min(unit, VLAN_TABLE(unit));
    850     index_max = soc_mem_index_max(unit, VLAN_TABLE(unit));
    851     if ((rv = soc_mem_read_range(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY,
    852                                  index_min, index_max, vbuf)) < 0 ) {
    853         goto cleanup;
    854     }
    855 
    856     /* Get the VPs */
    857     index_min = soc_mem_index_min(unit, AXP_WRX_SVP_ASSIGNMENTm);
    858     index_max = soc_mem_index_max(unit, AXP_WRX_SVP_ASSIGNMENTm);
    859     for (i = index_min; i <= index_max; i++) {
    860         axp_wrx_svp = soc_mem_table_idx_to_pointer
    861                         (unit, AXP_WRX_SVP_ASSIGNMENTm,
    862                          axp_wrx_svp_assignment_entry_t *, axp_wtx_svp_buf, i);
    863         if (soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit,
    864                                             axp_wrx_svp, VALIDf) == 0) {
    865             continue;
    866         }
    867         entry_type = soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit, axp_wrx_svp,
    868                                                              ENTRY_TYPEf);
    869         if ((entry_type != 1) && (entry_type != 2) && (entry_type != 3)) {
    870             continue; /* unknown entry type */
    871         }
    872         vp = soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit, axp_wrx_svp,
    873                                              SVPf);
    874         source_vp_attributes_2 = soc_mem_table_idx_to_pointer
    875                                     (unit, SOURCE_VP_ATTRIBUTES_2m, 
    876                                      source_vp_attributes_2_entry_t *, 
    877                                      source_vp_attributes_2_buf, vp);
    878         rv = _bcm_vp_used_set(unit, vp, vp_info);
    879         if (BCM_FAILURE(rv)) {
    880             goto cleanup;
    881         }
    882         switch (entry_type) {
    883             case 1:
    884                 WLAN_INFO(unit)->port_info[vp].match_radio =
    885                     soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit, axp_wrx_svp,
    886                                                     RIDf);
    887                 soc_mem_mac_addr_get(unit, AXP_WRX_SVP_ASSIGNMENTm, axp_wrx_svp,
    888                                     BSSIDf,
    889                                     WLAN_INFO(unit)->port_info[vp].match_bssid);
    890                 BCM_GPORT_TUNNEL_ID_SET
    891                         (WLAN_INFO(unit)->port_info[vp].match_tunnel,
    892                          soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit,
    893                          axp_wrx_svp, EXP_TUNNEL_IDf));
    894                 WLAN_INFO(unit)->port_info[vp].flags |=
    895                                                 _BCM_WLAN_PORT_MATCH_BSSID_RADIO;
    896                 break;
    897             case 2:
    898                 soc_mem_mac_addr_get(unit, AXP_WRX_SVP_ASSIGNMENTm, axp_wrx_svp,
    899                                     BSSIDf,
    900                                     WLAN_INFO(unit)->port_info[vp].match_bssid);
    901                 BCM_GPORT_TUNNEL_ID_SET
    902                             (WLAN_INFO(unit)->port_info[vp].match_tunnel,
    903                              soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit,
    904                              axp_wrx_svp, EXP_TUNNEL_IDf));
    905                 WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID;
    906                 break;
    907 
    908             case 3:
    909                 BCM_GPORT_TUNNEL_ID_SET
    910                         (WLAN_INFO(unit)->port_info[vp].match_tunnel,
    911                         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_get(unit,
    912                         axp_wrx_svp, TUNNEL_IDf));
    913                 WLAN_INFO(unit)->port_info[vp].flags |= 
    914                                             _BCM_WLAN_PORT_MATCH_TUNNEL;
    915                 break;
    916             /*
    917              * COVERITY
    918              * This default is unreachable. It is kept intentionally as a 
    919              * defensive default for future development.
    920              */
    921             /* coverity[dead_error_begin] */
    922             default:
    923                 rv = BCM_E_INTERNAL;
    924                 goto cleanup;
    925                 break;
    926         }
    927         /* Update LPORT profile entry refererence count */
    928         lport_profile_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get
    929                                 (unit, source_vp_attributes_2,
    930                                  LPORT_PROFILE_INDEXf);
    931         rv = _bcm_lport_profile_mem_reference(unit, lport_profile_ptr, 1);
    932         if (BCM_FAILURE(rv)) {
    933             goto cleanup;
    934         }
    935         rv = READ_LPORT_TABm(unit, MEM_BLOCK_ANY, lport_profile_ptr,
    936                              &lport_profile);
    937         if (BCM_FAILURE(rv)) {
    938             goto cleanup;
    939         }
    940         /* Get TPID reference count from the LPORT entry */
    941         rv = _bcm_tr3_wlan_lport_tpid_recover(unit, &lport_profile);
    942         if (BCM_FAILURE(rv)) {
    943             goto cleanup;
    944         }
    945         /* Recover flex stats from the SOURCE_VP table */
    946         rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &source_vp);
    947         if (BCM_FAILURE(rv)) {
    948             goto cleanup;
    949         }
    950         _bcm_tr3_wlan_port_flex_stat_recover(unit, &source_vp, vp);
    951         /* Get the TUNNEL_VLAN/PRI/CFI from the EGR_WLAN_DVP table */
    952         rv = READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &egr_dvp_attribute);
    953         if (BCM_FAILURE(rv)) {
    954             goto cleanup;
    955         }
    956         
    957         wlan_dvp_index = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit,
    958                                          &egr_dvp_attribute, WLAN_DVP_PROFILEf);
    959         entries[0] = &axp_wtx_dvp;
    960         rv = soc_profile_mem_get(unit, WLAN_DVP_PROFILE(unit), wlan_dvp_index,
    961                                  1, entries);
    962         if (BCM_FAILURE(rv)) {
    963             goto cleanup;
    964         }
    965         
    966         /* Restore tunnel id bitmap */        
    967         tnl_idx = soc_AXP_WTX_DVP_PROFILEm_field32_get(unit,
    968                                              &axp_wtx_dvp, WLAN_TUNNEL_INDEXf);
    969         _BCM_WLAN_TNL_USED_SET(unit, tnl_idx);
    970 
    971 
    972         TUNNEL_VLAN(unit, tnl_idx) = 
    973             soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp, TUNNEL_VLANf);
    974         TUNNEL_PRI(unit, tnl_idx) = 
    975             soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp, TUNNEL_PRIf);
    976         TUNNEL_CFI(unit, tnl_idx) = 
    977             soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp, TUNNEL_CFIf);
    978         
    979         /* Get the VLAN validation state from TUNNEL VPs */
    980         if (WLAN_INFO(unit)->port_info[vp].flags &
    981             _BCM_WLAN_PORT_MATCH_TUNNEL) {
    982             vvp = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &source_vp,
    983                                                   VLAN_MEMBERSHIP_PROFILEf);
    984             for (j = BCM_VLAN_MIN; j < BCM_VLAN_MAX; j++) {
    985                 vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABLE(unit),
    986                                                    vlan_tab_entry_t *, vbuf, j);
    987 
    988                 grp_vec[0] = grp_vec[1] = 0;
    989                 soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32*)vtab, VP_GROUP_BITMAPf, grp_vec);
    990                 COMPILER_64_ZERO(grp_bmp);
    991                 COMPILER_64_SET(grp_bmp, grp_vec[1], grp_vec[0]);
    992 
    993                 if (COMPILER_64_BITTEST(grp_bmp, vvp)) {
    994                     /* Increase use-count for this bit for this VLAN */
    995                     WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[j][vvp]++;
    996                 }
    997             }
    998         }
    999         /* Recover other port data */
   1000         rv = _bcm_tr3_wlan_port_associated_data_recover(unit, vp, stable_size);
   1001         if (BCM_FAILURE(rv)) {
   1002             goto cleanup;
   1003         }
   1004     }
   1005 
   1006 cleanup:
   1007     if (source_vp_attributes_2_buf) {
   1008         soc_cm_sfree(unit, source_vp_attributes_2_buf);
   1009     }
   1010     if (axp_wtx_svp_buf) {
   1011         soc_cm_sfree(unit, axp_wtx_svp_buf);
   1012     }
   1013     if (vbuf) {
   1014         soc_cm_sfree(unit, vbuf);
   1015     }
   1016     return rv;
   1017 }
   1018 #endif /* BCM_WARM_BOOT_SUPPORT */
   1019 
   1020 /*
   1021  * Function:
   1022  *      bcm_wlan_init
   1023  * Purpose:
   1024  *      Initialize the WLAN software module
   1025  * Parameters:
   1026  *      unit     - (IN)Device Number
   1027  * Returns:
   1028  *      BCM_E_XXX
   1029  */
   1030 int
   1031 bcm_tr3_wlan_init(int unit)
   1032 {
   1033     int i, num_vp, num_tnl, num_intf, rv = BCM_E_NONE;
   1034     _bcm_tr3_wlan_bookkeeping_t *wlan_info = WLAN_INFO(unit);
   1035 
   1036     if (!soc_feature(unit, soc_feature_wlan)) {
   1037         return BCM_E_UNAVAIL;
   1038     }
   1039     if (!L3_INFO(unit)->l3_initialized) {
   1040         LOG_INFO(BSL_LS_BCM_L3,
   1041                  (BSL_META_U(unit,
   1042                              "L3 module must be initialized first\n")));
   1043         return BCM_E_NONE;
   1044     }
   1045     if (_tr3_wlan_initialized[unit]) {
   1046         BCM_IF_ERROR_RETURN(bcm_tr3_wlan_detach(unit));
   1047     }
   1048 
   1049     sal_memset(wlan_info, 0, sizeof(_bcm_tr3_wlan_bookkeeping_t));
   1050 
   1051     /* Create WLAN virtual port usage bitmap */
   1052     num_vp = soc_mem_index_count(unit, SOURCE_VP_ATTRIBUTES_2m);
   1053     if (wlan_info->port_info == NULL) {
   1054         wlan_info->port_info = sal_alloc(sizeof(_bcm_tr3_wlan_port_info_t)
   1055                                        * num_vp, "wlan_port_info");
   1056         if (wlan_info->port_info == NULL) {
   1057             _bcm_tr3_wlan_free_resources(unit);
   1058             return BCM_E_MEMORY;
   1059         }
   1060     }
   1061     sal_memset(wlan_info->port_info, 0, sizeof(_bcm_tr3_wlan_port_info_t)
   1062                * num_vp);
   1063 
   1064     /* 
   1065      *  Create WTX_TUNNEL tunnelid usage bitmap of 1k tunnels
   1066      *  TR3 specifies, max of 1k tunnel is supported per chip
   1067      *  WTX_TUNNEL has 4K indexes with 4 indexes per tunnel
   1068      */
   1069     num_tnl = (soc_mem_index_count(unit, AXP_WTX_TUNNELm) / _BCM_WLAN_TNL_ENTRY_WIDTH);
   1070     wlan_info->wlan_tnl_bitmap =
   1071                             sal_alloc(SHR_BITALLOCSIZE(num_tnl), "wlan tnl_bitmap");
   1072     if (wlan_info->wlan_tnl_bitmap == NULL) {
   1073         _bcm_tr3_wlan_free_resources(unit);
   1074 	    return BCM_E_MEMORY;
   1075     }
   1076     sal_memset(wlan_info->wlan_tnl_bitmap, 0, SHR_BITALLOCSIZE(num_tnl));
   1077 
   1078     /* Allocate tunnel VLAN cache */
   1079     if (NULL == wlan_info->tunnel_vlan) {
   1080         wlan_info->tunnel_vlan =
   1081                 sal_alloc(sizeof(bcm_vlan_t) * num_tnl, "tunnel vlan cache");
   1082         if (wlan_info->tunnel_vlan == NULL) {
   1083             _bcm_tr3_wlan_free_resources(unit);
   1084             return BCM_E_MEMORY;
   1085         }
   1086     }
   1087     sal_memset(wlan_info->tunnel_vlan, 0, sizeof(bcm_vlan_t) * num_tnl);
   1088 
   1089     /* Allocate tunnel VLAN cache */
   1090     if (NULL == wlan_info->tunnel_pri) {
   1091         wlan_info->tunnel_pri =
   1092                 sal_alloc(sizeof(uint8) * num_tnl, "tunnel vlan pri cache");
   1093         if (wlan_info->tunnel_pri == NULL) {
   1094             _bcm_tr3_wlan_free_resources(unit);
   1095             return BCM_E_MEMORY;
   1096         }
   1097     }
   1098     sal_memset(wlan_info->tunnel_pri, 0, sizeof(uint8) * num_tnl);
   1099 
   1100     /* Allocate tunnel VLAN cache */
   1101     if (NULL == wlan_info->tunnel_cfi) {
   1102         wlan_info->tunnel_cfi =
   1103                 sal_alloc(sizeof(uint8) * num_tnl, "tunnel vlan cfi cache");
   1104         if (wlan_info->tunnel_cfi == NULL) {
   1105             _bcm_tr3_wlan_free_resources(unit);
   1106             return BCM_E_MEMORY;
   1107         }
   1108     }
   1109     sal_memset(wlan_info->tunnel_cfi, 0, sizeof(uint8) * num_tnl);
   1110 
   1111     /* Allocate L3 interface usage bitmap */
   1112     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1113     if (NULL == wlan_info->intf_bitmap) {
   1114         wlan_info->intf_bitmap =
   1115             sal_alloc(SHR_BITALLOCSIZE(num_intf), "intf_bitmap");
   1116         if (wlan_info->intf_bitmap == NULL) {
   1117             _bcm_tr3_wlan_free_resources(unit);
   1118             return BCM_E_MEMORY;
   1119         }
   1120     }
   1121     sal_memset(wlan_info->intf_bitmap, 0, SHR_BITALLOCSIZE(num_intf));
   1122 
   1123 
   1124     /* Allocate the VLAN group bitmap use count per VLAN */
   1125     wlan_info->vlan_grp_bmp_use_cnt = (uint8 **)sal_alloc(BCM_VLAN_COUNT *
   1126                              sizeof(uint8 *), "VLAN group bitmap pointer list");
   1127     if (wlan_info->vlan_grp_bmp_use_cnt == NULL) {
   1128         _bcm_tr3_wlan_free_resources(unit);
   1129 	return BCM_E_MEMORY;
   1130     }
   1131     for (i = 0; i < BCM_VLAN_COUNT; i++) {
   1132         int bitmap_size = soc_mem_field_length(unit, VLAN_TABLE(unit), VP_GROUP_BITMAPf);
   1133         wlan_info->vlan_grp_bmp_use_cnt[i] = (uint8 *)sal_alloc(bitmap_size *
   1134                                             sizeof(uint8), "VLAN group bitmap");
   1135         if (wlan_info->vlan_grp_bmp_use_cnt[i] == NULL) {
   1136             _bcm_tr3_wlan_free_resources(unit);
   1137             return BCM_E_MEMORY;
   1138         }
   1139         sal_memset(wlan_info->vlan_grp_bmp_use_cnt[i], 0, bitmap_size * sizeof(uint8));
   1140     }
   1141 
   1142     /* Create WLAN mutex */
   1143     if (_tr3_wlan_mutex[unit] == NULL) {
   1144         _tr3_wlan_mutex[unit] = sal_mutex_create("wlan mutex");
   1145         if (_tr3_wlan_mutex[unit] == NULL) {
   1146             _bcm_tr3_wlan_free_resources(unit);
   1147             return BCM_E_MEMORY;
   1148         }
   1149     }
   1150 
   1151     /* Create WLAN profile tables */
   1152     rv = _bcm_tr3_wlan_profile_init(unit);
   1153     if (BCM_FAILURE(rv)) {
   1154        _bcm_tr3_wlan_free_resources(unit);
   1155        return rv;
   1156     }
   1157 
   1158 #ifdef BCM_WARM_BOOT_SUPPORT
   1159     if (SOC_WARM_BOOT(unit)) {
   1160         /* Warm Boot recovery */
   1161         rv = _bcm_tr3_wlan_reinit(unit);
   1162     }
   1163 #endif
   1164 
   1165     /* Enable egress VXLT lookup for tunnel and payload vlanids 
   1166      * This requires to enable VXLT for WLAN ENCAP and DECAP loopback types
   1167      */
   1168     BCM_IF_ERROR_RETURN(bcm_esw_vlan_control_port_set
   1169                         (unit, AXP_PORT(unit,SOC_AXP_NLF_WLAN_ENCAP), 
   1170                                bcmVlanTranslateEgressEnable, 1));
   1171     BCM_IF_ERROR_RETURN(bcm_esw_vlan_control_port_set
   1172                         (unit, AXP_PORT(unit,SOC_AXP_NLF_WLAN_DECAP), 
   1173                                bcmVlanTranslateEgressEnable, 1));
   1174 
   1175 
   1176     /* set initialize state */
   1177     _tr3_wlan_initialized[unit] = TRUE;
   1178     return rv;
   1179 }
   1180 
   1181 /*
   1182  * Function:
   1183  *      _bcm_tr3_wlan_hw_clear
   1184  * Purpose:
   1185  *     Perform HW tables clean up for WLAN module.
   1186  * Parameters:
   1187  *      unit     - Device Number
   1188  * Returns:
   1189  *      BCM_E_XXX
   1190  */
   1191 STATIC int
   1192 _bcm_tr3_wlan_hw_clear(int unit)
   1193 {
   1194     int rv, rv_error = BCM_E_NONE;
   1195 
   1196     /* Delete all ports */
   1197     rv = bcm_tr3_wlan_port_delete_all(unit);
   1198     if (BCM_FAILURE(rv) && (BCM_E_NONE == rv_error)) {
   1199         rv_error = rv;
   1200     }
   1201 
   1202     /* Delete all clients */
   1203     rv = bcm_tr3_wlan_client_delete_all(unit);
   1204     if (BCM_FAILURE(rv) && (BCM_E_NONE == rv_error)) {
   1205         rv_error = rv;
   1206     }
   1207 
   1208     return rv_error;
   1209 }
   1210 
   1211 /*
   1212  * Function:
   1213  *      bcm_wlan_detach
   1214  * Purpose:
   1215  *      Detach the WLAN software module
   1216  * Parameters:
   1217  *      unit     - Device Number
   1218  * Returns:
   1219  *      BCM_E_XXX
   1220  */
   1221 int
   1222 bcm_tr3_wlan_detach(int unit)
   1223 {
   1224     int rv = BCM_E_NONE;
   1225 
   1226     if (_tr3_wlan_initialized[unit])
   1227     {
   1228         if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
   1229             rv = _bcm_tr3_wlan_hw_clear(unit);
   1230         }
   1231 
   1232         _bcm_tr3_wlan_free_resources(unit);
   1233         _tr3_wlan_initialized[unit] = FALSE;
   1234     }
   1235 
   1236     return rv;
   1237 }
   1238 
   1239 /*
   1240  * Function:
   1241  *      _bcm_tr3_wlan_client_api_to_hw
   1242  * Purpose:
   1243  *      Convert a hardware-independent WLAN client entry to a TR3 Wireless
   1244  *      client database (WCD) HW entry
   1245  * Parameters:
   1246  *      unit - Unit number
   1247  *      hw_entry - (OUT) Triumph 2 HW entry
   1248  *      info - Hardware-independent WLAN client entry
   1249  */
   1250 STATIC int
   1251 _bcm_tr3_wlan_client_api_to_hw(int unit, axp_wrx_wcd_entry_t *hw_entry,
   1252                                bcm_wlan_client_t *info)
   1253 {
   1254     sal_memset(hw_entry, 0, sizeof(axp_wrx_wcd_entry_t));
   1255     if ((info->flags & BCM_WLAN_CLIENT_ROAMED_IN) &&
   1256         (info->flags & BCM_WLAN_CLIENT_ROAMED_OUT)) {
   1257          LOG_WARN(BSL_LS_BCM_COMMON,
   1258                   (BSL_META_U(unit,
   1259                               "Invalid! ROAMED_IN and ROAMED_OUT flags are enabled \n")));
   1260         return BCM_E_PARAM;
   1261     }
   1262     if (BCM_MAC_IS_MCAST(info->mac)) {
   1263         return BCM_E_PARAM;
   1264     }
   1265     soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, VALIDf, 1);
   1266     soc_mem_mac_addr_set(unit, AXP_WRX_WCDm, hw_entry, MAC_ADDRf, info->mac);
   1267 
   1268     /* Client MACSA/MACDA is RIC, associate WTP DVP and AC2AC Home Agent DVP */
   1269     if (info->flags & BCM_WLAN_CLIENT_ROAMED_IN) {
   1270         int vp;
   1271         if (!BCM_GPORT_IS_WLAN_PORT(info->home_agent) ||
   1272             !BCM_GPORT_IS_WLAN_PORT(info->wtp)) {
   1273             return BCM_E_PARAM;
   1274         }
   1275         soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, RICf, 1);
   1276         vp = BCM_GPORT_WLAN_PORT_ID_GET(info->home_agent);
   1277         soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, RIC_HA_VPf, vp);
   1278         vp = BCM_GPORT_WLAN_PORT_ID_GET(info->wtp);
   1279         soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, RIC_WTP_VPf, vp);
   1280     }
   1281 
   1282     /* Client MACSA is ROC, DVP is determined by forwarding logic */
   1283     if (info->flags & BCM_WLAN_CLIENT_ROAMED_OUT) {
   1284         soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, ROCf, 1);
   1285     }
   1286 
   1287     if (info->flags & BCM_WLAN_CLIENT_AUTHORIZED) {
   1288         soc_AXP_WRX_WCDm_field32_set(unit, hw_entry, DOT1X_STATEf, 1);
   1289     }
   1290     return BCM_E_NONE;
   1291 }
   1292 
   1293 /*
   1294  * Function:
   1295  *      _bcm_tr3_wlan_client_api_from_hw
   1296  * Purpose:
   1297  *      Convert a TR3 Wireless Client Datbase(WCD) HW entry to a hardware-independent
   1298  *      WLAN client entry
   1299  * Parameters:
   1300  *      unit - Unit number
   1301  *      hw_entry - Triumph 3 HW entry
   1302  *      info - (OUT) Hardware-independent WLAN client entry
   1303  */
   1304 STATIC int
   1305 _bcm_tr3_wlan_client_api_from_hw(int unit, bcm_wlan_client_t *info,
   1306                                  axp_wrx_wcd_entry_t *hw_entry)
   1307 {
   1308     int vp;
   1309     sal_memset(info, 0, sizeof (bcm_wlan_client_t));
   1310     soc_mem_mac_addr_get(unit, AXP_WRX_WCDm, hw_entry, MAC_ADDRf,
   1311                          info->mac);
   1312     if (soc_AXP_WRX_WCDm_field32_get(unit, hw_entry, RICf)) {
   1313         info->flags |= BCM_WLAN_CLIENT_ROAMED_IN;
   1314         vp = soc_AXP_WRX_WCDm_field32_get(unit, hw_entry,
   1315                                          RIC_HA_VPf);
   1316         BCM_GPORT_WLAN_PORT_ID_SET(info->home_agent, vp);
   1317         vp = soc_AXP_WRX_WCDm_field32_get(unit, hw_entry,
   1318                                          RIC_WTP_VPf);
   1319         BCM_GPORT_WLAN_PORT_ID_SET(info->wtp, vp);
   1320     }
   1321     if (soc_AXP_WRX_WCDm_field32_get(unit, hw_entry, ROCf)) {
   1322         info->flags |= BCM_WLAN_CLIENT_ROAMED_OUT;
   1323     }
   1324     if (soc_AXP_WRX_WCDm_field32_get(unit, hw_entry, DOT1X_STATEf)) {
   1325         info->flags |= BCM_WLAN_CLIENT_AUTHORIZED;
   1326     }
   1327     return BCM_E_NONE;
   1328 }
   1329 
   1330 /*
   1331  * Function:
   1332  *      bcm_wlan_client_add
   1333  * Purpose:
   1334  *      Add a wireless client to the wireless client database
   1335  * Parameters:
   1336  *      unit     - Device Number
   1337  *      info     - (IN/OUT) Wireless Client structure
   1338  * Returns:
   1339  *      BCM_E_XXX
   1340  */
   1341 int
   1342 bcm_tr3_wlan_client_add(int unit, bcm_wlan_client_t *info)
   1343 {
   1344     int index, rv = BCM_E_UNAVAIL;
   1345     axp_wrx_wcd_entry_t client_entry_key, client_entry_lookup;
   1346 
   1347     WLAN_INIT(unit);
   1348 
   1349     BCM_IF_ERROR_RETURN
   1350         (_bcm_tr3_wlan_client_api_to_hw(unit, &client_entry_key, info));
   1351 
   1352     WLAN_LOCK(unit);
   1353     rv = soc_mem_search(unit, AXP_WRX_WCDm, MEM_BLOCK_ANY, &index,
   1354                         (void *)&client_entry_key,
   1355                         (void *)&client_entry_lookup, 0);
   1356 
   1357     if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   1358         WLAN_UNLOCK(unit);
   1359         return rv;
   1360     } else if ((rv == BCM_E_NONE) &&
   1361                !(info->flags & BCM_WLAN_CLIENT_REPLACE)) {
   1362         WLAN_UNLOCK(unit);
   1363         return BCM_E_EXISTS;
   1364     }
   1365 
   1366     rv = soc_mem_insert(unit, AXP_WRX_WCDm, MEM_BLOCK_ALL,
   1367                                        (void *)&client_entry_key);
   1368     WLAN_UNLOCK(unit);
   1369     return rv;
   1370 }
   1371 
   1372 /*
   1373  * Function:
   1374  *      bcm_wlan_client_delete
   1375  * Purpose:
   1376  *      Delete a wireless client from the database
   1377  * Parameters:
   1378  *      unit     - Device Number
   1379  *      mac      - MAC address of client (lookup key)
   1380  * Returns:
   1381  *      BCM_E_XXX
   1382  */
   1383 int
   1384 bcm_tr3_wlan_client_delete(int unit, bcm_mac_t mac)
   1385 {
   1386     int index, rv = BCM_E_UNAVAIL;
   1387     axp_wrx_wcd_entry_t client_entry_key, client_entry_lookup;
   1388 
   1389     WLAN_INIT(unit);
   1390 
   1391     sal_memset(&client_entry_key, 0, sizeof(axp_wrx_wcd_entry_t));
   1392     sal_memset(&client_entry_lookup, 0, sizeof(axp_wrx_wcd_entry_t));
   1393 
   1394     soc_AXP_WRX_WCDm_field32_set(unit, &client_entry_key, VALIDf, 1);
   1395     soc_mem_mac_addr_set(unit, AXP_WRX_WCDm, &client_entry_key,
   1396                          MAC_ADDRf, mac);
   1397     WLAN_LOCK(unit);
   1398     rv = soc_mem_search(unit, AXP_WRX_WCDm, MEM_BLOCK_ANY, &index,
   1399                         (void *)&client_entry_key,
   1400                         (void *)&client_entry_lookup, 0);
   1401     if (BCM_FAILURE(rv)) {
   1402         WLAN_UNLOCK(unit);
   1403         return rv;
   1404     }
   1405     rv = soc_mem_delete(unit, AXP_WRX_WCDm, MEM_BLOCK_ALL,
   1406                         (void *)&client_entry_key);
   1407     WLAN_UNLOCK(unit);
   1408     return rv;
   1409 }
   1410 
   1411 /*
   1412  * Function:
   1413  *      bcm_wlan_client_delete_all
   1414  * Purpose:
   1415  *      Delete all wireless clients from the database
   1416  * Parameters:
   1417  *      unit     - Device Number
   1418  * Returns:
   1419  *      BCM_E_XXX
   1420  */
   1421 int
   1422 bcm_tr3_wlan_client_delete_all(int unit)
   1423 {
   1424     int i, valid, index_min, index_max, rv = BCM_E_NONE;
   1425     axp_wrx_wcd_entry_t hw_entry;
   1426 
   1427     WLAN_INIT(unit);
   1428 
   1429     index_min = soc_mem_index_min(unit, AXP_WRX_WCDm);
   1430     index_max = soc_mem_index_max(unit, AXP_WRX_WCDm);
   1431     WLAN_LOCK(unit);
   1432     for (i = index_min; i <= index_max; i++) {
   1433         rv = soc_mem_read(unit, AXP_WRX_WCDm, MEM_BLOCK_ANY, i,
   1434                           (void *)&hw_entry);
   1435         if (BCM_FAILURE(rv)) {
   1436             break;
   1437         }
   1438         valid = soc_AXP_WRX_WCDm_field32_get(unit, &hw_entry, VALIDf);
   1439         if (!valid ) {
   1440             continue;
   1441         }
   1442         soc_AXP_WRX_WCDm_field32_set(unit, &hw_entry, VALIDf, 0);
   1443         rv = soc_mem_write(unit, AXP_WRX_WCDm, MEM_BLOCK_ALL, i,
   1444                            (void *)&hw_entry);
   1445         if (BCM_FAILURE(rv)) {
   1446             break;
   1447         }
   1448     }
   1449     WLAN_UNLOCK(unit);
   1450     return rv;
   1451 }
   1452 
   1453 /*
   1454  * Function:
   1455  *      bcm_wlan_client_get
   1456  * Purpose:
   1457  *      Get a wireless client from the database
   1458  * Parameters:
   1459  *      unit     - Device Number
   1460  *      mac      - MAC address of client (lookup key)
   1461  *      info     - (IN/OUT) Wireless Client structure
   1462  * Returns:
   1463  *      BCM_E_XXX
   1464  */
   1465 int
   1466 bcm_tr3_wlan_client_get(int unit, bcm_mac_t mac, bcm_wlan_client_t *info)
   1467 {
   1468     int index, rv = BCM_E_UNAVAIL;
   1469     axp_wrx_wcd_entry_t client_entry_key, client_entry_lookup;
   1470 
   1471     WLAN_INIT(unit);
   1472 
   1473     sal_memset(&client_entry_key, 0, sizeof(axp_wrx_wcd_entry_t));
   1474     sal_memset(&client_entry_lookup, 0, sizeof(axp_wrx_wcd_entry_t));
   1475 
   1476     soc_AXP_WRX_WCDm_field32_set(unit, &client_entry_key, VALIDf, 1);
   1477     soc_mem_mac_addr_set(unit, AXP_WRX_WCDm, &client_entry_key,
   1478                          MAC_ADDRf, mac);
   1479     rv = soc_mem_search(unit, AXP_WRX_WCDm, MEM_BLOCK_ANY, &index,
   1480                         (void *)&client_entry_key,
   1481                         (void *)&client_entry_lookup, 0);
   1482     BCM_IF_ERROR_RETURN(rv);
   1483     bcm_wlan_client_t_init(info);
   1484     rv = _bcm_tr3_wlan_client_api_from_hw(unit, info, &client_entry_lookup);
   1485     return rv;
   1486 }
   1487 
   1488 /*
   1489  * Function:
   1490  *      bcm_wlan_client_traverse
   1491  * Purpose:
   1492  *      Walks through the valid WLAN client entries and calls
   1493  *      the user supplied callback function for each entry.
   1494  * Parameters:
   1495  *      unit       - (IN) bcm device.
   1496  *      trav_fn    - (IN) Callback function.
   1497  *      user_data  - (IN) User data to be passed to callback function.
   1498  * Returns:
   1499  *      BCM_E_NONE - Success.
   1500  *      BCM_E_XXX
   1501  */
   1502 int
   1503 bcm_tr3_wlan_client_traverse(int unit,
   1504                              bcm_wlan_client_traverse_cb cb,
   1505                              void *user_data)
   1506 {
   1507     int i, index_min, index_max, rv = BCM_E_NONE;
   1508     int valid, *buffer = NULL;
   1509     axp_wrx_wcd_entry_t *hw_entry;
   1510     bcm_wlan_client_t info;
   1511 
   1512     WLAN_INIT(unit);
   1513 
   1514     index_min = soc_mem_index_min(unit, AXP_WRX_WCDm);
   1515     index_max = soc_mem_index_max(unit, AXP_WRX_WCDm);
   1516 
   1517     WLAN_LOCK(unit);
   1518     buffer = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, AXP_WRX_WCDm),
   1519                            "wlan client traverse");
   1520     if (NULL == buffer) {
   1521         WLAN_UNLOCK(unit);
   1522         return BCM_E_MEMORY;
   1523     }
   1524     if ((rv = soc_mem_read_range(unit, AXP_WRX_WCDm, MEM_BLOCK_ALL,
   1525                                  index_min, index_max, buffer)) < 0 ) {
   1526         soc_cm_sfree(unit, buffer);
   1527         WLAN_UNLOCK(unit);
   1528         return rv;
   1529     }
   1530     for (i = index_min; i <= index_max; i++) {
   1531         hw_entry = soc_mem_table_idx_to_pointer(unit, AXP_WRX_WCDm,
   1532                                          axp_wrx_wcd_entry_t *, buffer, i);
   1533         valid = soc_AXP_WRX_WCDm_field32_get(unit, hw_entry, VALIDf);
   1534         if (!valid ) {
   1535             continue;
   1536         }
   1537         bcm_wlan_client_t_init(&info);
   1538         rv = _bcm_tr3_wlan_client_api_from_hw(unit, &info, hw_entry);
   1539         if (BCM_FAILURE(rv)) {
   1540             soc_cm_sfree(unit, buffer);
   1541             WLAN_UNLOCK(unit);
   1542             return rv;
   1543         }
   1544         rv = cb(unit, &info, user_data);
   1545         if (BCM_FAILURE(rv)) {
   1546             soc_cm_sfree(unit, buffer);
   1547             WLAN_UNLOCK(unit);
   1548             return rv;
   1549         }
   1550     }
   1551     soc_cm_sfree(unit, buffer);
   1552     WLAN_UNLOCK(unit);
   1553     return rv;
   1554 }
   1555 
   1556 /*
   1557  * Function:
   1558  *      _bcm_tr3_wlan_port_resolve
   1559  * Purpose:
   1560  *      Get the modid, port, trunk values for a WLAN port
   1561  * Returns:
   1562  *      BCM_E_XXX
   1563  */
   1564 /*
   1565  * Function:
   1566  *      _bcm_tr3_wlan_port_resolve
   1567  * Purpose:
   1568  *      Get the modid, port, trunk values for a WLAN port
   1569  * Parameters:
   1570  *      unit            - (IN) bcm device
   1571  *      wlan_port_id    - (IN) wlan gport
   1572  *      modid           - (OUT) module id
   1573  *      port            - (OUT) local port id
   1574  *      trunk_id        - (OUT) trunk id
   1575  *      id              - (OUT) virtual port id
   1576  * Returns:
   1577  *      BCM_E_NONE - Success
   1578  *      BCM_E_XXX
   1579  * Notes:
   1580  */
   1581 int
   1582 _bcm_tr3_wlan_port_resolve(int unit, bcm_gport_t wlan_port_id,
   1583                           bcm_module_t *modid, bcm_port_t *port,
   1584                           bcm_trunk_t *trunk_id, int *id)
   1585 
   1586 {
   1587     int rv = BCM_E_NONE, nh_index, vp;
   1588     ing_l3_next_hop_entry_t ing_nh;
   1589     ing_dvp_table_entry_t dvp;
   1590 
   1591     WLAN_INIT(unit);
   1592 
   1593     if (!BCM_GPORT_IS_WLAN_PORT(wlan_port_id)) {
   1594         return (BCM_E_BADID);
   1595     }
   1596 
   1597     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1598     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   1599         return BCM_E_NOT_FOUND;
   1600     }
   1601     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   1602     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   1603                                               NEXT_HOP_INDEXf);
   1604     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1605                                       nh_index, &ing_nh));
   1606 
   1607     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x2) {
   1608         /* Entry type is not L2 DVP */
   1609         return BCM_E_NOT_FOUND;
   1610     }
   1611     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1612         *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1613     } else {
   1614         /* Only add this to replication set if destination is local */
   1615         *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1616         *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1617     }
   1618     *id = vp;
   1619     return rv;
   1620 }
   1621 
   1622 /*
   1623  * Function:
   1624  *      bcm_tr3_wlan_port_learn_get
   1625  * Purpose:
   1626  *      Get the CPU Managed Learning (CML) bits for an wlan port
   1627  * Returns:
   1628  *      BCM_E_XXX
   1629  */
   1630 int
   1631 bcm_tr3_wlan_port_learn_get(int unit, bcm_gport_t wlan_port_id, uint32 *flags)
   1632 {
   1633     int rv, cml = 0;
   1634     uint32 vp;
   1635     source_vp_entry_t svp;
   1636     int lport_ptr = 0;
   1637     lport_tab_entry_t lport_profile;
   1638     rtag7_port_based_hash_entry_t rtag7_entry;
   1639     void *entries[2];
   1640 
   1641     WLAN_INIT(unit);
   1642 
   1643     /* Get the VP index from the gport */
   1644     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1645 
   1646     /* Be sure the entry is used and is set for wlan */
   1647     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   1648         return BCM_E_NOT_FOUND;
   1649     }
   1650     rv = READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp);
   1651     BCM_IF_ERROR_RETURN(rv);
   1652 
   1653     /* Get lport_profile */
   1654     lport_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &svp,
   1655                                                 LPORT_PROFILE_INDEXf);
   1656     entries[0] = &lport_profile;
   1657     entries[1] = &rtag7_entry;
   1658     rv = _bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries);
   1659     BCM_IF_ERROR_RETURN(rv);
   1660     cml = soc_LPORT_TABm_field32_get(unit, &lport_profile, CML_FLAGS_NEWf);
   1661 
   1662     *flags = 0;
   1663     if (!(cml & (1 << 0))) {
   1664        *flags |= BCM_PORT_LEARN_FWD;
   1665     }
   1666     if (cml & (1 << 1)) {
   1667        *flags |= BCM_PORT_LEARN_CPU;
   1668     }
   1669     if (cml & (1 << 2)) {
   1670        *flags |= BCM_PORT_LEARN_PENDING;
   1671     }
   1672     if (cml & (1 << 3)) {
   1673        *flags |= BCM_PORT_LEARN_ARL;
   1674     }
   1675     return BCM_E_NONE;
   1676 }
   1677 
   1678 /*
   1679  * Function:
   1680  *      bcm_tr3_wlan_port_learn_set
   1681  * Purpose:
   1682  *      Set the CML bits for an wlan port.
   1683  * Returns:
   1684  *      BCM_E_XXX
   1685  */
   1686 int
   1687 bcm_tr3_wlan_port_learn_set(int unit, bcm_gport_t wlan_port_id, uint32 flags)
   1688 {
   1689     int cml_old = 0, cml = 0, rv = BCM_E_NONE;
   1690     uint32 vp;
   1691     source_vp_attributes_2_entry_t svp;
   1692     lport_tab_entry_t lport_profile;
   1693     rtag7_port_based_hash_entry_t rtag7_entry;
   1694     int lport_ptr, old_lport_ptr = -1;
   1695     void *entries[2];
   1696 
   1697     WLAN_INIT(unit);
   1698 
   1699     cml = 0;
   1700     if (!(flags & BCM_PORT_LEARN_FWD)) {
   1701        cml |= (1 << 0);
   1702     }
   1703     if (flags & BCM_PORT_LEARN_CPU) {
   1704        cml |= (1 << 1);
   1705     }
   1706     if (flags & BCM_PORT_LEARN_PENDING) {
   1707        cml |= (1 << 2);
   1708     }
   1709     if (flags & BCM_PORT_LEARN_ARL) {
   1710        cml |= (1 << 3);
   1711     }
   1712 
   1713     /* Get the VP index from the gport */
   1714     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   1715 
   1716     WLAN_LOCK(unit);
   1717     /* Be sure the entry is used and is set for WLAN */
   1718     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   1719         WLAN_UNLOCK(unit);
   1720         return BCM_E_NOT_FOUND;
   1721     }
   1722     rv = READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp);
   1723     if (rv < 0) {
   1724         WLAN_UNLOCK(unit);
   1725         return rv;
   1726     }
   1727     /* Get old lport_profile */
   1728     old_lport_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &svp,
   1729                                                     LPORT_PROFILE_INDEXf);
   1730     entries[0] = &lport_profile;
   1731     entries[1] = &rtag7_entry;
   1732     rv = _bcm_lport_profile_entry_get(unit, old_lport_ptr, 1, entries);
   1733     if (rv < 0) {
   1734         WLAN_UNLOCK(unit);
   1735         return rv;
   1736     }
   1737     cml_old = soc_LPORT_TABm_field32_get(unit, &lport_profile, CML_FLAGS_NEWf);
   1738     if (cml != cml_old) {
   1739         soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, cml);
   1740         soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, cml);
   1741         rv = _bcm_lport_profile_entry_add(unit, entries, 1,
   1742                                           (uint32 *) &lport_ptr);
   1743         if (rv < 0) {
   1744             WLAN_UNLOCK(unit);
   1745             return rv;
   1746         }
   1747         soc_SOURCE_VP_ATTRIBUTES_2m_field32_set(unit, &svp, LPORT_PROFILE_INDEXf,
   1748                                         lport_ptr);
   1749         /* coverity[negative_returns : FALSE] */
   1750         rv = WRITE_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ALL, vp, &svp);
   1751         if (BCM_FAILURE(rv)) {
   1752             WLAN_UNLOCK(unit);
   1753             return rv;
   1754         }
   1755         rv = _bcm_lport_profile_entry_delete(unit, old_lport_ptr);
   1756     }
   1757     WLAN_UNLOCK(unit);
   1758     return rv;
   1759 }
   1760 
   1761 /*
   1762  * Function:
   1763  *      _bcm_tr3_wlan_l3_intf_add
   1764  * Purpose:
   1765  *      This function adds egress l3 interface for wlan
   1766  * Parameters:
   1767  *      unit       - (IN) bcm device
   1768  *      if_info    - (OUT) egress l3 interface
   1769  * Returns:
   1770  *      BCM_E_NONE - Success
   1771  *      BCM_E_XXX
   1772  * Notes:
   1773  */
   1774 STATIC int
   1775 _bcm_tr3_wlan_l3_intf_add(int unit, _bcm_l3_intf_cfg_t *if_info)
   1776 {
   1777     int i, num_intf;
   1778     egr_l3_intf_entry_t egr_intf;
   1779     bcm_mac_t hw_mac;
   1780     num_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1781     for (i = 0; i < num_intf; i++) {
   1782         if (_BCM_WLAN_INTF_USED_GET(unit, i)) {
   1783             BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm,
   1784                                              MEM_BLOCK_ANY, i, &egr_intf));
   1785             soc_mem_mac_addr_get(unit, EGR_L3_INTFm, &egr_intf,
   1786                                  MAC_ADDRESSf, hw_mac);
   1787             if (SAL_MAC_ADDR_EQUAL(hw_mac, if_info->l3i_mac_addr)) {
   1788                 if_info->l3i_index = i;
   1789                 return BCM_E_NONE;
   1790             }
   1791         }
   1792     }
   1793     /* Create an interface */
   1794     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_intf_create(unit, if_info));
   1795     _BCM_WLAN_INTF_USED_SET(unit, if_info->l3i_index);
   1796     return BCM_E_NONE;
   1797 }
   1798 
   1799 /*
   1800  * Function:
   1801  *      _bcm_tr3_wlan_trunk_group_update
   1802  * Purpose:
   1803  *      Function to update trunk group bitmap entry
   1804  *
   1805  * Parameters:
   1806  *      unit       - (IN) bcm device
   1807  *      trunk     - (IN) Trunk ID
   1808  * Returns:
   1809  *      BCM_E_NONE - Success
   1810  *      BCM_E_XXX
   1811  * Notes:
   1812  */
   1813 STATIC int
   1814 _bcm_tr3_wlan_trunk_group_update(int unit, int trunk)
   1815 {
   1816     int i, mem_size;
   1817     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   1818     int local_member_count;
   1819     axp_wtx_trunk_group_bitmap_entry_t trunk_group_bitmap_entry; /* AXP Trunk bitmap */
   1820     bcm_pbmp_t trunk_pbmp;
   1821     soc_mem_t   mem = AXP_WTX_TRUNK_GROUP_BITMAPm;
   1822     int rv = BCM_E_NONE;
   1823 
   1824     mem_size = soc_mem_index_count(unit, mem) ;
   1825     /* mem doesn't exist. no necessary to update */
   1826     if ( mem_size <= 0 ) {
   1827         return BCM_E_NONE;
   1828     }
   1829 
   1830     if ( trunk >= mem_size ) {
   1831         return BCM_E_PARAM;
   1832     }
   1833 
   1834     sal_memset(&trunk_group_bitmap_entry, 0, sizeof(trunk_group_bitmap_entry));
   1835 
   1836     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, trunk,
   1837         SOC_MAX_NUM_PORTS, local_member_array, &local_member_count));
   1838 
   1839     BCM_PBMP_CLEAR(trunk_pbmp);
   1840     for (i = 0; i < local_member_count; i++) {
   1841         BCM_PBMP_PORT_ADD(trunk_pbmp, local_member_array[i]);
   1842     }
   1843     soc_mem_pbmp_field_set(unit, mem, &trunk_group_bitmap_entry,
   1844         TRUNK_GROUP_BITMAPf, &trunk_pbmp);
   1845 
   1846     rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, trunk, &trunk_group_bitmap_entry);
   1847 
   1848     return rv;
   1849 }
   1850 
   1851 /*
   1852  * Function:
   1853  *      _bcm_tr3_wlan_trunk_block_mask_update
   1854  * Purpose:
   1855  *      Function to update trunk block mask table
   1856  *
   1857  * Parameters:
   1858  *      unit       - (IN) bcm device
   1859  * Returns:
   1860  *      BCM_E_NONE - Success
   1861  *      BCM_E_XXX
   1862  * Notes:
   1863  */
   1864 int
   1865 _bcm_tr3_wlan_trunk_block_mask_update(int unit)
   1866 {
   1867     int index, mem_size1, mem_size2, mem_size_min;
   1868     soc_mem_t  mem1, mem2;
   1869     bcm_pbmp_t pbmp;
   1870     nonucast_trunk_block_mask_entry_t *mask_entry_1;
   1871     nonucast_trunk_block_mask_entry_t *mask_table_1;
   1872     axp_wtx_trunk_block_mask_entry_t *mask_entry_2;
   1873     axp_wtx_trunk_block_mask_entry_t *mask_table_2;
   1874     int rv = BCM_E_NONE;
   1875 
   1876     mem1 = NONUCAST_TRUNK_BLOCK_MASKm;
   1877     mem2 = AXP_WTX_TRUNK_BLOCK_MASKm;
   1878 
   1879     mem_size1 = soc_mem_index_count(unit, mem1);
   1880     mem_size2 = soc_mem_index_count(unit, mem2);
   1881 
   1882     /* mem doesn't exist. no necessary to update */
   1883     if (( mem_size1 <= 0 ) || ( mem_size2 <= 0 ) ) {
   1884         return BCM_E_NONE;
   1885     }
   1886 
   1887     mem_size_min = mem_size1 > mem_size2 ?  mem_size2 : mem_size1;
   1888 
   1889     mask_table_1 = soc_cm_salloc(unit,
   1890                                     sizeof(nonucast_trunk_block_mask_entry_t) * mem_size_min,
   1891                                     "nonuc trunk mask tbl dma");
   1892     mask_table_2 = soc_cm_salloc(unit,
   1893                                     sizeof(axp_wtx_trunk_block_mask_entry_t) * mem_size_min,
   1894                                     "axp wtx trunk mask dma");
   1895 
   1896     soc_mem_lock(unit, mem1);
   1897     if ((rv = soc_mem_read_range(unit, mem1, MEM_BLOCK_ANY, 0,
   1898                             mem_size_min - 1, mask_table_1)) < 0) {
   1899         soc_mem_unlock(unit, mem1);
   1900         soc_cm_sfree(unit, mask_table_1);
   1901         soc_cm_sfree(unit, mask_table_2);
   1902         return rv;
   1903     }
   1904 
   1905     soc_mem_lock(unit, mem2);
   1906     if ((rv = soc_mem_read_range(unit, mem2, MEM_BLOCK_ANY, 0,
   1907                             mem_size_min - 1, mask_table_2)) < 0) {
   1908         soc_mem_unlock(unit, mem1);
   1909         soc_mem_unlock(unit, mem2);
   1910         soc_cm_sfree(unit, mask_table_1);
   1911         soc_cm_sfree(unit, mask_table_2);
   1912         return rv;
   1913     }
   1914 
   1915     for (index = 0; index < mem_size_min; index++) {
   1916         mask_entry_1 = soc_mem_table_idx_to_pointer(unit, mem1,
   1917                                             nonucast_trunk_block_mask_entry_t *,
   1918                                             mask_table_1, index);
   1919         soc_mem_pbmp_field_get(unit, mem1, mask_entry_1, BLOCK_MASKf, &pbmp);
   1920 
   1921         mask_entry_2 = soc_mem_table_idx_to_pointer(unit, mem2,
   1922                                             axp_wtx_trunk_block_mask_entry_t *,
   1923                                             mask_table_2, index);
   1924         soc_mem_pbmp_field_set(unit, mem2, mask_entry_2, TRUNK_BLOCK_MASKf, &pbmp);
   1925     }
   1926 
   1927     rv = soc_mem_write_range(unit, mem2, MEM_BLOCK_ANY, 0, mem_size_min - 1, mask_table_2);
   1928 
   1929     soc_mem_unlock(unit, mem2);
   1930     soc_mem_unlock(unit, mem1);
   1931 
   1932     soc_cm_sfree(unit, mask_table_1);
   1933     soc_cm_sfree(unit, mask_table_2);
   1934 
   1935     return rv;
   1936 }
   1937 
   1938 typedef struct _bcm_tr3_ing_nh_info_s {
   1939     int      port;
   1940     int      module;
   1941     int      trunk;
   1942     uint32   mtu;
   1943 } _bcm_tr3_ing_nh_info_t;
   1944 
   1945 typedef struct _bcm_tr3_egr_nh_info_s {
   1946     uint16    port;
   1947     uint8     entry_type;
   1948     uint16    capwap_mc_bitmap;
   1949     int       dvp;
   1950     int       intf_num;
   1951     bcm_mac_t macda;
   1952 } _bcm_tr3_egr_nh_info_t;
   1953 
   1954 /*
   1955  * Function:
   1956  *      bcm_tr3_wlan_nh_info_add
   1957  * Purpose:
   1958  *      This function adds resolved wlan gport in ingress and egress next hop
   1959  *      table
   1960  * Parameters:
   1961  *      unit        - (IN) bcm device
   1962  *      wlan_port   - (IN) wlan port info
   1963  *      vp          - (IN) virtual port
   1964  *      drop        - (IN) drop packet flag
   1965  *      nh_index    - (OUT) nh_index
   1966  *      local_port  - (OUT) outgoing local port
   1967  *      is_local    - (OUT) local port flag
   1968  * Returns:
   1969  *      BCM_E_NONE - Success
   1970  *      BCM_E_XXX
   1971  * Notes:
   1972  *      Get DVP from wlan gport
   1973  *      Get next hop index, calling bcm_xgs3_nh_add
   1974  *      Resolve wlan gport to port, modid, trunk id
   1975  *      Resolve trunk ports to physical ports
   1976  *      Add to L3 ingress next hop table with L2 DVP type
   1977  *      Create L2 interface and add l2 intf, dvp toegress next hop table
   1978  */
   1979 STATIC int
   1980 _bcm_tr3_wlan_nh_info_add(int unit, bcm_wlan_port_t *wlan_port, int vp, int drop,
   1981                            int *nh_index, bcm_port_t *local_port, int *is_local)
   1982 {
   1983     initial_ing_l3_next_hop_entry_t initial_ing_nh; /* Initial ingress L3 NH  */
   1984     ing_l3_next_hop_entry_t     ing_nh;             /* Ingress Next hop entry */
   1985     egr_l3_next_hop_entry_t     egr_nh;             /* Egress Next hop entry  */
   1986     _bcm_tr3_ing_nh_info_t      ing_nh_info;        /* Ingress Next hop info  */
   1987     _bcm_tr3_egr_nh_info_t      egr_nh_info;        /* Egress Next hop info   */
   1988     bcm_l3_egress_t             nh_info;            /* L3 Next hop info       */
   1989     _bcm_l3_intf_cfg_t          if_info;            /* L3 Interface           */
   1990     uint32                      nh_flags;           /* next hop flags         */
   1991     int                         gport_id, rv;       /* function vars          */
   1992     bcm_module_t                mod_out;            /* Port module out id     */
   1993     bcm_port_t                  port_out;           /* port destined          */
   1994     bcm_trunk_t                 trunk_id;           /* Trunk Id               */
   1995     _bcm_port_info_t            *info;              /* port info              */
   1996     uint32                      mtu_profile_index;  /* Index to MTU profile   */
   1997     uint32                      port_flags;
   1998 
   1999     /* Initialize values */
   2000     sal_memset(&ing_nh_info, 0, sizeof(_bcm_tr3_ing_nh_info_t));
   2001     sal_memset(&egr_nh_info, 0, sizeof(_bcm_tr3_egr_nh_info_t));
   2002     *local_port = 0;
   2003     *is_local = 0;
   2004     ing_nh_info.mtu = 0x3fff;
   2005     ing_nh_info.port = -1;
   2006     ing_nh_info.module = -1;
   2007     ing_nh_info.trunk = -1;
   2008 
   2009     egr_nh_info.dvp = vp;           /* dvp port */
   2010     egr_nh_info.intf_num = -1;
   2011     egr_nh_info.capwap_mc_bitmap = 0;
   2012     egr_nh_info.entry_type = 0x4;   /* wlan entry type */
   2013 
   2014     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   2015         if ((*nh_index > soc_mem_index_max(unit, EGR_L3_NEXT_HOPm)) ||
   2016             (*nh_index < soc_mem_index_min(unit, EGR_L3_NEXT_HOPm)))  {
   2017             return BCM_E_PARAM;
   2018         }
   2019         /* Read the existing egress next_hop entry */
   2020         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2021                           *nh_index, &egr_nh);
   2022         BCM_IF_ERROR_RETURN(rv);
   2023     } else {
   2024         /*
   2025          * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
   2026          * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
   2027          * allocated but nothing is written to hardware. The "nh_info"
   2028          * in this case is not used, so just set to all zeros.
   2029          */
   2030         bcm_l3_egress_t_init(&nh_info);
   2031 
   2032         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
   2033         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, nh_index);
   2034         BCM_IF_ERROR_RETURN(rv);
   2035     }
   2036 
   2037     /* Resolve the gport */
   2038     rv = _bcm_esw_gport_resolve(unit, wlan_port->port, &mod_out,
   2039                                 &port_out, &trunk_id, &gport_id);
   2040     BCM_IF_ERROR_RETURN(rv);
   2041 
   2042     if (BCM_GPORT_IS_TRUNK(wlan_port->port)) {
   2043         ing_nh_info.module = -1;
   2044         ing_nh_info.port = -1;
   2045         egr_nh_info.port = -1;
   2046         ing_nh_info.trunk = trunk_id;
   2047         WLAN_INFO(unit)->port_info[vp].modid = -1;
   2048         WLAN_INFO(unit)->port_info[vp].port = -1;
   2049         WLAN_INFO(unit)->port_info[vp].tgid = trunk_id;
   2050     } else {
   2051         ing_nh_info.module = mod_out;
   2052         ing_nh_info.port = port_out;
   2053         egr_nh_info.port = port_out;
   2054         ing_nh_info.trunk = -1;
   2055         BCM_IF_ERROR_RETURN(
   2056             _bcm_esw_modid_is_local(unit, mod_out, is_local));
   2057         if (TRUE == *is_local) {
   2058             /* Indicated to calling function that this is a local port */
   2059             *is_local = 1;
   2060             *local_port = ing_nh_info.port;
   2061         }
   2062         WLAN_INFO(unit)->port_info[vp].modid = mod_out;
   2063         WLAN_INFO(unit)->port_info[vp].port = port_out;
   2064         WLAN_INFO(unit)->port_info[vp].tgid = -1;
   2065     }
   2066 
   2067     if (wlan_port->flags & BCM_WLAN_PORT_EGRESS_CLIENT_MULTICAST) {
   2068         /* CAPWAP_WLAN_MC_BITMAP and MAC_ADDRESS are overlays */
   2069         egr_nh_info.capwap_mc_bitmap = wlan_port->client_multicast;
   2070     }
   2071 
   2072     /* Write INITIAL_ING_L3_NEXT_HOP entry */
   2073     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   2074     if (ing_nh_info.trunk == -1) {
   2075         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   2076                             &initial_ing_nh, PORT_NUMf, ing_nh_info.port);
   2077         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   2078                             &initial_ing_nh, MODULE_IDf, ing_nh_info.module);
   2079     } else {
   2080         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   2081                             &initial_ing_nh, Tf, 1);
   2082         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
   2083                             &initial_ing_nh, TGIDf, ing_nh_info.trunk);
   2084         BCM_GPORT_TRUNK_SET(*local_port, ing_nh_info.trunk);
   2085     }
   2086     rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   2087                        MEM_BLOCK_ALL, *nh_index, &initial_ing_nh);
   2088     if (rv < 0) {
   2089         goto cleanup;
   2090     }
   2091 
   2092     /* Add an L3 interface entry with L2_SWITCH=1 - ref count if exists */
   2093     sal_memset(&if_info, 0, sizeof(_bcm_l3_intf_cfg_t));
   2094     if_info.l3i_flags |= BCM_L3_L2ONLY | BCM_L3_SECONDARY;
   2095     rv = _bcm_tr3_wlan_l3_intf_add(unit, &if_info);
   2096     if (BCM_FAILURE(rv)) {
   2097         goto cleanup;
   2098     }
   2099 
   2100     /* Populate the fields of WLAN::EGR_l3_NEXT_HOP */
   2101     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   2102     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2103                         ENTRY_TYPEf, egr_nh_info.entry_type);
   2104     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2105                         WLAN__DVPf, egr_nh_info.dvp);
   2106     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2107                         WLAN__INTF_NUMf, if_info.l3i_index);
   2108     if (WLAN_INFO(unit)->port_info[vp].tgid == -1) {
   2109         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, WLAN__DGLPf,
   2110                             BCM_L3_DGLP_GET(mod_out, egr_nh_info.port));
   2111     } else {
   2112         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, WLAN__DGLPf,
   2113                             BCM_TGID_TRUNK_INDICATOR(unit) | WLAN_INFO(unit)->port_info[vp].tgid);
   2114     }
   2115 
   2116     if (egr_nh_info.capwap_mc_bitmap != 0) {
   2117         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2118                             WLAN__CAPWAP_WLAN_MC_BITMAPf,
   2119                             egr_nh_info.capwap_mc_bitmap);
   2120     }
   2121 
   2122     /* Write EGR_L3_NEXT_HOP entry */
   2123     rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   2124                        MEM_BLOCK_ALL, *nh_index, &egr_nh);
   2125     if (rv < 0) {
   2126         goto cleanup;
   2127     }
   2128 
   2129     /* Write ING_L3_NEXT_HOP entry */
   2130     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   2131     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, drop);
   2132     if (ing_nh_info.trunk == -1) {
   2133         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2134                             &ing_nh, PORT_NUMf, ing_nh_info.port);
   2135         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2136                             &ing_nh, MODULE_IDf, ing_nh_info.module);
   2137     } else {
   2138         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2139                             &ing_nh, Tf, 1);
   2140         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2141                             &ing_nh, TGIDf, ing_nh_info.trunk);
   2142     }
   2143     if (drop) {
   2144         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, drop);
   2145     }
   2146     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2147                        &ing_nh, ENTRY_TYPEf, 0x2); /* L2 DVP */
   2148     /* L3 api interfaces for ING_L3_ATTRIBUTE table */
   2149     BCM_IF_ERROR_RETURN(_bcm_tr3_mtu_profile_index_get(unit, 
   2150                                    ing_nh_info.mtu, &mtu_profile_index));
   2151     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2152                    &ing_nh, DVP_ATTRIBUTE_1_INDEXf, mtu_profile_index);
   2153     /* Enable NLF forwarding */
   2154     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
   2155                        &ing_nh, NLF_FORWARDING_ENABLEf, 1);
   2156     rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
   2157                        MEM_BLOCK_ALL, *nh_index, &ing_nh);
   2158     if (rv < 0) {
   2159         goto cleanup;
   2160     }
   2161 
   2162     /* Update the physical port's SW state */
   2163     if (*is_local) {
   2164         bcm_port_t phys_port = WLAN_INFO(unit)->port_info[vp].port;
   2165         if (soc_feature(unit, soc_feature_sysport_remap)) {
   2166             BCM_XLATE_SYSPORT_S2P(unit, &phys_port);
   2167         }
   2168         _bcm_port_info_access(unit, phys_port, &info);
   2169         info->vp_count++;
   2170         BCM_IF_ERROR_RETURN(
   2171             bcm_esw_port_vlan_member_get(
   2172                 unit, phys_port, &port_flags));
   2173         BCM_IF_ERROR_RETURN(
   2174             bcm_esw_port_vlan_member_set(
   2175                 unit, phys_port, port_flags));
   2176     }
   2177 
   2178     /* If associated with a trunk, update each local physical port's SW state */
   2179     if (ing_nh_info.trunk != -1) {
   2180         int idx;
   2181         bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   2182         int local_member_count;
   2183 
   2184         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
   2185                 SOC_MAX_NUM_PORTS, local_member_array, &local_member_count);
   2186         if (rv < 0) {
   2187             goto cleanup;
   2188         }
   2189         for (idx = 0; idx < local_member_count; idx++) {
   2190             _bcm_port_info_access(unit, local_member_array[idx], &info);
   2191             info->vp_count++;
   2192             BCM_IF_ERROR_RETURN(
   2193                 bcm_esw_port_vlan_member_get(
   2194                     unit, local_member_array[idx], &port_flags));
   2195             BCM_IF_ERROR_RETURN(
   2196                 bcm_esw_port_vlan_member_set(
   2197                     unit, local_member_array[idx], port_flags));
   2198         }
   2199     }
   2200 
   2201     /* If associated with a trunk, update axp trunk group bitmap table */
   2202     if (WLAN_INFO(unit)->port_info[vp].tgid != -1) {
   2203         _bcm_tr3_wlan_trunk_group_update(unit, WLAN_INFO(unit)->port_info[vp].tgid);
   2204     }
   2205 
   2206     return rv;
   2207 
   2208 cleanup:
   2209     if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   2210         (void) bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, *nh_index);
   2211     }
   2212     return rv;
   2213 }
   2214 
   2215 /*
   2216  * Function:
   2217  *      bcm_tr3_wlan_nh_info_delete
   2218  * Purpose:
   2219  *      This function clears and delete next hop table
   2220  * Parameters:
   2221  *      unit        - (IN) bcm device
   2222  *      nh_index    - (IN) nh_index
   2223  * Returns:
   2224  *      BCM_E_NONE - Success
   2225  *      BCM_E_XXX
   2226  * Notes:
   2227  *      Clear Ingress and egress next hop table
   2228  *      Delete Next hop index
   2229  */
   2230 STATIC int
   2231 _bcm_tr3_wlan_nh_info_delete(int unit, int nh_index)
   2232 {
   2233     int rv = BCM_E_NONE;
   2234     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   2235     ing_l3_next_hop_entry_t ing_nh;
   2236     egr_l3_next_hop_entry_t egr_nh;
   2237     int attr_index;
   2238 
   2239     if (nh_index <= 0) {
   2240         return BCM_E_NONE;
   2241     }    
   2242 
   2243     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   2244                                   MEM_BLOCK_ANY, nh_index, &egr_nh));
   2245 
   2246     if (soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
   2247                                                 ENTRY_TYPEf) != 0x4) {
   2248         /* Not a WLAN VP */
   2249         return BCM_E_NOT_FOUND;
   2250     }
   2251 
   2252     /* Clear EGR_L3_NEXT_HOP entry */
   2253     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   2254     BCM_IF_ERROR_RETURN (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   2255                                    MEM_BLOCK_ALL, nh_index, &egr_nh));
   2256 
   2257     /* Read  ING_L3_NEXT_HOPm */
   2258     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm,
   2259                                   MEM_BLOCK_ANY, nh_index, &ing_nh));
   2260 
   2261 
   2262     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh,
   2263                                                 ENTRY_TYPEf) != 0x2) {
   2264         /* Not a L2 DVP */
   2265         return BCM_E_NOT_FOUND;
   2266     }
   2267 
   2268 
   2269     /* Delete ING_L3_NEXT_HOP_ATTRIBUTE_1 reference */
   2270     attr_index = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh,
   2271                                                 DVP_ATTRIBUTE_1_INDEXf);
   2272     BCM_IF_ERROR_RETURN(_bcm_ing_l3_nh_attrib_entry_delete(unit, attr_index));
   2273 
   2274     /* Clear ING_L3_NEXT_HOP entry */
   2275     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   2276     BCM_IF_ERROR_RETURN (soc_mem_write (unit, ING_L3_NEXT_HOPm,
   2277                                    MEM_BLOCK_ALL, nh_index, &ing_nh));
   2278 
   2279     /* Clear INITIAL_ING_L3_NEXT_HOP entry */
   2280     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   2281     BCM_IF_ERROR_RETURN (soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   2282                                    MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
   2283 
   2284     /* Free the next-hop entry. */
   2285     rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
   2286     return rv;
   2287 }
   2288 /*
   2289  * Function:
   2290  *      _bcm_tr3_wlan_nh_info_get
   2291  * Purpose:
   2292  *      This funtion gets wlan port info from next hop index
   2293  * Parameters:
   2294  *      unit       - (IN) bcm device
   2295  *      wlan_port  - (IN/OUT) wlan port info
   2296  *      nh_index   - next hop index
   2297  * Returns:
   2298  *      BCM_E_NONE - Success
   2299  *      BCM_E_XXX
   2300  * Notes:
   2301  */
   2302 STATIC int
   2303 _bcm_tr3_wlan_nh_info_get(int unit, bcm_wlan_port_t *wlan_port, int nh_index)
   2304 {
   2305     ing_l3_next_hop_entry_t ing_nh;
   2306     bcm_module_t mod_out, mod_in;
   2307     bcm_port_t port_out, port_in;
   2308     bcm_trunk_t trunk_id;
   2309 
   2310     /* Read the HW entries */
   2311     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2312                                       nh_index, &ing_nh));
   2313 
   2314     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh,
   2315                                                 ENTRY_TYPEf) == 0x2) {
   2316         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   2317             trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   2318             BCM_GPORT_TRUNK_SET(wlan_port->port, trunk_id);
   2319         } else {
   2320             mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   2321             port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   2322 
   2323             SOC_IF_ERROR_RETURN
   2324                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   2325                                          mod_in, port_in, &mod_out, &port_out));
   2326             BCM_GPORT_MODPORT_SET(wlan_port->port, mod_out, port_out);
   2327         }
   2328     } else {
   2329         return BCM_E_NOT_FOUND;
   2330     }
   2331 
   2332     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, DROPf)) {
   2333         wlan_port->flags |= BCM_WLAN_PORT_DROP;
   2334     }
   2335 
   2336     return BCM_E_NONE;
   2337 }
   2338 
   2339 /*
   2340  * Function:
   2341  *      _bcm_tr3_wlan_match_get
   2342  * Purpose:
   2343  *      Get wlan port info for the virtual port
   2344  * Parameters:
   2345  *      unit       - (IN) bcm device
   2346  *      vp         - (IN) Virtual port no.
   2347  * Returns:
   2348  *      BCM_E_NONE - Success
   2349  *      BCM_E_XXX
   2350  * Notes:
   2351  */
   2352 STATIC int
   2353 _bcm_tr3_wlan_match_get(int unit, bcm_wlan_port_t *wlan_port, int vp)
   2354 {
   2355     int rv = BCM_E_NONE;
   2356     uint64 temp;
   2357 
   2358     if (WLAN_INFO(unit)->port_info[vp].flags &
   2359          _BCM_WLAN_PORT_MATCH_TUNNEL) {
   2360 
   2361         wlan_port->flags |= BCM_WLAN_PORT_MATCH_TUNNEL;
   2362         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   2363 
   2364     } else if (WLAN_INFO(unit)->port_info[vp].flags &
   2365                _BCM_WLAN_PORT_MATCH_BSSID_RADIO) {
   2366         wlan_port->flags |= BCM_WLAN_PORT_BSSID_RADIO;
   2367 
   2368         SAL_MAC_ADDR_TO_UINT64
   2369            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   2370         SAL_MAC_ADDR_FROM_UINT64(wlan_port->bssid, temp);
   2371         wlan_port->radio = WLAN_INFO(unit)->port_info[vp].match_radio;
   2372         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   2373 
   2374     } else if (WLAN_INFO(unit)->port_info[vp].flags &
   2375                _BCM_WLAN_PORT_MATCH_BSSID) {
   2376         wlan_port->flags |= BCM_WLAN_PORT_BSSID;
   2377 
   2378         SAL_MAC_ADDR_TO_UINT64
   2379            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   2380         SAL_MAC_ADDR_FROM_UINT64(wlan_port->bssid, temp);
   2381         wlan_port->match_tunnel = WLAN_INFO(unit)->port_info[vp].match_tunnel;
   2382     }
   2383     return rv;
   2384 }
   2385 /*
   2386  * Function:
   2387  *      _bcm_tr3_wlan_match_delete
   2388  * Purpose:
   2389  *      Tunnel Id, BSSID, RID keys are matched to delete Source Virtual port.
   2390  * Parameters:
   2391  *      unit       - (IN) bcm device
   2392  *      vp         - (IN) Virtual port no.
   2393  * Returns:
   2394  *      BCM_E_NONE - Success
   2395  *      BCM_E_XXX
   2396  * Notes:
   2397  */
   2398 STATIC int
   2399 _bcm_tr3_wlan_match_delete(int unit, int vp)
   2400 {
   2401     int  rv = BCM_E_NONE;
   2402     axp_wrx_svp_assignment_entry_t wlan_svp;
   2403     uint32 tunnel;
   2404 
   2405     sal_memset(&wlan_svp, 0, sizeof(axp_wrx_svp_assignment_entry_t));
   2406 
   2407     if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_BSSID) {
   2408         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x2);
   2409         soc_mem_mac_addr_set(unit, AXP_WRX_SVP_ASSIGNMENTm, &wlan_svp, BSSIDf,
   2410                              WLAN_INFO(unit)->port_info[vp].match_bssid);
   2411 
   2412     } else if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_BSSID_RADIO) {
   2413         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x1);
   2414         soc_mem_mac_addr_set(unit, AXP_WRX_SVP_ASSIGNMENTm, &wlan_svp, BSSIDf,
   2415                              WLAN_INFO(unit)->port_info[vp].match_bssid);
   2416         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, RIDf,
   2417                                         WLAN_INFO(unit)->port_info[vp].match_radio);
   2418 
   2419     } else if (WLAN_INFO(unit)->port_info[vp].flags & _BCM_WLAN_PORT_MATCH_TUNNEL) {
   2420         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x3);
   2421         tunnel = BCM_GPORT_TUNNEL_ID_GET(WLAN_INFO(unit)->port_info[vp].match_tunnel);
   2422         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, TUNNEL_IDf,
   2423                                         tunnel);
   2424     } else {
   2425         return rv;
   2426     }
   2427 
   2428     rv = soc_mem_delete(unit, AXP_WRX_SVP_ASSIGNMENTm, MEM_BLOCK_ALL, &wlan_svp);
   2429     return rv;
   2430 }
   2431 
   2432 /*
   2433  * Function:
   2434  *      _bcm_tr3_wlan_match_add
   2435  * Purpose:
   2436  *      Tunnel Id, BSSID, RID keys are matched to assign Source Virtual port.
   2437  *      This function adds Expected Tunnel Id, Tunnel Id, BSSID, RID keys for
   2438  *      the Virtual port in  wlan svp assignment table.
   2439  * Parameters:
   2440  *      unit       - (IN) bcm device
   2441  *      wlan_port  - (IN/OUT) WLAN Port Configuration Info
   2442  *      vp         - (IN) Virtual port no.
   2443  * Returns:
   2444  *      BCM_E_NONE - Success
   2445  *      BCM_E_XXX
   2446  * Notes:
   2447  *     (keys)    +----------+
   2448  *    BSSID/RID -| WLAN SVP |- SVP
   2449  *    TunnelID  -|Assignment|- EXP_TUNNEL_ID
   2450  *               +----------+
   2451  */
   2452 STATIC int
   2453 _bcm_tr3_wlan_match_add(int unit, bcm_wlan_port_t *wlan_port, int vp)
   2454 {
   2455     int rv = BCM_E_NONE;
   2456     axp_wrx_svp_assignment_entry_t wlan_svp;
   2457     uint32 tunnel;
   2458     uint64 temp;
   2459 
   2460     sal_memset(&wlan_svp, 0, sizeof(axp_wrx_svp_assignment_entry_t));
   2461     soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, VALIDf, 1);
   2462     soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, SVPf, vp);
   2463 
   2464     if (wlan_port->flags & BCM_WLAN_PORT_BSSID) {
   2465         /* Entry Type BSSID_KEY (0x2) */
   2466         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x2);
   2467         soc_mem_mac_addr_set(unit, AXP_WRX_SVP_ASSIGNMENTm, &wlan_svp, BSSIDf,
   2468                              wlan_port->bssid);
   2469         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   2470         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, EXP_TUNNEL_IDf,
   2471                                         tunnel);
   2472         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID;
   2473         SAL_MAC_ADDR_TO_UINT64(wlan_port->bssid, temp);
   2474         SAL_MAC_ADDR_FROM_UINT64
   2475            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   2476         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   2477 
   2478     } else if (wlan_port->flags & BCM_WLAN_PORT_BSSID_RADIO) {
   2479         /* Entry Key Type RID_BSSID_KEY (0x01) */
   2480         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x1);
   2481         soc_mem_mac_addr_set(unit, AXP_WRX_SVP_ASSIGNMENTm, &wlan_svp, BSSIDf,
   2482                              wlan_port->bssid);
   2483         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, RIDf,
   2484                                         wlan_port->radio);
   2485         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   2486         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, EXP_TUNNEL_IDf,
   2487                                         tunnel);
   2488         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_BSSID_RADIO;
   2489         SAL_MAC_ADDR_TO_UINT64(wlan_port->bssid, temp);
   2490         SAL_MAC_ADDR_FROM_UINT64
   2491            (WLAN_INFO(unit)->port_info[vp].match_bssid, temp);
   2492         WLAN_INFO(unit)->port_info[vp].match_radio = wlan_port->radio;
   2493         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   2494 
   2495     } else if (wlan_port->flags & BCM_WLAN_PORT_MATCH_TUNNEL) {
   2496         /* Entry type TUNNEL_ID_KEY (0x3) */
   2497         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, ENTRY_TYPEf, 0x3);
   2498         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   2499         soc_AXP_WRX_SVP_ASSIGNMENTm_field32_set(unit, &wlan_svp, TUNNEL_IDf,
   2500                                         tunnel);
   2501         WLAN_INFO(unit)->port_info[vp].flags |= _BCM_WLAN_PORT_MATCH_TUNNEL;
   2502         WLAN_INFO(unit)->port_info[vp].match_tunnel = wlan_port->match_tunnel;
   2503     }
   2504     rv = soc_mem_insert(unit, AXP_WRX_SVP_ASSIGNMENTm, MEM_BLOCK_ALL, &wlan_svp);
   2505     return rv;
   2506 }
   2507 
   2508 
   2509 
   2510 /*
   2511  * Function:
   2512  *      bcm_wlan_port_add
   2513  * Purpose:
   2514  *      Create or replace a WLAN port
   2515  * Parameters:
   2516  *      unit        - (IN)  Device Number
   2517  *      wlan_port   - (IN/OUT) WLAN port configuration info
   2518  * Returns:
   2519  *      BCM_E_XXX
   2520  * Notes:
   2521  *      For AC-to-AC VPs, the match_tunnel and egress_tunnel must have the same
   2522  *      ID. That way we can use a single VP for both directions. This constrains
   2523  *      the application to use the lower half of the tunnel initiators. Below is
   2524  *      the wlan port linkage to tables.
   2525  *
   2526  *      wlan_port(gport)
   2527  *          |
   2528  *          |                                                                    
   2529  *          +---[VP]-[SVP]-->[SOURCE_VP]---->{LPORT_TABLE}                       
   2530  *              |     |                                                         
   2531  *              |     +---->[ING_DVP_TABLE]                                     
   2532  *              |         (nhi)|                                                
   2533  *              |              +->{ING_L3_NEXT_HOP}                             
   2534  *              |              |                                                
   2535  *              |              +->{INITIAL_ING_L3_NEXT_HOP}                     
   2536  *              |              |                                                
   2537  *              |              +->{EGR_L3_NEXT_HOP}->(EGR_L3_INTF) 
   2538  *              |                                                               
   2539  *              |                                                               
   2540  *              +---[DVP]-->[EGR_DVP_ATTRIBUTE]                                 
   2541  *                             |                                                
   2542  *                             +--{AXP_WTX_DVP_PROFILE}->(AXP_WTX_TUNNEL)
   2543  */
   2544 int
   2545 bcm_tr3_wlan_port_add(int unit, bcm_wlan_port_t *wlan_port)
   2546 {
   2547     int drop, mode, is_local = 0, rv = BCM_E_PARAM, nh_index = 0;
   2548     int vp, num_vp, lport_ptr = -1;
   2549     int tpid_enable = 0, tpid_index;
   2550     uint32 wlan_dvp_idx;
   2551     bcm_port_t                      local_port;     /* Local port             */
   2552     bcm_module_t                    my_modid;       /* Switch module id       */
   2553     source_vp_attributes_2_entry_t  svp;            /* SVP Attributes         */
   2554     ing_dvp_table_entry_t           dvp;            /* Ingress DVP Attributes */
   2555     egr_dvp_attribute_entry_t       wlan_dvp;       /* Egress wlan dvp        */
   2556     axp_wtx_dvp_profile_entry_t     axp_wtx_dvp;    /* AXP DVP Profile        */
   2557     axp_wtx_tunnel_entry_t          axp_wtx_tunnel[_BCM_WLAN_TNL_ENTRY_WIDTH]; 
   2558                                                     /* AXP WTX Tunnel table   */
   2559     lport_tab_entry_t               lport_profile;  /* VP Lport table         */
   2560     rtag7_port_based_hash_entry_t   rtag7_entry;    /* Part of Lport table    */
   2561     uint32                          tunnel;         /* match tunnelid         */
   2562     void                            *entries[2];    /* For lport profile mem  */
   2563     int cml_default_enable=0, cml_default_new=0, cml_default_move=0;
   2564     _bcm_vp_info_t vp_info;
   2565 
   2566     _bcm_vp_info_init(&vp_info);
   2567     vp_info.vp_type = _bcmVpTypeWlan;
   2568 
   2569     WLAN_INIT(unit);
   2570 
   2571     rv = bcm_xgs3_l3_egress_mode_get(unit, &mode);
   2572     BCM_IF_ERROR_RETURN(rv);
   2573     if (!mode) {
   2574         LOG_INFO(BSL_LS_BCM_L3,
   2575                  (BSL_META_U(unit,
   2576                              "L3 egress mode must be set first\n")));
   2577         return BCM_E_DISABLED;
   2578     }
   2579 
   2580     if (!BCM_GPORT_IS_TUNNEL(wlan_port->match_tunnel)) {
   2581         return BCM_E_BADID;
   2582     } else {
   2583         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->match_tunnel);
   2584         if (tunnel > (1 << soc_mem_field_length(unit, AXP_WRX_SVP_ASSIGNMENTm,
   2585                                                EXP_TUNNEL_IDf)) - 1) {
   2586             return BCM_E_PARAM;
   2587         }
   2588     }
   2589 
   2590     WLAN_LOCK(unit);
   2591     /* Allocate a new VP or use provided one */
   2592     if (wlan_port->flags & BCM_WLAN_PORT_WITH_ID) {
   2593         if (!BCM_GPORT_IS_WLAN_PORT((wlan_port->wlan_port_id))) {
   2594             WLAN_UNLOCK(unit);
   2595             return BCM_E_PARAM;
   2596         }
   2597         vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port->wlan_port_id);
   2598         if (vp >= soc_mem_index_count(unit, SOURCE_VP_ATTRIBUTES_2m)) {
   2599             WLAN_UNLOCK(unit);
   2600             return BCM_E_PARAM;
   2601         }
   2602         if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   2603             if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   2604                 WLAN_UNLOCK(unit);
   2605                 return BCM_E_EXISTS;
   2606             }
   2607         } else {
   2608             rv = _bcm_vp_used_set(unit, vp, vp_info);
   2609             if (rv < 0) {
   2610                 WLAN_UNLOCK(unit);
   2611                 return rv;
   2612             }
   2613         }
   2614     } else {
   2615         /* allocate a new VP index */
   2616         num_vp = soc_mem_index_count(unit, SOURCE_VP_ATTRIBUTES_2m);
   2617         rv = _bcm_vp_alloc(unit, 0, (num_vp - 1), 1, SOURCE_VP_ATTRIBUTES_2m,
   2618                            vp_info, &vp);
   2619         if (rv < 0) {
   2620             WLAN_UNLOCK(unit);
   2621             return rv;
   2622         }
   2623     }
   2624 
   2625     /* Program, the next hop, matching and egress tables */
   2626     sal_memset(&lport_profile, 0, sizeof(lport_tab_entry_t));
   2627     sal_memset(&rtag7_entry, 0, sizeof(rtag7_port_based_hash_entry_t));
   2628 
   2629     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   2630         /* For existing ports, NH entry already exists */
   2631         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp);
   2632         if (rv < 0) {
   2633             WLAN_UNLOCK(unit);
   2634             return rv;
   2635         }
   2636         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   2637                                                   NEXT_HOP_INDEXf);
   2638         /* Read the existing SVP entry for potential modifications */
   2639         rv = READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp);
   2640         if (rv < 0) {
   2641             WLAN_UNLOCK(unit);
   2642             return rv;
   2643         }
   2644     } else {
   2645         sal_memset(&svp, 0, sizeof(source_vp_attributes_2_entry_t));
   2646         sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
   2647         sal_memset(&wlan_dvp, 0, sizeof(egr_dvp_attribute_entry_t));
   2648         /* Allocate a default profile entry for SVPs */
   2649 
   2650         /* Add 802.1Q outer TPID entry */
   2651         rv = _bcm_fb2_outer_tpid_entry_add(unit, 0x8100, &tpid_index);
   2652         if (rv < 0) {
   2653             WLAN_UNLOCK(unit);
   2654             goto port_cleanup;
   2655         }
   2656         tpid_enable = (1 << tpid_index);
   2657 
   2658         /* Set to Default VID (0x1) */
   2659         soc_LPORT_TABm_field32_set(unit, &lport_profile, PORT_VIDf, 0x1);
   2660         soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2661                                    TRUST_INCOMING_VIDf, 0x1);
   2662         soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2663                                    OUTER_TPID_ENABLEf, tpid_enable);
   2664         soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2665                                    MAC_BASED_VID_ENABLEf, 0x1);
   2666         if (!(wlan_port->flags & BCM_WLAN_PORT_NETWORK)) {
   2667             soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2668                                        PORT_BRIDGEf, 0x1);
   2669         }
   2670 
   2671         /* Q-in-Q( subnet based inner-outer vids) enable */
   2672         soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2673                                    SUBNET_BASED_VID_ENABLEf, 0x1);
   2674         /* Set Hardware Learning */
   2675 
   2676         /* Set the CML */
   2677         rv = _bcm_vp_default_cml_mode_get (unit, 
   2678                            &cml_default_enable, &cml_default_new, 
   2679                            &cml_default_move);
   2680          if (rv < 0) {
   2681             WLAN_UNLOCK(unit);
   2682             goto port_cleanup;
   2683          }
   2684 
   2685         if (cml_default_enable) {
   2686             /* Set the CML to default values */
   2687            soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, cml_default_new);
   2688            soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, cml_default_move);
   2689         } else {
   2690             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
   2691             soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_NEWf, 0x8);
   2692             soc_LPORT_TABm_field32_set(unit, &lport_profile, CML_FLAGS_MOVEf, 0x8);
   2693         }
   2694 
   2695         soc_LPORT_TABm_field32_set(unit, &lport_profile, PRI_MAPPINGf,
   2696                                    0xfac688);
   2697         soc_LPORT_TABm_field32_set(unit, &lport_profile, CFI_0_MAPPINGf, 0);
   2698         soc_LPORT_TABm_field32_set(unit, &lport_profile, CFI_1_MAPPINGf, 1);
   2699         soc_LPORT_TABm_field32_set(unit, &lport_profile, V4L3_ENABLEf, 0x1);
   2700         soc_LPORT_TABm_field32_set(unit, &lport_profile, V6L3_ENABLEf, 0x1);
   2701         soc_LPORT_TABm_field32_set(unit, &lport_profile, V4IPMC_ENABLEf, 0x1);
   2702         soc_LPORT_TABm_field32_set(unit, &lport_profile, V6IPMC_ENABLEf, 0x1);
   2703         soc_LPORT_TABm_field32_set(unit, &lport_profile, IPMC_DO_VLANf, 0x1);
   2704         soc_LPORT_TABm_field32_set(unit, &lport_profile, FILTER_ENABLEf, 0x1);
   2705         soc_LPORT_TABm_field32_set(unit, &lport_profile, VFP_ENABLEf, 0x1);
   2706         /* Allocate a fixed high index for the PORT_FIELD_SEL */
   2707         soc_LPORT_TABm_field32_set(unit, &lport_profile,
   2708                                    FP_PORT_FIELD_SEL_INDEXf,
   2709                                    soc_mem_index_max(unit, FP_PORT_FIELD_SELm));
   2710         /* The vt_key_types must be set to (MACSA)0x3 or (IPv4SIP)0x7 for WLAN */
   2711         soc_LPORT_TABm_field32_set(unit, &lport_profile, VT_KEY_TYPEf,
   2712                                    TR3_PT_XLT_KEY_TYPE_VLAN_MAC);
   2713         soc_LPORT_TABm_field32_set(unit, &lport_profile, VT_KEY_TYPE_2f,
   2714                                    TR3_PT_XLT_KEY_TYPE_VLAN_MAC);
   2715         /* Program MY_MODID for the LPORT entry */
   2716         rv = bcm_esw_stk_my_modid_get(unit, &my_modid);
   2717         if (rv < 0) {
   2718             WLAN_UNLOCK(unit);
   2719             goto port_cleanup;
   2720         }
   2721         soc_LPORT_TABm_field32_set(unit, &lport_profile, MY_MODIDf, my_modid);
   2722         entries[0] = &lport_profile;
   2723         entries[1] = &rtag7_entry;
   2724         rv = _bcm_lport_profile_entry_add(unit, entries, 1,
   2725                                           (uint32 *) &lport_ptr);
   2726         if (rv < 0) {
   2727             WLAN_UNLOCK(unit);
   2728             goto port_cleanup;
   2729         }
   2730         soc_SOURCE_VP_ATTRIBUTES_2m_field32_set(unit, &svp, LPORT_PROFILE_INDEXf,
   2731                                         lport_ptr);
   2732     }
   2733 
   2734     /* Program next hop entry using existing or new index */
   2735     drop = (wlan_port->flags & BCM_WLAN_PORT_DROP) ? 1 : 0;
   2736     rv = _bcm_tr3_wlan_nh_info_add(unit, wlan_port, vp, drop,
   2737                                    &nh_index, &local_port, &is_local);
   2738     if (rv < 0) {
   2739         WLAN_UNLOCK(unit);
   2740         goto port_cleanup;
   2741     }
   2742 
   2743     /* Program the VP tables */
   2744     if (wlan_port->flags & BCM_WLAN_PORT_NETWORK) {
   2745         /* Enable SVP & DVP network port to set split horizon pruning */
   2746         soc_SOURCE_VPm_field32_set(unit, &svp, NETWORK_PORTf, 1);
   2747         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &wlan_dvp,
   2748                                            WLAN__DISABLE_VP_PRUNINGf, 0);
   2749     } else {
   2750         soc_SOURCE_VPm_field32_set(unit, &svp, NETWORK_PORTf, 0);
   2751         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &wlan_dvp,
   2752                                            WLAN__DISABLE_VP_PRUNINGf, 1);
   2753     }
   2754 
   2755     /* Select HG2 PPD2 header for remote egress */
   2756     soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &wlan_dvp, WLAN__HG_HDR_SELf, 1);
   2757 
   2758     /* Program the matching criteria */
   2759     if (wlan_port->flags & BCM_WLAN_PORT_REPLACE) {
   2760         rv = WRITE_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ALL, vp, &svp);
   2761         if (rv < 0) {
   2762             WLAN_UNLOCK(unit);
   2763             goto port_cleanup;
   2764         }
   2765     } else {
   2766         /* Link in the newly allocated next-hop entry */
   2767         soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NEXT_HOP_INDEXf,
   2768                                        nh_index);
   2769         rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   2770         if (rv < 0) {
   2771             WLAN_UNLOCK(unit);
   2772             goto port_cleanup;
   2773         }
   2774 
   2775         if (!BCM_GPORT_IS_TUNNEL(wlan_port->egress_tunnel)) {
   2776             WLAN_UNLOCK(unit);
   2777             rv = BCM_E_BADID;
   2778             goto port_cleanup;
   2779         }
   2780         tunnel = BCM_GPORT_TUNNEL_ID_GET(wlan_port->egress_tunnel);
   2781         if ((wlan_port->flags & BCM_WLAN_PORT_BSSID) ||
   2782             (wlan_port->flags & BCM_WLAN_PORT_BSSID_RADIO)) {
   2783             /* Set BSSID mac address in wlan dvp profile */
   2784             soc_mem_mac_addr_set(unit, AXP_WTX_DVP_PROFILEm, &axp_wtx_dvp, BSSIDf,
   2785                                  wlan_port->bssid);
   2786             rv = _bcm_tr3_wlan_tnl_read(unit, tunnel, axp_wtx_tunnel);
   2787             if (BCM_FAILURE(rv)) {
   2788                 return rv;
   2789             }
   2790 
   2791            /* Enable Radio mac header CAPWAP encap */
   2792             if ((wlan_port->flags & BCM_WLAN_PORT_EGRESS_BSSID)) {
   2793                 soc_AXP_WTX_TUNNELm_field32_set(unit, &axp_wtx_tunnel[TNL_ENTRY_0],
   2794                                               BSSID_ENf, 1);
   2795             }
   2796 
   2797             /* Write to tunnel table */
   2798             rv = _bcm_tr3_wlan_tnl_write(unit, tunnel, axp_wtx_tunnel);
   2799             if (BCM_FAILURE(rv)) {
   2800                 return rv;
   2801             }
   2802 
   2803         }
   2804 
   2805         /* 
   2806          * Enable HA/FA for WLAN DVP port. HA/FA bit determines FROM_HA/FROM_FA 
   2807          * encodings in capwap headers for AC2AC tunnel
   2808          */
   2809         if ((wlan_port->flags & BCM_WLAN_PORT_ROAM_ENABLE) && 
   2810             (WLAN_TUNNEL_TYPE_AC2AC == soc_AXP_WTX_TUNNELm_field32_get(unit, 
   2811                                  &axp_wtx_tunnel[TNL_ENTRY_0], TUNNEL_TYPEf))) {
   2812             soc_AXP_WTX_DVP_PROFILEm_field32_set(unit, &axp_wtx_dvp, 
   2813                                                     HA_FA_ENABLEf, 1);
   2814         }
   2815 
   2816         /* Program the tunnel VLAN from the cached state */
   2817         soc_AXP_WTX_DVP_PROFILEm_field32_set(unit, &axp_wtx_dvp, TUNNEL_VLANf,
   2818                                       TUNNEL_VLAN(unit, tunnel));
   2819         soc_AXP_WTX_DVP_PROFILEm_field32_set(unit, &axp_wtx_dvp, TUNNEL_PRIf,
   2820                                       TUNNEL_PRI(unit, tunnel));
   2821         soc_AXP_WTX_DVP_PROFILEm_field32_set(unit, &axp_wtx_dvp, TUNNEL_CFIf,
   2822                                       TUNNEL_CFI(unit, tunnel));
   2823        
   2824         /* set wlan tunnel index */
   2825         soc_AXP_WTX_DVP_PROFILEm_field32_set(unit, &axp_wtx_dvp, 
   2826                                     WLAN_TUNNEL_INDEXf, tunnel);
   2827         /*
   2828          * Allocate new WLAN DVP profile index and link to EGR DVP
   2829          * [EGR_DVP_ATTRIBUTE.WLAN_DVP_PROFILE] ->  [AXP_WTX_DVP_PROFILE]
   2830          */
   2831 
   2832         /* Allocate new wlan DVP index */
   2833         entries[0] = &axp_wtx_dvp;
   2834         rv = soc_profile_mem_add(unit, WLAN_DVP_PROFILE(unit), entries, 1,
   2835                             &wlan_dvp_idx);
   2836         if (rv < 0) {
   2837             WLAN_UNLOCK(unit);
   2838             goto port_cleanup;
   2839         }
   2840         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &wlan_dvp, WLAN_DVP_PROFILEf,
   2841                                            wlan_dvp_idx );
   2842         /* Set WLAN VP Type */
   2843         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &wlan_dvp, VP_TYPEf,
   2844                                            0x2 );
   2845 
   2846         /* Write into EGR_EVP_ATTRIBUTEm */
   2847         rv = WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, vp, &wlan_dvp);
   2848         if (rv < 0) {
   2849             WLAN_UNLOCK(unit);
   2850             goto port_cleanup;
   2851         }
   2852 
   2853         /* Initialize the SVP parameters */
   2854         soc_SOURCE_VP_ATTRIBUTES_2m_field32_set(unit, &svp, DEFAULT_VLAN_IDf, 0x1);
   2855         rv = WRITE_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ALL, vp, &svp);
   2856         if (rv < 0) {
   2857             WLAN_UNLOCK(unit);
   2858             goto port_cleanup;
   2859         }
   2860 
   2861         /*
   2862          * Match entries cannot be replaced, instead, callers
   2863          * need to delete the existing entry and re-add with the
   2864          * new match parameters.
   2865          */
   2866         rv = _bcm_tr3_wlan_match_add(unit, wlan_port, vp);
   2867         if (rv < 0) {
   2868             WLAN_UNLOCK(unit);
   2869             goto port_cleanup;
   2870         } else {
   2871             /* Set the WLAN port ID */
   2872             BCM_GPORT_WLAN_PORT_ID_SET(wlan_port->wlan_port_id, vp);
   2873             /* Set IPMC next hop interface id */
   2874             wlan_port->encap_id = nh_index;
   2875         }
   2876     }
   2877     WLAN_UNLOCK(unit);
   2878 port_cleanup:
   2879     if (rv < 0) {
   2880         if (tpid_enable) {
   2881             (void) _bcm_fb2_outer_tpid_entry_delete(unit, tpid_index);
   2882         }
   2883         if (!(wlan_port->flags & BCM_WLAN_PORT_REPLACE)) {
   2884             (void) _bcm_vp_free(unit, _bcmVpTypeWlan, 1, vp);
   2885             _bcm_tr3_wlan_nh_info_delete(unit, nh_index);
   2886         }
   2887         if (lport_ptr != -1) {
   2888             (void) _bcm_lport_profile_entry_delete(unit, lport_ptr);
   2889         }
   2890     }
   2891     return rv;
   2892 }
   2893 
   2894 /*
   2895  * Function:
   2896  *      _bcm_tr3_wlan_port_delete
   2897  * Purpose: 
   2898  *      This function deletes wlan port
   2899  * Parameters: 
   2900  *      unit       - (IN) bcm device
   2901  *      vp         - (IN) virtual port
   2902  * Returns:
   2903  *      BCM_E_NONE - Success
   2904  *      BCM_E_XXX
   2905  * Notes:
   2906  */
   2907 STATIC int
   2908 _bcm_tr3_wlan_port_delete(int unit, int vp)
   2909 {
   2910     int rv = BCM_E_NONE;
   2911     int nh_index, wlan_dvp_index;
   2912     int lport_ptr = -1;
   2913     int is_local, i, tpid_enable = 0;
   2914     source_vp_attributes_2_entry_t svp;
   2915     ing_dvp_table_entry_t dvp;
   2916     egr_dvp_attribute_entry_t wlan_dvp;
   2917     lport_tab_entry_t lport_profile;
   2918     rtag7_port_based_hash_entry_t rtag7_entry;
   2919     _bcm_port_info_t *info;
   2920     void *entries[2];
   2921 
   2922     rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp);
   2923     BCM_IF_ERROR_RETURN(rv);
   2924     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2925 
   2926     rv = _bcm_tr3_wlan_match_delete(unit, vp);
   2927     BCM_IF_ERROR_RETURN(rv);
   2928 
   2929     /* Delete LPORT profile and its associated TPID entry */
   2930     rv = READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp);
   2931     BCM_IF_ERROR_RETURN(rv);
   2932     lport_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &svp,
   2933                                                         LPORT_PROFILE_INDEXf);
   2934     entries[0] = &lport_profile;
   2935     entries[1] = &rtag7_entry;
   2936     rv = _bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries);
   2937     BCM_IF_ERROR_RETURN(rv);
   2938     tpid_enable = soc_LPORT_TABm_field32_get(unit, &lport_profile,
   2939                                              OUTER_TPID_ENABLEf);
   2940     if (tpid_enable) {
   2941         for (i = 0; i < 4; i++) {
   2942             if (tpid_enable & (1 << i)) {
   2943                 (void) _bcm_fb2_outer_tpid_entry_delete(unit, i);
   2944                 break;
   2945             }
   2946         }
   2947     }
   2948     rv = _bcm_lport_profile_entry_delete(unit, lport_ptr);
   2949     BCM_IF_ERROR_RETURN(rv);
   2950 
   2951     /* Clear the SVP and DVP table entries */
   2952     sal_memset(&svp, 0, sizeof(source_vp_attributes_2_entry_t));
   2953     rv = WRITE_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ALL, vp, &svp);
   2954     BCM_IF_ERROR_RETURN(rv);
   2955 
   2956     sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
   2957     rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   2958     BCM_IF_ERROR_RETURN(rv);
   2959 
   2960     /* Delete wlan dvp profile */ 
   2961     BCM_IF_ERROR_RETURN(
   2962             READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &wlan_dvp));
   2963     wlan_dvp_index = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &wlan_dvp, WLAN_DVP_PROFILEf);
   2964     BCM_IF_ERROR_RETURN(
   2965             soc_profile_mem_delete(unit, WLAN_DVP_PROFILE(unit), wlan_dvp_index)); 
   2966     
   2967     sal_memset(&wlan_dvp, 0, sizeof(egr_dvp_attribute_entry_t));
   2968     rv = WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, vp, &wlan_dvp);
   2969     BCM_IF_ERROR_RETURN(rv);
   2970 
   2971     /* Clear the next-hop table entries */
   2972     rv = _bcm_tr3_wlan_nh_info_delete(unit, nh_index);
   2973     BCM_IF_ERROR_RETURN(rv);
   2974 
   2975     /* Update the physical port's SW state */
   2976     BCM_IF_ERROR_RETURN(
   2977         _bcm_esw_modid_is_local(unit, WLAN_INFO(unit)->port_info[vp].modid,
   2978                                 &is_local));
   2979     if (is_local && (WLAN_INFO(unit)->port_info[vp].tgid == -1)) {
   2980         bcm_port_t phys_port = WLAN_INFO(unit)->port_info[vp].port;
   2981         if (soc_feature(unit, soc_feature_sysport_remap)) {
   2982             BCM_XLATE_SYSPORT_S2P(unit, &phys_port);
   2983         }
   2984         _bcm_port_info_access(unit, phys_port, &info);
   2985         info->vp_count--;
   2986     }
   2987 
   2988     /* If associated with a trunk, update each local physical port's SW state */
   2989     if (WLAN_INFO(unit)->port_info[vp].tgid != -1) {
   2990         int idx;
   2991         bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   2992        int local_member_count;
   2993         bcm_trunk_t trunk_id = WLAN_INFO(unit)->port_info[vp].tgid;
   2994 
   2995         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, trunk_id,
   2996                     SOC_MAX_NUM_PORTS, local_member_array, &local_member_count));
   2997         for (idx = 0; idx < local_member_count; idx++) {
   2998             _bcm_port_info_access(unit, local_member_array[idx], &info);
   2999             info->vp_count--;
   3000         }
   3001     }
   3002 
   3003     /* Clear the SW state */
   3004     sal_memset(&(WLAN_INFO(unit)->port_info[vp]), 0,
   3005                sizeof(_bcm_tr3_wlan_port_info_t));
   3006 
   3007     /* Release Service counter, if any */
   3008     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   3009         bcm_gport_t gport;
   3010 
   3011         BCM_GPORT_WLAN_PORT_ID_SET(gport, vp);
   3012         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
   3013     }
   3014 
   3015     /* Free the VP */
   3016     (void) _bcm_vp_free(unit, _bcmVpTypeWlan, 1, vp);
   3017     return rv;
   3018 }
   3019 
   3020 /*
   3021  * Function:
   3022  *      bcm_wlan_port_delete
   3023  * Purpose:
   3024  *      Delete a wlan port
   3025  * Parameters:
   3026  *      unit       - (IN) Device Number
   3027  *      wlan_port_id - (IN) wlan port information
   3028  * Returns:
   3029  *      BCM_E_XXX
   3030  */
   3031 int
   3032 bcm_tr3_wlan_port_delete(int unit, bcm_gport_t wlan_port_id)
   3033 {
   3034     int vp, rv;
   3035 
   3036     WLAN_INIT(unit);
   3037 
   3038     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   3039     if (vp == -1) {
   3040         return BCM_E_PARAM;
   3041     }
   3042 
   3043     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   3044         return BCM_E_NOT_FOUND;
   3045     }
   3046     WLAN_LOCK(unit);
   3047     rv = _bcm_tr3_wlan_port_delete(unit, vp);
   3048     WLAN_UNLOCK(unit);
   3049     return rv;
   3050 }
   3051 
   3052 /*
   3053  * Function:
   3054  *      bcm_wlan_port_delete_all
   3055  * Purpose:
   3056  *      Delete all wlan ports
   3057  * Parameters:
   3058  *      unit       - (IN) Device Number
   3059  * Returns:
   3060  *      BCM_E_XXX
   3061  */
   3062 int
   3063 bcm_tr3_wlan_port_delete_all(int unit)
   3064 {
   3065     int rv = BCM_E_NONE;
   3066     uint32 vp, num_vp;
   3067     source_vp_entry_t svp, *svp_null;
   3068 
   3069     WLAN_INIT(unit);
   3070 
   3071     svp_null = soc_mem_entry_null(unit, SOURCE_VP_ATTRIBUTES_2m);
   3072     num_vp = soc_mem_index_count(unit, SOURCE_VP_ATTRIBUTES_2m);
   3073     sal_memset(&svp,0,sizeof(svp));
   3074     for (vp = 0; vp < num_vp; vp++) {
   3075         rv = READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp);
   3076         if (rv < 0) {
   3077             goto done;
   3078         }
   3079         if (sal_memcmp(&svp, svp_null, sizeof(source_vp_entry_t)) != 0) {
   3080             WLAN_LOCK(unit);
   3081             rv = _bcm_tr3_wlan_port_delete(unit, vp);
   3082             WLAN_UNLOCK(unit);
   3083             if (rv < 0) {
   3084                 goto done;
   3085             }
   3086         }
   3087     }
   3088 done:
   3089     return rv;
   3090 }
   3091 
   3092 /*
   3093  * Function:
   3094  *      _bcm_tr3_wlan_port_get
   3095  * Purpose: 
   3096  *      This function gets wlan port info.
   3097  * Parameters: 
   3098  *      unit       - (IN) bcm device
   3099  *      vp         - (IN) wlan virtual port
   3100  *      wlan_port  - (OUT) wlan port info
   3101  * Returns:
   3102  *      BCM_E_NONE - Success
   3103  *      BCM_E_XXX
   3104  * Notes:
   3105  */
   3106 int
   3107 _bcm_tr3_wlan_port_get(int unit, int vp, bcm_wlan_port_t *wlan_port)
   3108 {
   3109     int egress_tunnel, nh_index, rv = BCM_E_NONE;
   3110     int wlan_dvp_index;
   3111     ing_dvp_table_entry_t           dvp;            /* ING DVP entry        */
   3112     egr_dvp_attribute_entry_t       wlan_dvp;       /* EGR DVP entry        */
   3113     axp_wtx_dvp_profile_entry_t     axp_wtx_dvp;    /* AXP DVP Profile      */
   3114     axp_wtx_tunnel_entry_t          axp_wtx_tunnel[_BCM_WLAN_TNL_ENTRY_WIDTH]; 
   3115                                                     /* AXP WTX Tunnel table   */
   3116     void   *mem_entries[1];                         /* For profile mem entries */
   3117 
   3118     /* Initialize the structure */
   3119     bcm_wlan_port_t_init(wlan_port);
   3120     BCM_GPORT_WLAN_PORT_ID_SET(wlan_port->wlan_port_id, vp);
   3121 
   3122     BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   3123     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   3124 
   3125     /* Fill the IPMC next hop interface id(encap_id) */
   3126     wlan_port->encap_id = nh_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   3127 
   3128     /* Get the match parameters */
   3129     rv = _bcm_tr3_wlan_match_get(unit, wlan_port, vp);
   3130     BCM_IF_ERROR_RETURN(rv);
   3131 
   3132     /* Get the next-hop parameters */
   3133     rv = _bcm_tr3_wlan_nh_info_get(unit, wlan_port, nh_index);
   3134     BCM_IF_ERROR_RETURN(rv);
   3135 
   3136     /* Fill in egress parameters */
   3137     BCM_IF_ERROR_RETURN(
   3138             READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &wlan_dvp));
   3139     wlan_dvp_index = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &wlan_dvp, WLAN_DVP_PROFILEf);
   3140     mem_entries[0] = &axp_wtx_dvp;
   3141     rv = soc_profile_mem_get(unit, WLAN_DVP_PROFILE(unit), wlan_dvp_index, 1,
   3142                             mem_entries);
   3143     if (BCM_FAILURE(rv)) {
   3144         return rv;
   3145     }
   3146 
   3147     if (soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp, HA_FA_ENABLEf)) {
   3148         wlan_port->flags |= BCM_WLAN_PORT_ROAM_ENABLE;
   3149     }
   3150 
   3151     egress_tunnel = soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp,
   3152                                                         WLAN_TUNNEL_INDEXf);
   3153  
   3154     BCM_GPORT_TUNNEL_ID_SET(wlan_port->egress_tunnel, egress_tunnel);
   3155     rv = _bcm_tr3_wlan_tnl_read(unit, egress_tunnel, axp_wtx_tunnel);
   3156     if (BCM_FAILURE(rv)) {
   3157         return rv;
   3158     }
   3159     if (!soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &wlan_dvp, 
   3160                                            WLAN__DISABLE_VP_PRUNINGf)) {
   3161         wlan_port->flags |= BCM_WLAN_PORT_NETWORK;
   3162     }
   3163 
   3164     if (soc_AXP_WTX_TUNNELm_field32_get(unit, &axp_wtx_tunnel[TNL_ENTRY_0], BSSID_ENf)) {
   3165         wlan_port->flags |= BCM_WLAN_PORT_EGRESS_BSSID;
   3166     }
   3167 
   3168     return rv;
   3169 }
   3170 
   3171 /*
   3172  * Function:
   3173  *      bcm_wlan_port_get
   3174  * Purpose:
   3175  *      Get a wlan port
   3176  * Parameters:
   3177  *      unit       - (IN) Device Number
   3178  *      wlan_port  - (IN/OUT) wlan port information
   3179  */
   3180 int
   3181 bcm_tr3_wlan_port_get(int unit, bcm_gport_t wlan_port_id, bcm_wlan_port_t *wlan_port)
   3182 {
   3183     int vp;
   3184 
   3185     WLAN_INIT(unit);
   3186 
   3187     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   3188     if (vp == -1) {
   3189         return BCM_E_PARAM;
   3190     }
   3191 
   3192     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   3193         return BCM_E_NOT_FOUND;
   3194     }
   3195     return _bcm_tr3_wlan_port_get(unit, vp, wlan_port);
   3196 }
   3197 
   3198 /*
   3199  * Function:
   3200  *      bcm_wlan_port_traverse
   3201  * Purpose:
   3202  *      Walks through the valid WLAN port entries and calls
   3203  *      the user supplied callback function for each entry.
   3204  * Parameters:
   3205  *      unit       - (IN) bcm device.
   3206  *      trav_fn    - (IN) Callback function.
   3207  *      user_data  - (IN) User data to be passed to callback function.
   3208  * Returns:
   3209  *      BCM_E_NONE - Success.
   3210  *      BCM_E_XXX
   3211  */
   3212 int
   3213 bcm_tr3_wlan_port_traverse(int unit,
   3214                            bcm_wlan_port_traverse_cb cb,
   3215                            void *user_data)
   3216 {
   3217     int i, index_min, index_max, rv = BCM_E_NONE;
   3218     int wlan_port_id, *buffer = NULL;
   3219     bcm_wlan_port_t info;
   3220 
   3221     WLAN_INIT(unit);
   3222 
   3223     index_min = soc_mem_index_min(unit, SOURCE_VP_ATTRIBUTES_2m);
   3224     index_max = soc_mem_index_max(unit, SOURCE_VP_ATTRIBUTES_2m);
   3225 
   3226     WLAN_LOCK(unit);
   3227     buffer = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, SOURCE_VP_ATTRIBUTES_2m),
   3228                            "wlan port traverse");
   3229     if (NULL == buffer) {
   3230         WLAN_UNLOCK(unit);
   3231         return BCM_E_MEMORY;
   3232     }
   3233     if ((rv = soc_mem_read_range(unit, SOURCE_VP_ATTRIBUTES_2m, MEM_BLOCK_ALL,
   3234                                  index_min, index_max, buffer)) < 0 ) {
   3235         soc_cm_sfree(unit, buffer);
   3236         WLAN_UNLOCK(unit);
   3237         return rv;
   3238     }
   3239     for (i = index_min; i <= index_max; i++) {
   3240         bcm_wlan_port_t_init(&info);
   3241         BCM_GPORT_WLAN_PORT_ID_SET(wlan_port_id, i);
   3242         rv = bcm_tr3_wlan_port_get(unit, wlan_port_id, &info);
   3243         if (BCM_FAILURE(rv)) {
   3244             soc_cm_sfree(unit, buffer);
   3245             WLAN_UNLOCK(unit);
   3246             return rv;
   3247         }
   3248         rv = cb(unit, &info, user_data);
   3249         if (BCM_FAILURE(rv)) {
   3250             soc_cm_sfree(unit, buffer);
   3251             WLAN_UNLOCK(unit);
   3252             return rv;
   3253         }
   3254     }
   3255     soc_cm_sfree(unit, buffer);
   3256     WLAN_UNLOCK(unit);
   3257     return rv;
   3258 }
   3259 
   3260 /*
   3261  * Function:
   3262  *      _bcm_tr3_wlan_tunnel_init_add
   3263  * Purpose:
   3264  *      Add tunnel initiator entry to hw.
   3265  * Parameters:
   3266  *      unit     - (IN)SOC unit number.
   3267  *      info     - (IN)Tunnel initiator entry info.
   3268  *      *idx      -(OUT)new tunnel Index in wtx tunnel table
   3269  * Returns:
   3270  *      BCM_E_XXX
   3271  * Notes:
   3272  *      WLAN Tunnel (AXP_WTX_TUNNEL) has 1k tunnels * 4 entries/tunnel
   3273  *      
   3274  *      tnl_id : tunnel id returns the value in 1k tunnels
   3275  *      tnl_idex: tunnel index programmed in DVP profile table (4 * tnl_id)     
   3276  *
   3277  *      ENTRY0: TPID_SEL, UDP_TYPE .. TUNNEL_TYPE, BSSID_EN, IP_TYPE,DIP_LOW, SIP_LOW
   3278  *      ENTRY1: L4_DST(111-96)     MACSA(95-48) MACDA(47-0)
   3279  *      ENTRY2: L4_SRC(111-96)     DIP_HI(95-0)
   3280  *      ENTRY3: FLOW_LABEL(115-96) SIP_HI(95-0)
   3281 
   3282  */
   3283 STATIC int
   3284 _bcm_tr3_wlan_tunnel_init_add(int unit, bcm_tunnel_initiator_t *info, int *tnl_id_p)
   3285 {
   3286     soc_mem_t               mem;            /* Tunnel initiator table memory */
   3287     axp_wtx_tunnel_entry_t  tnl_entry[_BCM_WLAN_TNL_ENTRY_WIDTH];   
   3288                                             /* AXP_WTX_TUNNEL 4 hw entries   */
   3289     int df_val;                             /* Don't fragment encoding       */
   3290     int ipv6;                               /* IPv6 tunnel initiator         */
   3291     int hw_type_code = 0;                   /* Tunnel type.                  */
   3292     int old_tpid_index = -1;                /* Old TPID index                */
   3293     uint32 tpid_index = 0;                  /* TPID index                    */
   3294     int tnl_index = -1;                     /* Wlan tunnel Index             */
   3295     int rv = BCM_E_NONE;                    /* Return value                  */
   3296     uint32 ip6_fields[4];                   /* IPV6 addr fields              */
   3297     uint64 rval64, *rval64s[1];             /* For the profile register      */
   3298 
   3299     /* Get IP Type */
   3300     ipv6 = _BCM_TUNNEL_OUTER_HEADER_IPV6(info->type);
   3301 
   3302     mem = AXP_WTX_TUNNELm;
   3303 
   3304     /* Zero write buffer. */
   3305     sal_memset(&tnl_entry, 0, sizeof(tnl_entry));
   3306 
   3307     /* Get table memory. */
   3308     if (ipv6) {
   3309         /* IP_TYPE: IPV6 (0x01) */
   3310         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], IP_TYPEf, WLAN_TUNNEL_TYPE_V6);
   3311     } else {
   3312         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], IP_TYPEf, WLAN_TUNNEL_TYPE_V4);
   3313     }
   3314 
   3315     /* If replacing existing entry, first read the entry to get old
   3316        profile pointer and TPID */
   3317     if (info->flags & BCM_TUNNEL_REPLACE) {
   3318         tnl_index = BCM_GPORT_TUNNEL_ID_GET(info->tunnel_id);
   3319         rv = _bcm_tr3_wlan_tnl_read(unit, tnl_index, tnl_entry);
   3320         BCM_IF_ERROR_RETURN(rv);
   3321         old_tpid_index = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3322                                              TPID_SELf);
   3323         if (info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   3324             soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], 
   3325                                 VLAN_ASSIGN_POLICYf, 1);
   3326         } else {
   3327             soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3328                                 VLAN_ASSIGN_POLICYf, 0);
   3329         }
   3330     }
   3331 
   3332     /* Set Source and Destination address. */
   3333     if (ipv6) {
   3334         SAL_IP6_ADDR_TO_UINT32(info->dip6, ip6_fields);
   3335         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], DIP_LOWf, 
   3336                             ip6_fields[0]);
   3337         soc_mem_field_set(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_2], DIP_HIf, 
   3338                             (uint32 *)&ip6_fields[1]);
   3339         SAL_IP6_ADDR_TO_UINT32(info->sip6, ip6_fields);
   3340         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], SIP_LOWf, 
   3341                             ip6_fields[0]);
   3342         soc_mem_field_set(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_3], SIP_HIf, 
   3343                             (uint32 *)&ip6_fields[1]);
   3344     } else { /* ipv4 */
   3345         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], DIP_LOWf, info->dip);
   3346         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], SIP_LOWf, info->sip);
   3347     }
   3348 
   3349     /* IP tunnel hdr don't fragment (DNF) bit */
   3350     df_val = 0;
   3351     if (info->flags & BCM_TUNNEL_INIT_USE_INNER_DF) {
   3352         /* (0x02)Use INNER ipv4 DNF bit */
   3353         df_val |= 0x2;
   3354     } else if ((info->flags & BCM_TUNNEL_INIT_IPV4_SET_DF)
   3355                || (info->flags & BCM_TUNNEL_INIT_IPV6_SET_DF)) {
   3356         /* (0x01) Set DNF bit */
   3357         df_val |= 0x1;
   3358     }
   3359     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], DF_SELf, df_val);
   3360 
   3361     /* Set DSCP value.  */
   3362     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], DSCP_SRCf, info->dscp);
   3363 
   3364     /* Tunnel header DSCP select. */
   3365     
   3366     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], DSCP_SELf, info->dscp_sel);
   3367 
   3368     /* Set TTL. */
   3369     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], TTL_HLIMITf, info->ttl);
   3370 
   3371     /* Set tunnel type. */
   3372     if ( info->type == bcmTunnelTypeWlanWtpToAc) {
   3373         hw_type_code =  WLAN_TUNNEL_TYPE_WTP2AC;
   3374     } else if (info->type == bcmTunnelTypeWlanAcToAc) {
   3375         hw_type_code =  WLAN_TUNNEL_TYPE_AC2AC;
   3376     }
   3377     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], TUNNEL_TYPEf, 
   3378                         hw_type_code);
   3379 
   3380     /* Set flow label. */
   3381     if (ipv6) {
   3382         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_3], FLOW_LABELf,
   3383                             info->flow_label);
   3384     }
   3385 
   3386 
   3387     /* L4 fields */
   3388     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_2], L4_SRCf,
   3389                         info->udp_src_port);
   3390     soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_1], L4_DSTf,
   3391                         info->udp_dst_port);
   3392 
   3393     /* L2 fields */
   3394 
   3395     /* Set destination  and source mac address. */
   3396     soc_mem_mac_addr_set(unit, mem, &tnl_entry[TNL_ENTRY_1], MACDAf, info->dmac);
   3397     soc_mem_mac_addr_set(unit, mem, &tnl_entry[TNL_ENTRY_1], MACSAf, info->smac);
   3398 
   3399     if (info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   3400         /* VLAN Assign policy is single tagged */
   3401         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], 
   3402                             VLAN_ASSIGN_POLICYf, 1);
   3403         /* Use DVP Profile TUNNEL VLAN/PRI/CFI for vlan tag creation */
   3404         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0],        
   3405                             DOT1P_REMAPf, 0);
   3406 
   3407         /* Add  and set tpid index to AXP_WTX_TUNNEL_TPID tpid values */
   3408         COMPILER_64_ZERO(rval64);
   3409         COMPILER_64_SET(rval64, 0, info->tpid);
   3410         rval64s[0] = &rval64;
   3411         rv = soc_profile_reg_add(unit, WLAN_TPID_PROFILE(unit), rval64s, 1,
   3412                                  &tpid_index);
   3413         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], TPID_SELf, tpid_index);
   3414         if (BCM_FAILURE(rv)) {
   3415             goto tnl_cleanup;
   3416         }
   3417 
   3418     }
   3419 
   3420 
   3421     /* CAPWAP MTU */
   3422     if (info->flags & BCM_TUNNEL_INIT_WLAN_MTU && info->mtu > 0) {
   3423         uint32 encap_len = GET_CAPWAP_ENCAP_LEN(info->type);
   3424         
   3425         /* capwap payload length in 8 byte chunks = (mtu - max capwap encap len) */
   3426         uint32 first = (((info->mtu - encap_len) / 8) > 240) ? 240 :
   3427                        ((info->mtu - encap_len) / 8);
   3428         /* Fragment MTU in 4 byte chunks */
   3429         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], FRAG_MTUf,
   3430                             ((info->mtu) / 4 > 0xFFF) ? 0xFFF: (info->mtu / 4));
   3431         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], FRAG_LOCf, first);
   3432         /* Fragmentation is enabled by default */
   3433         soc_mem_field32_set(unit, mem, &tnl_entry[TNL_ENTRY_0], FRAG_ENf, 1);
   3434     }
   3435 
   3436     if (info->flags & BCM_TUNNEL_INIT_WLAN_TUNNEL_WITH_ID) {
   3437         /* Set Tunnel id */
   3438         _BCM_WLAN_TNL_USED_SET(unit, *tnl_id_p);
   3439     } else {
   3440         /* Get Free tnl_entry  */
   3441         rv = _bcm_tr3_wlan_tnl_create(unit,  tnl_id_p);
   3442         if (BCM_FAILURE(rv)) {
   3443             goto tnl_cleanup;
   3444         }
   3445     }
   3446 
   3447     /* Write TUNNEL entries in entry0, entry1, entry2, entry3 */
   3448     rv = _bcm_tr3_wlan_tnl_write(unit, *tnl_id_p, tnl_entry);
   3449     if (BCM_FAILURE(rv)) {
   3450         goto tnl_cleanup;
   3451     }
   3452 
   3453     /* Tunnel VLAN needs to be programmed in the WLAN_DVP_PROFILE table.
   3454      * We need to cache it so that the bcm_wlan_port_add API can
   3455      * program it in the correct location. It is always cached against
   3456      * the index to WTX_TUNNEL for both V4 and V6 for simplicity. */
   3457     TUNNEL_VLAN(unit, *tnl_id_p) = info->vlan;
   3458     TUNNEL_PRI(unit, *tnl_id_p) = info->pkt_pri;
   3459     TUNNEL_CFI(unit, *tnl_id_p) = info->pkt_cfi;
   3460 
   3461 tnl_cleanup:
   3462     if (old_tpid_index != -1) {
   3463         BCM_IF_ERROR_RETURN (
   3464             soc_profile_reg_delete(
   3465                 unit, WLAN_TPID_PROFILE(unit), old_tpid_index));
   3466     }
   3467     if (BCM_FAILURE(rv) && (!(info->flags & BCM_TUNNEL_REPLACE))) {
   3468         if (tnl_id_p && (*tnl_id_p != -1)) {
   3469             _BCM_WLAN_TNL_USED_CLR(unit, *tnl_id_p);
   3470         }
   3471     }
   3472     return rv;
   3473 }
   3474 
   3475 /*
   3476  * Function:
   3477  *      bcm_wlan_tunnel_initiator_create
   3478  * Purpose:
   3479  *      Create an outgong CAPWAP tunnel
   3480  * Parameters:
   3481  *      unit    - (IN) Device Number
   3482  *      info    - (IN/OUT) Tunnel initiator structure
   3483  * Returns:
   3484  *      BCM_E_NONE - Success
   3485  *      BCM_E_XXX
   3486  * Notes:
   3487  */
   3488 int
   3489 bcm_tr3_wlan_tunnel_initiator_create(int unit, bcm_tunnel_initiator_t *info)
   3490 {
   3491     int tnl_idx = 0, rv = BCM_E_NONE;
   3492     uint32 flags = 0;
   3493 
   3494     WLAN_INIT(unit);
   3495 
   3496     /* Input parameters check. */
   3497     if (NULL == info) {
   3498         return (BCM_E_PARAM);
   3499     }
   3500     if ((info->type != bcmTunnelTypeWlanWtpToAc) &&
   3501         (info->type != bcmTunnelTypeWlanAcToAc) &&
   3502         (info->type != bcmTunnelTypeWlanWtpToAc6) &&
   3503         (info->type != bcmTunnelTypeWlanAcToAc6)) {
   3504         return BCM_E_PARAM;
   3505     }
   3506     if (!BCM_TTL_VALID(info->ttl)) {
   3507         return BCM_E_PARAM;
   3508     }
   3509     if (info->dscp_sel > 2 || info->dscp_sel < 0) {
   3510         return BCM_E_PARAM;
   3511     }
   3512     if (info->dscp > 63 || info->dscp < 0) {
   3513         return BCM_E_PARAM;
   3514     }
   3515     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(info->type)) {
   3516         if (info->flow_label > (1 << 20)) {
   3517             return BCM_E_PARAM;
   3518         }
   3519     }
   3520     if (!BCM_VLAN_VALID(info->vlan)) {
   3521         return BCM_E_PARAM;
   3522     }
   3523     if (BCM_MAC_IS_MCAST(info->smac) || BCM_MAC_IS_ZERO(info->smac)) {
   3524         return BCM_E_PARAM;
   3525     }
   3526     if (info->flags & BCM_TUNNEL_INIT_WLAN_TUNNEL_WITH_ID) {
   3527         if (!BCM_GPORT_IS_TUNNEL(info->tunnel_id)) {
   3528             return BCM_E_PARAM;
   3529         }
   3530         flags |= _BCM_L3_SHR_WITH_ID;
   3531         tnl_idx = BCM_GPORT_TUNNEL_ID_GET(info->tunnel_id);
   3532         if (info->flags & BCM_TUNNEL_REPLACE) {
   3533             if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_idx)) {
   3534                 return BCM_E_PARAM;
   3535             }
   3536             flags |= _BCM_L3_SHR_UPDATE;
   3537         }
   3538     }
   3539     if (info->flags & BCM_TUNNEL_INIT_WLAN_MTU) {
   3540         if (info->mtu < 0) {
   3541             return BCM_E_PARAM;
   3542         }
   3543     }
   3544 
   3545     WLAN_LOCK(unit);
   3546     /* Allocate either existing or new tunnel initiator entry */
   3547     rv = _bcm_tr3_wlan_tunnel_init_add(unit, info, &tnl_idx);
   3548     if (BCM_FAILURE(rv)) {
   3549         WLAN_UNLOCK(unit);
   3550         return rv;
   3551     }
   3552 
   3553     if (!(info->flags & BCM_TUNNEL_INIT_WLAN_TUNNEL_WITH_ID)) {
   3554         BCM_GPORT_TUNNEL_ID_SET(info->tunnel_id, tnl_idx);
   3555     }
   3556 
   3557     /* Update usage bitmaps appropriately */
   3558     /* tnl_idx is always the index to WTX_TUNNEL */
   3559     /* If writing to IPV6 Type Tunnel, need to divide by 2 */
   3560     _BCM_WLAN_TNL_USED_SET(unit, tnl_idx);
   3561     WLAN_UNLOCK(unit);
   3562     return rv;
   3563 }
   3564 
   3565 /*
   3566  * Function:
   3567  *      _bcm_tr3_wlan_tunnel_init_get
   3568  * Purpose:
   3569  *      Get a tunnel initiator entry from hw.
   3570  * Parameters:
   3571  *      unit     - (IN)SOC unit number.
   3572  *      idx      - (IN)Index to read tunnel initiator.
   3573  *      info     - (OUT)Tunnel initiator entry info.
   3574  * Returns:
   3575  *      BCM_E_XXX
   3576  */
   3577 STATIC int
   3578 _bcm_tr3_wlan_tunnel_init_get(int unit, int idx, bcm_tunnel_initiator_t *info,
   3579                               int *pri_index, int *tpid_index)
   3580 {
   3581     soc_mem_t               mem;           /* Tunnel initiator table memory.*/
   3582     axp_wtx_tunnel_entry_t     tnl_entry[_BCM_WLAN_TNL_ENTRY_WIDTH];  
   3583                                            /* AXP_WTX_TUNNEL hw entry       */
   3584     int df_val;                            /* Don't fragment encoded value. */
   3585     int tnl_type;                          /* Tunnel type.                  */
   3586     uint32 entry_type = WLAN_TUNNEL_TYPE_V4;/* Entry type (IPv4/IPv6/MPLS)  */
   3587     uint32 rval;                           /* Generic register value        */
   3588     uint32 ip6_fields[4];                  /* IPV6 addr fields              */
   3589     uint64 rval64, *rval64s[1];            /* For the profile register      */
   3590 
   3591     /* Get table memory. */
   3592     mem = AXP_WTX_TUNNELm;
   3593 
   3594     /* Initialize the buffer. */
   3595     sal_memset(&tnl_entry, 0, sizeof(tnl_entry));
   3596 
   3597     /* Get tunnel VLAN from cache */
   3598     if (TUNNEL_VLAN(unit, idx) != 0) {
   3599         info->vlan = TUNNEL_VLAN(unit, idx);
   3600     }
   3601 
   3602     /* First read the entry to get the type */
   3603     BCM_IF_ERROR_RETURN(_bcm_tr3_wlan_tnl_read(unit, idx, tnl_entry));
   3604 
   3605     /* Get entry_type. */
   3606     entry_type = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], IP_TYPEf);
   3607 
   3608     /* VLAN tag added or not */
   3609     if (soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], 
   3610                             VLAN_ASSIGN_POLICYf)) {
   3611         info->flags |= BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED;
   3612     }
   3613 
   3614     /* Get profiled data */
   3615     *pri_index  = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3616                                       DOT1P_MAP_PTRf);
   3617     *tpid_index = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], TPID_SELf);
   3618 
   3619     /* Parse hw buffer. */
   3620     if (WLAN_TUNNEL_TYPE_V4 == entry_type) {
   3621         /* Get destination ip. */
   3622         info->dip = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3623                                         DIP_LOWf);
   3624 
   3625         /* Get source ip. */
   3626         info->sip = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3627                                         SIP_LOWf);
   3628     } else if (WLAN_TUNNEL_TYPE_V6 == entry_type) {
   3629         /* Get destination ip. */
   3630         soc_mem_field_get(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_0], DIP_LOWf,
   3631                           (uint32 *)&ip6_fields[0]);
   3632         soc_mem_field_get(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_2], DIP_HIf,
   3633                           (uint32 *)&ip6_fields[1]);
   3634         SAL_IP6_ADDR_FROM_UINT32(info->dip6, ip6_fields);
   3635 
   3636         /* Get source ip. */
   3637         soc_mem_field_get(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_0], SIP_LOWf,
   3638                           (uint32 *)&ip6_fields[0]);
   3639         soc_mem_field_get(unit, mem, (uint32 *)&tnl_entry[TNL_ENTRY_1], SIP_HIf,
   3640                           (uint32 *)&ip6_fields[1]);
   3641         SAL_IP6_ADDR_FROM_UINT32(info->sip6, ip6_fields);
   3642     }
   3643 
   3644     /* Tunnel header DSCP select. */
   3645     info->dscp_sel = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3646                                          DSCP_SELf);
   3647 
   3648     /* Tunnel header DSCP value. */
   3649     info->dscp = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], DSCP_SRCf);
   3650 
   3651     /* IP tunnel hdr DF bit for IPv4 */
   3652     df_val = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], DF_SELf);
   3653     if (0x2 == df_val) {
   3654         info->flags |= BCM_TUNNEL_INIT_USE_INNER_DF;
   3655     } else if (0x1 == df_val) {
   3656         if (WLAN_TUNNEL_TYPE_V4 == entry_type) {
   3657             info->flags |= BCM_TUNNEL_INIT_IPV4_SET_DF;
   3658         } else if (WLAN_TUNNEL_TYPE_V6 == entry_type) {
   3659             info->flags |= BCM_TUNNEL_INIT_IPV6_SET_DF;
   3660         }
   3661     }
   3662 
   3663     /* Get TTL. */
   3664     info->ttl = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3665                                     TTL_HLIMITf);
   3666 
   3667     /* Get tunnel type. */
   3668     tnl_type = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], TUNNEL_TYPEf);
   3669 
   3670     /* Translate hw tunnel type into API encoding. */
   3671     if (tnl_type == WLAN_TUNNEL_TYPE_WTP2AC) {
   3672         info->type = bcmTunnelTypeWlanWtpToAc;
   3673     } else if (tnl_type ==  WLAN_TUNNEL_TYPE_AC2AC) {
   3674         info->type = bcmTunnelTypeWlanAcToAc;
   3675     }
   3676 
   3677     /* Get flow label for IPv6 */
   3678     if (WLAN_TUNNEL_TYPE_V6 == entry_type) {
   3679         info->flow_label =
   3680             soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_3], FLOW_LABELf);
   3681     }
   3682 
   3683     /* Get L4 fields */
   3684     info->udp_dst_port = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_1],
   3685                                                  L4_DSTf);
   3686     info->udp_src_port = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_2],
   3687                                                  L4_SRCf);
   3688 
   3689     /* Get mac addresses */
   3690     soc_mem_mac_addr_get(unit, mem, &tnl_entry[TNL_ENTRY_1], MACDAf, info->dmac);
   3691     soc_mem_mac_addr_get(unit, mem, &tnl_entry[TNL_ENTRY_1], MACSAf, info->smac);
   3692 
   3693     /* Get other L2 fields */
   3694     if (info->flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   3695         info->pkt_pri = TUNNEL_PRI(unit, idx);
   3696         info->pkt_cfi = TUNNEL_CFI(unit, idx);
   3697 
   3698         *tpid_index = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0],
   3699                                           TPID_SELf);
   3700         COMPILER_64_ZERO(rval64);
   3701         rval64s[0] = &rval64;
   3702         BCM_IF_ERROR_RETURN(soc_profile_reg_get(unit, WLAN_TPID_PROFILE(unit),
   3703                                                 *tpid_index, 1, rval64s));
   3704         info->tpid = COMPILER_64_LO(rval64);
   3705     }
   3706 
   3707     /* Get the MTU */
   3708     rval = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], FRAG_MTUf);
   3709     info->mtu = rval == 0xFFF ? 0x3FFF :  (rval * 4); /* 4 byte chunks */
   3710     if (info->mtu > 0) {
   3711         info->flags |= BCM_TUNNEL_INIT_WLAN_MTU;
   3712         rval = soc_mem_field32_get(unit, mem, &tnl_entry[TNL_ENTRY_0], 
   3713                                    FRAG_ENf);
   3714         if(rval) {
   3715             info->flags |= BCM_TUNNEL_INIT_WLAN_FRAG_ENABLE;
   3716         }
   3717     }
   3718 
   3719     return BCM_E_NONE;
   3720 }
   3721 
   3722 /*
   3723  * Function:
   3724  *      bcm_wlan_tunnel_initiator_destroy
   3725  * Purpose:
   3726  *      Destroy an outgong CAPWAP tunnel
   3727  * Parameters:
   3728  *      unit           - (IN) Device Number
   3729  *      wlan_tunnel_id - (IN) Tunnel ID (Gport)
   3730  * Returns:
   3731  *      BCM_E_XXX
   3732  */
   3733 int
   3734 bcm_tr3_wlan_tunnel_initiator_destroy(int unit, bcm_gport_t wlan_tunnel_id)
   3735 {
   3736     int rv = BCM_E_NONE;
   3737     uint32 tpid_index;                     /* TPID index */
   3738     int pri_index;                         /* priority index */
   3739     int tnl_index;                         /* Tunnel index */
   3740     bcm_tunnel_initiator_t info;           /* Tunnel initiator structure */
   3741 
   3742     WLAN_INIT(unit);
   3743 
   3744     /* Input parameters check. */
   3745     if (!BCM_GPORT_IS_TUNNEL(wlan_tunnel_id)) {
   3746         return BCM_E_PARAM;
   3747     }
   3748     tnl_index = BCM_GPORT_TUNNEL_ID_GET(wlan_tunnel_id);
   3749     if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_index)) {
   3750         return BCM_E_PARAM;
   3751     }
   3752 
   3753     bcm_tunnel_initiator_t_init(&info);
   3754 
   3755     WLAN_LOCK(unit);
   3756     /* Get the entry first */
   3757     rv = _bcm_tr3_wlan_tunnel_init_get(unit, tnl_index, &info,
   3758                                        &pri_index, (int*)&tpid_index);
   3759     if (BCM_FAILURE(rv)) {
   3760         WLAN_UNLOCK(unit);
   3761         return rv;
   3762     }
   3763 
   3764     if (info.flags & BCM_TUNNEL_INIT_WLAN_VLAN_TAGGED) {
   3765         /* Destroy the profiles */
   3766         rv = soc_profile_reg_delete(unit, WLAN_TPID_PROFILE(unit), tpid_index);
   3767         if (BCM_FAILURE(rv)) {
   3768             WLAN_UNLOCK(unit);
   3769             return rv;
   3770         }
   3771     }
   3772 
   3773     /* Destroy the tunnel entry */
   3774     rv = _bcm_tr3_wlan_tnl_delete(unit, tnl_index);
   3775     if (BCM_FAILURE(rv)) {
   3776         WLAN_UNLOCK(unit);
   3777         return rv;
   3778     }
   3779 
   3780     /* Update usage bitmaps appropriately */
   3781     /* tnl_index is always the index to WTX Tunnel */
   3782     /* If writing to IPV6 type, need to divide by 2 */
   3783     _BCM_WLAN_TNL_USED_CLR(unit, tnl_index);
   3784     TUNNEL_VLAN(unit, tnl_index) = 0;
   3785     TUNNEL_PRI(unit, tnl_index) = 0;
   3786     TUNNEL_CFI(unit, tnl_index) = 0;
   3787     WLAN_UNLOCK(unit);
   3788     return rv;
   3789 }
   3790 
   3791 /*
   3792  * Function:
   3793  *      bcm_wlan_tunnel_initiator_get
   3794  * Purpose:
   3795  *      Get an outgong CAPWAP tunnel
   3796  * Parameters:
   3797  *      unit    - (IN) Device Number
   3798  *      info    - (IN/OUT) Tunnel initiator structure
   3799  */
   3800 int
   3801 bcm_tr3_wlan_tunnel_initiator_get(int unit, bcm_tunnel_initiator_t *info)
   3802 {
   3803     int tnl_idx, rv = BCM_E_NONE;
   3804     int pri_index;                         /* priority index */
   3805     int tpid_index;                        /* TPID index */
   3806 
   3807     WLAN_INIT(unit);
   3808 
   3809     /* Input parameters check. */
   3810     if (info == NULL) {
   3811         return BCM_E_PARAM;
   3812     }
   3813     if (!BCM_GPORT_IS_TUNNEL(info->tunnel_id)) {
   3814         return BCM_E_PARAM;
   3815     }
   3816     tnl_idx = BCM_GPORT_TUNNEL_ID_GET(info->tunnel_id);
   3817     if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_idx)) {
   3818         return BCM_E_NOT_FOUND;
   3819     }
   3820 
   3821     /* Get the entry */
   3822     rv = _bcm_tr3_wlan_tunnel_init_get(unit, tnl_idx, info,
   3823                                        &pri_index, (int*)&tpid_index);
   3824     return rv;
   3825 }
   3826 
   3827 /*
   3828  * Function:
   3829  *      bcm_tr3_wlan_tunnel_terminator_vlan_get
   3830  * Purpose:
   3831  *      Get the allowed VLANs for a WLAN tunnel (AC2AC only)
   3832  * Parameters:
   3833  *      unit    - (IN)SOC unit number.
   3834  *      tunnel  - (IN)Tunnel ID.
   3835  *      vlan_vec - (OUT)VLAN vector
   3836  * Returns:
   3837  *      BCM_E_XXX
   3838  * Notes:
   3839  *   1. Get assigned svp for the matched tunnelid
   3840  *   2. Get SVP vlan membership group and VP Group bitmap
   3841  *   3. Get all allowed vlans for the vp group bitmap
   3842  */
   3843 int
   3844 bcm_tr3_wlan_tunnel_terminator_vlan_get(int unit, bcm_gport_t tunnel,
   3845                                    bcm_vlan_vector_t *vlan_vec)
   3846 {
   3847     int i, tnl_id, rv = BCM_E_NONE;
   3848     vlan_tab_entry_t *vtab;
   3849     uint32 grp_vec[2];
   3850     uint64 grp_bmp;
   3851     uint32 *buf;
   3852     int num_vp = 0, vp = -1, vvp = -1;
   3853     source_vp_entry_t svp;
   3854 
   3855     WLAN_INIT(unit);
   3856 
   3857     /* Input parameters check. */
   3858     if (!BCM_GPORT_IS_TUNNEL(tunnel)) {
   3859         return BCM_E_PARAM;
   3860     }
   3861     tnl_id = BCM_GPORT_TUNNEL_ID_GET(tunnel);
   3862     if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_id)) {
   3863         return BCM_E_PARAM;
   3864     }
   3865     if (vlan_vec == NULL) {
   3866         return BCM_E_PARAM;
   3867     }
   3868 
   3869     /* Find the VP that corresponds to this tunnel */
   3870     
   3871     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   3872     for (vp = 0; vp < num_vp; vp++) {
   3873         if ((WLAN_INFO(unit)->port_info[vp].match_tunnel == tunnel) &&
   3874             (WLAN_INFO(unit)->port_info[vp].flags &
   3875              _BCM_WLAN_PORT_MATCH_TUNNEL)) {
   3876             /* Found the matching VP  - get the VLAN_MEMBERSHIP_PROFILE */
   3877             BCM_IF_ERROR_RETURN
   3878                 (soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY, vp, &svp));
   3879             /* Get VP Vlan group membership profile (mapped to 64 vp groups) */
   3880             vvp = soc_SOURCE_VPm_field32_get(unit, &svp,
   3881                                                   VLAN_MEMBERSHIP_PROFILEf);
   3882             break;
   3883         }
   3884     }
   3885     if ((vp == num_vp) || (vvp < 0)) {
   3886         return BCM_E_NOT_FOUND;
   3887     }
   3888 
   3889     /* Compare vlan membership against the VP_GROUP_BITMAP in vlan table */
   3890     buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABLE(unit)),
   3891                         "vlan_table");
   3892     if (buf == NULL) {
   3893         return BCM_E_MEMORY;
   3894     }
   3895     
   3896     if ((rv = soc_mem_read_range(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY,
   3897                                  BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   3898         soc_cm_sfree(unit, buf);
   3899         return rv;
   3900     }
   3901 
   3902     /* Get all allowed vlans for the VP_GROUP_BITMAP */
   3903     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3904         vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABLE(unit), vlan_tab_entry_t *,
   3905                                             buf, i);
   3906         if (!soc_mem_field32_get(unit, VLAN_TABLE(unit), vtab, VALIDf)) {
   3907             continue;                                     
   3908         }
   3909         grp_vec[0] = grp_vec[1] = 0;
   3910         soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32*)vtab,
   3911                           VP_GROUP_BITMAPf, grp_vec);
   3912         
   3913         COMPILER_64_ZERO(grp_bmp);
   3914         COMPILER_64_SET(grp_bmp, grp_vec[1], grp_vec[0]);
   3915 
   3916         if (COMPILER_64_BITTEST(grp_bmp, vvp)) {
   3917             /* VLAN is allowed to come in on this AC 2 AC tunnel */
   3918             BCM_VLAN_VEC_SET((*vlan_vec), i);
   3919         }
   3920     }
   3921 
   3922     soc_cm_sfree(unit, buf);
   3923     return rv;
   3924 }
   3925 
   3926 
   3927 /*
   3928  * Function:
   3929  *      bcm_tr3_wlan_tunnel_terminator_vlan_set
   3930  * Purpose:
   3931  *      Set the allowed VLANs for a WLAN tunnel (AC2AC only)
   3932  * Parameters:
   3933  *      unit    -   (IN)SOC unit number.
   3934  *      tunnel  -   (IN)Tunnel ID.
   3935  *      vlan_vec -  (IN)VLAN vector
   3936  * Returns:
   3937  *      BCM_E_XXX
   3938  * Notes:
   3939  *
   3940  *   [Tunnel Id]  +----------+SVP             (map to 64 vp groups)
   3941  *       |        |AXP_SVP_  |--->+-----------+ vlan_membership-----+
   3942  *     [SVP]      |ASSIGNMENT|    | SOURCE_VP |     +-----------+    \
   3943  *       |        +----------+    |           |     |VLAN_TAB   |vp_bitmap
   3944  * [Allowed Vlans]                +-----------+     |           |
   3945  *                                                  +-----------+
   3946  */
   3947 
   3948 int
   3949 bcm_tr3_wlan_tunnel_terminator_vlan_set(int unit, bcm_gport_t tunnel,
   3950                                    bcm_vlan_vector_t vlan_vec)
   3951 {
   3952     int i, tnl_idx, rv = BCM_E_NONE;
   3953     uint32 count = 0, diff = 0;
   3954     uint64 grp_bmp, grp_bmp_union, val64;
   3955     uint32 grp_vec[2];
   3956     uint32 *buf;
   3957     vlan_tab_entry_t *vtab;
   3958     bcm_vlan_vector_t vlan_vec_old;
   3959     int num_vp = 0, vp = -1, vvp = -1;
   3960     source_vp_entry_t svp;
   3961 
   3962     WLAN_INIT(unit);
   3963 
   3964     /* Input parameters check. */
   3965     if (!BCM_GPORT_IS_TUNNEL(tunnel)) {
   3966         return BCM_E_PARAM;
   3967     }
   3968     tnl_idx = BCM_GPORT_TUNNEL_ID_GET(tunnel);
   3969     if (!_BCM_WLAN_TNL_USED_GET(unit, tnl_idx)) {
   3970         return BCM_E_PARAM;
   3971     }
   3972     if (BCM_VLAN_VEC_GET(vlan_vec, BCM_VLAN_MAX) ||
   3973         BCM_VLAN_VEC_GET(vlan_vec, BCM_VLAN_MIN)) {
   3974         return BCM_E_PARAM;
   3975     }
   3976 
   3977     WLAN_LOCK(unit);
   3978     
   3979     /* First get existing VLAN vector, all allowed vlans for the tunnel */
   3980     BCM_VLAN_VEC_ZERO(vlan_vec_old);
   3981     rv = bcm_tr3_wlan_tunnel_terminator_vlan_get(unit, tunnel, &vlan_vec_old);
   3982     if (BCM_FAILURE(rv)) {
   3983         WLAN_UNLOCK(unit);
   3984         return rv;
   3985     }
   3986 
   3987     /* Check if old == new and if old vector is empty */
   3988     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   3989         if (BCM_VLAN_VEC_GET(vlan_vec_old, i) !=
   3990             BCM_VLAN_VEC_GET(vlan_vec, i)) {
   3991             diff = 1;
   3992             if (BCM_VLAN_VEC_GET(vlan_vec_old, i)) {
   3993                 count++;
   3994                 break;
   3995             }
   3996         }
   3997     }
   3998     if (!diff) {
   3999         WLAN_UNLOCK(unit);
   4000         return rv;
   4001     }
   4002 
   4003     /* Find the SVP corresponding to this tunnel */
   4004     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   4005     for (vp = 0; vp < num_vp; vp++) {
   4006         if ((WLAN_INFO(unit)->port_info[vp].match_tunnel == tunnel) &&
   4007             (WLAN_INFO(unit)->port_info[vp].flags &
   4008              _BCM_WLAN_PORT_MATCH_TUNNEL)) {
   4009             /* Found the matching VP  -  get the VLAN_MEMBERSHIP_PROFILE */
   4010             BCM_IF_ERROR_RETURN
   4011                 (soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY, vp, &svp));
   4012             vvp = soc_SOURCE_VPm_field32_get(unit, &svp,
   4013                                                   VLAN_MEMBERSHIP_PROFILEf);
   4014             break;
   4015         }
   4016     }
   4017     if ((vp == num_vp) || (vvp < 0)) {
   4018         WLAN_UNLOCK(unit);
   4019         return BCM_E_NOT_FOUND;
   4020     }
   4021 
   4022     /* DMA the VLAN table */
   4023     buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, VLAN_TABLE(unit)),
   4024                         "vlan_table");
   4025     if (buf == NULL) {
   4026         WLAN_UNLOCK(unit);
   4027         return BCM_E_MEMORY;
   4028     }
   4029     soc_mem_lock(unit, VLAN_TABLE(unit));
   4030     if ((rv = soc_mem_read_range(unit, VLAN_TABLE(unit), MEM_BLOCK_ANY,
   4031                                  BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   4032         goto vlan_set_end;
   4033     }
   4034 
   4035     /* Initialize values */
   4036     COMPILER_64_ZERO(grp_bmp);
   4037     COMPILER_64_ZERO(grp_bmp_union);
   4038 
   4039     if (count == 0) {
   4040         /* Old vector is empty, allocate a new bit in VLAN_GROUP_BITMAP */
   4041         /* Otherwise use the existing VLAN_MEMBERSHIP_PROFILE from the SVP */
   4042         for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   4043             vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABLE(unit),
   4044                                                 vlan_tab_entry_t *, buf, i);
   4045             if (!soc_mem_field32_get(unit, VLAN_TABLE(unit), vtab, VALIDf)) {
   4046                 if (BCM_VLAN_VEC_GET(vlan_vec, i)) {
   4047                     rv = BCM_E_NOT_FOUND;
   4048                     goto vlan_set_end;
   4049                 } else {
   4050                     continue;
   4051                 }
   4052             }
   4053             grp_vec[0] = grp_vec[1] = 0;
   4054             soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32*)vtab, VP_GROUP_BITMAPf, grp_vec);
   4055             COMPILER_64_ZERO(grp_bmp);
   4056             COMPILER_64_ZERO(grp_bmp_union);
   4057             COMPILER_64_SET(grp_bmp, grp_vec[1], grp_vec[0]);
   4058 
   4059             COMPILER_64_OR(grp_bmp_union, grp_bmp);
   4060         }
   4061 
   4062         COMPILER_64_SET(val64, 0xFFF, 0xFFFFF);
   4063 
   4064         if (COMPILER_64_EQ(grp_bmp_union, val64)) {
   4065             rv = BCM_E_RESOURCE;
   4066             goto vlan_set_end;
   4067         }
   4068        
   4069         /* Use the first available zero bit - skip vvp == 0 */
   4070         for (i = 1; i < soc_mem_field_length(unit, VLAN_TABLE(unit),
   4071                                              VP_GROUP_BITMAPf); i++) {
   4072             if (COMPILER_64_BITTEST(grp_bmp_union, i)) {
   4073                 vvp = i;
   4074                 break;
   4075             }
   4076         }
   4077     }
   4078 
   4079     /* Write the VP_GROUP_BITMAP for all applicable VLANs */
   4080     for (i = BCM_VLAN_MIN; i < BCM_VLAN_MAX; i++) {
   4081         vtab = soc_mem_table_idx_to_pointer(unit, VLAN_TABLE(unit), vlan_tab_entry_t *,
   4082                                             buf, i);
   4083         grp_vec[0] = grp_vec[1] = 0;
   4084         soc_mem_field_get(unit, VLAN_TABLE(unit), (uint32*)vtab, VP_GROUP_BITMAPf, grp_vec);
   4085         COMPILER_64_ZERO(grp_bmp);
   4086         COMPILER_64_SET(grp_bmp, grp_vec[1], grp_vec[0]);
   4087 
   4088         /* Prepare one bit (1 << vvp) in uint64 */
   4089         COMPILER_64_SET(val64, 0, 1);
   4090         COMPILER_64_SHL(val64, vvp);
   4091 
   4092         if (BCM_VLAN_VEC_GET(vlan_vec, i)) {
   4093 
   4094             COMPILER_64_OR(grp_bmp, val64);
   4095             /* Increase use-count for this bit for this VLAN */
   4096             WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp]++;
   4097         } else {
   4098             /* Decrease use-count for this bit for this VLAN */
   4099             if (BCM_VLAN_VEC_GET(vlan_vec_old, i)) {
   4100                 WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp]--;
   4101             }
   4102             if (WLAN_INFO(unit)->vlan_grp_bmp_use_cnt[i][vvp] == 0) {
   4103                 COMPILER_64_NOT(val64); /* Invert one bit to mask */
   4104                 COMPILER_64_AND(grp_bmp, val64);
   4105             }
   4106         }
   4107         
   4108         grp_vec[0] = grp_vec[1] = 0;
   4109         COMPILER_64_TO_32_LO(grp_vec[0], grp_bmp);
   4110         COMPILER_64_TO_32_HI(grp_vec[1], grp_bmp);
   4111         soc_mem_field_set(unit, VLAN_TABLE(unit), (uint32 *)vtab, VP_GROUP_BITMAPf, grp_vec);
   4112     }
   4113     if ((rv = soc_mem_write_range(unit, VLAN_TABLE(unit), MEM_BLOCK_ALL,
   4114                                   BCM_VLAN_MIN, BCM_VLAN_MAX, buf)) < 0) {
   4115         goto vlan_set_end;
   4116     }
   4117     soc_SOURCE_VPm_field32_set(unit, &svp, VLAN_MEMBERSHIP_PROFILEf, vvp);
   4118     /* Enable Vlan-Vp Membership check */
   4119     soc_SOURCE_VPm_field32_set(unit, &svp, ENABLE_IFILTERf, 1);
   4120     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp);
   4121 vlan_set_end:
   4122     soc_mem_unlock(unit, VLAN_TABLE(unit));
   4123     WLAN_UNLOCK(unit);
   4124     soc_cm_sfree(unit, buf);
   4125     return rv;
   4126 }
   4127 
   4128 
   4129 /*
   4130  * Helper functions for setting/getting a field in the LPORT table and
   4131  * update corresponding reference in the WLAN_SVP_TABLE.
   4132  * Assumes locks are taken outside.
   4133  */
   4134 int
   4135 bcm_tr3_wlan_lport_field_set(int unit, bcm_gport_t wlan_port_id,
   4136                              soc_field_t field, int value)
   4137 {
   4138     int value_old = 0, rv = BCM_E_NONE;
   4139     uint32 vp;
   4140     source_vp_attributes_2_entry_t svp;
   4141     lport_tab_entry_t lport_profile;
   4142     rtag7_port_based_hash_entry_t rtag7_entry;
   4143     int lport_ptr, old_lport_ptr = -1;
   4144     void *entries[2];
   4145 
   4146     /* Check valid LPORT field */
   4147     if (!SOC_MEM_FIELD_VALID(unit, LPORT_TABm, field)) {
   4148         return BCM_E_UNAVAIL;
   4149     }
   4150 
   4151     /* Get the VP index from the gport */
   4152     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   4153 
   4154     /* Be sure the entry is used and is set for WLAN */
   4155     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   4156         return BCM_E_BADID;
   4157     }
   4158     BCM_IF_ERROR_RETURN(READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp));
   4159 
   4160     /* Get old lport_profile */
   4161     old_lport_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &svp, 
   4162                                                     LPORT_PROFILE_INDEXf);
   4163     entries[0] = &lport_profile;
   4164     entries[1] = &rtag7_entry;
   4165     BCM_IF_ERROR_RETURN
   4166         (_bcm_lport_profile_entry_get(unit, old_lport_ptr, 1, entries));
   4167     value_old = soc_LPORT_TABm_field32_get(unit, &lport_profile, field);
   4168     if (value != value_old) {
   4169         soc_LPORT_TABm_field32_set(unit, &lport_profile, field, value);
   4170         BCM_IF_ERROR_RETURN(_bcm_lport_profile_entry_add(unit, entries, 1, 
   4171                                                         (uint32 *) &lport_ptr));
   4172         soc_SOURCE_VP_ATTRIBUTES_2m_field32_set(unit, &svp, LPORT_PROFILE_INDEXf, 
   4173                                         lport_ptr);
   4174         /* coverity[negative_returns : FALSE] */
   4175         BCM_IF_ERROR_RETURN
   4176             (WRITE_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ALL, vp, &svp));
   4177         BCM_IF_ERROR_RETURN
   4178             (_bcm_lport_profile_entry_delete(unit, old_lport_ptr));
   4179     }
   4180     return rv;
   4181 }
   4182 
   4183 int
   4184 bcm_tr3_wlan_lport_field_get(int unit, bcm_gport_t wlan_port_id, 
   4185                              soc_field_t field, int *value)
   4186 {
   4187     int rv = BCM_E_NONE;
   4188     uint32 vp;
   4189     source_vp_attributes_2_entry_t svp;
   4190     lport_tab_entry_t lport_profile;
   4191     rtag7_port_based_hash_entry_t rtag7_entry;
   4192     int lport_ptr;
   4193     void *entries[2];
   4194 
   4195     /* Check valid LPORT field */
   4196     if (!SOC_MEM_FIELD_VALID(unit, LPORT_TABm, field)) {
   4197         return BCM_E_UNAVAIL;
   4198     }
   4199 
   4200     /* Get the VP index from the gport */
   4201     vp = BCM_GPORT_WLAN_PORT_ID_GET(wlan_port_id);
   4202 
   4203     /* Be sure the entry is used and is set for WLAN */
   4204     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   4205         return BCM_E_BADID;
   4206     }
   4207     BCM_IF_ERROR_RETURN(READ_SOURCE_VP_ATTRIBUTES_2m(unit, MEM_BLOCK_ANY, vp, &svp));
   4208 
   4209     /* Get old lport_profile */
   4210     lport_ptr = soc_SOURCE_VP_ATTRIBUTES_2m_field32_get(unit, &svp,
   4211                                                         LPORT_PROFILE_INDEXf);
   4212     entries[0] = &lport_profile;
   4213     entries[1] = &rtag7_entry;
   4214     BCM_IF_ERROR_RETURN
   4215         (_bcm_lport_profile_entry_get(unit, lport_ptr, 1, entries));
   4216     *value = soc_LPORT_TABm_field32_get(unit, &lport_profile, field);
   4217     return rv;
   4218 }
   4219 
   4220 
   4221 int
   4222 _bcm_tr3_wlan_port_set(int unit, bcm_gport_t wlan_port_id, soc_field_t field,
   4223                        uint32 value)
   4224 {
   4225     int rv = BCM_E_NONE;
   4226     WLAN_LOCK(unit);
   4227 
   4228     rv = bcm_tr3_wlan_lport_field_set(unit, wlan_port_id, field, value);
   4229 
   4230     WLAN_UNLOCK(unit);
   4231     return rv;
   4232 }
   4233 
   4234 int
   4235 bcm_tr3_wlan_port_untagged_vlan_set(int unit, bcm_gport_t port, bcm_vlan_t vid)
   4236 {
   4237     int old_profile = 0, profile, rv = BCM_E_NONE;
   4238     bcm_vlan_action_set_t action;
   4239     WLAN_LOCK(unit);
   4240 
   4241     /* Get current default tag action entry */
   4242     rv = bcm_tr3_wlan_lport_field_get(unit, port, TAG_ACTION_PROFILE_PTRf, 
   4243                                       &old_profile);
   4244     if (rv < 0) {
   4245         WLAN_UNLOCK(unit);
   4246         return rv;
   4247     }
   4248     bcm_vlan_action_set_t_init(&action);
   4249     _bcm_trx_vlan_action_profile_entry_get(unit, &action, old_profile);
   4250 
   4251     /* Add new tag action entry */
   4252     action.new_outer_vlan = vid;
   4253     rv = bcm_tr3_wlan_lport_field_get(unit, port, PORT_PRIf,
   4254                                       &(action.priority));
   4255     if (rv < 0) {
   4256         WLAN_UNLOCK(unit);
   4257         return rv;
   4258     }
   4259 
   4260     rv = _bcm_trx_vlan_action_profile_entry_add(unit, &action, (uint32*) &profile);
   4261     if (rv < 0) {
   4262         WLAN_UNLOCK(unit);
   4263         return rv;
   4264     }
   4265 
   4266     /* Set the port VID value */
   4267     rv = bcm_tr3_wlan_lport_field_set(unit, port, PORT_VIDf, vid);
   4268     if (rv < 0) {
   4269         WLAN_UNLOCK(unit);
   4270         return rv;
   4271     }
   4272     /* Point to the new profile */
   4273     rv = bcm_tr3_wlan_lport_field_set(unit, port,
   4274                                       TAG_ACTION_PROFILE_PTRf, profile);
   4275     if (rv < 0) {
   4276         WLAN_UNLOCK(unit);
   4277         return rv;
   4278     }
   4279     /* Delete the old profile */
   4280     rv = _bcm_trx_vlan_action_profile_entry_delete(unit, old_profile);
   4281     WLAN_UNLOCK(unit);
   4282     return rv;
   4283 }
   4284 /*
   4285  * Function:
   4286  *      bcm_tr3_wlan_port_untagged_vlan_get
   4287  * Purpose:
   4288  *      This function gets port vid for untagged tag action profile
   4289  * Parameters:
   4290  *      unit       - (IN) bcm device
   4291  *      port       - (IN) gport
   4292  *      vid_ptr    - (OUT) port vid
   4293  * Returns:
   4294  *      BCM_E_NONE - Success
   4295  *      BCM_E_XXX
   4296  * Notes:
   4297  */
   4298 int
   4299 bcm_tr3_wlan_port_untagged_vlan_get(int unit, bcm_gport_t port,
   4300                                     bcm_vlan_t *vid_ptr)
   4301 {
   4302     int value = 0, rv = BCM_E_NONE;
   4303 
   4304     rv = bcm_tr3_wlan_lport_field_get(unit, port, PORT_VIDf, &value);
   4305     *vid_ptr = (bcm_vlan_t)value;
   4306 
   4307     return rv;
   4308 }
   4309 
   4310 /*
   4311  * Function:
   4312  *      bcm_tr3_wlan_port_untagged_prio_set
   4313  * Purpose:
   4314  *      This function sets port default priority in lport_table
   4315  * Parameters:
   4316  *      unit       - (IN) bcm device
   4317  *      port       - (IN) gport
   4318  *      prio       - (IN) Port priority
   4319  * Returns:
   4320  *      BCM_E_NONE - Success
   4321  *      BCM_E_XXX
   4322  * Notes:
   4323  */
   4324 
   4325 int
   4326 bcm_tr3_wlan_port_untagged_prio_set(int unit, bcm_gport_t port, int prio)
   4327 {
   4328     int rv = BCM_E_NONE;
   4329     if (prio > 7) {
   4330         return BCM_E_PARAM;
   4331     }
   4332     rv = _bcm_tr3_wlan_port_set(unit, port, PORT_PRIf, prio);
   4333     return rv;
   4334 }
   4335 
   4336 /*
   4337  * Function:
   4338  *      bcm_tr3_wlan_port_untagged_prio_get
   4339  * Purpose:
   4340  *      This function gets port default priority from lport_table
   4341  * Parameters:
   4342  *      unit       - (IN) bcm device
   4343  *      port       - (IN) gport
   4344  *      *prio_ptr  - (OUT) Port priority
   4345  * Returns:
   4346  *      BCM_E_NONE - Success
   4347  *      BCM_E_XXX
   4348  * Notes:
   4349  */
   4350 int
   4351 bcm_tr3_wlan_port_untagged_prio_get(int unit, bcm_gport_t port, int *prio_ptr)
   4352 {
   4353     int value = 0, rv = BCM_E_NONE;
   4354 
   4355     rv = bcm_tr3_wlan_lport_field_get(unit, port, PORT_PRIf, &value);
   4356     *prio_ptr = value;
   4357 
   4358     return rv;
   4359 }
   4360 
   4361 /*
   4362  * Function:
   4363  *      _bcm_tr3_qos_wlan_port_map_set
   4364  * Purpose: 
   4365  *      Function sets the egress priority maps in AXP for wlan port
   4366  *
   4367  * Parameters: 
   4368  *      unit       - (IN) bcm device
   4369  *      port       - (IN) wlan port
   4370  *      egr_map    - (IN) egr map id
   4371  *      pri_index  - (IN) egr priority index
   4372  * Returns:
   4373  *      BCM_E_NONE - Success
   4374  *      BCM_E_XXX
   4375  * Notes:
   4376  */
   4377 int
   4378 _bcm_tr3_qos_wlan_port_map_set(int unit, bcm_gport_t port, int egr_map, 
   4379                                  int pri_index)
   4380 {
   4381     axp_wtx_pri_map_entry_t         *wlan_pri_map;  /* Wlan Priority Map     */
   4382     egr_dvp_attribute_entry_t       wlan_dvp;       /* Egress wlan dvp        */
   4383     axp_wtx_dvp_profile_entry_t     axp_wtx_dvp;    /* AXP DVP Profile        */
   4384     axp_wtx_tunnel_entry_t          axp_wtx_tunnel[_BCM_WLAN_TNL_ENTRY_WIDTH]; 
   4385     void   *entry, *mem_entries[1];                 /* For profile mem entries       */
   4386     int wlan_dvp_index, egress_tunnel;
   4387     uint32 vp;
   4388     int alloc_size, index;
   4389     int idx, new_pri, new_cfi;
   4390     soc_mem_t             mem;
   4391     int rv = BCM_E_NONE;
   4392     
   4393  
   4394     /* Deal with WLAN ports */
   4395     vp = BCM_GPORT_WLAN_PORT_ID_GET(port);
   4396     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
   4397         return BCM_E_BADID;
   4398     }
   4399 
   4400     if (egr_map != -1) { /* -1 means no change */
   4401             
   4402         /* Get AXP_WTX_TUNNEL index and set the dot1p pointer for WLAN AXP */
   4403             
   4404         /* Get EGR DVP Attribute for the vp */
   4405         BCM_IF_ERROR_RETURN(
   4406                 READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, vp, &wlan_dvp));
   4407         wlan_dvp_index = soc_EGR_DVP_ATTRIBUTEm_field32_get(unit, &wlan_dvp, WLAN_DVP_PROFILEf);
   4408         mem_entries[0] = &axp_wtx_dvp;
   4409         rv = soc_profile_mem_get(unit, WLAN_DVP_PROFILE(unit), wlan_dvp_index, 1,
   4410                                 mem_entries);
   4411         if (BCM_FAILURE(rv)) {
   4412             return rv;
   4413         }
   4414 
   4415         /* Get Egress Tunnel Attributes */
   4416         egress_tunnel = soc_AXP_WTX_DVP_PROFILEm_field32_get(unit, &axp_wtx_dvp,
   4417                                                             WLAN_TUNNEL_INDEXf);
   4418 
   4419         rv = _bcm_tr3_wlan_tnl_read(unit, egress_tunnel, axp_wtx_tunnel);
   4420         if (BCM_FAILURE(rv)) {
   4421             return rv;
   4422         }
   4423 
   4424         mem = AXP_WTX_TUNNELm;
   4425         if (egr_map == 0) {
   4426             /* Clear WTX Tunnel DOT1P priority map, 
   4427              * the priorities are got from DVP tunnel pri/cfi
   4428              */
   4429             soc_mem_field32_set(unit, mem, &axp_wtx_tunnel[TNL_ENTRY_0],        
   4430                                 DOT1P_REMAPf, 0);
   4431         } else {
   4432             /* Use the provided map */
   4433             soc_mem_field32_set(unit, mem, &axp_wtx_tunnel[TNL_ENTRY_0],        
   4434                                 DOT1P_REMAPf, 1);
   4435             soc_mem_field32_set(unit, mem, &axp_wtx_tunnel[TNL_ENTRY_0],
   4436                                 DOT1P_MAP_PTRf, pri_index);
   4437 
   4438             /* Read from Egress "EGR_MPLS_PRI_MAPPING" and write to WLAN AXP
   4439              * "AXP_WTX_PRI_MAP" table for the egr priority profile index. 
   4440              */
   4441 
   4442             alloc_size = (_BCM_AXP_PRI_MAP_CHUNK * sizeof(egr_mpls_pri_mapping_entry_t));
   4443             wlan_pri_map = soc_cm_salloc(unit, alloc_size,
   4444                                                  "wlan pri map");
   4445             if (NULL == wlan_pri_map) {
   4446                 return (BCM_E_MEMORY);
   4447             }
   4448             sal_memset(wlan_pri_map, 0, alloc_size);
   4449 
   4450             /* Priority Map index */
   4451             index = pri_index * _BCM_AXP_PRI_MAP_CHUNK; 
   4452                                    
   4453             rv = soc_mem_read_range(unit, EGR_MPLS_PRI_MAPPINGm, MEM_BLOCK_ANY, 
   4454                                         index, 
   4455                                         (index + (_BCM_AXP_PRI_MAP_CHUNK -1)),
   4456                                         wlan_pri_map);
   4457             if (BCM_FAILURE(rv)) {
   4458                 soc_cm_sfree(unit, wlan_pri_map);
   4459                 return (rv);
   4460             }
   4461 
   4462             for (idx = 0; idx < _BCM_AXP_PRI_MAP_CHUNK; idx++ )
   4463             {
   4464                 new_pri = new_cfi = 0;
   4465                 mem = EGR_MPLS_PRI_MAPPINGm;
   4466                 entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 
   4467                                                  wlan_pri_map, idx);
   4468                 new_pri = soc_mem_field32_get(unit, mem, entry, NEW_PRIf);
   4469                 new_cfi = soc_mem_field32_get(unit, mem, entry, NEW_CFIf);
   4470 
   4471                 mem = AXP_WTX_PRI_MAPm;
   4472                 entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 
   4473                                                  wlan_pri_map, idx);
   4474                 soc_mem_field32_set(unit, mem, entry, PRIf, new_pri);
   4475                 soc_mem_field32_set(unit, mem, entry, CFIf, new_cfi);
   4476             }
   4477        
   4478              /* Write Priority maps to AXP_WTX_PRI_MAP */ 
   4479              rv = soc_mem_write_range(unit, AXP_WTX_PRI_MAPm, MEM_BLOCK_ALL, 
   4480                                         index, 
   4481                                         (index + (_BCM_AXP_PRI_MAP_CHUNK -1)),
   4482                                         wlan_pri_map);
   4483             if (BCM_FAILURE(rv)) {
   4484                 soc_cm_sfree(unit, wlan_pri_map);
   4485                 return (rv);
   4486             }
   4487             soc_cm_sfree(unit, wlan_pri_map);
   4488         }
   4489         
   4490         /* Write to axp_wtx_tunnel table */
   4491         rv = _bcm_tr3_wlan_tnl_write(unit, egress_tunnel, axp_wtx_tunnel);
   4492         if (BCM_FAILURE(rv)) {
   4493             return rv;
   4494         }
   4495 
   4496     }
   4497     return rv;
   4498 }
   4499 
   4500 int
   4501 _bcm_tr3_wlan_tunnel_set_roam(int unit, bcm_gport_t tunnel_id)
   4502 {
   4503     int rv = BCM_E_NONE;
   4504     uint32 tunnel;
   4505     egr_wlan_attributes_entry_t wlan_attr;
   4506 
   4507     WLAN_INIT(unit);
   4508 
   4509     /* Get Tunnel */
   4510     tunnel = BCM_GPORT_TUNNEL_ID_GET(tunnel_id);
   4511 
   4512     WLAN_LOCK(unit);
   4513 
   4514     /* Enable HA/FA roam model */ 
   4515     rv = READ_EGR_WLAN_ATTRIBUTESm(unit, MEM_BLOCK_ANY, tunnel, &wlan_attr);
   4516     if (BCM_FAILURE(rv)) {
   4517         goto cleanup;
   4518     }
   4519     soc_EGR_WLAN_ATTRIBUTESm_field32_set(unit, &wlan_attr, HA_FA_ENABLEf, 1);
   4520     rv = WRITE_EGR_WLAN_ATTRIBUTESm(unit, MEM_BLOCK_ANY, tunnel, &wlan_attr);
   4521 
   4522 cleanup:
   4523     WLAN_UNLOCK(unit);
   4524     return rv;
   4525 }
   4526 
   4527 int
   4528 _bcm_tr3_wlan_tunnel_get_roam(int unit, bcm_gport_t tunnel_id)
   4529 {
   4530     int rv = BCM_E_NONE;
   4531     uint32 tunnel;
   4532     egr_wlan_attributes_entry_t wlan_attr;
   4533 
   4534     WLAN_INIT(unit);
   4535 
   4536     if (tunnel_id <= 0) {
   4537         return BCM_E_PARAM;
   4538     } 
   4539 
   4540     /* Get Tunnel */
   4541     tunnel = BCM_GPORT_TUNNEL_ID_GET(tunnel_id);
   4542 
   4543     WLAN_LOCK(unit);
   4544 
   4545     /* Enable HA/FA roam model */ 
   4546     rv = READ_EGR_WLAN_ATTRIBUTESm(unit, MEM_BLOCK_ANY, tunnel, &wlan_attr);
   4547     if (BCM_FAILURE(rv))  {
   4548         goto cleanup;
   4549     }
   4550 
   4551     rv = soc_EGR_WLAN_ATTRIBUTESm_field32_get(unit, &wlan_attr, HA_FA_ENABLEf);
   4552 
   4553 cleanup:
   4554     
   4555     WLAN_UNLOCK(unit);
   4556     return rv;
   4557 }
   4558 #endif /* BCM_TRIUMPH3_SUPPORT && INCLUDE_L3 */