brd_common.c (46076B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: brd_common.c 8 * Purpose: Common XGS board programming functions 9 */ 10 #include <shared/bsl.h> 11 #include <shared/alloc.h> 12 13 #include <sdk_config.h> 14 #include <sal/core/sync.h> 15 16 #include <bcm/error.h> 17 #include <bcm/port.h> 18 #include <bcm/stack.h> 19 #include <bcm/init.h> /* bcm_info_get */ 20 #include <bcm/trunk.h> 21 #include <bcm/topo.h> 22 #include <bcm/mirror.h> 23 #include <bcm/switch.h> 24 #include <bcm_int/esw/mirror.h> 25 26 #include <appl/cputrans/nh_tx.h> /* nh_tx_src_get */ 27 #include <appl/cputrans/cpu2cpu.h> /* nh_tx_src_get */ 28 #include <appl/stktask/topology.h> 29 #include <appl/stktask/topo_brd.h> 30 #include <appl/stktask/stktask.h> /* bcm_st_reserved_modid_enable_get */ 31 32 #include "topo_int.h" 33 34 #if defined(BCM_BOARD_AUTO_TRUNK) 35 #define AUTO_TRUNK_DEFAULT TRUE 36 #else 37 #define AUTO_TRUNK_DEFAULT FALSE 38 #endif 39 40 typedef struct _trunk_info_s { 41 int num_ports; 42 bcm_trunk_member_t member[BCM_TRUNK_FABRIC_MAX_PORTCNT]; 43 bcm_trunk_info_t info; 44 } _trunk_info_t; 45 46 static int _bcm_board_auto_trunk_enable = AUTO_TRUNK_DEFAULT; 47 48 #ifndef BCM_BOARD_MAX_MODID 49 #define BCM_BOARD_MAX_MODID 32 50 #endif 51 52 static int _bcm_board_num_modids = BCM_BOARD_MAX_MODID; 53 54 /* 55 * Function: 56 * bcm_board_auto_trunk_set 57 * Purpose: 58 * Sets the auto trunk state for this CPU subsystem 59 * Parameters: 60 * flag - FALSE=no automatic trunking !FALSE=automatic trunking 61 * Returns: 62 * BCM_E_NONE 63 * Notes: 64 */ 65 66 int 67 bcm_board_auto_trunk_set(int flag) 68 { 69 _bcm_board_auto_trunk_enable = flag; 70 71 return BCM_E_NONE; 72 } 73 74 /* 75 * Function: 76 * bcm_board_auto_trunk_get 77 * Purpose: 78 * Gets the current auto trunk state for this CPU subsystem 79 * Parameters: 80 * flag - pointer to state variable 81 * Returns: 82 * BCM_E_NONE 83 * Notes: 84 * See bcm_board_auto_trunk_set for the meaning of the flag variable 85 */ 86 87 int 88 bcm_board_auto_trunk_get(int *flag) 89 { 90 if (flag) { 91 *flag = _bcm_board_auto_trunk_enable; 92 } 93 94 return BCM_E_NONE; 95 } 96 97 98 /* 99 * Function: 100 * bcm_board_num_modid_set 101 * Purpose: 102 * Gets the maximum number of modids for this CPU subsystem 103 * Parameters: 104 * num - maximum number of modids 105 * Returns: 106 * BCM_E_NONE 107 * Notes: 108 */ 109 110 int 111 bcm_board_num_modid_set(int num) 112 { 113 _bcm_board_num_modids = num; 114 115 return BCM_E_NONE; 116 } 117 118 /* 119 * Function: bcm_board_num_modid_get 120 * 121 * Purpose: 122 * Gets the maximum number of modids for this CPU subsystem 123 * Parameters: 124 * num - pointer to variable 125 * Returns: 126 * BCM_E_NONE 127 */ 128 129 int 130 bcm_board_num_modid_get(int *num) 131 { 132 if (num) { 133 *num = _bcm_board_num_modids; 134 } 135 136 return BCM_E_NONE; 137 } 138 139 STATIC bcm_board_trunk_cb_f bcm_board_trunk_callback_func; 140 STATIC void * bcm_board_trunk_callback_cookie; 141 142 int bcm_board_trunk_callback_add(bcm_board_trunk_cb_f func, 143 void *cookie) 144 { 145 bcm_board_trunk_callback_func = func; 146 bcm_board_trunk_callback_cookie = cookie; 147 148 return BCM_E_NONE; 149 } 150 151 int bcm_board_trunk_callback_remove(bcm_board_trunk_cb_f func, 152 void *cookie) 153 { 154 bcm_board_trunk_callback_func = NULL; 155 bcm_board_trunk_callback_cookie = NULL; 156 157 return BCM_E_NONE; 158 } 159 160 #define TRUNK_STATUS_FREE 1 161 #define TRUNK_STATUS_BUSY 2 162 163 STATIC int 164 _to_devport(int unit, bcm_gport_t gport) 165 { 166 return (BCM_GPORT_IS_DEVPORT(gport)) ? 167 gport : BCM_GPORT_DEVPORT(unit, gport); 168 } 169 170 STATIC int 171 _bcm_board_port_match(int unit, bcm_trunk_member_t *a, bcm_trunk_member_t *b) 172 { 173 bcm_gport_t ga, gb; 174 175 ga = _to_devport(unit, a->gport); 176 gb = _to_devport(unit, b->gport); 177 178 if (ga != gb) { 179 return FALSE; 180 } 181 182 if (a->flags != b->flags) { 183 return FALSE; 184 } 185 186 return TRUE; 187 188 } 189 STATIC int 190 _bcm_board_trunk_match(int unit, 191 _trunk_info_t *a, _trunk_info_t *b) 192 { 193 int i; 194 195 if (a->num_ports != b->num_ports) { 196 return FALSE; 197 } 198 199 for (i=0; i<a->num_ports; i++) { 200 if (!_bcm_board_port_match(unit, a->member + i, b->member + i)) { 201 return FALSE; 202 } 203 } 204 205 return TRUE; 206 } 207 208 STATIC int 209 _bcm_board_trunk_make(int unit, _trunk_info_t *trunk, 210 int start_tid, int *status, int trunk_maxnum) 211 { 212 int tid_offset; 213 int tid_available; 214 int tid; 215 int rv; 216 _trunk_info_t current; 217 218 tid_available = -1; 219 for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) { 220 if (status[tid_offset] == 0) { 221 tid = start_tid + tid_offset; 222 rv = bcm_trunk_get(unit, tid, ¤t.info, 223 COUNTOF(current.member), current.member, 224 ¤t.num_ports); 225 226 if (BCM_FAILURE(rv)) { 227 if (rv == BCM_E_NOT_FOUND) { 228 if (tid_available < 0) { 229 tid_available = tid_offset; 230 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 231 (BSL_META_U(unit, 232 "Available trunk %d\n"), 233 tid)); 234 } else { 235 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 236 (BSL_META_U(unit, 237 "Free trunk %d\n"), 238 tid)); 239 } 240 status[tid_offset] = TRUNK_STATUS_FREE; 241 } else if (rv == BCM_E_PARAM) { 242 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 243 (BSL_META_U(unit, 244 "Illegal trunk %d\n"), 245 tid)); 246 break; 247 } else { 248 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 249 (BSL_META_U(unit, 250 "Trunk %d error %d\n"), 251 tid, rv)); 252 return rv; 253 } 254 } else if (_bcm_board_trunk_match(unit, trunk, ¤t)) { 255 /* have a trunk that matches requirements */ 256 status[tid_offset] = TRUNK_STATUS_BUSY; 257 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 258 (BSL_META_U(unit, 259 "Reusing trunk %d\n"), 260 tid)); 261 return BCM_E_NONE; 262 } 263 } else if (status[tid_offset] == TRUNK_STATUS_FREE && 264 tid_available < 0) { 265 tid_available = tid_offset; 266 } 267 } 268 269 if (tid_available < 0) { 270 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 271 (BSL_META_U(unit, 272 "No free trunk was found\n"))); 273 return BCM_E_UNAVAIL; 274 } 275 tid = start_tid + tid_available; 276 BCM_IF_ERROR_RETURN 277 (bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid)); 278 BCM_IF_ERROR_RETURN(bcm_trunk_set(unit, tid, &trunk->info, 279 trunk->num_ports, 280 trunk->member)); 281 status[tid_available] = TRUNK_STATUS_BUSY; 282 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 283 (BSL_META_U(unit, 284 "Created trunk %d\n"), 285 tid)); 286 return BCM_E_NONE; 287 } 288 289 STATIC int 290 _bcm_board_trunk_remove(int unit, 291 int start_tid, int *status, int trunk_maxnum) 292 { 293 int tid_offset; 294 int tid; 295 int rv; 296 297 for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) { 298 if (status[tid_offset] == 0) { 299 tid = start_tid + tid_offset; 300 rv = bcm_trunk_destroy(unit, tid); 301 if (BCM_FAILURE(rv) && (BCM_E_NOT_FOUND != rv)) { 302 break; 303 } 304 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 305 (BSL_META_U(unit, 306 "Destroyed trunk %d\n"), 307 tid)); 308 } 309 } 310 311 return BCM_E_NONE; 312 } 313 314 315 /* 316 * Function: 317 * _bcm_board_trunk_interconnect_mark 318 * 319 * Purpose: 320 * Iterate through all the existing fabric trunks and find out the 321 * one's which are interconnect trunks. For these trunks mark the 322 * status as 'TRUNK_STATUS_BUSY' in the given status array. 323 * 324 * Parameters: 325 * unit - device of fabric unit 326 * entry - local board's cpudb entry 327 * start - starting tid 328 * status - array to maintain trunk status 329 * trunk_maxnum - max number of fabric trunks 330 * Returns: 331 * BCM_E_NONE 332 */ 333 STATIC int 334 _bcm_board_trunk_interconnect_mark(int unit, cpudb_entry_t *entry, 335 int start, int *status, int trunk_maxnum) 336 { 337 int rv; 338 int tid_offset; 339 int member_prt; 340 int cpudb_prt; 341 _trunk_info_t trunk; 342 343 /* 344 * Check the status of the interconnect/internal trunk and if exists then 345 * do not destroy the interconnects while setting up External Stack Links 346 */ 347 for (tid_offset = 0; tid_offset < trunk_maxnum; tid_offset++) { 348 if (status[tid_offset] == 0) { 349 rv = bcm_trunk_get(unit, (start + tid_offset), &trunk.info, 350 COUNTOF(trunk.member), trunk.member, 351 &trunk.num_ports); 352 if (BCM_SUCCESS(rv)) { 353 354 /* 355 * Check whether this trunk is an interconnect trunk by 356 * comparing the IC trunk ports with the external stacking ports 357 */ 358 for (member_prt = 0, cpudb_prt = 0; 359 member_prt < trunk.num_ports; member_prt++) { 360 361 /* Iterate through the ports in CPUDB */ 362 for (; cpudb_prt < entry->base.num_stk_ports; cpudb_prt++) { 363 /* Skip if port unit is not the one being processed */ 364 if (entry->base.stk_ports[cpudb_prt].unit != unit) { 365 continue; 366 } 367 368 /* 369 * Here stk_ports are external stacking ports only, They 370 * do not include interconnect stacking links. If the 371 * member of this trunk matches with any stacking ports, 372 * then mark the current trunk as non-interconnect. 373 */ 374 if (trunk.member[member_prt].gport 375 == BCM_GPORT_DEVPORT(unit, 376 entry->base.stk_ports[cpudb_prt].port)) { 377 break; 378 } 379 } 380 381 /* 382 * If the trunk port is external stack port then 383 * do not continue with other ports of the trunk. 384 */ 385 if (cpudb_prt < entry->base.num_stk_ports) break; 386 } 387 388 /* If it is interconnect trunk, then update the status */ 389 if ((member_prt >= trunk.num_ports) 390 && (cpudb_prt >= entry->base.num_stk_ports)) { 391 status[tid_offset] = TRUNK_STATUS_BUSY; 392 } 393 } 394 } 395 } 396 397 return BCM_E_NONE; 398 } 399 400 /* 401 * Function: 402 * _bcm_board_trunk_unit 403 * Purpose: 404 * Program fabric trunks for external stack ports (unit specific). 405 * External stack ports for the specified unit are trunked if 406 * the following conditions are met: 407 * - TX CPU keys are the same, and 408 * - If stack-port information for the remote TX CPU entry is valid, 409 * check that the remote stack-port units are the same. 410 * 411 * This routine can be used to create/destroy trunks that are 412 * symmetric as well as asymmetric. 413 * 414 * Symmetric trunks are defined when stack links on a unit are 415 * connected to the same remote unit, or, if different remote units, 416 * these must reside in different CPUs. 417 * 418 * Asymmetric trunks are defined when stack links on a unit are 419 * connected to two different remote units that reside on the 420 * same CPU. To set the trunks correctly, the CPU database must 421 * contain valid stack-port information for remote CPU entries. 422 * 423 * If stack-port information for remote CPU entries is not 424 * available, perform old behavior. 425 * 426 * If a trunk create callback is set, the the callback will be 427 * called with the constructed trunk parameters; the application 428 * must then call bcm_trunk_set(). This allows the application 429 * to affect trunk setup (before trunk creation) and also 430 * perform trunk post processing. 431 * 432 * If there is no callback, then this function will call 433 * bcm_trunk_set() to construct the trunk. 434 * 435 * Parameters: 436 * unit - device of fabric unit 437 * entry - local board's cpudb entry 438 * db_ref - database of current configuration 439 * start - starting tid 440 * flags - control flags 441 * Returns: 442 * BCM_E_XXX 443 * Notes: 444 * Some early discovery versions do not carry stack-port information 445 * for remote CPU entries. 446 */ 447 448 449 STATIC int 450 _bcm_board_trunk_unit(int unit, cpudb_entry_t *entry, cpudb_ref_t db_ref, 451 int start, int flags) 452 { 453 int tid, rv = BCM_E_NONE, i, j; 454 int idx; 455 _trunk_info_t trunk; 456 cpudb_entry_t *tx_entry; 457 cpudb_key_t tx_key; /* TX key, unit on master port to .. */ 458 int tx_unit; /* .. compare against */ 459 cpudb_key_t pkey; /* TX key, unit on other ports being ..*/ 460 int punit; /* .. compare to master port */ 461 bcm_gport_t devport; 462 SHR_BITDCLNAME(pseen, CPUDB_CXN_MAX); 463 int *trunk_status; 464 bcm_trunk_chip_info_t ti; 465 int trunk_maxnum; 466 467 /* Destroy any pre-existing fabric trunks */ 468 if (flags & BCM_BOARD_TRUNK_DESTROY) { 469 for (tid = start;; tid++) { 470 rv = bcm_trunk_destroy(unit, tid); 471 if (BCM_FAILURE(rv) && (BCM_E_NOT_FOUND != rv)) { 472 break; 473 } 474 } 475 if (tid != start) { 476 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 477 (BSL_META_U(unit, 478 "TOPO: destroyed %d trunks\n"), 479 tid-start)); 480 } 481 return BCM_E_NONE; 482 } 483 484 485 BCM_IF_ERROR_RETURN(bcm_trunk_chip_info_get(unit, &ti)); 486 trunk_maxnum = (ti.trunk_fabric_id_max - ti.trunk_fabric_id_min + 1); 487 trunk_status = sal_alloc(trunk_maxnum * sizeof(int), "trunk_status_ptr"); 488 sal_memset(trunk_status, 0, trunk_maxnum * sizeof(int)); 489 490 sal_memset(pseen, 0, SHR_BITALLOCSIZE(CPUDB_CXN_MAX)); 491 sal_memset(&trunk, 0, sizeof(trunk)); 492 trunk.info.psc = -1; /* Default hash algorithm */ 493 trunk.info.dlf_index = -1; 494 trunk.info.mc_index = -1; 495 trunk.info.ipmc_index = -1; 496 tid = start; 497 498 /* 499 * For each external stack port in entry (this is 500 * the master port to compare against 501 */ 502 for (i = 0; i < entry->base.num_stk_ports; i++) { 503 /* Skip if stack port was already analyzed */ 504 if (SHR_BITGET(pseen, i)) { 505 continue; 506 } 507 508 /* Set flag to indicate stack port is being analyzed */ 509 SHR_BITSET(pseen, i); 510 511 /* Skip if TX is not known */ 512 if (!(entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED)) { 513 continue; 514 } 515 516 /* Skip if stack-port unit is not the one being processed */ 517 if (entry->base.stk_ports[i].unit != unit) { 518 continue; 519 } 520 521 /* 522 * Get the remote TX CPU key and unit for the master port 523 */ 524 CPUDB_KEY_COPY(tx_key, entry->sp_info[i].tx_cpu_key); 525 tx_entry = NULL; 526 tx_unit = -1; 527 if (db_ref) { 528 CPUDB_KEY_SEARCH(db_ref, tx_key, tx_entry); 529 if (tx_entry) { 530 idx = entry->sp_info[i].tx_stk_idx; 531 if ((idx >= 0) && (idx < CPUDB_CXN_MAX)) { 532 tx_unit = tx_entry->base.stk_ports[idx].unit; 533 } 534 } 535 } 536 537 /* 538 * Trunk only stack ports with same TX CPU key and 539 * same remote stack-port unit. 540 * 541 * Note: If stack-port information for remote CPU entries 542 * is not available, then check for CPU key only 543 * (old behavior). 544 */ 545 trunk.num_ports = 0; 546 devport = BCM_GPORT_DEVPORT(unit, entry->base.stk_ports[i].port); 547 bcm_trunk_member_t_init(&trunk.member[trunk.num_ports]); 548 trunk.member[trunk.num_ports].gport = devport; 549 trunk.num_ports++; 550 for (j = i+1; j < entry->base.num_stk_ports; j++) { 551 /* 552 * Skip if: stack port was already analyzed, or 553 * TX is not known 554 * stack-port unit is not the one being processed 555 */ 556 if (SHR_BITGET(pseen, j)) { 557 continue; 558 } 559 if (!(entry->sp_info[j].flags & CPUDB_SPF_TX_RESOLVED)) { 560 continue; 561 } 562 if (entry->base.stk_ports[j].unit != unit) { 563 continue; 564 } 565 566 /* 567 * Get other stack port TX CPU key and unit to 568 * compare against master port 569 */ 570 571 if ((flags & BCM_BOARD_TRUNK_ALL) == 0) { 572 CPUDB_KEY_COPY(pkey, entry->sp_info[j].tx_cpu_key); 573 punit = -1; 574 if (tx_unit >= 0) { 575 idx = entry->sp_info[j].tx_stk_idx; 576 if ((idx >= 0) && (idx < CPUDB_CXN_MAX) && tx_entry) { 577 punit = tx_entry->base.stk_ports[idx].unit; 578 } 579 } 580 581 /* Skip port if TX CPU key or unit are different */ 582 if (!CPUDB_KEY_EQUAL(tx_key, pkey) || (tx_unit != punit)) { 583 continue; 584 } 585 586 } 587 588 /* Mark stack port as analyzed, add to trunk group */ 589 SHR_BITSET(pseen, j); 590 devport = BCM_GPORT_DEVPORT(unit, entry->base.stk_ports[j].port); 591 bcm_trunk_member_t_init(trunk.member + trunk.num_ports); 592 trunk.member[trunk.num_ports].gport = devport; 593 trunk.num_ports++; 594 } 595 596 if (trunk.num_ports > 1) { 597 if (bcm_board_trunk_callback_func) { 598 rv = bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid); 599 if (BCM_FAILURE(rv) && (BCM_E_EXISTS != rv)) { 600 goto cleanup; 601 } 602 rv = bcm_board_trunk_callback_func( 603 unit, tid, &trunk.info, trunk.num_ports, 604 trunk.member, bcm_board_trunk_callback_cookie); 605 if (BCM_FAILURE(rv)) { 606 goto cleanup; 607 } 608 trunk_status[tid - start] = TRUNK_STATUS_BUSY; 609 } else { 610 rv = _bcm_board_trunk_make( 611 unit, &trunk, start, trunk_status, trunk_maxnum); 612 if (BCM_FAILURE(rv)) { 613 goto cleanup; 614 } 615 } 616 tid++; 617 } 618 } 619 620 _bcm_board_trunk_interconnect_mark(unit, entry, start, 621 trunk_status, trunk_maxnum); 622 623 /* destroy any left over fabric trunks */ 624 rv = _bcm_board_trunk_remove(unit, start, trunk_status, trunk_maxnum); 625 cleanup: 626 sal_free(trunk_status); 627 628 return rv; 629 } 630 631 /* 632 * Function: 633 * bcm_board_trunk_system 634 * Purpose: 635 * Program fabric trunks for stack ports using system information 636 * provided by CPU database. This routine can be used 637 * to create/destroy trunks that are symmetric as well as asymmetric. 638 * 639 * Symmetric trunks are defined when stack links on a unit are 640 * connected to the same remote unit, or, if different remote units, 641 * these must reside in different CPUs. 642 * 643 * Asymmetric trunks are defined when stack links on a unit are 644 * connected to two different remote units that reside on the 645 * same CPU. To set the trunks correctly, the CPU database must 646 * contain valid stack-port information for remote CPU entries. 647 * 648 * Parameters: 649 * entry - local board's cpudb entry 650 * db_ref - database of current configuration 651 * flags - trunk flags 652 * Returns: 653 * BCM_E_XXX 654 * Note: 655 * Some early discovery versions do not carry stack-port information 656 * for remote CPU entries. 657 */ 658 int 659 bcm_board_trunk_system(cpudb_entry_t *entry, cpudb_ref_t db_ref, int flags) 660 { 661 int unit; 662 bcm_trunk_chip_info_t ti; 663 int auto_trunk; 664 665 666 BCM_IF_ERROR_RETURN(bcm_board_auto_trunk_get(&auto_trunk)); 667 if (auto_trunk) { 668 /* scan for board fabric units */ 669 for (unit = 0; unit < entry->base.num_units; unit++) { 670 BCM_IF_ERROR_RETURN(bcm_trunk_chip_info_get(unit, &ti)); 671 if (ti.trunk_fabric_id_min >= 0) { 672 BCM_IF_ERROR_RETURN 673 (_bcm_board_trunk_unit(unit, entry, db_ref, 674 ti.trunk_fabric_id_min, 675 flags)); 676 } 677 } 678 } 679 return BCM_E_NONE; 680 } 681 682 /* 683 * Function: 684 * bcm_board_trunk_local 685 * Purpose: 686 * Program fabric trunks for stack ports using local information. 687 * When creating trunks, this routine should be used for 688 * symmetric trunks only (see bcm_board_trunk_system for more 689 * information). 690 * 691 * Parameters: 692 * entry - local board's cpudb entry 693 * flags - trunk flags 694 * Returns: 695 * BCM_E_XXX 696 */ 697 int 698 bcm_board_trunk_local(cpudb_entry_t *entry, int flags) 699 { 700 return bcm_board_trunk_system(entry, NULL, flags); 701 } 702 703 /* 704 * Function: 705 * bcm_board_trunk_destroy 706 * Purpose: 707 * Destroy all fabric trunks on board 708 * 709 * Parameters: 710 * entry - local board's cpudb entry 711 * Returns: 712 * BCM_E_XXX 713 */ 714 int 715 bcm_board_trunk_destroy(cpudb_entry_t *entry) 716 { 717 return bcm_board_trunk_system(entry, NULL, BCM_BOARD_TRUNK_DESTROY); 718 } 719 720 /* 721 * Function: 722 * bcm_board__unknown_src_modid_setup 723 * Purpose: 724 * Iterate over local stack ports and set NH src mod ID appropriately 725 * Parameters: 726 * entry - local board's cpudb entry 727 * Returns: 728 * BCM_E_XXX 729 */ 730 int 731 bcm_board_unknown_src_modid_setup(cpudb_entry_t *entry) 732 { 733 int i; 734 bcm_port_t port; 735 int unit, modid; 736 737 nh_tx_unknown_modid_get(&modid); 738 for (i = 0; i < entry->base.num_stk_ports; i++) { 739 unit = entry->base.stk_ports[i].unit; 740 port = entry->base.stk_ports[i].port; 741 742 if (!(entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED) && 743 !(entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED) && 744 !(entry->sp_info[i].flags & CPUDB_SPF_ETHERNET)) { 745 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, 746 port, modid, TRUE)); 747 } 748 } 749 750 return BCM_E_NONE; 751 } 752 753 754 /* 755 * Function: 756 * bcm_board_module_filter 757 * Purpose: 758 * Program fabric source module filtering to prevent 759 * fabric loops. Also programs egress port masking. 760 * Parameters: 761 * unit - fabric device 762 * tp_cpu - topology programming structure 763 * db_ref - database of current configuration 764 * config - port configuration for fabric device 765 * Returns: 766 * BCM_E_XXX 767 * Notes: 768 * Must be called once per board fabric device. 769 * 770 * Some early discovery versions do not carry stack-port information 771 * for remote CPU entries. This is needed for cases where stack 772 * links on a unit are connected to two different remote units 773 * that reside on the same CPU and are interconnected through 774 * their internal stack links. 775 * 776 * If stack-port information for remote CPU entries is not 777 * available, perform old behavior. 778 * 779 * Also, verify that device has the corresponding support 780 * for SOURCE MODID BLOCKING. 781 */ 782 783 784 int 785 bcm_board_module_filter(int unit, 786 topo_cpu_t *tp_cpu, 787 cpudb_ref_t db_ref, 788 bcm_port_config_t *config) 789 { 790 cpudb_entry_t *entry; 791 int i, j, m, rv, enable; 792 bcm_port_t port, eport; 793 bcm_module_t mod; 794 bcm_pbmp_t intports, extports, disports, enaports, ethports; 795 topo_stk_port_t *tsp; 796 int nhmod = -1, nhport; 797 int idx; 798 cpudb_entry_t *rx_entry; 799 cpudb_key_t rx_key; /* RX key, unit on master port to .. */ 800 int rx_unit; /* .. compare against */ 801 cpudb_key_t pkey; /* RX key, unit on other ports being ..*/ 802 int punit; /* .. compare to master port */ 803 int num_modids; 804 SHR_BITDCLNAME(rxmod, BCM_BOARD_MAX_MODID); 805 806 entry = &tp_cpu->local_entry; 807 BCM_PBMP_ASSIGN(intports, config->stack_ext); 808 BCM_PBMP_CLEAR(extports); 809 BCM_PBMP_CLEAR(disports); 810 BCM_PBMP_CLEAR(ethports); 811 812 BCM_IF_ERROR_RETURN(bcm_board_num_modid_get(&num_modids)); 813 for (i = 0; i < entry->base.num_stk_ports; i++) { 814 if (entry->base.stk_ports[i].unit != unit) { 815 continue; 816 } 817 port = entry->base.stk_ports[i].port; 818 819 if ((entry->sp_info[i].flags & CPUDB_SPF_ETHERNET)) { 820 BCM_PBMP_PORT_ADD(ethports, port); 821 continue; 822 } 823 824 /* If we're using a reserved NH modid, or there's no 825 nhmod defined for this stack port, or there was a nhmod 826 for this stack port but it was was less than zero, then get the 827 default */ 828 829 if (bcm_st_reserved_modid_enable_get() || 830 nh_tx_src_mod_port_get(unit, port, &nhmod, &nhport) < 0 || 831 nhmod < 0) { 832 if (nh_tx_src_get(&nhmod, &nhport) < 0 || nhmod < 0) { 833 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 834 (BSL_META_U(unit, 835 "TOPO: Could not get default NH src modid.\n"))); 836 } 837 } 838 839 sal_memset(rxmod, 0, SHR_BITALLOCSIZE(BCM_BOARD_MAX_MODID)); 840 if (nhmod >= 0 && nhmod < num_modids) { 841 SHR_BITSET(rxmod, nhmod); /* add nexthop module */ 842 } 843 844 /* 845 * Get the remote RX CPU key and unit for the master port 846 */ 847 CPUDB_KEY_COPY(rx_key, entry->sp_info[i].rx_cpu_key); 848 rx_entry = NULL; 849 rx_unit = -1; 850 if (db_ref) { 851 CPUDB_KEY_SEARCH(db_ref, rx_key, rx_entry); 852 if (rx_entry) { 853 idx = entry->sp_info[i].rx_stk_idx; 854 if ((idx >= 0) && (idx < CPUDB_CXN_MAX)) { 855 rx_unit = rx_entry->base.stk_ports[idx].unit; 856 } 857 } 858 } 859 860 /* 861 * Allow only mod IDs of those stack ports with same RX CPU key 862 * and same remote stack-port unit. 863 * 864 * Note: If stack-port information for remote CPU entries 865 * is not available, then check for CPU key only 866 * (old behavior). 867 */ 868 for (j = 0; j < entry->base.num_stk_ports; j++) { 869 if (entry->base.stk_ports[j].unit != unit) { 870 continue; 871 } 872 if (!(entry->sp_info[j].flags & CPUDB_SPF_RX_RESOLVED)) { 873 continue; 874 } 875 876 /* 877 * Get other stack port RX CPU key and unit to 878 * compare against master port 879 */ 880 CPUDB_KEY_COPY(pkey, entry->sp_info[j].rx_cpu_key); 881 punit = -1; 882 if (rx_unit >= 0) { 883 idx = entry->sp_info[j].rx_stk_idx; 884 if ((idx >= 0) && (idx < CPUDB_CXN_MAX) && rx_entry) { 885 punit = rx_entry->base.stk_ports[idx].unit; 886 } 887 } 888 889 /* Skip port if RX CPU key or unit are different */ 890 if (!CPUDB_KEY_EQUAL(rx_key, pkey) || (rx_unit != punit)) { 891 continue; 892 } 893 894 /* add modules that are rxable on this stack port */ 895 tsp = &tp_cpu->tp_stk_port[j]; 896 for (m = 0; m < tsp->rx_mod_num; m++) { 897 SHR_BITSET(rxmod, tsp->rx_mods[m]); 898 } 899 } 900 901 for (mod = 0; mod < BCM_BOARD_MAX_MODID; mod++) { 902 enable = SHR_BITGET(rxmod, mod) ? TRUE : FALSE; 903 rv = bcm_port_modid_enable_set(unit, port, mod, enable); 904 if (rv < 0) { 905 break; 906 } 907 } 908 BCM_PBMP_PORT_REMOVE(intports, port); 909 if (entry->sp_info[i].flags & 910 (CPUDB_SPF_TX_RESOLVED|CPUDB_SPF_RX_RESOLVED)) { 911 BCM_PBMP_PORT_ADD(extports, port); 912 } else { 913 BCM_PBMP_PORT_ADD(disports, port); 914 } 915 } 916 917 /* 918 * HG ports are now partitioned into three bitmaps: 919 * extports - external stack ports that have connectivity 920 * disports - external stack ports with no connectivity 921 * intports - internal ports to other switches on the board 922 * 923 * enaports is a bitmap of all enabled ports (intports | extports) 924 */ 925 926 BCM_PBMP_ASSIGN(enaports, intports); 927 BCM_PBMP_OR(enaports, extports); 928 929 /* 930 * Egress port masking works in two classes: 931 * - disabled ingress ports (disports) cannot send to any egress port 932 * (other than the cpu) 933 * - enabled ingress ports (enaports) can send to any other enabled 934 * port 935 */ 936 937 BCM_PBMP_ITER(disports, port) { 938 BCM_PBMP_ITER(config->stack_ext, eport) { 939 rv = bcm_port_flood_block_set(unit, port, eport, -1U); 940 if (rv < 0) { 941 break; 942 } 943 } 944 } 945 946 BCM_PBMP_ITER(enaports, port) { 947 BCM_PBMP_ITER(config->stack_ext, eport) { 948 int flag = BCM_PBMP_MEMBER(enaports, eport) ? 0 : -1; 949 rv = bcm_port_flood_block_set(unit, port, eport, flag); 950 if (rv < 0) { 951 break; 952 } 953 } 954 } 955 956 /* 957 * internal and Ethernet ports allow any module ids 958 */ 959 enable = TRUE; 960 BCM_PBMP_OR(intports, ethports); 961 BCM_PBMP_ITER(intports, port) { 962 rv = bcm_port_modid_enable_set(unit, port, -1, enable); 963 } 964 965 return BCM_E_NONE; 966 } 967 968 969 /* 970 * Add stack ports according to configuration; 971 * Adds internal ports assuming: 972 * Single fabric (funit >= 0) 973 * Each device attached to the fabric has an IPIC port specified. 974 * unitport is indexed by unit number and gives port on fabric 975 */ 976 977 int 978 bcm_board_internal_stk_port_add(int unit, int port) 979 { 980 uint32 flags; 981 982 BCM_IF_ERROR_RETURN(bcm_stk_port_get(unit, port, &flags)); 983 if (!(flags & BCM_STK_ENABLE)) { 984 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, port, 985 BCM_BOARD_INT_STK_FLAGS)); 986 } 987 988 return BCM_E_NONE; 989 } 990 991 STATIC int 992 _bcm_board_xgs_stk_port_add(int funit, topo_cpu_t *tp_cpu, int *unitport) 993 { 994 int unit, port; 995 cpudb_entry_t *l_entry; 996 uint32 flags; 997 998 l_entry = &tp_cpu->local_entry; 999 1000 /* First, make sure internal ports have been added */ 1001 for (unit = 0; unit < l_entry->base.num_units; unit++) { 1002 port = unitport[unit]; 1003 if (port < 0) { /* Skip device (eg fabric module) */ 1004 continue; 1005 } 1006 BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(funit, port)); 1007 1008 if (bcm_stk_port_get(unit, BCM_STK_USE_HG_IF, &flags) < 0) { 1009 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 1010 (BSL_META_U(unit, 1011 "Could not get IPIC stack info for unit %d\n"), 1012 unit)); 1013 continue; 1014 } 1015 if (!(flags & BCM_STK_ENABLE)) { 1016 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, BCM_STK_USE_HG_IF, 1017 BCM_BOARD_INT_STK_FLAGS)); 1018 } 1019 } 1020 1021 return BCM_E_NONE; 1022 } 1023 1024 1025 /* Program stack port mod IDs */ 1026 int 1027 bcm_board_fab_mod_map(int funit, topo_cpu_t *tp_cpu, cpudb_entry_t *l_entry) 1028 { 1029 int i, m; 1030 topo_stk_port_t *tsp; 1031 bcm_port_t port; 1032 bcm_module_t mod; 1033 1034 /* set up module routing for fabric ports */ 1035 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 1036 tsp = &tp_cpu->tp_stk_port[i]; 1037 port = l_entry->base.stk_ports[i].port; 1038 1039 for (m = 0; m < tsp->tx_mod_num; m++) { 1040 mod = tsp->tx_mods[m]; 1041 BCM_IF_ERROR_RETURN(bcm_stk_modport_set(funit, mod, port)); 1042 } 1043 } 1044 1045 return BCM_E_NONE; 1046 } 1047 1048 /* 1049 * Common code for XGS boards with 1050 * a single fabric device (5670, 5671) and 1051 * 0 or more switch devices (5690, 5673, etc) 1052 */ 1053 1054 STATIC int 1055 _bcm_board_xgs_connection_add(int funit, 1056 bcm_board_port_connection_t *connection, 1057 int num_connections) 1058 { 1059 int unit, fport, sport; 1060 uint32 flags; 1061 1062 /* First, make sure internal ports have been added */ 1063 for (unit = 0; unit < num_connections; unit++) { 1064 fport = connection[unit].to; 1065 if (fport < 0) { /* Skip device (eg fabric module) */ 1066 continue; 1067 } 1068 BCM_IF_ERROR_RETURN(bcm_board_internal_stk_port_add(funit, fport)); 1069 1070 sport = connection[unit].from; 1071 if (bcm_stk_port_get(unit, sport, &flags) < 0) { 1072 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 1073 (BSL_META_U(unit, 1074 "Could not get stack info for (%d,%d)\n"), 1075 unit, sport)); 1076 continue; 1077 } 1078 if (!(flags & BCM_STK_ENABLE)) { 1079 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, sport, 1080 BCM_BOARD_INT_STK_FLAGS)); 1081 } 1082 } 1083 1084 return BCM_E_NONE; 1085 } 1086 1087 1088 int 1089 bcm_board_xgs_local_switch(int funit, 1090 topo_cpu_t *tp_cpu, 1091 bcm_port_config_t *config, 1092 bcm_board_port_connection_t *connection) 1093 { 1094 int i, m, unit; 1095 cpudb_entry_t *l_entry; 1096 bcm_port_t hport, port; 1097 bcm_pbmp_t pbm, empty; 1098 bcm_module_t mod; 1099 1100 l_entry = &tp_cpu->local_entry; 1101 1102 BCM_IF_ERROR_RETURN( 1103 _bcm_board_xgs_connection_add(funit, 1104 connection, 1105 l_entry->base.num_units)); 1106 1107 /* program fabric for how to get to local units */ 1108 BCM_PBMP_CLEAR(empty); 1109 for (unit = 0; unit < l_entry->base.num_units; unit++) { 1110 port = connection[unit].to; 1111 if (port < 0) { 1112 continue; 1113 } 1114 mod = l_entry->mod_ids[unit]; 1115 if (mod < 0) { 1116 continue; 1117 } 1118 m = l_entry->base.mod_ids_req[unit]; 1119 BCM_PBMP_PORT_SET(pbm, port); 1120 BCM_PBMP_ITER(config->hg, hport) { 1121 for (i = 0; i < m; i++) { 1122 BCM_IF_ERROR_RETURN 1123 (bcm_stk_ucbitmap_set(funit, hport, mod+i, 1124 hport == port ? empty : pbm)); 1125 } 1126 } 1127 } 1128 1129 for (unit = 0; unit < l_entry->base.num_units; unit++) { 1130 if (unit == funit) { /* skip fabric */ 1131 continue; 1132 } 1133 mod = l_entry->mod_ids[unit]; 1134 if (mod >= 0) { 1135 BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod)); 1136 BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit)); 1137 } 1138 } 1139 1140 return BCM_E_NONE; 1141 } 1142 1143 1144 int 1145 bcm_board_xgs_local_fabric(int funit, 1146 topo_cpu_t *tp_cpu, 1147 bcm_port_config_t *config) 1148 { 1149 int i, m; 1150 topo_stk_port_t *tsp; 1151 cpudb_entry_t *l_entry; 1152 bcm_module_t mod; 1153 bcm_info_t info; 1154 bcm_port_t port, hport; 1155 bcm_pbmp_t pbm; 1156 1157 /* 1158 * Module programming for fabric 1159 * (usually only occurs if board is fabric only) 1160 */ 1161 l_entry = &tp_cpu->local_entry; 1162 mod = l_entry->mod_ids[funit]; 1163 if (mod >= 0) { 1164 BCM_IF_ERROR_RETURN(bcm_info_get(funit, &info)); 1165 if (info.capability & BCM_INFO_FABRIC) { 1166 BCM_PBMP_ITER(config->hg, hport) { 1167 BCM_IF_ERROR_RETURN 1168 (bcm_stk_ucbitmap_set(funit, hport, mod, config->cpu)); 1169 } 1170 } 1171 } 1172 1173 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 1174 tsp = &tp_cpu->tp_stk_port[i]; 1175 port = l_entry->base.stk_ports[i].port; 1176 1177 for (m = 0; m < tsp->tx_mod_num; m++) { 1178 mod = tsp->tx_mods[m]; 1179 1180 BCM_PBMP_ITER(config->hg, hport) { 1181 BCM_PBMP_CLEAR(pbm); 1182 if (hport != port) { 1183 BCM_PBMP_PORT_ADD(pbm, port); 1184 } 1185 #ifdef BCM_ESW_SUPPORT 1186 BCM_IF_ERROR_RETURN 1187 (_bcm_esw_mirror_stk_update(funit, mod, hport, pbm)); 1188 #endif 1189 } 1190 } 1191 } 1192 1193 return BCM_E_NONE; 1194 } 1195 1196 /* 1197 * Common code for XGS boards with 1198 * a single fabric device (5670, 5671) and 1199 * 0 or more switch devices (5690, 5673, etc) 1200 */ 1201 1202 1203 1204 int 1205 bcm_board_xgs_common(int funit, topo_cpu_t *tp_cpu, cpudb_ref_t db_ref, 1206 int *unitport) 1207 { 1208 int i, m, unit; 1209 topo_stk_port_t *tsp; 1210 bcm_pbmp_t pbm, empty; 1211 cpudb_entry_t *l_entry; 1212 bcm_port_t port, hport; 1213 bcm_module_t mod; 1214 bcm_port_config_t config; 1215 bcm_info_t info; 1216 1217 /* Notify BCM layer of internal stack ports */ 1218 BCM_IF_ERROR_RETURN(_bcm_board_xgs_stk_port_add(funit, tp_cpu, unitport)); 1219 1220 l_entry = &tp_cpu->local_entry; 1221 1222 BCM_IF_ERROR_RETURN(bcm_port_config_get(funit, &config)); 1223 1224 /* program fabric for how to get to local units */ 1225 BCM_PBMP_CLEAR(empty); 1226 for (unit = 0; unit < l_entry->base.num_units; unit++) { 1227 port = unitport[unit]; 1228 if (port < 0) { 1229 continue; 1230 } 1231 mod = l_entry->mod_ids[unit]; 1232 if (mod < 0) { 1233 continue; 1234 } 1235 m = l_entry->base.mod_ids_req[unit]; 1236 BCM_PBMP_PORT_SET(pbm, port); 1237 BCM_PBMP_ITER(config.hg, hport) { 1238 for (i = 0; i < m; i++) { 1239 BCM_IF_ERROR_RETURN 1240 (bcm_stk_ucbitmap_set(funit, hport, mod+i, 1241 hport == port ? empty : pbm)); 1242 } 1243 } 1244 } 1245 1246 unit = funit; /* board fabric unit */ 1247 1248 /* 1249 * Module programming for fabric 1250 * (usually only occurs if board is fabric only) 1251 */ 1252 mod = l_entry->mod_ids[unit]; 1253 if (mod >= 0) { 1254 BCM_IF_ERROR_RETURN(bcm_info_get(unit, &info)); 1255 if (info.capability & BCM_INFO_FABRIC) { 1256 BCM_PBMP_ITER(config.hg, hport) { 1257 BCM_IF_ERROR_RETURN 1258 (bcm_stk_ucbitmap_set(unit, hport, mod, config.cpu)); 1259 } 1260 } 1261 } 1262 1263 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 1264 tsp = &tp_cpu->tp_stk_port[i]; 1265 port = l_entry->base.stk_ports[i].port; 1266 1267 for (m = 0; m < tsp->tx_mod_num; m++) { 1268 mod = tsp->tx_mods[m]; 1269 1270 BCM_PBMP_ITER(config.hg, hport) { 1271 BCM_PBMP_CLEAR(pbm); 1272 if (hport != port) { 1273 BCM_PBMP_PORT_ADD(pbm, port); 1274 } 1275 #ifdef BCM_ESW_SUPPORT 1276 BCM_IF_ERROR_RETURN 1277 (_bcm_esw_mirror_stk_update(unit, mod, hport, pbm)); 1278 #endif 1279 } 1280 } 1281 } 1282 1283 BCM_IF_ERROR_RETURN(bcm_board_fab_mod_map(funit, tp_cpu, l_entry)); 1284 BCM_IF_ERROR_RETURN(bcm_board_module_filter(unit, tp_cpu, db_ref, 1285 &config)); 1286 BCM_IF_ERROR_RETURN(bcm_board_trunk_system(l_entry, db_ref, TRUE)); 1287 1288 /* 1289 * Transient state setup: program dflt modid if ports 1290 * are not resolved 1291 */ 1292 bcm_board_unknown_src_modid_setup(l_entry); 1293 1294 /* 1295 * Module programming for switches 1296 */ 1297 for (unit = 0; unit < l_entry->base.num_units; unit++) { 1298 if (unit == funit) { /* skip fabric */ 1299 continue; 1300 } 1301 mod = l_entry->mod_ids[unit]; 1302 if (mod >= 0) { 1303 BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, mod)); 1304 BCM_IF_ERROR_RETURN(bcm_stk_modport_clear_all(unit)); 1305 } 1306 } 1307 1308 #ifdef BCM_BOARD_AUTO_E2E 1309 /* intra-board end to end flow control, if available */ 1310 BCM_IF_ERROR_RETURN(bcm_board_e2e_set()); 1311 #endif /* BCM_BOARD_AUTO_E2E */ 1312 1313 return BCM_E_NONE; 1314 } 1315 1316 /* 1317 * Find output stack port on src_unit to get to a remote modid 1318 */ 1319 int 1320 bcm_board_topomap_stk(int src_unit, int dest_modid, bcm_port_t *exit_port) 1321 { 1322 cpudb_unit_port_t *stk_port; 1323 topo_cpu_t *tp_cpu; 1324 int sp_idx, m_idx; 1325 int mod_id; 1326 1327 /* Remote module ID; look up in CPU database */ 1328 bcm_board_topo_get(&tp_cpu); 1329 if (tp_cpu == NULL) { 1330 return BCM_E_INIT; 1331 } 1332 1333 /* Search topo info for the stack port with the given mod id */ 1334 TOPO_FOREACH_STK_PORT(stk_port, tp_cpu, sp_idx) { 1335 TOPO_FOREACH_TX_MODID(mod_id, tp_cpu, sp_idx, m_idx) { 1336 if (dest_modid == mod_id && stk_port->unit == src_unit) { 1337 *exit_port = stk_port->port; 1338 return BCM_E_NONE; 1339 } 1340 } 1341 } 1342 1343 return BCM_E_NOT_FOUND; 1344 } 1345 1346 int 1347 bcm_board_untrunkable_stack_ports(int unit, topo_cpu_t *tp_cpu) 1348 { 1349 int i, punit; 1350 bcm_port_t port; 1351 cpudb_entry_t *l_entry; 1352 1353 l_entry = &tp_cpu->local_entry; 1354 for (i=0; i < l_entry->base.num_stk_ports; i++) { 1355 punit = l_entry->base.stk_ports[i].unit; 1356 port = l_entry->base.stk_ports[i].port; 1357 1358 if (unit != punit) { 1359 continue; 1360 } 1361 1362 if (l_entry->sp_info[i].flags & CPUDB_SPF_CUT_PORT) { 1363 BCM_IF_ERROR_RETURN(bcm_port_modid_enable_set(unit, 1364 port, 1365 -1, 1366 0)); 1367 } 1368 } 1369 1370 return BCM_E_NONE; 1371 } 1372 1373 /* 1374 * Rapid Recovery 1375 */ 1376 1377 /* 1378 * Function: 1379 * bcm_board_topo_trunk_failover 1380 * Purpose: 1381 * Re-programs the local board to recover from a trunk link failure 1382 * case. 1383 * Parameters: 1384 * topo_cpu - Local topology 1385 * unit - Unit of failed stack port 1386 * fail_sp - Failed stack port 1387 * faiL_sp_idx - Failed stack port index 1388 * tid - Trunk id of failed stack port 1389 * trunk - New trunk information; should NOT contain the failed 1390 * stack port 1391 * member_count - Number of trunk members in member_array 1392 * member_array - Array of trunk members 1393 * Returns: 1394 * BCM_E_NONE - Success 1395 * BCM_E_XXX - System cannot perform rapid recovery 1396 * 1397 * Note: 1398 * Caller MUST provide new trunk information in argument. 1399 */ 1400 int 1401 bcm_board_topo_trunk_failover(topo_cpu_t *topo_cpu, 1402 int unit, bcm_port_t fail_sp, int fail_sp_idx, 1403 bcm_trunk_t tid, bcm_trunk_info_t *trunk, 1404 int member_count, 1405 bcm_trunk_member_t *member_array) 1406 { 1407 int i, rv; 1408 bcm_module_t mod; 1409 bcm_port_t port; 1410 bcm_port_t repl_sp; /* Port to replace failed port */ 1411 topo_stk_port_t *fail_topo_sp; /* Topo info for failed port */ 1412 int mirr_dir; /* True if mode is directed mirroring */ 1413 1414 1415 /* Get first active port of trunk to replace failed port */ 1416 if (member_count <= 0) { /* Trunk should contain at least 1 port */ 1417 return BCM_E_FAIL; 1418 } 1419 BCM_IF_ERROR_RETURN 1420 (bcm_port_local_get(unit, member_array[0].gport, &repl_sp)); 1421 1422 /* 1423 * Destination-module port table 1424 */ 1425 fail_topo_sp = &topo_cpu->tp_stk_port[fail_sp_idx]; 1426 1427 for (i = 0; i < fail_topo_sp->tx_mod_num; i++) { 1428 mod = fail_topo_sp->tx_mods[i]; 1429 BCM_IF_ERROR_RETURN(bcm_stk_modport_get(unit, mod, &port)); 1430 if (port == fail_sp) { 1431 BCM_IF_ERROR_RETURN(bcm_stk_modport_set(unit, mod, repl_sp)); 1432 } 1433 } 1434 1435 /* 1436 * Fabric trunk 1437 * 1438 * Note: The trunk is kept with 1 additional port member left 1439 */ 1440 BCM_IF_ERROR_RETURN 1441 (bcm_trunk_set(unit, tid, trunk, member_count, member_array)); 1442 1443 /* 1444 * Mirror 1445 */ 1446 rv = bcm_switch_control_get(unit, bcmSwitchDirectedMirroring, &mirr_dir); 1447 if (BCM_FAILURE(rv)) { 1448 mirr_dir = 0; 1449 } 1450 /* Non-directed mirroring or Draco compat mode requires update */ 1451 if (!mirr_dir) { 1452 bcm_port_config_t config; 1453 bcm_port_t hport; 1454 bcm_pbmp_t mtp_pbmp; 1455 1456 /* MTP bitmap on HG ports */ 1457 BCM_IF_ERROR_RETURN(bcm_port_config_get(unit, &config)); 1458 BCM_PBMP_ITER(config.hg, hport) { 1459 BCM_PBMP_CLEAR(mtp_pbmp); 1460 rv = bcm_mirror_to_pbmp_get(unit, hport, &mtp_pbmp); 1461 if (rv == BCM_E_UNAVAIL) { 1462 continue; 1463 } 1464 BCM_IF_ERROR_RETURN(rv); 1465 1466 /* Update if failed port is part of the mirror mtp pbmp */ 1467 if (BCM_PBMP_MEMBER(mtp_pbmp, fail_sp)) { 1468 BCM_PBMP_PORT_REMOVE(mtp_pbmp, fail_sp); 1469 BCM_PBMP_PORT_ADD(mtp_pbmp, repl_sp); 1470 BCM_IF_ERROR_RETURN(bcm_mirror_to_pbmp_set(unit, hport, 1471 mtp_pbmp)); 1472 } 1473 } 1474 1475 /* MTP port */ 1476 BCM_IF_ERROR_RETURN(bcm_mirror_to_get(unit, &port)); 1477 if (port == fail_sp) { 1478 if (BCM_FAILURE(bcm_mirror_to_set(unit, repl_sp))) { 1479 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1480 (BSL_META_U(unit, 1481 "Cannot set MTP on unit %d, port %d\n"), 1482 unit, repl_sp)); 1483 return BCM_E_FAIL; 1484 } 1485 } 1486 } 1487 1488 return BCM_E_NONE; 1489 }