trunk.c (125122B)
1 /* 2 * $ID: trunk.c,v 1.0 Broadcom SDK $ 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 * Tomahawk 3 Trunking (Ether) 8 */ 9 #include <soc/mem.h> 10 #include <bcm/error.h> 11 12 #include <bcm_int/esw/mbcm.h> 13 #include <bcm_int/esw/link.h> 14 #include <bcm_int/esw/trunk.h> 15 #include <bcm_int/esw/switch.h> 16 17 #include <bcm_int/esw/stack.h> 18 #include <bcm_int/esw_dispatch.h> 19 20 #include <bcm_int/esw/tomahawk3.h> 21 22 #include <bcm_int/esw/portctrl.h> 23 24 #ifdef BCM_TOMAHAWK3_SUPPORT 25 26 #define _BCM_TH3_TRUNK_NUM_MAX 144 27 #define _BCM_TH3_PORTS_PER_TRUNK_MAX 64 28 #define _BCM_TH3_TRUNK_FAILOVER_PORT_NUM 8 29 30 /* 31 * Trunk Membership Info 32 * TH3 supports 64 ports per trunk and does NOT support stacking or HiGig 33 */ 34 typedef struct { 35 uint8 num_ports; /* Number of ports in the trunk */ 36 uint16 *port;/* Device Ports in the trunk */ 37 uint32 *member_flags; /* Flags for the port */ 38 #ifdef BCM_WARM_BOOT_SUPPORT 39 uint8 recovered_from_scache; 40 #endif 41 } _th3_member_info_t; 42 43 typedef struct { 44 _th3_member_info_t *member_info; 45 } _th3_trunk_member_info_t; 46 47 /* Pointer to array of trunks that will be allocated in init. */ 48 STATIC _th3_trunk_member_info_t *_th3_trunk_member_info[BCM_MAX_NUM_UNITS]; 49 50 #define MEMBER_INFO(_unit_, _tid_) (_th3_trunk_member_info[_unit_]->member_info[_tid_]) 51 52 /* Port to the Trunk ID Mapping */ 53 STATIC uint8 *_th3_port_to_tid_map[BCM_MAX_NUM_UNITS]; 54 55 /* 56 * Hardware Trunk Failover: 57 * 58 * For the devices which support hardware trunk failover, the failover 59 * configuration must be retained if it is one of the standard models 60 * for the retrieval function to use the same encoding as the set function. 61 * 62 * Note: The trunk members stored in _th3_tinfo_t's port array do not 63 * include those members with the BCM_TRUNK_MEMBER_EGRESS_DISABLE set. 64 */ 65 typedef struct { 66 uint8 num_ports; 67 uint8 *psc; 68 uint16 *port; 69 uint32 *flags; 70 } _th3_hw_tinfo_t; 71 72 typedef struct { 73 _th3_hw_tinfo_t *hw_tinfo; 74 } _th3_trunk_hwfail_t; 75 76 STATIC _th3_trunk_hwfail_t *_th3_trunk_hwfail[BCM_MAX_NUM_UNITS]; 77 78 /* ----------------------- */ 79 /* Software Trunk Failover */ 80 /* ----------------------- */ 81 82 /* Even without hardware failover support, given the high speed link 83 * change notification possible with devices, a port that has been 84 * indicated as link down can cause the trunk_group table to be immediately 85 * updated with the link down port removed. 86 * 87 * Note: The trunk members stored in _th3_tinfo_t's port array do not 88 * include those members with the BCM_TRUNK_MEMBER_EGRESS_DISABLE set. 89 * If a trunk member port is down, it'll be removed from_th3_tinfo_t's 90 * port array by _bcm_th3_trunk_swfailover_trigger. 91 */ 92 typedef struct { 93 uint8 rtag; 94 uint16 num_ports; 95 uint16 *port; 96 uint32 *member_flags; 97 uint32 flags; 98 } _th3_tinfo_t; 99 100 typedef struct { 101 uint8 mymodid; 102 #if (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 103 bcm_trunk_t trunk[SOC_MAX_NUM_PP_PORTS]; 104 #else 105 bcm_trunk_t trunk[SOC_MAX_NUM_PORTS]; /* If port is not a member of any 106 trunk group, trunk = 0; else 107 trunk = trunk id + 1. */ 108 #endif 109 _th3_tinfo_t *tinfo; 110 } _th3_trunk_swfail_t; 111 112 STATIC _th3_trunk_swfail_t *_th3_trunk_swfail[BCM_MAX_NUM_UNITS]; 113 114 115 #if 1 116 /* fields from FAST_TRUNK_PORTS_1 and FAST_TRUNK_PORTS_2 */ 117 static soc_field_t _th3_fast_portf[64] = { 118 TRUNK_MEMBER_0f, TRUNK_MEMBER_1f, TRUNK_MEMBER_2f, TRUNK_MEMBER_3f, 119 TRUNK_MEMBER_4f, TRUNK_MEMBER_5f, TRUNK_MEMBER_6f, TRUNK_MEMBER_7f, 120 TRUNK_MEMBER_8f, TRUNK_MEMBER_9f, TRUNK_MEMBER_10f, TRUNK_MEMBER_11f, 121 TRUNK_MEMBER_12f, TRUNK_MEMBER_13f, TRUNK_MEMBER_14f, TRUNK_MEMBER_15f, 122 TRUNK_MEMBER_16f, TRUNK_MEMBER_17f, TRUNK_MEMBER_18f, TRUNK_MEMBER_19f, 123 TRUNK_MEMBER_20f, TRUNK_MEMBER_21f, TRUNK_MEMBER_22f, TRUNK_MEMBER_23f, 124 TRUNK_MEMBER_24f, TRUNK_MEMBER_25f, TRUNK_MEMBER_26f, TRUNK_MEMBER_27f, 125 TRUNK_MEMBER_28f, TRUNK_MEMBER_29f, TRUNK_MEMBER_30f, TRUNK_MEMBER_31f, 126 TRUNK_MEMBER_32f, TRUNK_MEMBER_33f, TRUNK_MEMBER_34f, TRUNK_MEMBER_35f, 127 TRUNK_MEMBER_36f, TRUNK_MEMBER_37f, TRUNK_MEMBER_38f, TRUNK_MEMBER_39f, 128 TRUNK_MEMBER_40f, TRUNK_MEMBER_41f, TRUNK_MEMBER_42f, TRUNK_MEMBER_43f, 129 TRUNK_MEMBER_44f, TRUNK_MEMBER_45f, TRUNK_MEMBER_46f, TRUNK_MEMBER_47f, 130 TRUNK_MEMBER_48f, TRUNK_MEMBER_49f, TRUNK_MEMBER_50f, TRUNK_MEMBER_51f, 131 TRUNK_MEMBER_52f, TRUNK_MEMBER_53f, TRUNK_MEMBER_54f, TRUNK_MEMBER_55f, 132 TRUNK_MEMBER_56f, TRUNK_MEMBER_57f, TRUNK_MEMBER_58f, TRUNK_MEMBER_59f, 133 TRUNK_MEMBER_60f, TRUNK_MEMBER_61f, TRUNK_MEMBER_62f, TRUNK_MEMBER_63f 134 }; 135 #endif 136 #if 1 137 138 /* 139 * Function: 140 * _bcm_th3_trunk_member_info_deinit 141 * Purpose: 142 * De-allocate trunk membership info. 143 * Parameters: 144 * unit - (IN)SOC unit number. 145 * Returns: 146 * None 147 */ 148 STATIC void 149 _bcm_th3_trunk_member_info_deinit(int unit) 150 { 151 int trunk_num_groups; 152 int i; 153 154 if (_th3_trunk_member_info[unit]) { 155 if (_th3_trunk_member_info[unit]->member_info) { 156 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 157 for (i = 0; i < trunk_num_groups; i++) { 158 if (MEMBER_INFO(unit, i).port) { 159 sal_free(MEMBER_INFO(unit, i).port); 160 MEMBER_INFO(unit, i).port = NULL; 161 } 162 if (MEMBER_INFO(unit, i).member_flags) { 163 sal_free(MEMBER_INFO(unit, i).member_flags); 164 MEMBER_INFO(unit, i).member_flags = NULL; 165 } 166 } 167 sal_free(_th3_trunk_member_info[unit]->member_info); 168 _th3_trunk_member_info[unit]->member_info = NULL; 169 } 170 sal_free(_th3_trunk_member_info[unit]); 171 _th3_trunk_member_info[unit] = NULL; 172 } 173 } 174 175 /* 176 * Function: 177 * _bcm_th3_trunk_member_info_init 178 * Purpose: 179 * Allocate and Initialize trunk member info 180 * Parameters: 181 * unit - (IN) SOC unit number 182 * Returns: 183 * BCM_X_XXX 184 */ 185 STATIC int 186 _bcm_th3_trunk_member_info_init(int unit) 187 { 188 int trunk_num_groups; 189 190 if (_th3_trunk_member_info[unit] == NULL) { 191 _th3_trunk_member_info[unit] = 192 sal_alloc(sizeof(_th3_trunk_member_info_t), 193 "_th3_trunk_member_info"); 194 if (_th3_trunk_member_info[unit] == NULL) { 195 return BCM_E_MEMORY; 196 } 197 } 198 sal_memset(_th3_trunk_member_info[unit], 0, 199 sizeof(_th3_trunk_member_info_t)); 200 201 /* Allocate the array of trunk groups */ 202 203 /* Only need to count FAST_TRUNK_PORTS_1m because 204 * FAST_TRUNK_PORTS_2m is extension of the same LAG */ 205 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 206 207 if (_th3_trunk_member_info[unit]->member_info == NULL) { 208 _th3_trunk_member_info[unit]->member_info = 209 sal_alloc(sizeof(_th3_member_info_t) * trunk_num_groups, 210 "member_info"); 211 if (_th3_trunk_member_info[unit]->member_info == NULL) { 212 _bcm_th3_trunk_member_info_deinit(unit); 213 return BCM_E_MEMORY; 214 } 215 } 216 sal_memset(_th3_trunk_member_info[unit]->member_info, 0, 217 sizeof(_th3_member_info_t) * trunk_num_groups); 218 219 /* Note: The maximum number of member ports in a trunk group is 64 in TH3. 220 * But it would be quite wasteful to allocate 64 entries to each 221 * _th3_trunk_member_info[unit]->member_info[x].port/member_flags 222 * arrays. 223 * These arrays will be allocated as member ports are added to 224 * trunk group. 225 */ 226 227 228 return BCM_E_NONE; 229 } 230 231 232 233 /* 234 * Function: 235 * _bcm_th3_trunk_hwfailover_deinit 236 * Purpose: 237 * Deallocate _th3_trunk_hwfail 238 * Parameters: 239 * unit - (IN)SOC unit number. 240 * Returns: 241 * None 242 */ 243 STATIC void 244 _bcm_th3_trunk_hwfailover_deinit(int unit) 245 { 246 int trunk_num_groups; 247 int i; 248 249 if (_th3_trunk_hwfail[unit]) { 250 if (_th3_trunk_hwfail[unit]->hw_tinfo) { 251 /* Only need to count FAST_TRUNK_PORTS_1m because 252 * FAST_TRUNK_PORTS_2m is extension of the same LAG */ 253 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 254 for (i = 0; i < trunk_num_groups; i++) { 255 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].port) { 256 sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].port); 257 _th3_trunk_hwfail[unit]->hw_tinfo[i].port = NULL; 258 } 259 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].psc) { 260 sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].psc); 261 _th3_trunk_hwfail[unit]->hw_tinfo[i].psc = NULL; 262 } 263 if (_th3_trunk_hwfail[unit]->hw_tinfo[i].flags) { 264 sal_free(_th3_trunk_hwfail[unit]->hw_tinfo[i].flags); 265 _th3_trunk_hwfail[unit]->hw_tinfo[i].flags = NULL; 266 } 267 } 268 sal_free(_th3_trunk_hwfail[unit]->hw_tinfo); 269 _th3_trunk_hwfail[unit]->hw_tinfo = NULL; 270 } 271 sal_free(_th3_trunk_hwfail[unit]); 272 _th3_trunk_hwfail[unit] = NULL; 273 } 274 } 275 276 /* 277 * Function: 278 * _bcm_th3_trunk_hwfailover_init 279 * Purpose: 280 * Allocate and initialize _th3_trunk_hwfail 281 * Parameters: 282 * unit - (IN)SOC unit number. 283 * Returns: 284 * BCM_X_XXX 285 */ 286 STATIC int 287 _bcm_th3_trunk_hwfailover_init(int unit) 288 { 289 int trunk_num_groups; 290 291 if (_th3_trunk_hwfail[unit] == NULL) { 292 _th3_trunk_hwfail[unit] = sal_alloc(sizeof(_th3_trunk_hwfail_t), 293 "_th3_trunk_hwfail"); 294 if (_th3_trunk_hwfail[unit] == NULL) { 295 return BCM_E_MEMORY; 296 } 297 } 298 sal_memset(_th3_trunk_hwfail[unit], 0, sizeof(_th3_trunk_hwfail_t)); 299 300 /* Only need to count FAST_TRUNK_PORTS_1m because 301 * FAST_TRUNK_PORTS_2m is extension of the same LAG */ 302 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 303 if (_th3_trunk_hwfail[unit]->hw_tinfo == NULL) { 304 _th3_trunk_hwfail[unit]->hw_tinfo = 305 sal_alloc(sizeof(_th3_hw_tinfo_t) * trunk_num_groups, 306 "_th3_trunk_hwfail_hw_tinfo"); 307 if (_th3_trunk_hwfail[unit]->hw_tinfo == NULL) { 308 _bcm_th3_trunk_hwfailover_deinit(unit); 309 return BCM_E_MEMORY; 310 } 311 } 312 sal_memset(_th3_trunk_hwfail[unit]->hw_tinfo, 0, 313 sizeof(_th3_hw_tinfo_t) * trunk_num_groups); 314 315 /* Note: The maximum number of member ports in a trunk group is 64 in TH3. 316 * But it would be quite wasteful to allocate 64 entries to each 317 * _th3_trunk_hwfail[unit]->hw_tinfo[x].port/psc/flags arrays. 318 * These arrays will be allocated as member ports are added to trunk group. 319 */ 320 321 return BCM_E_NONE; 322 } 323 /* 324 * Function: 325 * _bcm_th3_trunk_port_map_init 326 * Purpose: 327 * Initialize a software cache for the SOURCE_TRUNK_MAP_TABLE. 328 * Parameters: 329 * unit - (IN)SOC unit number. 330 * Returns: 331 * BCM_X_XXX 332 */ 333 int 334 _bcm_th3_trunk_port_map_init(int unit) 335 { 336 int mem_size; 337 uint8 *ptr; 338 339 if (NULL != _th3_port_to_tid_map[unit]) { 340 _bcm_th3_trunk_port_map_deinit(unit); 341 } 342 343 /* Allocated mapping array */ 344 345 mem_size = SOC_MAX_NUM_PORTS * sizeof(uint8); 346 ptr = sal_alloc(mem_size, "TH3_Port_Trunk"); 347 if (NULL == ptr) { 348 return BCM_E_MEMORY; 349 } 350 351 /* Reset buffer */ 352 sal_memset(ptr, 0, mem_size); 353 354 _th3_port_to_tid_map[unit] = ptr; 355 356 return BCM_E_NONE; 357 } 358 359 /* 360 * Function: 361 * _bcm_th3_trunk_port_map_deinit 362 * Purpose: 363 * Deinitialize a software cache for the SOURCE_TRUNK_MAP_TABLE. 364 * Parameters: 365 * unit - (IN)SOC unit number. 366 * Returns: 367 * BCM_X_XXX 368 */ 369 int 370 _bcm_th3_trunk_port_map_deinit(int unit) 371 { 372 void *ptr; 373 374 ptr = (void *)_th3_port_to_tid_map[unit]; 375 376 _th3_port_to_tid_map[unit] = NULL; 377 378 if (NULL != ptr) { 379 sal_free(ptr); 380 } 381 return (BCM_E_NONE); 382 } 383 384 /* 385 * Function: 386 * _bcm_th3_trunk_port_map_set 387 * Purpose: 388 * Set (port) to trunk id map. 389 * Map implements a software cache for the SOURCE_TRUNK_MAP_TABLE. 390 * Parameters: 391 * unit - (IN) BCM device number. 392 * modid - (IN) Member port module id (not used, but from api call) 393 * port - (IN) Member port number. 394 * trunk_id - (IN) Trunk number or negative value for reset. 395 * Returns: 396 * BCM_X_XXX 397 */ 398 STATIC int 399 _bcm_th3_trunk_port_map_set(int unit, bcm_module_t modid, 400 bcm_port_t port, bcm_trunk_t trunk_id) 401 { 402 if (NULL == _th3_port_to_tid_map[unit]) { 403 return BCM_E_INIT; 404 } 405 406 /* Trunk id range check. */ 407 if (trunk_id >= _BCM_TH3_TRUNK_NUM_MAX) { 408 return BCM_E_INTERNAL; 409 } 410 411 if (port >= SOC_MAX_NUM_PORTS) { 412 return BCM_E_PARAM; 413 } 414 415 _th3_port_to_tid_map[unit][port] = (trunk_id < 0) ? 0 : (++trunk_id); 416 417 return BCM_E_NONE; 418 } 419 420 /* 421 * Function: 422 * _bcm_th3_trunk_port_map_get 423 * Purpose: 424 * Read mapping (port) to trunk id from software cache 425 * for the SOURCE_TRUNK_MAP_TABLE. 426 * Parameters: 427 * unit - (IN) BCM device number. 428 * port - (IN) Member port number. 429 * trunk_id - (OUT) Trunk number or negative value for reset. 430 * Returns: 431 * BCM_X_XXX 432 */ 433 STATIC int 434 _bcm_th3_trunk_port_map_get(int unit, 435 bcm_port_t port, bcm_trunk_t *trunk_id) 436 { 437 438 int idx; /* Map array index. */ 439 440 if (NULL == _th3_port_to_tid_map[unit]) { 441 return BCM_E_INIT; 442 } 443 444 idx = port; 445 if (idx >= SOC_MAX_NUM_PORTS) { 446 return (BCM_E_PARAM); 447 } 448 449 *trunk_id = _th3_port_to_tid_map[unit][idx] - 1; 450 451 return (_th3_port_to_tid_map[unit][idx]) ? BCM_E_NONE : BCM_E_NOT_FOUND; 452 } 453 454 /* 455 * Function: 456 * _bcm_th3_trunk_get_port_property 457 * Purpose: 458 * Get trunk group ID for a port 459 * Parameters: 460 * unit - (IN) SOC unit number 461 * port - (IN) Port number 462 * tid - (OUT) Trunk group ID 463 * Returns: 464 * BCM_E_xxx 465 */ 466 int 467 _bcm_th3_trunk_get_port_property(int unit, bcm_port_t port, int *tid) 468 { 469 return _bcm_th3_trunk_port_map_get(unit, port, tid); 470 } 471 /* 472 * Function: 473 * _bcm_th3_trunk_swfailover_deinit 474 * Purpose: 475 * Deallocate _th3_trunk_swfail 476 * Parameters: 477 * unit - (IN)SOC unit number. 478 * Returns: 479 * None 480 */ 481 STATIC void 482 _bcm_th3_trunk_swfailover_deinit(int unit) 483 { 484 int trunk_num_groups; 485 int i; 486 487 if (_th3_trunk_swfail[unit]) { 488 if (_th3_trunk_swfail[unit]->tinfo) { 489 /* Only need to count FAST_TRUNK_PORTS_1m because 490 * FAST_TRUNK_PORTS_2m is extension of the same LAG */ 491 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 492 for (i = 0; i < trunk_num_groups; i++) { 493 if (_th3_trunk_swfail[unit]->tinfo[i].port) { 494 sal_free(_th3_trunk_swfail[unit]->tinfo[i].port); 495 _th3_trunk_swfail[unit]->tinfo[i].port = NULL; 496 } 497 } 498 sal_free(_th3_trunk_swfail[unit]->tinfo); 499 _th3_trunk_swfail[unit]->tinfo = NULL; 500 } 501 sal_free(_th3_trunk_swfail[unit]); 502 _th3_trunk_swfail[unit] = NULL; 503 } 504 } 505 506 /* 507 * Function: 508 * _th3_trunk_add_info_member_free 509 * Purpose: 510 * Free member_flags, tp, and tm of _esw_trunk_add_info_t. 511 * Parameters: 512 * add_info - (IN) Pointer to trunk add info structure. 513 * Returns: 514 * BCM_E_xxx 515 */ 516 STATIC void 517 _th3_trunk_add_info_member_free(_esw_trunk_add_info_t *add_info) 518 { 519 if (NULL != add_info->member_flags) { 520 sal_free(add_info->member_flags); 521 } 522 523 if (NULL != add_info->tp) { 524 sal_free(add_info->tp); 525 } 526 527 if (NULL != add_info->tm) { 528 sal_free(add_info->tm); 529 } 530 531 if (NULL != add_info->dynamic_scaling_factor) { 532 sal_free(add_info->dynamic_scaling_factor); 533 } 534 if (NULL != add_info->dynamic_load_weight) { 535 sal_free(add_info->dynamic_load_weight); 536 } 537 if (NULL != add_info->dynamic_queue_size_weight) { 538 sal_free(add_info->dynamic_queue_size_weight); 539 } 540 } 541 542 543 /* 544 * Function: 545 * _th3_trunk_add_info_member_alloc 546 * Purpose: 547 * Allocate member_flags, tp, and tm of _esw_trunk_add_info_t. 548 * Parameters: 549 * add_info - (IN/OUT) Pointer to trunk add info structure. 550 * num_ports - (IN) Number of member ports. 551 * Returns: 552 * BCM_E_xxx 553 */ 554 STATIC int 555 _th3_trunk_add_info_member_alloc(_esw_trunk_add_info_t *add_info, 556 int num_ports) 557 { 558 int rv = BCM_E_NONE; 559 560 add_info->member_flags = sal_alloc(sizeof(uint32) * num_ports, 561 "_th3_trunk_add_info_member_flags"); 562 if (add_info->member_flags == NULL) { 563 rv = BCM_E_MEMORY; 564 goto error; 565 } 566 sal_memset(add_info->member_flags, 0, sizeof(uint32) * num_ports); 567 568 add_info->tp = sal_alloc(sizeof(bcm_port_t) * num_ports, 569 "_th3_trunk_add_info_tp"); 570 if(add_info->tp == NULL) { 571 rv = BCM_E_MEMORY; 572 goto error; 573 } 574 sal_memset(add_info->tp, 0, sizeof(bcm_port_t) * num_ports); 575 576 /* Following fields are not used by TH3, but add memory for 577 * instances where we will fill it with 0 */ 578 add_info->tm = sal_alloc(sizeof(bcm_module_t) * num_ports, 579 "_th3_trunk_add_info_tm"); 580 if (add_info->tm == NULL) { 581 rv = BCM_E_MEMORY; 582 goto error; 583 } 584 sal_memset(add_info->tm, 0, sizeof(bcm_module_t) * num_ports); 585 586 add_info->dynamic_scaling_factor = sal_alloc(sizeof(int) * num_ports, 587 "_trident_trunk_add_info_dynamic_scaling_factor"); 588 if (add_info->dynamic_scaling_factor == NULL) { 589 rv = BCM_E_MEMORY; 590 goto error; 591 } 592 sal_memset(add_info->dynamic_scaling_factor, 0, sizeof(int) * num_ports); 593 594 add_info->dynamic_load_weight = sal_alloc(sizeof(int) * num_ports, 595 "_trident_trunk_add_info_dynamic_load_weight"); 596 if (add_info->dynamic_load_weight == NULL) { 597 rv = BCM_E_MEMORY; 598 goto error; 599 } 600 sal_memset(add_info->dynamic_load_weight, 0, sizeof(int) * num_ports); 601 602 add_info->dynamic_queue_size_weight = sal_alloc(sizeof(int) * num_ports, 603 "_trident_trunk_add_info_dynamic_queue_size_weight"); 604 if (add_info->dynamic_queue_size_weight == NULL) { 605 rv = BCM_E_MEMORY; 606 goto error; 607 } 608 sal_memset(add_info->dynamic_queue_size_weight, 0, sizeof(int) * num_ports); 609 610 return rv; 611 612 error: 613 if (NULL != add_info->member_flags) { 614 sal_free(add_info->member_flags); 615 add_info->member_flags = NULL; 616 } 617 if (NULL != add_info->tp) { 618 sal_free(add_info->tp); 619 add_info->tp = NULL; 620 } 621 if (NULL != add_info->tm) { 622 sal_free(add_info->tm); 623 add_info->tm = NULL; 624 } 625 if (NULL != add_info->dynamic_scaling_factor) { 626 sal_free(add_info->dynamic_scaling_factor); 627 add_info->dynamic_scaling_factor = NULL; 628 } 629 if (NULL != add_info->dynamic_load_weight) { 630 sal_free(add_info->dynamic_load_weight); 631 add_info->dynamic_load_weight = NULL; 632 } 633 if (NULL != add_info->dynamic_queue_size_weight) { 634 sal_free(add_info->dynamic_queue_size_weight); 635 add_info->dynamic_queue_size_weight = NULL; 636 } 637 638 return rv; 639 } 640 641 /* 642 * Function: 643 * _bcm_th3_trunk_get 644 * Purpose: 645 * Return a trunk information of given trunk ID. 646 * Parameters: 647 * unit - (IN) StrataSwitch PCI device unit number (driver internal). 648 * tid - (IN) Trunk ID. 649 * t_data - (OUT) Place to store returned trunk add info. 650 * t_info - (IN) Trunk info. 651 * Returns: 652 * BCM_E_NONE Success. 653 * BCM_E_XXX 654 */ 655 STATIC int 656 _bcm_th3_trunk_get(int unit, 657 bcm_trunk_t tid, 658 _esw_trunk_add_info_t *t_data, 659 trunk_private_t *t_info) 660 { 661 int i; 662 bcm_module_t mod; 663 bcm_port_t port; 664 665 t_data->flags = t_info->flags; 666 t_data->psc = t_info->psc; 667 t_data->ipmc_psc = t_info->ipmc_psc; 668 t_data->dlf_index = t_info->dlf_index_used; 669 t_data->mc_index = t_info->mc_index_used; 670 t_data->ipmc_index = t_info->ipmc_index_used; 671 t_data->dynamic_size = t_info->dynamic_size; 672 t_data->dynamic_age = t_info->dynamic_age; 673 t_data->dynamic_load_exponent = 674 t_info->dynamic_load_exponent; 675 t_data->dynamic_expected_load_exponent = 676 t_info->dynamic_expected_load_exponent; 677 678 if (!t_info->in_use) { 679 t_data->num_ports = 0; 680 return BCM_E_NONE; 681 } 682 683 if (t_data->num_ports == 0) { 684 t_data->num_ports = MEMBER_INFO(unit, tid).num_ports; 685 } else { 686 if (MEMBER_INFO(unit, tid).num_ports <= t_data->num_ports) { 687 t_data->num_ports = MEMBER_INFO(unit, tid).num_ports; 688 } 689 690 /* Fill in data for each port in the trunk */ 691 for (i = 0; i < t_data->num_ports; i++) { 692 mod = 0; /* True for TH3 */ 693 port = MEMBER_INFO(unit, tid).port[i] & 0xff; 694 t_data->tm[i] = mod; 695 t_data->tp[i] = port; 696 t_data->member_flags[i] = MEMBER_INFO(unit, tid).member_flags[i]; 697 698 t_data->dynamic_scaling_factor[i] = 0; 699 t_data->dynamic_load_weight[i] = 0; 700 t_data->dynamic_queue_size_weight[i] = 0; 701 } 702 } 703 704 return BCM_E_NONE; 705 } 706 707 /* 708 * Function: 709 * bcm_th3_trunk_get 710 * Purpose: 711 * Return a trunk information of given trunk ID. 712 * Parameters: 713 * unit - (IN) StrataSwitch PCI device unit number (driver internal). 714 * tid - (IN) Trunk ID. 715 * trunk_info - (OUT) Place to store returned trunk info. 716 * member_max - (IN) Size of member_array. 717 * member_array - (OUT) Array of trunk member structures. 718 * member_count - (OUT) Number of trunk members returned. 719 * t_info - (IN) Internal trunk info. 720 * Returns: 721 * BCM_E_NONE Success. 722 * BCM_E_XXX 723 */ 724 int 725 bcm_th3_trunk_get(int unit, 726 bcm_trunk_t tid, 727 bcm_trunk_info_t *trunk_info, 728 int member_max, 729 bcm_trunk_member_t *member_array, 730 int *member_count, 731 trunk_private_t *t_info) 732 { 733 _esw_trunk_add_info_t add_info; 734 int i; 735 int rv = BCM_E_NONE; 736 bcm_trunk_chip_info_t chip_info; 737 int higig_trunk; 738 739 sal_memset(&add_info, 0, sizeof(_esw_trunk_add_info_t)); 740 add_info.num_ports = member_max; 741 if (member_max > 0) { 742 BCM_IF_ERROR_RETURN 743 (_th3_trunk_add_info_member_alloc(&add_info, member_max)); 744 } 745 746 rv = _bcm_th3_trunk_get(unit, tid, &add_info, t_info); 747 if (BCM_FAILURE(rv)) { 748 if (member_max > 0) { 749 _th3_trunk_add_info_member_free(&add_info); 750 } 751 return rv; 752 } 753 754 trunk_info->flags = add_info.flags; 755 trunk_info->psc = add_info.psc; 756 trunk_info->ipmc_psc = add_info.ipmc_psc; 757 trunk_info->dlf_index = add_info.dlf_index; 758 trunk_info->mc_index = add_info.mc_index; 759 trunk_info->ipmc_index = add_info.ipmc_index; 760 trunk_info->dynamic_size = add_info.dynamic_size; 761 trunk_info->dynamic_age = add_info.dynamic_age; 762 trunk_info->dynamic_load_exponent = 763 add_info.dynamic_load_exponent; 764 trunk_info->dynamic_expected_load_exponent = 765 add_info.dynamic_expected_load_exponent; 766 767 *member_count = add_info.num_ports; 768 769 if (member_max > 0) { 770 if (member_max < *member_count) { 771 *member_count = member_max; 772 } 773 774 /* Construct member gport */ 775 rv = bcm_esw_trunk_chip_info_get(unit, &chip_info); 776 if (BCM_FAILURE(rv)) { 777 _th3_trunk_add_info_member_free(&add_info); 778 return rv; 779 } 780 /* No HiGig in TH3 */ 781 higig_trunk = 0; 782 rv = _bcm_esw_trunk_gport_construct(unit, higig_trunk, 783 *member_count, 784 add_info.tp, add_info.tm, 785 add_info.tp); 786 if (BCM_FAILURE(rv)) { 787 _th3_trunk_add_info_member_free(&add_info); 788 return rv; 789 } 790 791 for (i = 0; i < *member_count; i++) { 792 bcm_trunk_member_t_init(&member_array[i]); 793 member_array[i].flags = add_info.member_flags[i]; 794 member_array[i].gport = add_info.tp[i]; 795 member_array[i].dynamic_scaling_factor = 796 add_info.dynamic_scaling_factor[i]; 797 member_array[i].dynamic_load_weight = 798 add_info.dynamic_load_weight[i]; 799 member_array[i].dynamic_queue_size_weight= 800 add_info.dynamic_queue_size_weight[i]; 801 } 802 803 _th3_trunk_add_info_member_free(&add_info); 804 } 805 806 return rv; 807 } 808 809 /* Function: 810 * bcm_th3_trunk_mcast_join 811 * Purpose: 812 * 813 * Returns: 814 */ 815 int 816 bcm_th3_trunk_mcast_join(int unit, bcm_trunk_t tid, 817 bcm_vlan_t vid, sal_mac_addr_t mac, trunk_private_t *t_info) 818 { 819 trunk_bitmap_entry_t trunk_bitmap_entry; 820 bcm_mcast_addr_t mc_addr; 821 bcm_trunk_chip_info_t chip_info; 822 823 /* Initialising and setting the mc_addr by bcm_mcast_addr_t_init() */ 824 bcm_mcast_addr_t_init(&mc_addr, mac, vid); 825 826 BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &chip_info)); 827 if ((tid >= chip_info.trunk_id_min) && (tid <= chip_info.trunk_id_max)) { 828 /* get the ports in the trunk group */ 829 SOC_IF_ERROR_RETURN 830 (READ_TRUNK_BITMAPm(unit, MEM_BLOCK_ANY, tid, &trunk_bitmap_entry)); 831 soc_mem_pbmp_field_get(unit, TRUNK_BITMAPm, &trunk_bitmap_entry, 832 TRUNK_BITMAPf, &mc_addr.pbmp); 833 } else { 834 return BCM_E_PARAM; 835 } 836 837 /* Add the trunk group's ports to the multicast group. */ 838 return bcm_esw_mcast_port_add(unit, &mc_addr); 839 } 840 841 /* 842 * Function: 843 * _bcm_th3_trunk_swfailover_init 844 * Purpose: 845 * Allocate and initialize _th3_trunk_swfail 846 * Parameters: 847 * unit - (IN)SOC unit number. 848 * Returns: 849 * BCM_X_XXX 850 */ 851 STATIC int 852 _bcm_th3_trunk_swfailover_init(int unit) 853 { 854 int trunk_num_groups; 855 856 if (_th3_trunk_swfail[unit] == NULL) { 857 _th3_trunk_swfail[unit] = sal_alloc(sizeof(_th3_trunk_swfail_t), 858 "_th3_trunk_swfail"); 859 if (_th3_trunk_swfail[unit] == NULL) { 860 return BCM_E_MEMORY; 861 } 862 } 863 sal_memset(_th3_trunk_swfail[unit], 0, sizeof(_th3_trunk_swfail_t)); 864 /* Only need to count FAST_TRUNK_PORTS_1m because 865 * FAST_TRUNK_PORTS_2m is extension of the same LAG */ 866 trunk_num_groups = soc_mem_index_count(unit, FAST_TRUNK_PORTS_1m); 867 if (_th3_trunk_swfail[unit]->tinfo == NULL) { 868 _th3_trunk_swfail[unit]->tinfo = 869 sal_alloc(sizeof(_th3_tinfo_t) * trunk_num_groups, 870 "_th3_trunk_swfail_tinfo"); 871 if (_th3_trunk_swfail[unit]->tinfo == NULL) { 872 _bcm_th3_trunk_swfailover_deinit(unit); 873 return BCM_E_MEMORY; 874 } 875 } 876 sal_memset(_th3_trunk_swfail[unit]->tinfo, 0, 877 sizeof(_th3_tinfo_t) * trunk_num_groups); 878 879 /* Note: The maximum number of member ports in a trunk group is 64 in TH3. 880 * But it would be quite wasteful to allocate 64 entries to each 881 * _th3_trunk_swfail[unit]->tinfo[x].port array. The port 882 * array will be allocated as member ports are added to trunk group. 883 */ 884 885 return BCM_E_NONE; 886 } 887 888 /* 889 * Function: 890 * _bcm_th3_trunk_deinit 891 * Purpose: 892 * Deallocate global data structures 893 * Parameters: 894 * unit - (IN)SOC unit number. 895 * Returns: 896 * BCM_E_xxx 897 */ 898 void 899 _bcm_th3_trunk_deinit(int unit) 900 { 901 _bcm_th3_trunk_member_info_deinit(unit); 902 903 _bcm_th3_trunk_port_map_deinit(unit); 904 905 906 _bcm_th3_trunk_hwfailover_deinit(unit); 907 908 _bcm_th3_trunk_swfailover_deinit(unit); 909 } 910 /* 911 * Function: 912 * _bcm_th3_trunk_init 913 * Purpose: 914 * Initialize global data structures 915 * Parameters: 916 * unit - (IN)SOC unit number. 917 * Returns: 918 * BCM_E_xxx 919 */ 920 int 921 _bcm_th3_trunk_init(int unit) 922 { 923 int rv; 924 925 _bcm_th3_trunk_deinit(unit); 926 927 rv = _bcm_th3_trunk_member_info_init(unit); 928 if (BCM_FAILURE(rv)) { 929 _bcm_th3_trunk_member_info_deinit(unit); 930 return rv; 931 } 932 933 rv = _bcm_th3_trunk_port_map_init(unit); 934 if (BCM_FAILURE(rv)) { 935 _bcm_th3_trunk_deinit(unit); 936 return rv; 937 } 938 939 rv = _bcm_th3_trunk_hwfailover_init(unit); 940 if (BCM_FAILURE(rv)) { 941 _bcm_th3_trunk_deinit(unit); 942 return rv; 943 } 944 945 rv = _bcm_th3_trunk_swfailover_init(unit); 946 if (BCM_FAILURE(rv)) { 947 _bcm_th3_trunk_deinit(unit); 948 return rv; 949 } 950 951 return BCM_E_NONE; 952 } 953 /* Function: 954 * _bcm_th3_trunk_psc_to_rtag 955 * Purpose: 956 * Convert PSC to RTAG 957 * Parameters: 958 * unit - (IN) unit number 959 * psc - (IN) Port selection criteria 960 * rtag - (OUT) Pointer to RTAG 961 * Returns: 962 * BCM_E_XXX 963 */ 964 STATIC int 965 _bcm_th3_trunk_psc_to_rtag(int unit, int psc, int *rtag) 966 { 967 switch (psc) { 968 case BCM_TRUNK_PSC_SRCMAC: 969 case BCM_TRUNK_PSC_DSTMAC: 970 case BCM_TRUNK_PSC_SRCDSTMAC: 971 case BCM_TRUNK_PSC_SRCIP: 972 case BCM_TRUNK_PSC_DSTIP: 973 case BCM_TRUNK_PSC_SRCDSTIP: 974 /* These BCM_TRUNK_PSC_ values match the hardware RTAG values */ 975 *rtag = psc; 976 break; 977 case BCM_TRUNK_PSC_PORTINDEX: 978 if (!soc_feature(unit, soc_feature_port_trunk_index)) { 979 return BCM_E_PARAM; 980 } 981 *rtag = 7; 982 break; 983 case BCM_TRUNK_PSC_RANDOMIZED: 984 *rtag = 0; 985 break; 986 case BCM_TRUNK_PSC_PORTFLOW: 987 if (!soc_feature(unit, soc_feature_port_flow_hash)) { 988 return BCM_E_PARAM; 989 } 990 *rtag = 7; 991 break; 992 case BCM_TRUNK_PSC_DYNAMIC: 993 case BCM_TRUNK_PSC_DYNAMIC_ASSIGNED: 994 case BCM_TRUNK_PSC_DYNAMIC_OPTIMAL: 995 *rtag = 7; 996 #ifdef BCM_TOMAHAWK3_SUPPORT 997 if (SOC_IS_TOMAHAWK3(unit)) { 998 return BCM_E_UNAVAIL; 999 } else 1000 #endif 1001 if (SOC_IS_ENDURO(unit)) { 1002 if (!soc_feature(unit, soc_feature_lag_dlb)) { 1003 return BCM_E_UNAVAIL; 1004 } 1005 } 1006 break; 1007 default: 1008 return BCM_E_PARAM; 1009 } 1010 1011 if ((*rtag == 7) && 1012 (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) { 1013 /* Hurricanex/Greyhound don't support enhanced hashing */ 1014 return BCM_E_PARAM; 1015 } 1016 1017 return BCM_E_NONE; 1018 } 1019 1020 /* 1021 * Function: 1022 * _bcm_th3_nuc_tpbm_get 1023 * Purpose: 1024 * Get non-unicast panel trunk members. 1025 * Parameters: 1026 * unit - (IN) SOC unit number. 1027 * num_ports - (IN) Number of ports in trunk group. 1028 * tm - (IN) Pointer to array of module IDs. 1029 * nuc_tpbm - (OUT) Bitmap of ports eligible for non-unicast. 1030 * Returns: 1031 * BCM_E_xxx 1032 */ 1033 STATIC 1034 int _bcm_th3_nuc_tpbm_get(int unit, 1035 int num_ports, 1036 bcm_module_t *tm, 1037 SHR_BITDCL *nuc_tpbm) 1038 { 1039 int rv = BCM_E_NONE; 1040 int i, mod = -1; 1041 uint32 mod_type; 1042 int all_equal = 1; 1043 1044 SHR_BITDCL *xgs12_tpbm = NULL; 1045 SHR_BITDCL *xgs3_tpbm = NULL; 1046 SHR_BITDCL *unknown_tpbm = NULL; 1047 1048 SHR_BITDCL xgs12_tpbm_result; 1049 SHR_BITDCL xgs3_tpbm_result; 1050 SHR_BITDCL unknown_tpbm_result; 1051 1052 xgs12_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "xgs12_tpbm"); 1053 if (xgs12_tpbm == NULL) { 1054 return BCM_E_MEMORY; 1055 } 1056 sal_memset(xgs12_tpbm, 0, SHR_BITALLOCSIZE(num_ports)); 1057 1058 xgs3_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "xgs3_tpbm"); 1059 if (xgs3_tpbm == NULL) { 1060 sal_free(xgs12_tpbm); 1061 return BCM_E_MEMORY; 1062 } 1063 sal_memset(xgs3_tpbm, 0, SHR_BITALLOCSIZE(num_ports)); 1064 1065 unknown_tpbm = sal_alloc(SHR_BITALLOCSIZE(num_ports), "unknown_tpbm"); 1066 if (unknown_tpbm == NULL) { 1067 sal_free(xgs12_tpbm); 1068 sal_free(xgs3_tpbm); 1069 return BCM_E_MEMORY; 1070 } 1071 sal_memset(unknown_tpbm, 0, SHR_BITALLOCSIZE(num_ports)); 1072 1073 SHR_BITSET(nuc_tpbm, 0); 1074 for (i = 0; i < num_ports; i++) { 1075 if (i == 0) { 1076 mod = tm[i]; 1077 } else if (mod != tm[i]) { 1078 all_equal = 0; 1079 } 1080 rv = _bcm_switch_module_type_get(unit, tm[i], &mod_type); 1081 if (BCM_FAILURE(rv)) { 1082 sal_free(xgs12_tpbm); 1083 sal_free(xgs3_tpbm); 1084 sal_free(unknown_tpbm); 1085 return rv; 1086 } 1087 switch(mod_type) { 1088 case BCM_SWITCH_MODULE_XGS1: 1089 /* passthru */ 1090 case BCM_SWITCH_MODULE_XGS2: 1091 SHR_BITSET(xgs12_tpbm, i); 1092 break; 1093 case BCM_SWITCH_MODULE_XGS3: 1094 SHR_BITSET(xgs3_tpbm, i); 1095 break; 1096 case BCM_SWITCH_MODULE_UNKNOWN: 1097 /* passthru */ 1098 default: 1099 SHR_BITSET(unknown_tpbm, i); 1100 break; 1101 } 1102 } 1103 1104 /* tpbm_result will be 0 if all bits in the range are 0 */ 1105 SHR_BITTEST_RANGE(xgs12_tpbm, 0, num_ports, xgs12_tpbm_result); 1106 SHR_BITTEST_RANGE(xgs3_tpbm, 0, num_ports, xgs3_tpbm_result); 1107 SHR_BITTEST_RANGE(unknown_tpbm, 0, num_ports, unknown_tpbm_result); 1108 1109 if (all_equal) { 1110 SHR_BITSET_RANGE(nuc_tpbm, 0, num_ports); 1111 } else if (xgs12_tpbm_result || unknown_tpbm_result) { 1112 SHR_BITSET(nuc_tpbm, 0); 1113 } else if (xgs3_tpbm_result) { 1114 SHR_BITCOPY_RANGE(nuc_tpbm, 0, xgs3_tpbm, 0, num_ports); 1115 } 1116 1117 sal_free(xgs12_tpbm); 1118 sal_free(xgs3_tpbm); 1119 sal_free(unknown_tpbm); 1120 1121 return rv; 1122 } 1123 1124 /* 1125 * Function: 1126 * _bcm_th3_trunk_set_port_property 1127 * Purpose: 1128 * Mark a mod/port pair as being in a particular trunk (or not) 1129 * A negative tid sets the mod/port back to non-trunk status. 1130 */ 1131 STATIC int 1132 _bcm_th3_trunk_set_port_property(int unit, 1133 bcm_module_t mod, 1134 bcm_port_t port, 1135 int tid) 1136 { 1137 source_trunk_map_table_entry_t stm; 1138 soc_mem_t mem; 1139 int idx, rv, ptype_get, ptype_set, tid_get, tid_set; 1140 1141 if (tid < 0) { 1142 ptype_set = 0; /* normal port */ 1143 tid_set = 0; 1144 } else { 1145 ptype_set = 1; /* trunk port */ 1146 tid_set = tid; 1147 } 1148 /* 1149 BCM_IF_ERROR_RETURN 1150 (_bcm_esw_src_mod_port_table_index_get(unit, mod, port, &idx)); 1151 */ 1152 idx = port; 1153 1154 mem = SOURCE_TRUNK_MAP_TABLEm; 1155 soc_mem_lock(unit, mem); 1156 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, &stm); 1157 if (BCM_SUCCESS(rv)) { 1158 ptype_get = soc_mem_field32_get(unit, mem, (uint32 *)&stm, PORT_TYPEf); 1159 tid_get = soc_mem_field32_get(unit, mem, (uint32 *)&stm, TGIDf); 1160 if ((ptype_get != ptype_set) || (tid_get != tid_set)) { 1161 soc_mem_field32_set(unit, mem, (uint32 *)&stm, 1162 PORT_TYPEf, ptype_set); 1163 soc_mem_field32_set(unit, mem, (uint32 *)&stm, 1164 TGIDf, tid_set); 1165 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, &stm); 1166 } 1167 } 1168 soc_mem_unlock(unit, mem); 1169 1170 /* Update SW module, port to tid mapping. */ 1171 if (BCM_SUCCESS(rv)) { 1172 rv = _bcm_th3_trunk_port_map_set(unit, mod, port, tid); 1173 } 1174 1175 return rv; 1176 } 1177 1178 /* 1179 * Function: 1180 * _bcm_th3_trunk_block_mask 1181 * Purpose: 1182 * Update the trunk block mask table. 1183 * Old ports are cleared and new ports are added to each entry. 1184 * Each hash index location entry is owned by a specific unit/modid 1185 * across all units in a stack. Hash index location entry owned by 1186 * local unit/modid is provided by my_modid_bmap. member_count is 1187 * the number of NUC forwarding eligible ports in the trunk group. 1188 * Each eligible entry also has a rolling port that is not masked 1189 * from among the new NUC forwarding eligible ports (nuc_ports). 1190 * This is what spreads non-unicast traffic across multiple ports. 1191 */ 1192 STATIC int 1193 _bcm_th3_trunk_block_mask(int unit, 1194 int nuc_type, 1195 pbmp_t old_ports, 1196 pbmp_t new_ports, 1197 int *localport_array, 1198 int localport_count, 1199 SHR_BITDCL *my_modid_bmap, 1200 uint32 member_count, 1201 uint32 flags) 1202 { 1203 int i, imin, imax; 1204 int rv, index_count, region_size; 1205 soc_mem_t mem; 1206 nonucast_trunk_block_mask_entry_t *mask_entry; 1207 nonucast_trunk_block_mask_entry_t *mask_table; 1208 bcm_pbmp_t pbmp, old_pbmp; 1209 1210 rv = BCM_E_NONE; 1211 1212 /* On TH3 everything should be local port because there is no stacking 1213 * or HiGig 1214 if (!((localport_count > 0) && (localport_count == member_count))) { 1215 return BCM_E_PARAM; 1216 }*/ 1217 1218 /* The NONUCAST_TRUNK_BLOCK_MASK table is divided into 4 regions: 1219 * IPMC, L2MC, broadcast, and unknown unicast/multicast. 1220 */ 1221 mem = NONUCAST_TRUNK_BLOCK_MASKm; 1222 region_size = soc_mem_index_count(unit, mem) / 4; 1223 if (nuc_type == TRUNK_BLOCK_MASK_TYPE_IPMC) { 1224 imin = 0; 1225 } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_L2MC) { 1226 imin = region_size; 1227 } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_BCAST) { 1228 imin = region_size * 2; 1229 } else if (nuc_type == TRUNK_BLOCK_MASK_TYPE_DLF) { 1230 imin = region_size * 3; 1231 } else { 1232 return BCM_E_PARAM; 1233 } 1234 1235 imax = imin + region_size - 1; 1236 1237 mask_table = soc_cm_salloc(unit, 1238 sizeof(nonucast_trunk_block_mask_entry_t) * 1239 region_size, 1240 "TH3 Block of NONUCAST_TRUNK_BLOCK_MASK entries"); 1241 1242 if (NULL == mask_table) { 1243 return BCM_E_MEMORY; 1244 } 1245 1246 soc_mem_lock(unit, mem); 1247 1248 if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 1249 imin, imax, mask_table)) < 0) { 1250 soc_mem_unlock(unit, mem); 1251 soc_cm_sfree(unit, mask_table); 1252 return rv; 1253 } 1254 1255 index_count = 0; 1256 for (i = imin; i <= imax; i++) { 1257 mask_entry = soc_mem_table_idx_to_pointer(unit, mem, 1258 nonucast_trunk_block_mask_entry_t *, 1259 mask_table, i - imin); 1260 soc_mem_pbmp_field_get(unit, mem, mask_entry, BLOCK_MASKf, &pbmp); 1261 SOC_PBMP_ASSIGN(old_pbmp, pbmp); 1262 SOC_PBMP_REMOVE(pbmp, old_ports); 1263 1264 if (nuc_type == TRUNK_BLOCK_MASK_TYPE_IPMC && 1265 (flags & BCM_TRUNK_FLAG_IPMC_CLEAVE)) { 1266 /* If the flag BCM_TRUNK_FLAG_IPMC_CLEAVE is set, 1267 * IPMC trunk resolution is disabled, and the bits in 1268 * pbmp corresponding to new_ports are not set. 1269 */ 1270 } else { 1271 SOC_PBMP_OR(pbmp, new_ports); 1272 if (localport_count > 0) { 1273 /* All ports in TH3 are going to be local. 1274 * Assuming onlhy one region for now, but may need to change to 1275 * reflect: TRUNK_BLOCK_MASK_TYPE_IPMC, TRUNK_BLOCK_MASK_TYPE_L2MC, 1276 * etc. Compare with _bcm_trident_trunk_block_mask 1277 */ 1278 if (SHR_BITGET(my_modid_bmap, 1279 ((i % region_size) % member_count))) { 1280 SOC_PBMP_PORT_REMOVE( 1281 pbmp, localport_array[index_count % localport_count]); 1282 index_count++; 1283 } 1284 } 1285 } 1286 if (SOC_PBMP_EQ(pbmp, old_pbmp)) { 1287 continue; 1288 } 1289 soc_mem_pbmp_field_set(unit, mem, mask_entry, BLOCK_MASKf, &pbmp); 1290 } 1291 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, imin, imax, mask_table); 1292 soc_mem_unlock(unit, mem); 1293 soc_cm_sfree(unit, mask_table); 1294 1295 return rv; 1296 } 1297 1298 /* Function: 1299 * _bcm_th3_trunk_failover_set 1300 * Purpose: 1301 * Disable hardware failover for old trunk ports, and configure 1302 * hardware failover for new trunk ports. 1303 * 1304 * This function first deletes any existing trunk failover setting. 1305 * It then frees that SDK memory up and reallocates it for 1306 * the passed in new failover settings (add_info). 1307 * 1308 * Any existing failover settings on the passed in trunk id will 1309 * be deleted. 1310 * Parameters: 1311 * unit - (IN) SOC unit number 1312 * tid - (IN) Trunk group ID 1313 * hg_trunk - (IN) Indicates if HiGig Trunk, (NO FOR TH3) 1314 * add_info - (IN) Pointer to trunk add info structure 1315 * Returns: 1316 * BCM_E_xxx 1317 */ 1318 STATIC int 1319 _bcm_th3_trunk_failover_set(int unit, 1320 bcm_trunk_t tid, 1321 int hg_trunk, 1322 _esw_trunk_add_info_t *add_info) 1323 { 1324 int trunk_index, failover_flags, num_hw_fail_ports, rv; 1325 _th3_hw_tinfo_t *hw_fail_trunk; 1326 bcm_port_t trunk_port; 1327 bcm_port_t *port_array = NULL; 1328 1329 failover_flags = 0; 1330 if (add_info != NULL) { 1331 if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_NEXT) { 1332 failover_flags = BCM_TRUNK_FLAG_FAILOVER_NEXT; 1333 } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL) { 1334 failover_flags = BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL; 1335 } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_ALL) { 1336 failover_flags = BCM_TRUNK_FLAG_FAILOVER_ALL; 1337 } else if (add_info->flags & BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL) { 1338 failover_flags = BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL; 1339 } 1340 } 1341 1342 /* No stacking, so no need to calculate trunk info index with 1343 * HG. Just use trunk id passed in */ 1344 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 1345 1346 /* Delete the existing hardware failover configuration */ 1347 if ((NULL == add_info) || (0 != failover_flags)) { 1348 /*Disable hardware failover for old trunk ports */ 1349 for (trunk_index = 0; 1350 trunk_index < hw_fail_trunk->num_ports; 1351 trunk_index++) { 1352 /* in previous implementations, the lower 8 bits 1353 * were the port and the upper 8 bits were modid. 1354 * No modid since no stacking 1355 */ 1356 trunk_port = hw_fail_trunk->port[trunk_index] & 0xff; 1357 1358 BCM_IF_ERROR_RETURN 1359 (_bcm_th3_trunk_hwfailover_set(unit, tid, trunk_port, 1360 hw_fail_trunk->psc[trunk_index], 1361 0, 0, NULL)); 1362 } 1363 } 1364 1365 /* Clean up the hardware trunk failover structure */ 1366 if (hw_fail_trunk->port) { 1367 sal_free(hw_fail_trunk->port); 1368 hw_fail_trunk->port = NULL; 1369 } 1370 if (hw_fail_trunk->psc) { 1371 sal_free(hw_fail_trunk->psc); 1372 hw_fail_trunk->psc = NULL; 1373 } 1374 if (hw_fail_trunk->flags) { 1375 sal_free(hw_fail_trunk->flags); 1376 hw_fail_trunk->flags = NULL; 1377 } 1378 hw_fail_trunk->num_ports = 0; 1379 1380 /* Done if we're just deleting the trunk */ 1381 if (NULL == add_info) { 1382 return BCM_E_NONE; 1383 } 1384 1385 1386 /* Add new trunk data */ 1387 1388 /* Allocate space for the ports */ 1389 if (hw_fail_trunk->port == NULL) { 1390 hw_fail_trunk->port = sal_alloc(sizeof(uint16) * add_info->num_ports, 1391 "hw_tinfo_port"); 1392 if (hw_fail_trunk->port == NULL) { 1393 return BCM_E_MEMORY; 1394 } 1395 } 1396 sal_memset(hw_fail_trunk->port, 0, sizeof(uint16) * add_info->num_ports); 1397 1398 /* Allocate space for the port selection criteria */ 1399 if (hw_fail_trunk->psc == NULL) { 1400 hw_fail_trunk->psc = sal_alloc(sizeof(uint8) * add_info->num_ports, 1401 "hw_tinfo_psc"); 1402 if (hw_fail_trunk->psc == NULL) { 1403 sal_free(hw_fail_trunk->port); 1404 hw_fail_trunk->port = NULL; 1405 return BCM_E_MEMORY; 1406 } 1407 } 1408 sal_memset(hw_fail_trunk->psc, 0, sizeof(uint8) * add_info->num_ports); 1409 1410 /* Allocate space for flags */ 1411 if (hw_fail_trunk->flags == NULL) { 1412 hw_fail_trunk->flags = sal_alloc(sizeof(uint32) * add_info->num_ports, 1413 "hw_tinfo_flags"); 1414 if (hw_fail_trunk->flags == NULL) { 1415 sal_free(hw_fail_trunk->port); 1416 hw_fail_trunk->port = NULL; 1417 sal_free(hw_fail_trunk->psc); 1418 hw_fail_trunk->psc = NULL; 1419 return BCM_E_MEMORY; 1420 } 1421 } 1422 sal_memset(hw_fail_trunk->flags, 0, sizeof(uint32) * add_info->num_ports); 1423 1424 /* Allocate space for local port array, to be freed at end of function */ 1425 if (port_array == NULL) { 1426 port_array = sal_alloc(sizeof(bcm_port_t) * add_info->num_ports, 1427 "port_array"); 1428 if (port_array == NULL) { 1429 sal_free(hw_fail_trunk->port); 1430 hw_fail_trunk->port = NULL; 1431 sal_free(hw_fail_trunk->psc); 1432 hw_fail_trunk->psc = NULL; 1433 sal_free(hw_fail_trunk->flags); 1434 hw_fail_trunk->flags = NULL; 1435 return BCM_E_MEMORY; 1436 } 1437 } 1438 sal_memset(port_array, 0, sizeof(bcm_port_t) * add_info->num_ports); 1439 1440 /* Copy info from the add_info into the local hardware failover 1441 * structure */ 1442 num_hw_fail_ports = 0; 1443 for(trunk_index = 0; trunk_index < add_info->num_ports; trunk_index++) { 1444 if (add_info->member_flags[trunk_index] & 1445 BCM_TRUNK_MEMBER_EGRESS_DISABLE) { 1446 continue; 1447 } 1448 1449 hw_fail_trunk->flags[num_hw_fail_ports] = failover_flags; 1450 hw_fail_trunk->psc[num_hw_fail_ports] = add_info->psc; 1451 hw_fail_trunk->port[num_hw_fail_ports] = add_info->tp[trunk_index]; 1452 1453 /* Add all the passed in ports to this array. If there are any 1454 * flags set for a port, it is updated, else a port from 1455 * this array is added. */ 1456 port_array[num_hw_fail_ports] = add_info->tp[trunk_index]; 1457 1458 num_hw_fail_ports++; 1459 } 1460 1461 hw_fail_trunk->num_ports = num_hw_fail_ports; 1462 1463 /* No flags in trunk_set means no failover changes */ 1464 if (0 != failover_flags) { 1465 /* Configure hardware failover for new trunk ports */ 1466 for (trunk_index = 0; trunk_index < hw_fail_trunk->num_ports; 1467 trunk_index++) { 1468 1469 /* modport is always 0 and there is no HiGig, and no 1470 * cascaded physical ports, so just calling to set 1471 * hwfailover 1472 */ 1473 rv = _bcm_th3_trunk_hwfailover_set(unit, tid, 1474 hw_fail_trunk->port[trunk_index], 1475 hw_fail_trunk->psc[trunk_index], 1476 hw_fail_trunk->flags[trunk_index], 1477 hw_fail_trunk->num_ports, 1478 port_array); 1479 if (BCM_FAILURE(rv)) { 1480 sal_free(port_array); 1481 return rv; 1482 } 1483 } 1484 } 1485 1486 sal_free(port_array); 1487 1488 return BCM_E_NONE; 1489 } 1490 #ifdef BCM_WARM_BOOT_SUPPORT 1491 /* 1492 * Function: 1493 * _bcm_th3_trunk_member_info_set 1494 * Purpose: 1495 * Set trunk member info - used by trunk_reinit 1496 * Parameters: 1497 * unit - (IN) SOC unit number. 1498 * tid - (IN) Trunk ID. 1499 * num_ports - (IN) Number of trunk members. 1500 * member_port - (IN) Trunk member port ID array. 1501 * member_flags - (IN) Trunk member flags array. 1502 * Returns: 1503 * BCM_E_xxx 1504 */ 1505 int 1506 _bcm_th3_trunk_member_info_set(int unit, bcm_trunk_t tid, 1507 uint16 num_ports, uint8 *member_port, uint32 *member_flags) 1508 { 1509 int i, rv; 1510 bcm_module_t mod = 0; 1511 /* Save new trunk member info. Free up the old memory and allocate new space 1512 * since there may be a different number of entries. */ 1513 1514 if (MEMBER_INFO(unit, tid).port) { 1515 sal_free(MEMBER_INFO(unit, tid).port); 1516 MEMBER_INFO(unit, tid).port = NULL; 1517 } 1518 if (MEMBER_INFO(unit, tid).member_flags) { 1519 sal_free(MEMBER_INFO(unit, tid).member_flags); 1520 MEMBER_INFO(unit, tid).member_flags = NULL; 1521 } 1522 1523 MEMBER_INFO(unit, tid).port = sal_alloc( 1524 sizeof(uint16) * num_ports, "member info port"); 1525 if (NULL == MEMBER_INFO(unit, tid).port) { 1526 return BCM_E_MEMORY ; 1527 } 1528 1529 MEMBER_INFO(unit, tid).member_flags = sal_alloc( 1530 sizeof(uint32) * num_ports, "member info flags"); 1531 if (NULL == MEMBER_INFO(unit, tid).member_flags) { 1532 sal_free(MEMBER_INFO(unit, tid).port); 1533 MEMBER_INFO(unit, tid).port = NULL; 1534 return BCM_E_MEMORY ; 1535 } 1536 MEMBER_INFO(unit, tid).num_ports = num_ports; 1537 1538 for (i = 0; i < num_ports; i++) { 1539 MEMBER_INFO(unit, tid).port[i] = member_port[i]; 1540 MEMBER_INFO(unit, tid).member_flags[i] = member_flags[i]; 1541 /* restore inverted relationship also */ 1542 if ((rv = _bcm_th3_trunk_port_map_set(unit, mod, 1543 member_port[i], tid)) != BCM_E_NONE) { 1544 return rv; 1545 } 1546 } 1547 return BCM_E_NONE; 1548 } 1549 1550 /* 1551 * Function: 1552 * _bcm_th3_trunk_member_info_get 1553 * Purpose: 1554 * Return tunk and member info - used by trunk_sync 1555 * Parameters: 1556 * unit - (IN) SOC unit number. 1557 * tid - (IN) Trunk ID. 1558 * t_data - (OUT) carries trunk and member data filled out 1559 * t_info - (IN) Internal trunk info. 1560 * Returns: 1561 * BCM_E_xxx 1562 */ 1563 int 1564 _bcm_th3_trunk_member_info_get(int unit, bcm_trunk_t tid, 1565 _esw_trunk_add_info_t *t_data, trunk_private_t *t_info) 1566 { 1567 int rv = BCM_E_NONE; 1568 if (t_data->num_ports != 0) { 1569 rv = _th3_trunk_add_info_member_alloc(t_data, t_data->num_ports); 1570 if (BCM_FAILURE(rv)) { 1571 return rv; 1572 } 1573 } 1574 rv = _bcm_th3_trunk_get(unit, tid, t_data, t_info); 1575 if (BCM_FAILURE(rv)) { 1576 _th3_trunk_add_info_member_free(t_data); 1577 } 1578 return rv; 1579 } 1580 /* 1581 * Function: 1582 * _bcm_th3_trunk_hwfailover_num_ports_get 1583 * Purpose: 1584 * Get hwfailover fail to ports 1585 * Parameters: 1586 * unit - (IN) SOC unit number. 1587 * tid - (IN) Trunk ID. 1588 * Returns: 1589 * hwfailover fail to ports 1590 */ 1591 uint16 1592 _bcm_th3_trunk_hwfailover_num_ports_get(int unit, bcm_trunk_t tid) 1593 { 1594 uint16 num_ports; 1595 1596 num_ports = _th3_trunk_hwfail[unit]->hw_tinfo[tid].num_ports; 1597 1598 return num_ports; 1599 } 1600 /* 1601 * Function: 1602 * _bcm_th3_trunk_hwfailover_num_ports_set 1603 * Purpose: 1604 * Set hwfailover fail to ports 1605 * Parameters: 1606 * unit - (IN) SOC unit number. 1607 * tid - (IN) Trunk ID. 1608 * num_ports - (IN) hwfailover fail to ports 1609 * Returns: 1610 * hwfailover num ports 1611 */ 1612 void 1613 _bcm_th3_trunk_hwfailover_num_ports_set(int unit, bcm_trunk_t tid, uint16 num_ports) 1614 { 1615 _th3_trunk_hwfail[unit]->hw_tinfo[tid].num_ports = num_ports; 1616 } 1617 /* 1618 * Function: 1619 * _bcm_th3_trunk_hwfailover_flags_get 1620 * Purpose: 1621 * Get hwfailover per port flags 1622 * Parameters: 1623 * unit - (IN) SOC unit number. 1624 * tid - (IN) Trunk ID. 1625 * port - (IN) port. 1626 * Returns: 1627 * hwfailover per port flags 1628 */ 1629 uint8 1630 _bcm_th3_trunk_hwfailover_flags_get(int unit, bcm_trunk_t tid, int port) 1631 { 1632 uint8 flags; 1633 _th3_hw_tinfo_t *hw_fail_trunk; 1634 1635 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 1636 1637 if (NULL != hw_fail_trunk->flags) { 1638 flags = hw_fail_trunk->flags[port]; 1639 } else { 1640 flags = 0; 1641 } 1642 1643 return flags; 1644 } 1645 /* 1646 * Function: 1647 * _bcm_th3_trunk_hwfailover_flags_set 1648 * Purpose: 1649 * Set hwfailover per port flags 1650 * Parameters: 1651 * unit - (IN) SOC unit number. 1652 * tid - (IN) Trunk ID. 1653 * port - (IN) port. 1654 * flags - (IN) hwfailover per port flags. 1655 * Returns: 1656 * None 1657 */ 1658 void 1659 _bcm_th3_trunk_hwfailover_flags_set(int unit, bcm_trunk_t tid, int port, uint8 flags) 1660 { 1661 _th3_hw_tinfo_t *hw_fail_trunk; 1662 1663 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 1664 1665 if (NULL != hw_fail_trunk->flags) { 1666 hw_fail_trunk->flags[port] = flags; 1667 } 1668 } 1669 #endif 1670 /* 1671 * Function: 1672 * _bcm_th3_trunk_swfailover_set 1673 * Purpose: 1674 * Set front panel trunk software failover config. 1675 * Parameters: 1676 * unit - (IN) SOC unit number. 1677 * tid - (IN) Trunk ID. 1678 * rtag - (IN) Port selection criteria. 1679 * nports - (IN) Number of trunk members. 1680 * mods - (IN) Trunk member module ID array. 1681 * ports - (IN) Trunk member port ID array. 1682 * member_flags - (IN) Trunk member flags array. 1683 * flags - (IN) Trunk group flags. 1684 * Returns: 1685 * BCM_E_xxx 1686 */ 1687 STATIC int 1688 _bcm_th3_trunk_swfailover_set(int unit, 1689 bcm_trunk_t tid, 1690 int rtag, 1691 int nports, 1692 int *mods, 1693 int *ports, 1694 uint32 *member_flags, 1695 uint32 flags) 1696 { 1697 _th3_trunk_swfail_t *swf; 1698 _th3_tinfo_t *swft; 1699 bcm_pbmp_t localports; 1700 bcm_port_t port; 1701 int i; 1702 bcm_pbmp_t all_pbmp; 1703 1704 if (_th3_trunk_swfail[unit] == NULL) { 1705 return BCM_E_INIT; 1706 } 1707 1708 swf = _th3_trunk_swfail[unit]; 1709 swft = &swf->tinfo[tid]; 1710 1711 swf->mymodid = 0; 1712 swft->rtag = rtag; 1713 swft->num_ports = nports; 1714 swft->flags = flags; 1715 1716 if (swft->port) { 1717 sal_free(swft->port); 1718 swft->port = NULL; 1719 } 1720 if (swft->member_flags) { 1721 sal_free(swft->member_flags); 1722 swft->member_flags = NULL; 1723 } 1724 1725 BCM_PBMP_CLEAR(localports); 1726 if (swft->num_ports > 0) { 1727 swft->port = sal_alloc(sizeof(uint16) * swft->num_ports, 1728 "swfail_tinfo_port"); 1729 if (swft->port == NULL) { 1730 return BCM_E_MEMORY; 1731 } 1732 swft->member_flags = sal_alloc(sizeof(uint32) * swft->num_ports, 1733 "swfail_tinfo_member_flags"); 1734 if (swft->member_flags == NULL) { 1735 sal_free(swft->port); 1736 swft->port = NULL; 1737 return BCM_E_MEMORY; 1738 } 1739 1740 for (i = 0; i < nports; i++) { 1741 swft->port[i] = (mods[i] << 8) | ports[i]; 1742 if (mods[i] == 0) { 1743 BCM_PBMP_PORT_ADD(localports, ports[i]); 1744 } 1745 1746 swft->member_flags[i] = member_flags[i]; 1747 } 1748 } 1749 1750 BCM_PBMP_CLEAR(all_pbmp); 1751 BCM_PBMP_ASSIGN(all_pbmp, PBMP_ALL(unit)); 1752 1753 PBMP_ITER(all_pbmp, port) { 1754 if (BCM_PBMP_MEMBER(localports, port)) { 1755 /* coverity[overrun-local : FALSE] */ 1756 swf->trunk[port] = tid + 1; 1757 } else if (swf->trunk[port] == tid + 1) { 1758 swf->trunk[port] = 0; /* remove stale pointers to tid */ 1759 } 1760 } 1761 return BCM_E_NONE; 1762 } 1763 1764 /* 1765 * Function: 1766 * _bcm_th3_trunk_lag_reinit 1767 * Purpose: 1768 * Initialize global data structures 1769 * Parameters: 1770 * unit - (IN)SOC unit number. 1771 * Returns: 1772 * BCM_E_xxx 1773 */ 1774 int 1775 _bcm_th3_trunk_lag_reinit(int unit, int ngroups_fp, trunk_private_t *trunk_info) 1776 { 1777 _th3_hw_tinfo_t *hw_fail_trunk; 1778 int tid; 1779 int rv = BCM_E_NONE; 1780 int i; 1781 int num_ports, rtag; 1782 bcm_module_t *egr_hw_mods; 1783 bcm_port_t *egr_hw_ports; 1784 1785 for (tid = 0; tid < ngroups_fp; tid++, trunk_info++) { 1786 num_ports = MEMBER_INFO(unit, tid).num_ports; 1787 egr_hw_mods = sal_alloc(sizeof(bcm_module_t) * num_ports, 1788 "egr_hw_mods"); 1789 if (egr_hw_mods == NULL) { 1790 return BCM_E_MEMORY; 1791 } 1792 1793 egr_hw_ports = sal_alloc(sizeof(bcm_port_t) * num_ports, 1794 "egr_hw_ports"); 1795 if (egr_hw_ports == NULL) { 1796 sal_free(egr_hw_mods); 1797 return BCM_E_MEMORY; 1798 } 1799 sal_memset(egr_hw_mods, 0, sizeof(bcm_module_t) * num_ports); 1800 for (i = 0; i < num_ports; i++) { 1801 egr_hw_ports[i] = MEMBER_INFO(unit, tid).port[i]; 1802 } 1803 rv = _bcm_th3_trunk_psc_to_rtag(unit, trunk_info->psc, &rtag); 1804 if (BCM_FAILURE(rv)) { 1805 sal_free(egr_hw_mods); 1806 sal_free(egr_hw_ports); 1807 return rv; 1808 } 1809 rv = _bcm_th3_trunk_swfailover_set( unit, tid, 1810 rtag, 1811 num_ports, 1812 egr_hw_mods, 1813 egr_hw_ports, 1814 MEMBER_INFO(unit, tid).member_flags, 1815 trunk_info->flags); 1816 sal_free(egr_hw_mods); 1817 sal_free(egr_hw_ports); 1818 if (BCM_FAILURE(rv)) { 1819 return rv; 1820 } 1821 1822 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 1823 hw_fail_trunk->port = sal_alloc(sizeof(uint16) * hw_fail_trunk->num_ports, 1824 "hw_tinfo_port"); 1825 if (hw_fail_trunk->port == NULL) { 1826 return BCM_E_MEMORY; 1827 } 1828 sal_memset(hw_fail_trunk->port, 0, sizeof(uint16) * hw_fail_trunk->num_ports); 1829 1830 /* Allocate space for the port selection criteria */ 1831 hw_fail_trunk->psc = sal_alloc(sizeof(uint8) * hw_fail_trunk->num_ports, 1832 "hw_tinfo_psc"); 1833 if (hw_fail_trunk->psc == NULL) { 1834 sal_free(hw_fail_trunk->port); 1835 hw_fail_trunk->port = NULL; 1836 return BCM_E_MEMORY; 1837 } 1838 sal_memset(hw_fail_trunk->psc, 0, sizeof(uint8) * hw_fail_trunk->num_ports); 1839 1840 /* Allocate space for flags */ 1841 hw_fail_trunk->flags = sal_alloc(sizeof(uint32) * hw_fail_trunk->num_ports, 1842 "hw_tinfo_flags"); 1843 if (hw_fail_trunk->flags == NULL) { 1844 sal_free(hw_fail_trunk->port); 1845 hw_fail_trunk->port = NULL; 1846 sal_free(hw_fail_trunk->psc); 1847 hw_fail_trunk->psc = NULL; 1848 return BCM_E_MEMORY; 1849 } 1850 sal_memset(hw_fail_trunk->flags, 0, sizeof(uint32) * hw_fail_trunk->num_ports); 1851 for (i = 0; i < hw_fail_trunk->num_ports; i++) { 1852 hw_fail_trunk->psc[i] = trunk_info->psc; 1853 hw_fail_trunk->port[i] = MEMBER_INFO(unit, tid).port[i]; 1854 hw_fail_trunk->flags[i] = MEMBER_INFO(unit, tid).member_flags[i]; 1855 } 1856 1857 1858 } /* for tid */ 1859 1860 return rv; 1861 } 1862 1863 #if 0 1864 /* 1865 * Function: 1866 * _bcm_th3_lag_slb_free_resource 1867 * Purpose: 1868 * Free resources for a LAG static load balancing group. 1869 * Parameters: 1870 * unit - (IN) SOC unit number. 1871 * tid - (IN) Trunk group ID. 1872 * Returns: 1873 * BCM_E_xxx 1874 */ 1875 STATIC int 1876 _bcm_th3_lag_slb_free_resource(int unit, int tid) 1877 { 1878 trunk_group_entry_t tg_entry; 1879 int base_ptr; 1880 int tg_size; 1881 int rtag; 1882 int num_entries; 1883 1884 SOC_IF_ERROR_RETURN 1885 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry)); 1886 base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1887 BASE_PTRf); 1888 tg_size = 1 + soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1889 TG_SIZEf); 1890 rtag = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1891 RTAGf); 1892 1893 if (rtag != 0) { 1894 num_entries = tg_size; 1895 if (rtag >= 1 && rtag <= 6) { 1896 #ifdef BCM_KATANA_SUPPORT 1897 if (SOC_IS_KATANAX(unit)) { 1898 num_entries = _BCM_KATANA_FP_TRUNK_RTAG1_6_MAX_PORTCNT; 1899 } else 1900 #endif 1901 if (soc_feature(unit, 1902 soc_feature_rtag1_6_max_portcnt_less_than_rtag7)) { 1903 num_entries = _BCM_TD_FP_TRUNK_RTAG1_6_MAX_PORTCNT; 1904 } 1905 } 1906 1907 _BCM_FP_TRUNK_MEMBER_USED_CLR_RANGE(unit, base_ptr, num_entries); 1908 } 1909 return BCM_E_NONE; 1910 } 1911 #endif 1912 1913 /* 1914 * Function: 1915 * _bcm_th3_lag_slb_set 1916 * Purpose: 1917 * Configure a LAG static load balancing group. 1918 * Memories modified: 1919 * FAST_TRUNK_PORTS_1 1920 * FAST_TRUNK_PORTS_2 1921 * FAST_TRUNK_SIZE 1922 * Parameters: 1923 * unit - (IN) SOC unit number. 1924 * tid - (IN) Trunk group ID. 1925 * num_uc_egr_ports - (IN) Number of trunk member ports eligible for 1926 * unicast egress 1927 * uc_egr_hwmod - (IN) Array of module IDs 1928 * uc_egr_hwport - (IN) Array of port IDs 1929 * t_info - (IN) Pointer to trunk info. 1930 * Returns: 1931 * BCM_E_xxx 1932 */ 1933 STATIC int 1934 _bcm_th3_lag_slb_set(int unit, int tid, int num_uc_egr_ports, 1935 int *uc_egr_hwmod, int *uc_egr_hwport, trunk_private_t *t_info) 1936 { 1937 int i, pipe; 1938 uint32 rval; 1939 uint16 seed = 0; 1940 soc_reg_t reg; 1941 fast_trunk_ports_1_entry_t fast_1; 1942 fast_trunk_ports_2_entry_t fast_2; 1943 fast_trunk_size_entry_t fast_trunk_size; 1944 1945 memset(&fast_1, 0, sizeof(fast_trunk_ports_1_entry_t)); 1946 memset(&fast_2, 0, sizeof(fast_trunk_ports_2_entry_t)); 1947 memset(&fast_trunk_size, 0, sizeof(fast_trunk_size_entry_t)); 1948 1949 /* No enabled ports in the trunk. Clear it all out */ 1950 if (num_uc_egr_ports == 0) { 1951 1952 /* Clear out all 64 ports in this trunk */ 1953 for (i = 0; i < _BCM_TH3_PORTS_PER_TRUNK_MAX; i++) { 1954 /* Clear the first 32 Fast LAG Ports */ 1955 if (i < _BCM_TH3_PORTS_PER_TRUNK_MAX / 2) { 1956 soc_FAST_TRUNK_PORTS_1m_field32_set(unit, &fast_1, 1957 _th3_fast_portf[i], 0); 1958 } else { 1959 /* Clear the last 32 Fast LAG Ports */ 1960 soc_FAST_TRUNK_PORTS_2m_field32_set(unit, &fast_2, 1961 _th3_fast_portf[i], 0); 1962 } 1963 } 1964 1965 /* Set the size of the Fast LAG to 0 and reset the trunk mode */ 1966 soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, 1967 TRUNK_MODEf, 0); 1968 soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, 1969 TG_SIZEf, 0); 1970 1971 } else { 1972 /* Fill in the Fast LAG Ports */ 1973 for (i = 0; i < num_uc_egr_ports; i++) { 1974 /* Set the first 32 Fast LAG Ports */ 1975 if (i < _BCM_TH3_PORTS_PER_TRUNK_MAX / 2) { 1976 soc_FAST_TRUNK_PORTS_1m_field32_set(unit, &fast_1, 1977 _th3_fast_portf[i], uc_egr_hwport[i]); 1978 } else { 1979 /* Set the last 32 Fast LAG Ports */ 1980 soc_FAST_TRUNK_PORTS_2m_field32_set(unit, &fast_2, 1981 _th3_fast_portf[i], uc_egr_hwport[i]); 1982 } 1983 } 1984 1985 1986 soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, TG_SIZEf, 1987 num_uc_egr_ports - 1); 1988 1989 /* Set the Trunk Mode */ 1990 if (t_info->psc == BCM_TRUNK_PSC_RANDOMIZED) { 1991 /* Random */ 1992 soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, 1993 TRUNK_MODEf, 0x1); 1994 /* Configure Rand LB Seed */ 1995 seed = (sal_rand()) % 0xFFFF; 1996 rval = 0; 1997 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 1998 reg = SOC_REG_UNIQUE_ACC(unit, TRUNK_RAND_LB_SEEDr)[pipe]; 1999 soc_reg_field_set(unit, reg, &rval, SEEDf, seed); 2000 SOC_IF_ERROR_RETURN 2001 (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 2002 } 2003 2004 } else { 2005 /* Hash */ 2006 soc_FAST_TRUNK_SIZEm_field32_set(unit, &fast_trunk_size, 2007 TRUNK_MODEf, 0x0); 2008 } 2009 } 2010 2011 SOC_IF_ERROR_RETURN 2012 (WRITE_FAST_TRUNK_PORTS_1m(unit, MEM_BLOCK_ALL, tid, &fast_1)); 2013 SOC_IF_ERROR_RETURN 2014 (WRITE_FAST_TRUNK_PORTS_2m(unit, MEM_BLOCK_ALL, tid, &fast_2)); 2015 SOC_IF_ERROR_RETURN 2016 (WRITE_FAST_TRUNK_SIZEm(unit, MEM_BLOCK_ALL, tid, &fast_trunk_size)); 2017 2018 #if 0 2019 2020 2021 2022 int i; 2023 int num_entries; 2024 int max_base_ptr; 2025 int base_ptr; 2026 SHR_BITDCL occupied; 2027 trunk_member_entry_t trunk_member_entry; 2028 trunk_group_entry_t tg_entry; 2029 #ifdef BCM_TOMAHAWK_SUPPORT 2030 trunk_rr_cnt_entry_t rrlb_cnt_entry; 2031 uint16 seed=0; 2032 soc_reg_t reg; 2033 uint32 rval; 2034 int pipe; 2035 #endif 2036 2037 if (num_uc_egr_ports == 0) { 2038 SOC_IF_ERROR_RETURN 2039 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry)); 2040 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, BASE_PTRf, 0); 2041 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TG_SIZEf, 0); 2042 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RTAGf, 0); 2043 SOC_IF_ERROR_RETURN 2044 (WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, &tg_entry)); 2045 return BCM_E_NONE; 2046 } 2047 2048 /* Find a contiguous region of TRUNK_MEMBERm table that's large 2049 * enough to hold all of the trunk group's egress member ports. 2050 */ 2051 2052 num_entries = num_uc_egr_ports; 2053 2054 /* If RTAG is 1-6, Trident A0 and Katana ignore the TG_SIZE field and 2055 * assume the trunk group occupies FP_TRUNK_RTAG1_6_MAX_PORTCNT 2056 * contiguous entries in TRUNK_MEMBER table. 2057 */ 2058 if (t_info->rtag >= 1 && t_info->rtag <= 6) { 2059 #ifdef BCM_KATANA_SUPPORT 2060 if (SOC_IS_KATANAX(unit)) { 2061 num_entries = _BCM_KATANA_FP_TRUNK_RTAG1_6_MAX_PORTCNT; 2062 } else 2063 #endif 2064 if (soc_feature(unit, 2065 soc_feature_rtag1_6_max_portcnt_less_than_rtag7)) { 2066 num_entries = _BCM_TD_FP_TRUNK_RTAG1_6_MAX_PORTCNT; 2067 } 2068 } 2069 2070 max_base_ptr = soc_mem_index_count(unit, TRUNK_MEMBERm) - num_entries; 2071 for (base_ptr = 0; base_ptr <= max_base_ptr; base_ptr++) { 2072 /* Check if the contiguous region of TRUNK_MEMBERm table from 2073 * index base_ptr to (base_ptr + num_entries - 1) is free. 2074 */ 2075 _BCM_FP_TRUNK_MEMBER_TEST_RANGE(unit, base_ptr, num_entries, occupied); 2076 if (!occupied) { 2077 break; 2078 } 2079 } 2080 2081 if (base_ptr > max_base_ptr) { 2082 /* A contiguous region of the desired size could not be found in 2083 * TRUNK_MEMBERm table. 2084 */ 2085 return BCM_E_RESOURCE; 2086 } 2087 2088 for (i = 0; i < num_entries; i++) { 2089 sal_memset(&trunk_member_entry, 0, sizeof(trunk_member_entry_t)); 2090 soc_TRUNK_MEMBERm_field32_set 2091 (unit, &trunk_member_entry, MODULE_IDf, 2092 uc_egr_hwmod[i % num_uc_egr_ports]); 2093 soc_TRUNK_MEMBERm_field32_set 2094 (unit, &trunk_member_entry, PORT_NUMf, 2095 uc_egr_hwport[i % num_uc_egr_ports]); 2096 SOC_IF_ERROR_RETURN(WRITE_TRUNK_MEMBERm(unit, MEM_BLOCK_ALL, 2097 base_ptr + i, &trunk_member_entry)); 2098 } 2099 2100 /* Set fp_trunk_member_bitmap */ 2101 _BCM_FP_TRUNK_MEMBER_USED_SET_RANGE(unit, base_ptr, num_entries); 2102 2103 /* Update TRUNK_GROUP table */ 2104 2105 SOC_IF_ERROR_RETURN 2106 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry)); 2107 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, BASE_PTRf, base_ptr); 2108 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TG_SIZEf, 2109 num_uc_egr_ports-1); 2110 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RTAGf, t_info->rtag); 2111 2112 #ifdef BCM_APACHE_SUPPORT 2113 if (t_info->psc == BCM_TRUNK_PSC_ROUND_ROBIN) { 2114 if (soc_feature(unit, soc_feature_apache_round_robin_fp_lag)) { 2115 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RR_LB_ENABLEf, 0x1); 2116 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, RR_LB_COUNTER_SELECTf, t_info->rr_lag_select); 2117 } 2118 } 2119 #endif /* BCM_APACHE_SUPPORT */ 2120 2121 #ifdef BCM_TOMAHAWK_SUPPORT 2122 if (t_info->psc == BCM_TRUNK_PSC_ROUND_ROBIN) { 2123 if (soc_feature(unit, soc_feature_round_robin_load_balance)) { 2124 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TRUNK_MODEf, 0x2); 2125 2126 BCM_IF_ERROR_RETURN(READ_TRUNK_RR_CNTm(unit, MEM_BLOCK_ANY, 2127 tid, &rrlb_cnt_entry)); 2128 soc_TRUNK_RR_CNTm_field32_set(unit, &rrlb_cnt_entry, 2129 RRLB_CNTf, 0); 2130 BCM_IF_ERROR_RETURN(WRITE_TRUNK_RR_CNTm(unit, MEM_BLOCK_ALL, 2131 tid, &rrlb_cnt_entry)); 2132 } 2133 } else if (t_info->psc == BCM_TRUNK_PSC_RANDOMIZED) { 2134 if (soc_feature(unit, soc_feature_randomized_load_balance)) { 2135 soc_TRUNK_GROUPm_field32_set(unit, &tg_entry, TRUNK_MODEf, 0x1); 2136 /* Configure Rand LB Seed */ 2137 seed = (sal_rand()) % 0xFFFF; 2138 rval = 0; 2139 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 2140 reg = SOC_REG_UNIQUE_ACC(unit, TRUNK_RAND_LB_SEEDr)[pipe]; 2141 soc_reg_field_set(unit, reg, &rval, SEEDf, seed); 2142 SOC_IF_ERROR_RETURN 2143 (soc_reg32_set(unit, reg, REG_PORT_ANY, 0, rval)); 2144 } 2145 } 2146 } 2147 #endif 2148 2149 SOC_IF_ERROR_RETURN 2150 (WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, &tg_entry)); 2151 #endif 2152 return BCM_E_NONE; 2153 } 2154 2155 2156 /* Macro to free memory and return code */ 2157 2158 #define _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(_r_) \ 2159 if (nuc_tpbm) { \ 2160 sal_free(nuc_tpbm); \ 2161 } \ 2162 if (ipmc_tpbm) { \ 2163 sal_free(ipmc_tpbm); \ 2164 } \ 2165 if (l2mc_tpbm) { \ 2166 sal_free(l2mc_tpbm); \ 2167 } \ 2168 if (bcast_tpbm) { \ 2169 sal_free(bcast_tpbm); \ 2170 } \ 2171 if (dlf_tpbm) { \ 2172 sal_free(dlf_tpbm); \ 2173 } \ 2174 if (ipmc_my_modid_bmap) { \ 2175 sal_free(ipmc_my_modid_bmap); \ 2176 } \ 2177 if (l2mc_my_modid_bmap) { \ 2178 sal_free(l2mc_my_modid_bmap); \ 2179 } \ 2180 if (bcast_my_modid_bmap) { \ 2181 sal_free(bcast_my_modid_bmap); \ 2182 } \ 2183 if (dlf_my_modid_bmap) { \ 2184 sal_free(dlf_my_modid_bmap); \ 2185 } \ 2186 if (hwmod) { \ 2187 sal_free(hwmod); \ 2188 } \ 2189 if (hwport) { \ 2190 sal_free(hwport); \ 2191 } \ 2192 if (egr_hwmod) { \ 2193 sal_free(egr_hwmod); \ 2194 } \ 2195 if (egr_hwport) { \ 2196 sal_free(egr_hwport); \ 2197 } \ 2198 if (egr_member_flags) { \ 2199 sal_free(egr_member_flags); \ 2200 } \ 2201 if (egr_scaling_factor) { \ 2202 sal_free(egr_scaling_factor); \ 2203 } \ 2204 if (egr_load_weight) { \ 2205 sal_free(egr_load_weight); \ 2206 } \ 2207 if (egr_qsize_weight) { \ 2208 sal_free(egr_qsize_weight); \ 2209 } \ 2210 if (uc_egr_hwmod) { \ 2211 sal_free(uc_egr_hwmod); \ 2212 } \ 2213 if (uc_egr_hwport) { \ 2214 sal_free(uc_egr_hwport); \ 2215 } \ 2216 if (uc_egr_scaling_factor) { \ 2217 sal_free(uc_egr_scaling_factor); \ 2218 } \ 2219 if (uc_egr_load_weight) { \ 2220 sal_free(uc_egr_load_weight); \ 2221 } \ 2222 if (uc_egr_qsize_weight) { \ 2223 sal_free(uc_egr_qsize_weight); \ 2224 } \ 2225 if (leaving_members) { \ 2226 sal_free(leaving_members); \ 2227 } \ 2228 if (staying_members) { \ 2229 sal_free(staying_members); \ 2230 } \ 2231 if (joining_members) { \ 2232 sal_free(joining_members); \ 2233 } \ 2234 if (ipmc_localport_array) { \ 2235 sal_free(ipmc_localport_array); \ 2236 } \ 2237 if (l2mc_localport_array) { \ 2238 sal_free(l2mc_localport_array); \ 2239 } \ 2240 if (bcast_localport_array) { \ 2241 sal_free(bcast_localport_array); \ 2242 } \ 2243 if (dlf_localport_array) { \ 2244 sal_free(dlf_localport_array); \ 2245 } \ 2246 return _r_; 2247 2248 /* 2249 * Function: 2250 * _bcm_th3_trunk_set 2251 * Purpose: 2252 * Set trunk members. 2253 * Parameters: 2254 * unit - (IN) SOC unit number. 2255 * tid - (IN) Trunk group ID. 2256 * add_info - (IN) Pointer to trunk add info structure. 2257 * t_info - (IN) Pointer to trunk info. 2258 * Returns: 2259 * BCM_E_xxx 2260 */ 2261 STATIC int 2262 _bcm_th3_trunk_set(int unit, 2263 bcm_trunk_t tid, 2264 _esw_trunk_add_info_t *add_info, 2265 trunk_private_t *t_info) 2266 { 2267 #if 1 2268 int rv = BCM_E_NONE; 2269 SHR_BITDCL *nuc_tpbm = NULL; 2270 SHR_BITDCL *ipmc_tpbm = NULL; 2271 SHR_BITDCL *l2mc_tpbm = NULL; 2272 SHR_BITDCL *bcast_tpbm = NULL; 2273 SHR_BITDCL *dlf_tpbm = NULL; 2274 SHR_BITDCL *ipmc_my_modid_bmap = NULL; 2275 SHR_BITDCL *l2mc_my_modid_bmap = NULL; 2276 SHR_BITDCL *bcast_my_modid_bmap = NULL; 2277 SHR_BITDCL *dlf_my_modid_bmap = NULL; 2278 int *hwmod = NULL; 2279 int *hwport = NULL; 2280 int num_egr_ports = 0; 2281 int *egr_hwmod = NULL; 2282 int *egr_hwport = NULL; 2283 uint32 *egr_member_flags = NULL; 2284 int *egr_scaling_factor = NULL; 2285 int *egr_load_weight = NULL; 2286 int *egr_qsize_weight = NULL; 2287 int num_uc_egr_ports = 0; 2288 int *uc_egr_hwmod = NULL; 2289 int *uc_egr_hwport = NULL; 2290 int *uc_egr_scaling_factor = NULL; 2291 int *uc_egr_load_weight = NULL; 2292 int *uc_egr_qsize_weight = NULL; 2293 int negr_disable_port = 0; 2294 int num_uc_egr_disable_port = 0; 2295 pbmp_t new_trunk_pbmp; 2296 uint32 ipmc_member_count; 2297 uint32 l2mc_member_count; 2298 uint32 bcast_member_count; 2299 uint32 dlf_member_count; 2300 int mod, port, mod_out, port_out; 2301 bcm_gport_t gport; 2302 bcm_port_t loc_port = BCM_GPORT_INVALID; 2303 int i; 2304 trunk_bitmap_entry_t trunk_bitmap_entry; 2305 pbmp_t old_trunk_pbmp; 2306 int j, k, remove_trunk_port; 2307 int num_leaving_members = 0; 2308 bcm_gport_t *leaving_members = NULL; 2309 int match_leaving_members; 2310 int num_staying_members = 0; 2311 bcm_gport_t *staying_members = NULL; 2312 int match_staying_members; 2313 int num_joining_members = 0; 2314 bcm_gport_t *joining_members = NULL; 2315 int match_joining_members; 2316 int is_local; 2317 int is_local_subport = 0; 2318 int *ipmc_localport_array = NULL; 2319 int *l2mc_localport_array = NULL; 2320 int *bcast_localport_array = NULL; 2321 int *dlf_localport_array = NULL; 2322 int ipmc_localport_count; 2323 int l2mc_localport_count; 2324 int bcast_localport_count; 2325 int dlf_localport_count; 2326 2327 if (add_info->num_ports > _BCM_TH3_PORTS_PER_TRUNK_MAX) { 2328 return BCM_E_PARAM; 2329 } 2330 2331 /* Audit unsupported flag combination */ 2332 for (i = 0; i < add_info->num_ports; i++) { 2333 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) { 2334 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_INGRESS_DISABLE) { 2335 return BCM_E_PARAM; 2336 } 2337 if (add_info->member_flags[i] & 2338 BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) { 2339 return BCM_E_PARAM; 2340 } 2341 if (add_info->member_flags[i] & 2342 BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) { 2343 return BCM_E_PARAM; 2344 } 2345 if (add_info->member_flags[i] & 2346 BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) { 2347 return BCM_E_PARAM; 2348 } 2349 if (add_info->member_flags[i] & 2350 BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) { 2351 return BCM_E_PARAM; 2352 } 2353 if (add_info->member_flags[i] & 2354 BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) { 2355 return BCM_E_PARAM; 2356 } 2357 } 2358 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) { 2359 if (add_info->ipmc_index != BCM_TRUNK_UNSPEC_INDEX) { 2360 return BCM_E_PARAM; 2361 } 2362 } 2363 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) { 2364 if (add_info->mc_index != BCM_TRUNK_UNSPEC_INDEX) { 2365 return BCM_E_PARAM; 2366 } 2367 } 2368 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) { 2369 if (add_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) { 2370 return BCM_E_PARAM; 2371 } 2372 } 2373 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) { 2374 if (add_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) { 2375 return BCM_E_PARAM; 2376 } 2377 } 2378 } 2379 2380 if (add_info->dlf_index >= add_info->num_ports) { 2381 return BCM_E_PARAM; 2382 } 2383 2384 #if 1 2385 /* Derive a member bitmap of non-unicast eligible members */ 2386 nuc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "nuc_tpbm"); 2387 if (nuc_tpbm == NULL) { 2388 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2389 } 2390 sal_memset(nuc_tpbm, 0, SHR_BITALLOCSIZE(add_info->num_ports)); 2391 if (add_info->dlf_index == -1) { 2392 rv = _bcm_th3_nuc_tpbm_get(unit, add_info->num_ports, 2393 add_info->tm, nuc_tpbm); 2394 if (BCM_FAILURE(rv)) { 2395 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2396 } 2397 } else { 2398 SHR_BITSET(nuc_tpbm, add_info->dlf_index); 2399 } 2400 2401 /* Copy the non-unicast eligible member bitmap to IPMC, L2MC, broadcast, 2402 * and DLF eligible member bitmaps. 2403 */ 2404 ipmc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "ipmc_tpbm"); 2405 if (ipmc_tpbm == NULL) { 2406 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2407 } 2408 sal_memcpy(ipmc_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports)); 2409 2410 l2mc_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "l2mc_tpbm"); 2411 if (l2mc_tpbm == NULL) { 2412 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2413 } 2414 sal_memcpy(l2mc_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports)); 2415 2416 bcast_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "bcast_tpbm"); 2417 if (bcast_tpbm == NULL) { 2418 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2419 } 2420 sal_memcpy(bcast_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports)); 2421 2422 dlf_tpbm = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), "dlf_tpbm"); 2423 if (dlf_tpbm == NULL) { 2424 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2425 } 2426 sal_memcpy(dlf_tpbm, nuc_tpbm, SHR_BITALLOCSIZE(add_info->num_ports)); 2427 2428 /* Iterate through the trunk member list to get module ID (SHOULD BE 0) 2429 * and port number of each member, a port bitmap of local members, and 2430 * port bitmaps of IPMC/L2MC/BCAST/DLF eligible local members. 2431 */ 2432 hwmod = sal_alloc(sizeof(int) * (add_info->num_ports), "hwmod"); 2433 if (hwmod == NULL) { 2434 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2435 } 2436 sal_memset(hwmod, 0, sizeof(int) * (add_info->num_ports)); 2437 2438 hwport = sal_alloc(sizeof(int) * (add_info->num_ports), "hwport"); 2439 if (hwport == NULL) { 2440 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2441 } 2442 sal_memset(hwport, 0, sizeof(int) * (add_info->num_ports)); 2443 2444 ipmc_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), 2445 "ipmc_my_modid_bmap"); 2446 if (ipmc_my_modid_bmap == NULL) { 2447 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2448 } 2449 sal_memset(ipmc_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports)); 2450 2451 l2mc_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), 2452 "l2mc_my_modid_bmap"); 2453 if (l2mc_my_modid_bmap == NULL) { 2454 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2455 } 2456 sal_memset(l2mc_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports)); 2457 2458 bcast_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), 2459 "bcast_my_modid_bmap"); 2460 if (bcast_my_modid_bmap == NULL) { 2461 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2462 } 2463 sal_memset(bcast_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports)); 2464 2465 dlf_my_modid_bmap = sal_alloc(SHR_BITALLOCSIZE(add_info->num_ports), 2466 "dlf_my_modid_bmap"); 2467 if (dlf_my_modid_bmap == NULL) { 2468 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2469 } 2470 sal_memset(dlf_my_modid_bmap, 0, SHR_BITALLOCSIZE(add_info->num_ports)); 2471 ipmc_localport_array = sal_alloc(add_info->num_ports * sizeof(int), 2472 "ipmc_localport_array"); 2473 if (ipmc_localport_array == NULL) { 2474 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2475 } 2476 sal_memset(ipmc_localport_array, 0, add_info->num_ports * sizeof(int)); 2477 l2mc_localport_array = sal_alloc(add_info->num_ports * sizeof(int), 2478 "l2mc_localport_array"); 2479 if (l2mc_localport_array == NULL) { 2480 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2481 } 2482 sal_memset(l2mc_localport_array, 0, add_info->num_ports * sizeof(int)); 2483 bcast_localport_array = sal_alloc(add_info->num_ports * sizeof(int), 2484 "bcast_localport_array"); 2485 if (bcast_localport_array == NULL) { 2486 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2487 } 2488 sal_memset(bcast_localport_array, 0, add_info->num_ports * sizeof(int)); 2489 dlf_localport_array = sal_alloc(add_info->num_ports * sizeof(int), 2490 "dlf_localport_array"); 2491 if (dlf_localport_array == NULL) { 2492 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2493 } 2494 sal_memset(dlf_localport_array, 0, add_info->num_ports * sizeof(int)); 2495 2496 SOC_PBMP_CLEAR(new_trunk_pbmp); 2497 ipmc_member_count = 0; 2498 l2mc_member_count = 0; 2499 bcast_member_count = 0; 2500 dlf_member_count = 0; 2501 negr_disable_port = 0; 2502 num_uc_egr_disable_port = 0; 2503 ipmc_localport_count = 0; 2504 l2mc_localport_count = 0; 2505 bcast_localport_count = 0; 2506 dlf_localport_count = 0; 2507 2508 for (i = 0; i < add_info->num_ports; i++) { 2509 mod = 0; /* Set modid to 0 */ 2510 port = add_info->tp[i]; 2511 /*In case of feature not supported on chip return E_PARAM*/ 2512 /*if (!soc_feature(unit, soc_feature_shared_trunk_member_table)) { 2513 _BCM_TRIDENT_TRUNK_FP_SET_FREE_MEM_RETURN(BCM_E_PARAM); 2514 }*/ 2515 2516 mod_out = mod; 2517 port_out = port; 2518 2519 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 2520 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_BADID); 2521 } 2522 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 2523 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_PORT); 2524 } 2525 hwmod[i] = mod_out; /* SHOULD BE 0! */ 2526 hwport[i] = port_out; 2527 2528 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) { 2529 SHR_BITCLR(ipmc_tpbm, i); 2530 SHR_BITCLR(l2mc_tpbm, i); 2531 SHR_BITCLR(bcast_tpbm, i); 2532 SHR_BITCLR(dlf_tpbm, i); 2533 negr_disable_port++; 2534 } else { 2535 if (add_info->member_flags[i] & 2536 BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) { 2537 num_uc_egr_disable_port++; 2538 } 2539 if (add_info->member_flags[i] & 2540 BCM_TRUNK_MEMBER_IPMC_EGRESS_DISABLE) { 2541 SHR_BITCLR(ipmc_tpbm, i); 2542 } 2543 if (add_info->member_flags[i] & 2544 BCM_TRUNK_MEMBER_L2MC_EGRESS_DISABLE) { 2545 SHR_BITCLR(l2mc_tpbm, i); 2546 } 2547 if (add_info->member_flags[i] & 2548 BCM_TRUNK_MEMBER_BCAST_EGRESS_DISABLE) { 2549 SHR_BITCLR(bcast_tpbm, i); 2550 } 2551 if (add_info->member_flags[i] & 2552 BCM_TRUNK_MEMBER_DLF_EGRESS_DISABLE) { 2553 SHR_BITCLR(dlf_tpbm, i); 2554 } 2555 } 2556 2557 BCM_GPORT_MODPORT_SET(gport, mod_out, port_out); 2558 loc_port = BCM_GPORT_INVALID; 2559 if (BCM_SUCCESS(bcm_esw_port_local_get(unit, gport, &loc_port))) { 2560 #if 0 2561 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe)) { 2562 #if defined(BCM_HGPROXY_COE_SUPPORT) 2563 if(_bcm_xgs5_subport_coe_mod_port_local(unit, mod_out, 2564 port_out)) { 2565 2566 is_local_subport = 1; 2567 } 2568 #endif 2569 } else 2570 2571 if (soc_feature(unit, soc_feature_linkphy_coe) || 2572 soc_feature(unit, soc_feature_subtag_coe)) { 2573 #if defined(BCM_KATANA2_SUPPORT) 2574 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_is_local_coe_subport(unit, 2575 mod_out, port_out, &is_local_subport)); 2576 #endif 2577 } 2578 if (!is_local_subport) { 2579 if (!(IS_E_PORT(unit, loc_port) || IS_HG_PORT(unit, loc_port)) || 2580 /* Cascaded physical ports are not considered as front-panel port */ 2581 (soc_feature(unit, soc_feature_linkphy_coe) && 2582 IS_LP_PORT(unit, loc_port)) || 2583 (soc_feature(unit, soc_feature_subtag_coe) && 2584 IS_SUBTAG_PORT(unit, loc_port)) || 2585 (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 2586 IS_SUBTAG_PORT (unit, loc_port))) { 2587 _BCM_TRIDENT_TRUNK_FP_SET_FREE_MEM_RETURN(BCM_E_PARAM); 2588 } 2589 } 2590 #endif 2591 SOC_PBMP_PORT_ADD(new_trunk_pbmp, loc_port); 2592 if (SHR_BITGET(ipmc_tpbm, i)) { 2593 ipmc_localport_array[ipmc_localport_count++] = loc_port; 2594 SHR_BITSET(ipmc_my_modid_bmap, ipmc_member_count); 2595 } 2596 if (SHR_BITGET(l2mc_tpbm, i)) { 2597 l2mc_localport_array[l2mc_localport_count++] = loc_port; 2598 SHR_BITSET(l2mc_my_modid_bmap, l2mc_member_count); 2599 } 2600 if (SHR_BITGET(bcast_tpbm, i)) { 2601 bcast_localport_array[bcast_localport_count++] = loc_port; 2602 SHR_BITSET(bcast_my_modid_bmap, bcast_member_count); 2603 } 2604 if (SHR_BITGET(dlf_tpbm, i)) { 2605 dlf_localport_array[dlf_localport_count++] = loc_port; 2606 SHR_BITSET(dlf_my_modid_bmap, dlf_member_count); 2607 } 2608 } 2609 2610 2611 if (SHR_BITGET(ipmc_tpbm, i)) { 2612 /* Eligible for IPMC forwarding */ 2613 ipmc_member_count++; 2614 } 2615 if (SHR_BITGET(l2mc_tpbm, i)) { 2616 /* Eligible for L2MC forwarding */ 2617 l2mc_member_count++; 2618 } 2619 if (SHR_BITGET(bcast_tpbm, i)) { 2620 /* Eligible for broadcast forwarding */ 2621 bcast_member_count++; 2622 } 2623 if (SHR_BITGET(dlf_tpbm, i)) { 2624 /* Eligible for DLF forwarding */ 2625 dlf_member_count++; 2626 } 2627 } 2628 2629 /* Figure out which trunk ports are eligible for egress and 2630 * unicast egress 2631 */ 2632 num_egr_ports = add_info->num_ports - negr_disable_port; 2633 if (num_egr_ports > 0) { 2634 egr_hwmod = sal_alloc(sizeof(bcm_module_t) * num_egr_ports, 2635 "egr_hwmod"); 2636 if (egr_hwmod == NULL) { 2637 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2638 } 2639 egr_hwport = sal_alloc(sizeof(bcm_port_t) * num_egr_ports, 2640 "egr_hwport"); 2641 if (egr_hwport == NULL) { 2642 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2643 } 2644 egr_member_flags = sal_alloc(sizeof(uint32) * num_egr_ports, 2645 "egr_member_flags"); 2646 if (egr_member_flags == NULL) { 2647 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2648 } 2649 egr_scaling_factor = sal_alloc(sizeof(int) * num_egr_ports, 2650 "egr_scaling_factor"); 2651 if (egr_scaling_factor == NULL) { 2652 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2653 } 2654 egr_load_weight = sal_alloc(sizeof(int) * num_egr_ports, 2655 "egr_load_weight"); 2656 if (egr_load_weight == NULL) { 2657 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2658 } 2659 egr_qsize_weight = sal_alloc(sizeof(int) * num_egr_ports, 2660 "egr_qsize_weight"); 2661 if (egr_qsize_weight == NULL) { 2662 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2663 } 2664 for (i = 0, j = 0; i < add_info->num_ports; i++) { 2665 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) { 2666 continue; 2667 } 2668 egr_hwmod[j] = hwmod[i]; 2669 egr_hwport[j] = hwport[i]; 2670 egr_member_flags[j] = add_info->member_flags[i]; 2671 egr_scaling_factor[j] = add_info->dynamic_scaling_factor[i]; 2672 egr_load_weight[j] = add_info->dynamic_load_weight[i]; 2673 egr_qsize_weight[j] = add_info->dynamic_queue_size_weight[i]; 2674 j++; 2675 } 2676 2677 /* Figure out which of these egress ports are unicast */ 2678 num_uc_egr_ports = num_egr_ports - num_uc_egr_disable_port; 2679 if (num_uc_egr_ports > 0 ) { 2680 uc_egr_hwmod = sal_alloc(sizeof(bcm_module_t) * num_uc_egr_ports, 2681 "uc_egr_hwmod"); 2682 if (uc_egr_hwmod == NULL) { 2683 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2684 } 2685 uc_egr_hwport = sal_alloc(sizeof(bcm_port_t) * num_uc_egr_ports, 2686 "uc_egr_hwport"); 2687 if (uc_egr_hwport == NULL) { 2688 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2689 } 2690 uc_egr_scaling_factor = sal_alloc(sizeof(int) * num_uc_egr_ports, 2691 "uc_egr_scaling_factor"); 2692 if (uc_egr_scaling_factor == NULL) { 2693 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2694 } 2695 uc_egr_load_weight = sal_alloc(sizeof(int) * num_uc_egr_ports, 2696 "uc_egr_load_weight"); 2697 if (uc_egr_load_weight == NULL) { 2698 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2699 } 2700 uc_egr_qsize_weight = sal_alloc(sizeof(int) * num_uc_egr_ports, 2701 "uc_egr_qsize_weight"); 2702 if (uc_egr_qsize_weight == NULL) { 2703 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2704 } 2705 for (i = 0, k = 0; i < j; i++) { 2706 if (egr_member_flags[i] & 2707 BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE) { 2708 continue; 2709 } 2710 uc_egr_hwmod[k] = egr_hwmod[i]; 2711 uc_egr_hwport[k] = egr_hwport[i]; 2712 uc_egr_scaling_factor[k] = egr_scaling_factor[i]; 2713 uc_egr_load_weight[k] = egr_load_weight[i]; 2714 uc_egr_qsize_weight[k] = egr_qsize_weight[i]; 2715 k++; 2716 } 2717 } 2718 } else { 2719 2720 #if 0 2721 /* Time to use entry 0 reserved for this purpose. 2722 * Set mod and port to inavlid values in entry */ 2723 if (trunk_mbr_entry_zero_rsvd == TRUE) { 2724 trunk_member_entry_t trunk_member_entry; 2725 sal_memset(&trunk_member_entry, 0, sizeof(trunk_member_entry_t)); 2726 soc_TRUNK_MEMBERm_field32_set(unit,&trunk_member_entry, 2727 MODULE_IDf,0xff); 2728 soc_TRUNK_MEMBERm_field32_set(unit,&trunk_member_entry, 2729 PORT_NUMf, 0x7f); 2730 SOC_IF_ERROR_RETURN 2731 (WRITE_TRUNK_MEMBERm(unit, MEM_BLOCK_ALL, 2732 0,&trunk_member_entry)); 2733 trunk_mbr_entry_zero_rsvd = FALSE; 2734 } 2735 #endif 2736 } 2737 2738 #if 0 2739 if (t_info->in_use) { 2740 rv = _bcm_th3_lag_slb_free_resource(unit, tid); 2741 if (BCM_FAILURE(rv)) { 2742 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2743 } 2744 } 2745 #endif 2746 2747 /* Write TH3 memory for Fast LAG settings. Static load 2748 * balancing. There is no dynamic load balancing in TH3. */ 2749 rv = _bcm_th3_lag_slb_set(unit, tid, num_uc_egr_ports, 2750 uc_egr_hwmod, uc_egr_hwport, t_info); 2751 if (BCM_FAILURE(rv)) { 2752 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2753 } 2754 2755 /* Update TRUNK_BITMAP table */ 2756 rv = READ_TRUNK_BITMAPm(unit, MEM_BLOCK_ANY, tid, &trunk_bitmap_entry); 2757 if (BCM_FAILURE(rv)) { 2758 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2759 } 2760 SOC_PBMP_CLEAR(old_trunk_pbmp); 2761 soc_mem_pbmp_field_get(unit, TRUNK_BITMAPm, &trunk_bitmap_entry, 2762 TRUNK_BITMAPf, &old_trunk_pbmp); 2763 soc_mem_pbmp_field_set(unit, TRUNK_BITMAPm, &trunk_bitmap_entry, 2764 TRUNK_BITMAPf, &new_trunk_pbmp); 2765 rv = WRITE_TRUNK_BITMAPm(unit, MEM_BLOCK_ALL, tid, &trunk_bitmap_entry); 2766 if (BCM_FAILURE(rv)) { 2767 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2768 } 2769 2770 /* Update source trunk map configuration */ 2771 for (i = 0; i < add_info->num_ports; i++) { 2772 mod = hwmod[i%add_info->num_ports]; /* SHOULD ALL BE 0 */ 2773 port = hwport[i%add_info->num_ports]; 2774 2775 if (add_info->member_flags[i] & BCM_TRUNK_MEMBER_INGRESS_DISABLE) { 2776 rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1); 2777 } else { 2778 rv = _bcm_th3_trunk_set_port_property(unit, mod, port, tid); 2779 } 2780 if (BCM_FAILURE(rv)) { 2781 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2782 } 2783 } 2784 2785 /* Update the trunk block mask */ 2786 if (SOC_PBMP_NOT_NULL(new_trunk_pbmp) || 2787 SOC_PBMP_NOT_NULL(old_trunk_pbmp)) { 2788 rv = _bcm_th3_trunk_block_mask(unit, 2789 TRUNK_BLOCK_MASK_TYPE_IPMC, 2790 old_trunk_pbmp, 2791 new_trunk_pbmp, 2792 ipmc_localport_array, 2793 ipmc_localport_count, 2794 ipmc_my_modid_bmap, 2795 ipmc_member_count, 2796 add_info->flags); 2797 if (BCM_FAILURE(rv)) { 2798 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2799 } 2800 rv = _bcm_th3_trunk_block_mask(unit, 2801 TRUNK_BLOCK_MASK_TYPE_L2MC, 2802 old_trunk_pbmp, 2803 new_trunk_pbmp, 2804 l2mc_localport_array, 2805 l2mc_localport_count, 2806 l2mc_my_modid_bmap, 2807 l2mc_member_count, 2808 add_info->flags); 2809 if (BCM_FAILURE(rv)) { 2810 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2811 } 2812 rv = _bcm_th3_trunk_block_mask(unit, 2813 TRUNK_BLOCK_MASK_TYPE_BCAST, 2814 old_trunk_pbmp, 2815 new_trunk_pbmp, 2816 bcast_localport_array, 2817 bcast_localport_count, 2818 bcast_my_modid_bmap, 2819 bcast_member_count, 2820 add_info->flags); 2821 if (BCM_FAILURE(rv)) { 2822 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2823 } 2824 rv = _bcm_th3_trunk_block_mask(unit, 2825 TRUNK_BLOCK_MASK_TYPE_DLF, 2826 old_trunk_pbmp, 2827 new_trunk_pbmp, 2828 dlf_localport_array, 2829 dlf_localport_count, 2830 dlf_my_modid_bmap, 2831 dlf_member_count, 2832 add_info->flags); 2833 if (BCM_FAILURE(rv)) { 2834 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2835 } 2836 } 2837 2838 /* Hardware trunk failover */ 2839 rv = _bcm_th3_trunk_failover_set(unit, tid, FALSE, add_info); 2840 if (BCM_FAILURE(rv)) { 2841 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2842 } 2843 2844 /* Software failover; called from linkscan */ 2845 rv = _bcm_th3_trunk_swfailover_set(unit, tid, t_info->rtag, 2846 num_egr_ports, egr_hwmod, egr_hwport, 2847 egr_member_flags, add_info->flags); 2848 2849 2850 /* Figure out which members are leaving, staying or joining 2851 * the trunk group 2852 */ 2853 if (t_info->in_use) { 2854 if (MEMBER_INFO(unit, tid).num_ports > 0) { 2855 leaving_members = sal_alloc(sizeof(bcm_gport_t) * 2856 MEMBER_INFO(unit, tid).num_ports, "leaving members"); 2857 if (leaving_members == NULL) { 2858 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2859 } 2860 sal_memset(leaving_members, 0, 2861 sizeof(bcm_gport_t) * MEMBER_INFO(unit, tid).num_ports); 2862 2863 staying_members = sal_alloc(sizeof(bcm_gport_t) * 2864 MEMBER_INFO(unit, tid).num_ports, "staying members"); 2865 if (staying_members == NULL) { 2866 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2867 } 2868 sal_memset(staying_members, 0, 2869 sizeof(bcm_gport_t) * MEMBER_INFO(unit, tid).num_ports); 2870 2871 for (i = 0; i < MEMBER_INFO(unit, tid).num_ports; i++) { 2872 mod = 0; /*MEMBER_INFO(unit, tid).modport[i] >> 8; */ 2873 port = MEMBER_INFO(unit, tid).port[i] & 0xff; 2874 BCM_GPORT_MODPORT_SET(gport, mod, port); 2875 2876 /* Invalidate port only if it is not a part from new trunk group */ 2877 remove_trunk_port = TRUE; 2878 for (j = 0; j < add_info->num_ports; j++) { 2879 if (mod == add_info->tm[j] && port == add_info->tp[j]) { 2880 remove_trunk_port = FALSE; 2881 } 2882 } 2883 if (remove_trunk_port) { 2884 /* Add port to array containing members leaving the trunk 2885 * group if it is different from previous leaving members 2886 */ 2887 match_leaving_members = FALSE; 2888 for (k = 0; k < num_leaving_members; k++) { 2889 if (gport == leaving_members[k]) { 2890 match_leaving_members = TRUE; 2891 break; 2892 } 2893 } 2894 if (!match_leaving_members) { 2895 leaving_members[num_leaving_members++] = gport; 2896 } 2897 2898 rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1); 2899 if (BCM_FAILURE(rv)) { 2900 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2901 } 2902 2903 is_local = is_local_subport = 0; 2904 /* If deleted port is local, clear HW failover info */ 2905 rv = _bcm_esw_modid_is_local(unit, mod, &is_local); 2906 if (BCM_FAILURE(rv)) { 2907 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2908 } 2909 2910 if (!is_local && !is_local_subport) { 2911 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2912 /* continue; */ 2913 } 2914 2915 BCM_GPORT_MODPORT_SET(gport, mod, port); 2916 rv = bcm_esw_port_local_get(unit, gport, &loc_port); 2917 if (BCM_FAILURE(rv)) { 2918 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2919 } 2920 if (IS_HG_PORT(unit, loc_port)) { 2921 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2922 /* continue; */ 2923 } 2924 /* ERROR on Cascaded Physical Ports. No Support */ 2925 if ((soc_feature(unit, soc_feature_linkphy_coe) && 2926 IS_LP_PORT(unit, loc_port)) || 2927 (soc_feature(unit, soc_feature_subtag_coe) && 2928 IS_SUBTAG_PORT(unit, loc_port)) || 2929 (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 2930 IS_SUBTAG_PORT (unit, loc_port))) { 2931 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2932 /* continue; */ 2933 } 2934 rv = _bcm_th3_trunk_hwfailover_set(unit, tid, 2935 port, add_info->psc, 2936 0, 0, NULL); 2937 if (BCM_FAILURE(rv)) { 2938 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2939 } 2940 } else { 2941 /* Add port to array containing members staying in the trunk 2942 * group if it is different from previous staying members 2943 */ 2944 match_staying_members = FALSE; 2945 for (k = 0; k < num_staying_members; k++) { 2946 if (gport == staying_members[k]) { 2947 match_staying_members = TRUE; 2948 break; 2949 } 2950 } 2951 if (!match_staying_members) { 2952 staying_members[num_staying_members++] = gport; 2953 } 2954 2955 } 2956 } 2957 } 2958 } 2959 2960 /* allocate space and set joining members for comparison. If a joining 2961 * member matches a staying member, don't need to add it again. */ 2962 joining_members = sal_alloc(sizeof(bcm_gport_t) * add_info->num_ports, 2963 "joining members"); 2964 if (joining_members == NULL) { 2965 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 2966 } 2967 sal_memset(joining_members, 0, sizeof(bcm_gport_t) * add_info->num_ports); 2968 for (i = 0; i < add_info->num_ports; i++) { 2969 BCM_GPORT_MODPORT_SET(gport, hwmod[i], hwport[i]); 2970 match_staying_members = FALSE; 2971 for (j = 0; j < num_staying_members; j++) { 2972 if (gport == staying_members[j]) { 2973 match_staying_members = TRUE; 2974 break; 2975 } 2976 } 2977 if (!match_staying_members) { 2978 match_joining_members = FALSE; 2979 for (j = 0; j < num_joining_members; j++) { 2980 if (gport == joining_members[j]) { 2981 match_joining_members = TRUE; 2982 break; 2983 } 2984 } 2985 if (!match_joining_members) { 2986 joining_members[num_joining_members++] = gport; 2987 } 2988 } 2989 } 2990 2991 2992 2993 rv = _bcm_xgs3_trunk_property_migrate(unit, 2994 num_leaving_members, leaving_members, 2995 num_staying_members, staying_members, 2996 num_joining_members, joining_members); 2997 if (BCM_FAILURE(rv)) { 2998 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 2999 } 3000 3001 /* Save new trunk member info. Free up the old memory and allocate new space 3002 * since there may be a different number of entries. */ 3003 if (MEMBER_INFO(unit, tid).port) { 3004 sal_free(MEMBER_INFO(unit, tid).port); 3005 MEMBER_INFO(unit, tid).port = NULL; 3006 } 3007 if (MEMBER_INFO(unit, tid).member_flags) { 3008 sal_free(MEMBER_INFO(unit, tid).member_flags); 3009 MEMBER_INFO(unit, tid).member_flags = NULL; 3010 } 3011 3012 MEMBER_INFO(unit, tid).port = sal_alloc( 3013 sizeof(uint16) * add_info->num_ports, "member info port"); 3014 if (NULL == MEMBER_INFO(unit, tid).port) { 3015 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 3016 } 3017 3018 MEMBER_INFO(unit, tid).member_flags = sal_alloc( 3019 sizeof(uint32) * add_info->num_ports, "member info flags"); 3020 if (NULL == MEMBER_INFO(unit, tid).member_flags) { 3021 sal_free(MEMBER_INFO(unit, tid).port); 3022 MEMBER_INFO(unit, tid).port = NULL; 3023 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(BCM_E_MEMORY); 3024 } 3025 3026 /* Save the information to our memory */ 3027 for (i = 0; i < add_info->num_ports; i++) { 3028 MEMBER_INFO(unit, tid).port[i] = ((hwmod[i] & 0xff) << 8) | 3029 (hwport[i] & 0xff); 3030 MEMBER_INFO(unit, tid).member_flags[i] = add_info->member_flags[i]; 3031 } 3032 MEMBER_INFO(unit, tid).num_ports = add_info->num_ports; 3033 3034 #endif 3035 #endif 3036 3037 /* Free all dynamically allocated memory used in this function */ 3038 _BCM_TH3_TRUNK_SET_FREE_MEM_RETURN(rv); 3039 } 3040 3041 3042 /* 3043 * Function: 3044 * bcm_th3_trunk_modify 3045 * Purpose: 3046 * Set trunk members. 3047 * Parameters: 3048 * unit - (IN) SOC unit number. 3049 * tid - (IN) Trunk group ID. 3050 * trunk_info - (IN) Pointer to user provided trunk info. 3051 * member_count - (IN) Number of trunk members. 3052 * member_array - (IN) Array of trunk members. 3053 * t_info - (IN) Pointer to internal trunk info. 3054 * op - (IN) Not used by this procedure. 3055 * member - (IN) Not used by this procedure. 3056 * Returns: 3057 * BCM_E_xxx 3058 */ 3059 int 3060 bcm_th3_trunk_modify(int unit, 3061 bcm_trunk_t tid, 3062 bcm_trunk_info_t *trunk_info, 3063 int member_count, 3064 bcm_trunk_member_t *member_array, 3065 trunk_private_t *t_info, 3066 int op, 3067 bcm_trunk_member_t *member) 3068 { 3069 int rv = BCM_E_NONE; 3070 int rtag; 3071 #if 1 3072 /* bcm_trunk_chip_info_t chip_info; */ 3073 _esw_trunk_add_info_t add_info; 3074 int i; 3075 int higig_trunk; 3076 3077 if (trunk_info->psc <= 0) { 3078 trunk_info->psc = BCM_TRUNK_PSC_PORTFLOW; 3079 } 3080 BCM_IF_ERROR_RETURN 3081 (_bcm_th3_trunk_psc_to_rtag(unit, trunk_info->psc, &rtag)); 3082 t_info->rtag = rtag; 3083 t_info->flags = trunk_info->flags; 3084 3085 if ((trunk_info->dlf_index != trunk_info->mc_index) || 3086 (trunk_info->dlf_index != trunk_info->ipmc_index)) { 3087 return BCM_E_PARAM; 3088 } 3089 3090 t_info->dlf_index_spec = 3091 t_info->dlf_index_used = 3092 t_info->mc_index_spec = 3093 t_info->mc_index_used = 3094 t_info->ipmc_index_spec = 3095 t_info->ipmc_index_used = trunk_info->dlf_index; 3096 3097 if (member_count < 1) { 3098 if (t_info->in_use) { 3099 /* Delete existing trunk member ports */ 3100 BCM_IF_ERROR_RETURN 3101 (bcm_th3_trunk_destroy(unit, tid, t_info)); 3102 } 3103 } else { 3104 sal_memset(&add_info, 0, sizeof(_esw_trunk_add_info_t)); 3105 3106 /* Fill in fields. Don't need to fill in DLB fields because 3107 * TH3 does not support DLB and already initialized mem to 0 */ 3108 add_info.flags = trunk_info->flags; 3109 add_info.num_ports = member_count; 3110 add_info.psc = trunk_info->psc; 3111 add_info.ipmc_psc = trunk_info->ipmc_psc; 3112 add_info.dlf_index = trunk_info->dlf_index; 3113 add_info.mc_index = trunk_info->mc_index; 3114 add_info.ipmc_index = trunk_info->ipmc_index; 3115 3116 BCM_IF_ERROR_RETURN 3117 (_th3_trunk_add_info_member_alloc(&add_info, member_count)); 3118 3119 for (i = 0; i < member_count; i++) { 3120 add_info.member_flags[i] = member_array[i].flags; 3121 add_info.tp[i] = member_array[i].gport; 3122 add_info.tm[i] = -1; 3123 } 3124 3125 /* Convert member gport to module and port */ 3126 3127 higig_trunk = 0; 3128 rv = _bcm_esw_trunk_gport_array_resolve(unit, 3129 higig_trunk, 3130 member_count, 3131 add_info.tp, 3132 add_info.tp, 3133 add_info.tm); 3134 3135 3136 if (BCM_FAILURE(rv)) { 3137 _th3_trunk_add_info_member_free(&add_info); 3138 return rv; 3139 } 3140 3141 /* Check modids of passed in gports in member_array. Return error 3142 * if nonzero 3143 */ 3144 for (i = 0; i < member_count; i++) { 3145 if (!SOC_MODID_ADDRESSABLE(unit, add_info.tm[i])) { 3146 rv = BCM_E_BADID; 3147 _th3_trunk_add_info_member_free(&add_info); 3148 break; 3149 } 3150 } 3151 if (BCM_SUCCESS(rv)) { 3152 /* The new psc in trunk_info is the one to be programmed */ 3153 t_info->psc = trunk_info->psc; 3154 rv = _bcm_th3_trunk_set(unit, tid, &add_info, t_info); 3155 _th3_trunk_add_info_member_free(&add_info); 3156 } 3157 } 3158 #endif 3159 return rv; 3160 } 3161 3162 3163 3164 /* 3165 * Function: 3166 * bcm_th3_trunk_destroy 3167 * Purpose: 3168 * Deletes the trunk specified 3169 */ 3170 int 3171 bcm_th3_trunk_destroy(int unit, 3172 bcm_trunk_t tid, 3173 trunk_private_t *t_info) 3174 { 3175 3176 bcm_module_t mod; 3177 bcm_port_t port, loc_port; 3178 bcm_gport_t gport; 3179 pbmp_t old_ports, new_ports; 3180 int i, rv; 3181 int num_leaving_members = 0; 3182 bcm_gport_t *leaving_members = NULL; 3183 3184 SOC_PBMP_CLEAR(new_ports); 3185 3186 /* front panel trunks */ 3187 3188 SOC_PBMP_CLEAR(old_ports); 3189 3190 /* Dynamically allocate this because 64 * 4 bytes 3191 * is a lot to put on the stack */ 3192 leaving_members = sal_alloc(MEMBER_INFO(unit, tid).num_ports * sizeof(int), 3193 "bcm_th3_drunk_destroy leaving_members"); 3194 if (NULL == leaving_members) { 3195 return BCM_E_MEMORY; 3196 } 3197 sal_memset(leaving_members, 0, MEMBER_INFO(unit, tid).num_ports * sizeof(int)); 3198 3199 for (i = 0; i < MEMBER_INFO(unit, tid).num_ports; i++) { 3200 mod = 0; /* MEMBER_INFO(tid).port[i] >> 8; */ 3201 port = MEMBER_INFO(unit, tid).port[i] & 0xff; 3202 BCM_GPORT_MODPORT_SET(gport, mod, port); 3203 if (BCM_SUCCESS(bcm_esw_port_local_get(unit, gport, &loc_port))) { 3204 SOC_PBMP_PORT_ADD(old_ports, loc_port); 3205 } 3206 leaving_members[num_leaving_members++] = gport; 3207 rv = _bcm_th3_trunk_set_port_property(unit, mod, port, -1); 3208 if (BCM_FAILURE(rv)) { 3209 goto cleanup; 3210 } 3211 } 3212 3213 /* 3214 * Remove ports from the block mask table 3215 */ 3216 if (SOC_PBMP_NOT_NULL(old_ports)) { 3217 SOC_PBMP_CLEAR(new_ports); 3218 /* coverity[divide_by_zero] */ 3219 rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_IPMC, 3220 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags); 3221 if (BCM_FAILURE(rv)) { 3222 goto cleanup; 3223 } 3224 rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_L2MC, 3225 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags); 3226 if (BCM_FAILURE(rv)) { 3227 goto cleanup; 3228 } 3229 rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_BCAST, 3230 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags); 3231 if (BCM_FAILURE(rv)) { 3232 goto cleanup; 3233 } 3234 rv = _bcm_th3_trunk_block_mask(unit, TRUNK_BLOCK_MASK_TYPE_DLF, 3235 old_ports, new_ports, NULL, 0, NULL, 0, t_info->flags); 3236 if (BCM_FAILURE(rv)) { 3237 goto cleanup; 3238 } 3239 } 3240 3241 /* 3242 * Reset table entries to empty state 3243 */ 3244 rv = soc_mem_write(unit, TRUNK_BITMAPm, MEM_BLOCK_ALL, tid, 3245 soc_mem_entry_null(unit, TRUNK_BITMAPm)); 3246 if (BCM_FAILURE(rv)) { 3247 goto cleanup; 3248 } 3249 rv = soc_mem_write(unit, FAST_TRUNK_PORTS_1m, MEM_BLOCK_ALL, tid, 3250 soc_mem_entry_null(unit, FAST_TRUNK_PORTS_1m)); 3251 if (BCM_FAILURE(rv)) { 3252 goto cleanup; 3253 } 3254 rv = soc_mem_write(unit, FAST_TRUNK_PORTS_2m, MEM_BLOCK_ALL, tid, 3255 soc_mem_entry_null(unit, FAST_TRUNK_PORTS_2m)); 3256 if (BCM_FAILURE(rv)) { 3257 goto cleanup; 3258 } 3259 rv = soc_mem_write(unit, FAST_TRUNK_SIZEm, MEM_BLOCK_ALL, tid, 3260 soc_mem_entry_null(unit, FAST_TRUNK_SIZEm)); 3261 if (BCM_FAILURE(rv)) { 3262 goto cleanup; 3263 } 3264 3265 /* 3266 * Remove ports from failover 3267 */ 3268 rv = _bcm_th3_trunk_failover_set(unit, tid, FALSE, NULL); 3269 if (BCM_FAILURE(rv)) { 3270 goto cleanup; 3271 } 3272 3273 rv = _bcm_th3_trunk_swfailover_set(unit, 3274 tid, 3275 0, 3276 0, 3277 NULL, 3278 NULL, 3279 NULL, 3280 0); 3281 if (BCM_FAILURE(rv)) { 3282 goto cleanup; 3283 } 3284 3285 3286 rv = _bcm_xgs3_trunk_property_migrate(unit, 3287 num_leaving_members, leaving_members, 3288 0, NULL, 0, NULL); 3289 if (BCM_FAILURE(rv)) { 3290 goto cleanup; 3291 } 3292 3293 3294 3295 /* Free memory allocated for ports and member flags in the trunk_set 3296 * function */ 3297 if (MEMBER_INFO(unit, tid).port) { 3298 sal_free(MEMBER_INFO(unit, tid).port); 3299 MEMBER_INFO(unit, tid).port = NULL; 3300 } 3301 if (MEMBER_INFO(unit, tid).member_flags) { 3302 sal_free(MEMBER_INFO(unit, tid).member_flags); 3303 MEMBER_INFO(unit, tid).member_flags = NULL; 3304 } 3305 MEMBER_INFO(unit, tid).num_ports = 0; 3306 3307 t_info->in_use = FALSE; 3308 3309 cleanup: 3310 sal_free(leaving_members); 3311 3312 return rv; 3313 } 3314 3315 static soc_field_t _th3_trunk_failover_portf[8] = { 3316 PORT0f, PORT1f, PORT2f, PORT3f, 3317 PORT4f, PORT5f, PORT6f, PORT7f 3318 }; 3319 3320 /* 3321 * Function: 3322 * _bcm_th3_trunk_hwfailover_write 3323 * Purpose: 3324 * Set front panel trunk hardware failover config 3325 * Parameters: 3326 * unit - (IN) SOC unit number. 3327 * failport - (IN) Fail port 3328 * rtag - (IN) Port selection criteria for failover port list 3329 * hw_count - (IN) Number of ports in failover port list 3330 * ftp - (IN) Pointer to failover port list port ID 3331 * Returns: 3332 * BCM_E_xxx 3333 */ 3334 STATIC int 3335 _bcm_th3_trunk_hwfailover_write(int unit, 3336 bcm_port_t failport, int rtag, 3337 int hw_count, bcm_port_t *ftp) 3338 { 3339 int failover_status, failover_max_portcnt, mirror_enable, i; 3340 port_lag_failover_set_entry_t fail_entry; 3341 3342 3343 if (SOC_USE_PORTCTRL(unit)) { 3344 BCM_IF_ERROR_RETURN 3345 (bcmi_esw_portctrl_hwfailover_status_get(unit, failport, 3346 &failover_status)); 3347 } else { 3348 /* TH3 uses portmod and portctrl */ 3349 return BCM_E_INIT; 3350 } 3351 3352 if (failover_status) { 3353 /* 3354 * Already in failover mode. Do not change HW settings! 3355 * This should be dealt with as part of the port link processing. 3356 */ 3357 if (hw_count == 0) { 3358 /* Notify linkscan of port removal from trunk */ 3359 BCM_IF_ERROR_RETURN 3360 (_bcm_esw_link_failover_set(unit, failport, FALSE)); 3361 return BCM_E_NONE; 3362 } else { 3363 /* Failed port has not yet been removed from the trunk 3364 * -- do not change the failover configuration 3365 */ 3366 return BCM_E_NONE; 3367 } 3368 } 3369 3370 /* Enabling trunk failover */ 3371 if (hw_count) { 3372 /* Must be in directed mirroring mode to use this feature */ 3373 BCM_IF_ERROR_RETURN 3374 (bcm_esw_switch_control_get(unit, bcmSwitchDirectedMirroring, 3375 &mirror_enable)); 3376 if (!mirror_enable) { 3377 return BCM_E_CONFIG; 3378 } 3379 3380 sal_memset(&fail_entry, 0, sizeof(fail_entry)); 3381 soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm, 3382 (uint32 *)&fail_entry, 3383 FAILOVER_SET_SIZEf, hw_count - 1); 3384 soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm, 3385 (uint32 *)&fail_entry, RTAGf, rtag); 3386 3387 failover_max_portcnt = 1 << soc_mem_field_length(unit, 3388 PORT_LAG_FAILOVER_SETm, FAILOVER_SET_SIZEf); 3389 3390 /* Set each port to failover to for failport */ 3391 for(i = 0; i < failover_max_portcnt; i++) { 3392 soc_mem_field32_set(unit, PORT_LAG_FAILOVER_SETm, 3393 (uint32 *)&fail_entry, 3394 _th3_trunk_failover_portf[i], 3395 ftp[i % hw_count]); 3396 } 3397 3398 SOC_IF_ERROR_RETURN 3399 (WRITE_PORT_LAG_FAILOVER_SETm(unit, MEM_BLOCK_ALL, failport, 3400 &fail_entry)); 3401 } 3402 3403 if (SOC_USE_PORTCTRL(unit)) { 3404 BCM_IF_ERROR_RETURN 3405 (bcmi_esw_portctrl_hwfailover_enable_set(unit, failport, 3406 (hw_count != 0) ? 1 : 0)); 3407 } else { 3408 /* TH3 uses portmod and portctrl */ 3409 return BCM_E_INIT; 3410 } 3411 3412 /* Notify linkscan of failover status */ 3413 BCM_IF_ERROR_RETURN 3414 (_bcm_esw_link_failover_set(unit, failport, (hw_count != 0))); 3415 3416 return BCM_E_NONE; 3417 } 3418 3419 /* 3420 * Function: 3421 * _bcm_th3_trunk_hwfailover_read 3422 * Purpose: 3423 * Set front panel trunk hardware failover config 3424 * Parameters: 3425 * unit - (IN) SOC unit number. 3426 * failport - (IN) Fail port 3427 * max_ports - (IN) max ports to copy out 3428 * ftp - (OUT) Pointer to port IDs in failover port list 3429 * hw_count - (OUT) Number of failover ports copied out. 3430 * rtag - (OUT) pointer to failover ports rtag 3431 * Returns: 3432 * BCM_E_xxx 3433 */ 3434 STATIC int 3435 _bcm_th3_trunk_hwfailover_read(int unit, bcm_port_t failport, int max_ports, 3436 bcm_port_t *ftp, int *hw_count, int *rtag) 3437 { 3438 int enable = FALSE, mirror_enable, i; 3439 port_lag_failover_set_entry_t fail_entry; 3440 uint32 failover_set_size; 3441 3442 *hw_count = 0; 3443 3444 if (SOC_USE_PORTCTRL(unit)) { 3445 BCM_IF_ERROR_RETURN 3446 (bcmi_esw_portctrl_hwfailover_enable_get(unit, failport, 3447 &enable)); 3448 } else { 3449 /* TH3 uses portmod and portctrl */ 3450 return BCM_E_INIT; 3451 } 3452 3453 if (!enable) { 3454 return BCM_E_NONE; 3455 } 3456 3457 /* Must be in directed mirroring mode to use this feature */ 3458 BCM_IF_ERROR_RETURN 3459 (bcm_esw_switch_control_get(unit, bcmSwitchDirectedMirroring, 3460 &mirror_enable)); 3461 if (!mirror_enable) { 3462 return BCM_E_NONE; 3463 } 3464 3465 sal_memset(&fail_entry, 0, sizeof(fail_entry)); 3466 SOC_IF_ERROR_RETURN 3467 (READ_PORT_LAG_FAILOVER_SETm(unit, MEM_BLOCK_ALL, failport, 3468 &fail_entry)); 3469 3470 failover_set_size = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm, 3471 (uint32 *)&fail_entry, FAILOVER_SET_SIZEf) + 1; 3472 *rtag = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm, 3473 (uint32 *)&fail_entry, RTAGf); 3474 *hw_count = failover_set_size > max_ports? max_ports: failover_set_size; 3475 3476 /* Set each port to failover to for failport */ 3477 for(i = 0; i < *hw_count; i++) { 3478 ftp[i] = soc_mem_field32_get(unit, PORT_LAG_FAILOVER_SETm, 3479 (uint32 *)&fail_entry, 3480 _th3_trunk_failover_portf[i]); 3481 } 3482 3483 return BCM_E_NONE; 3484 } 3485 3486 /* 3487 * Function: 3488 * _bcm_th3_trunk_hwfailover_set 3489 * Purpose: 3490 * Derive hardware failover port list and set hardware 3491 * failover config. 3492 * Parameters: 3493 * unit - (IN) unit number 3494 * tid - (IN) Trunk Group ID 3495 * port - (IN) Port ID of the fail port 3496 * psc - (IN) Port selection criteria for the failover port list 3497 * flags - (IN) BCM_TRUNK_FLAG_FAILOVER_xxx 3498 * count - (IN) Number of ports in failover port list 3499 * ftp - (IN) Pointer to port IDs in failover port list 3500 * Returns: 3501 * BCM_E_xxx 3502 */ 3503 int 3504 _bcm_th3_trunk_hwfailover_set(int unit, bcm_trunk_t tid, 3505 bcm_port_t port, int psc, uint32 flags, 3506 int count, bcm_port_t *ftp) 3507 { 3508 int rtag, trunk_ports, trunk_index, failover_max_portcnt; 3509 int hw_count, i, rv, next; 3510 uint16 fail_port; 3511 bcm_port_t *port_list = NULL; 3512 _th3_hw_tinfo_t *hw_fail_trunk; 3513 3514 /* Passed in port is the fail port. No HG/stacking calc */ 3515 fail_port = port; 3516 3517 BCM_IF_ERROR_RETURN(_bcm_th3_trunk_psc_to_rtag(unit, psc, &rtag)); 3518 3519 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 3520 trunk_ports = hw_fail_trunk->num_ports; 3521 3522 for(trunk_index = 0; trunk_index < trunk_ports; trunk_index++) { 3523 if (fail_port == hw_fail_trunk->port[trunk_index]) { 3524 break; 3525 } 3526 } 3527 3528 if ((0 != count) && (trunk_index == trunk_ports)) { 3529 /* Port not in trunk! */ 3530 return BCM_E_NOT_FOUND; 3531 } 3532 3533 /* TH3 allows a max of 8 failover ports */ 3534 failover_max_portcnt = 1 << soc_mem_field_length(unit, 3535 PORT_LAG_FAILOVER_SETm, FAILOVER_SET_SIZEf); 3536 3537 port_list = sal_alloc(sizeof(bcm_port_t) * failover_max_portcnt, 3538 "failover port list"); 3539 3540 if (port_list == NULL) { 3541 return BCM_E_MEMORY; 3542 } 3543 3544 sal_memset(port_list, 0, sizeof(bcm_port_t) * failover_max_portcnt); 3545 3546 if (flags) { 3547 switch (flags) { 3548 case BCM_TRUNK_FLAG_FAILOVER_NEXT_LOCAL: 3549 next = TRUE; 3550 break; 3551 case BCM_TRUNK_FLAG_FAILOVER_NEXT: 3552 next = TRUE; 3553 break; 3554 case BCM_TRUNK_FLAG_FAILOVER_ALL_LOCAL: 3555 next = FALSE; 3556 break; 3557 case BCM_TRUNK_FLAG_FAILOVER_ALL: 3558 next = FALSE; 3559 break; 3560 default: 3561 /* Illegal flags setting */ 3562 sal_free(port_list); 3563 return BCM_E_PARAM; 3564 } 3565 3566 hw_count = 0; 3567 3568 for (i = ((trunk_index + 1) % trunk_ports); /* Start after fail port */ 3569 i != trunk_index; /* Stop after cycling around */ 3570 i = ((i + 1) % trunk_ports)) { /* Cycle through trunk port list */ 3571 3572 /* All ports are local; modid is 0, so only add port */ 3573 port_list[hw_count] = hw_fail_trunk->port[i]; 3574 hw_count++; 3575 if (hw_count == failover_max_portcnt) { 3576 break; 3577 } 3578 if (next) { 3579 break; 3580 } 3581 } 3582 } else { 3583 hw_count = 0; 3584 3585 if (count) { 3586 for (i = 0; i < count && i < failover_max_portcnt; i++) { 3587 port_list[i] = BCM_GPORT_MODPORT_PORT_GET(ftp[i]); 3588 3589 } 3590 hw_count = i; 3591 } 3592 } 3593 3594 rv = _bcm_th3_trunk_hwfailover_write(unit, port, rtag, 3595 hw_count, port_list); 3596 3597 sal_free(port_list); 3598 if (BCM_FAILURE(rv)) { 3599 return rv; 3600 } 3601 3602 /* Set the port selection criteria and the flags in the 3603 * port that hardware failover was just configured for 3604 */ 3605 if (trunk_index < hw_fail_trunk->num_ports) { 3606 hw_fail_trunk->flags[trunk_index] = flags; 3607 hw_fail_trunk->psc[trunk_index] = psc; 3608 } 3609 3610 return rv; 3611 } 3612 /* 3613 * Function: 3614 * _bcm_th3_trunk_hwfailover_get 3615 * Purpose: 3616 * Derive hardware failover port list and set hardware 3617 * failover config. 3618 * Parameters: 3619 * unit - (IN) unit number 3620 * tid - (IN) Trunk Group ID 3621 * port - (IN) Port ID of the fail port 3622 * array_size - (IN) numbers of max failovers ports to copy out 3623 * psc - (OUT) Port selection criteria for the failover port list 3624 * flags - (OUT) BCM_TRUNK_FLAG_FAILOVER_xxx 3625 * array_count - (OUT) Number of failover ports copied out 3626 * ftp - (OUT) Pointer to port IDs in failover port list 3627 * Returns: 3628 * BCM_E_xxx 3629 */ 3630 int 3631 _bcm_th3_trunk_hwfailover_get(int unit, bcm_trunk_t tid, 3632 bcm_port_t port, int *psc, uint32 *flags, 3633 int array_size, bcm_port_t *ftp, int *array_count) 3634 { 3635 int trunk_ports, trunk_index; 3636 int rv = BCM_E_NONE; 3637 uint16 fail_port; 3638 _th3_hw_tinfo_t *hw_fail_trunk; 3639 int rtag; 3640 3641 /* Passed in port is the fail port. No HG/stacking calc */ 3642 fail_port = port; 3643 3644 if (array_size != 0 && ftp == NULL) { 3645 return BCM_E_PARAM; 3646 } 3647 hw_fail_trunk = &(_th3_trunk_hwfail[unit]->hw_tinfo[tid]); 3648 trunk_ports = hw_fail_trunk->num_ports; 3649 3650 for(trunk_index = 0; trunk_index < trunk_ports; trunk_index++) { 3651 if (fail_port == hw_fail_trunk->port[trunk_index]) { 3652 break; 3653 } 3654 } 3655 3656 if (trunk_index == trunk_ports) { 3657 /* Port not in trunk! */ 3658 return BCM_E_NOT_FOUND; 3659 } 3660 *psc = hw_fail_trunk->psc[trunk_index]; 3661 *flags = hw_fail_trunk->flags[trunk_index]; 3662 3663 if (array_size > 0) { 3664 sal_memset(ftp, 0, sizeof(bcm_port_t) * array_size); 3665 rv = _bcm_th3_trunk_hwfailover_read(unit, port, array_size, ftp, array_count, &rtag); 3666 } 3667 3668 return rv; 3669 } 3670 3671 #endif 3672 #endif /* BCM_TOMAHAWK3_SUPPORT */