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