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