safc.c (55970B)
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: safc.c 8 * Purpose: SAFC board programming implementation 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/alloc.h> 14 #include <bcm/types.h> 15 #include <bcm/error.h> 16 #include <bcm/field.h> 17 #include <bcm/stack.h> 18 #include <appl/stktask/topology.h> 19 #include <appl/stktask/topo_pkt.h> 20 #include <appl/stktask/topo_brd.h> 21 #include <appl/stktask/stktask.h> 22 #include <appl/cputrans/nh_tx.h> 23 #include <appl/stktask/safc.h> 24 #include "topo_int.h" 25 26 /* 27 Generic topology matrix handling. 28 */ 29 30 31 #define TX_CXN(topo_info, src_idx, dest_idx) \ 32 (topo_info->tp_tx_cxns[db_ref->num_cpus * src_idx + dest_idx]) 33 34 #define RX_CXN(topo_info, src_idx, dest_idx) \ 35 (topo_info->tp_rx_cxns[db_ref->num_cpus * src_idx + dest_idx]) 36 37 /* modid, unit, stack port index set types */ 38 typedef SHR_BITDCLNAME(modset_t, TOPO_MODIDS_MAX); 39 typedef SHR_BITDCLNAME(uset_t, BCM_MAX_NUM_UNITS); 40 typedef SHR_BITDCLNAME(stkset_t, CPUDB_CXN_MAX); 41 42 /* SAFC programming data 43 44 'normal' means a port that handles non-SAFC traffic only 45 'safc' means a port than handles SAFC traffic and non-SAFC traffic 46 47 This is because a SAFC ports are a subset of all stack ports. 48 49 'all' is the union of normal and safc ports 50 51 */ 52 typedef struct safc_data_s { 53 /* topology inputs */ 54 topo_cpu_t *tp_cpu; 55 cpudb_ref_t db_ref; 56 topo_info_t *safc_topo; 57 58 /* BCM programming inputs */ 59 int group_priority; 60 bcm_field_group_t group[BCM_MAX_NUM_UNITS]; 61 bcm_field_qset_t qset; 62 uint32 safc_cos_map; 63 uint32 safc_vlan_mask; 64 bcm_port_config_t port_config[BCM_MAX_NUM_UNITS]; 65 66 /* derived */ 67 uset_t units; /* set of units with stack ports */ 68 int s_idx[TOPO_MODIDS_MAX]; /* modid to safc sp index */ 69 int n_idx[TOPO_MODIDS_MAX]; /* modid to normal sp index */ 70 modset_t modid[CPUDB_CXN_MAX]; /* sp index to modid set */ 71 modset_t blocked[CPUDB_CXN_MAX]; /* sp index to blocked modid set */ 72 modset_t all_modid; /* all modids in stack */ 73 bcm_pbmp_t trunk[CPUDB_CXN_MAX]; /* sp index to trunk ports */ 74 int t_idx[CPUDB_CXN_MAX]; /* sp/trunk mapping */ 75 bcm_pbmp_t none_pbm_mask; /* empty PBM */ 76 bcm_pbmp_t all_pbm_mask; /* full PBM */ 77 78 bcm_pbmp_t safc_pbm[BCM_MAX_NUM_UNITS]; /* SAFC stack PBM */ 79 bcm_pbmp_t normal_pbm[BCM_MAX_NUM_UNITS]; /* normal *only* stack PBM */ 80 stkset_t safc; /* set of SAFC sp idxs */ 81 stkset_t normal; /* set of normal sp idxs */ 82 stkset_t trunked; /* set of trunked sp idxs */ 83 stkset_t s_visit; /* visited flags for collect */ 84 /* true if this system has *only* SAFC ports*/ 85 int safc_only; 86 87 } safc_data_t; 88 89 /* iterator function pointers */ 90 typedef int (*_ufunc_t)(safc_data_t *info, int unit); 91 typedef int (*_pfunc_t)(safc_data_t *info, int spidx); 92 typedef int (*_cfunc_t)(safc_data_t *info, int unit, bcm_cos_t cos); 93 94 /* unit iterator */ 95 STATIC int 96 _bcm_board_safc_unit_iterate(safc_data_t *info, _ufunc_t func) 97 { 98 int unit; 99 int rv; 100 101 rv = BCM_E_NONE; 102 103 for (unit = 0; unit < BCM_MAX_NUM_UNITS; unit++) { 104 if (SHR_BITGET(info->units, unit)) { 105 rv = func(info, unit); 106 if (BCM_FAILURE(rv)) { 107 break; 108 } 109 } 110 } 111 112 return rv; 113 } 114 115 /* stack port iterator */ 116 STATIC int 117 _bcm_board_safc_stkport_iterate(safc_data_t *info, _pfunc_t func) 118 { 119 int rv; 120 int i; 121 122 rv = BCM_E_NONE; 123 124 for (i = 0; i < info->db_ref->local_entry->base.num_stk_ports; i++) { 125 rv = func(info, i); 126 if (BCM_FAILURE(rv)) { 127 break; 128 } 129 } 130 131 return rv; 132 } 133 134 /* cos iterator */ 135 STATIC int 136 _bcm_board_safc_cos_iterate(safc_data_t *info, int unit, _cfunc_t func) 137 { 138 bcm_cos_t cos; 139 int rv; 140 141 for (cos = BCM_COS_MAX; cos >= BCM_COS_MIN; cos--) { 142 if ((info->safc_cos_map & (1<<cos)) == 0) { 143 continue; 144 } 145 rv = func(info, unit, cos); 146 BCM_IF_ERROR_RETURN(rv); 147 } 148 return BCM_E_NONE; 149 } 150 151 152 153 /* 154 Allocate a TX/RX topology matrix. 155 */ 156 topo_info_t *_topo_info_t_create(cpudb_ref_t db_ref) 157 { 158 topo_info_t *topo; 159 uint8 *rx, *tx; 160 int topo_len, cpu_mtx_len; /* CPUxCPU matrix */ 161 162 topo_len = sizeof(*topo); 163 cpu_mtx_len = db_ref->num_cpus * db_ref->num_cpus; 164 165 topo = sal_alloc(topo_len, "topo_info_t_create"); 166 rx = sal_alloc(cpu_mtx_len, "topo_info_t_create"); 167 tx = sal_alloc(cpu_mtx_len, "topo_info_t_create"); 168 if (topo != NULL && rx != NULL && tx != NULL) { 169 sal_memset(topo, 0, topo_len); 170 sal_memset(rx, TOPO_CXN_UNKNOWN, cpu_mtx_len); 171 sal_memset(tx, TOPO_CXN_UNKNOWN, cpu_mtx_len); 172 topo->tp_rx_cxns = rx; 173 topo->tp_tx_cxns = tx; 174 } else { 175 if (rx) { 176 sal_free(rx); 177 } 178 if (tx) { 179 sal_free(tx); 180 } 181 if (topo) { 182 sal_free(topo); 183 184 } 185 topo = NULL; 186 } 187 188 return topo; 189 190 } 191 192 /* Mark all cut ports disabled */ 193 STATIC void 194 _bcm_topo_disable_cut_ports(cpudb_ref_t db_ref) 195 { 196 cpudb_entry_t *entry; 197 int i; 198 199 CPUDB_FOREACH_ENTRY(db_ref, entry) { 200 for (i = 0; i < entry->base.num_stk_ports; i++) { 201 if (entry->sp_info[i].flags & CPUDB_SPF_CUT_PORT) { 202 entry->sp_info[i].flags |= CPUDB_SPF_TX_DISABLE_FORCE; 203 } 204 } 205 } 206 } 207 208 /* copy out topo info from cpudb */ 209 STATIC void 210 _bcm_topo_info_copy(topo_info_t *connection, cpudb_ref_t db_ref) 211 { 212 topo_info_t *from; 213 int cpu_mtx_len; 214 215 from = (topo_info_t *)db_ref->topo_cookie; 216 cpu_mtx_len = db_ref->num_cpus * db_ref->num_cpus; 217 218 if (from) { 219 sal_memcpy(connection->tp_rx_cxns, from->tp_rx_cxns, cpu_mtx_len); 220 sal_memcpy(connection->tp_tx_cxns, from->tp_tx_cxns, cpu_mtx_len); 221 } 222 } 223 224 /* Create a spanning tree topology from the existing CPUDB */ 225 STATIC int 226 _bcm_topo_use_cut_port_spanning_tree(cpudb_ref_t db_ref, 227 topo_info_t *connection) 228 { 229 cpudb_ref_t newdb; 230 topo_cpu_t *tp_cpu; 231 int rv; 232 233 rv = BCM_E_INTERNAL; 234 235 /* topo_cpu_t is pretty big, so alloc from heap, not stack */ 236 tp_cpu = sal_alloc(sizeof(*tp_cpu), "_bcm_topo_spt"); 237 238 if (tp_cpu != NULL) { 239 newdb = cpudb_copy(db_ref); 240 if (newdb != NULL) { 241 _bcm_topo_disable_cut_ports(newdb); 242 rv = bcm_stack_topo_create(newdb, tp_cpu); 243 if (BCM_SUCCESS(rv)) { 244 _bcm_topo_info_copy(connection, newdb); 245 } 246 cpudb_destroy(newdb); 247 } else { 248 rv = BCM_E_MEMORY; 249 } 250 sal_free(tp_cpu); 251 } else { 252 rv = BCM_E_MEMORY; 253 } 254 255 return rv; 256 } 257 258 /* Generic spanning tree calculator - not implemented yet */ 259 STATIC int 260 _bcm_topo_spanning_tree_create(cpudb_ref_t db_ref, 261 cpudb_entry_t *root, 262 topo_info_t *connection) 263 { 264 COMPILER_REFERENCE(db_ref); 265 COMPILER_REFERENCE(root); 266 COMPILER_REFERENCE(connection); 267 268 return BCM_E_UNAVAIL; 269 } 270 271 272 /* 273 * Function: 274 * bcm_stack_spanning_tree_create(cpudb_ref_t db_ref, 275 * cpudb_entry_t *root_entry, 276 * topo_info_t **connection) 277 * Purpose: 278 * Calculate a local spanning tree topology from db_ref rooted at 279 * root_entry, returning a connection matrix 'connection'. 280 * Parameters: 281 * db_ref - (IN) CPU database 282 * root_entry - (IN) Root of spanning tree 283 * connection - (OUT) Calculated topology 284 * Returns: 285 * BCM_E_NONE - no errors 286 * BCM_E_PARAM - db_ref NULL, db_ref not fully constructed 287 * BCM_E_MEMORY - not enough memory or system resources 288 * BCM_E_FAIL - topology calculation failed (CPUDB incomplete) 289 * Notes: 290 * Does not perform any device programming. 291 * 292 * If root_entry is NULL, then the spanning tree is recovered from 293 * the existing 'CUT Ports' calculated from the default topology. 294 */ 295 296 int 297 bcm_stack_spanning_tree_create(cpudb_ref_t db_ref, 298 cpudb_entry_t *root, 299 topo_info_t **connection) 300 { 301 int rv; 302 topo_info_t *conn = NULL; 303 304 rv = BCM_E_PARAM; 305 306 if (!cpudb_valid(db_ref)) { 307 return BCM_E_PARAM; 308 } 309 310 if (db_ref->num_cpus > 1) { 311 conn = _topo_info_t_create(db_ref); 312 if (conn == NULL) { 313 return BCM_E_MEMORY; 314 } 315 316 if (root == NULL) { 317 /* As a shortcut, use existing cut port topology as the 318 spanning tree */ 319 rv = _bcm_topo_use_cut_port_spanning_tree(db_ref, conn); 320 } else { 321 /* (re)calculate a spanning tree */ 322 rv = _bcm_topo_spanning_tree_create(db_ref, root, conn); 323 } 324 } else { 325 /* More than one CPU is required for a useful topology */ 326 rv = BCM_E_NONE; 327 } 328 329 if (BCM_SUCCESS(rv)) { 330 *connection = conn; 331 } else { 332 (void)bcm_stack_connection_destroy(conn); 333 } 334 335 return rv; 336 } 337 338 339 /* 340 * Function: 341 * int bcm_stack_connection_destroy(topo_info_t *connection) 342 * Purpose: 343 * Free a connection data structure 344 * Parameters: 345 * connection - (IN) connection structure 346 * Returns: 347 * BCM_E_NONE - no errors 348 * BCM_E_FAIL - error 349 */ 350 351 int 352 bcm_stack_connection_destroy(topo_info_t *connection) 353 { 354 if (connection) { 355 sal_free((void *)connection->tp_tx_cxns); 356 sal_free((void *)connection->tp_rx_cxns); 357 sal_free((void *)connection); 358 } 359 360 return BCM_E_NONE; 361 } 362 363 364 365 /* 366 Problem - When SAFC is enabled in a ring configuration (or Stack) 367 the flow control among XGS devices create a deadlock in the ring. 368 369 Solution - Break the loop structure of the ring configuration among 370 XGS devices "just" for the SAFC enabled traffic. To break the loop 371 structure of the ring, SAFC traffic is redirected to a new Higig 372 distribution configuration using IFP. Basically the current 373 MODPORT_MAP Table would generate two HiGIG Output ports for an 374 outgoing Higig packet (one for SAFC Traffic, and one for non-SAFC) 375 and IFP, based on Traffic class, shall mask one of the outgoing 376 Higig Ports (by an IFP rule to "and" the Port Bit Map). 377 378 For SAFC-traffic: One pre-designated Higig link in the ring shall be 379 disabled using IFP for SAFC traffic. XGS devices that are connected 380 to the disabled link will not allow SAFC-traffic to be forwarded to 381 the this link using an IFP rule. All other XGS devices (which are 382 not connected to the disabled link) will forward SAFC traffic 383 without applying the regular "SRC MODID based block" . 384 385 For Non-SAFC-Traffic: IFP will apply the SRC_MODID based mask 386 (instead of the traditional table driven Mask) so that non-SAFC 387 traffic is forwarded as today. Non-SAFC traffic is allowed to flow 388 through the disabled link also. 389 390 The following IFP rules are required - (assuming 16 nodes in a ring, 391 and one SAFC traffic class and rest are non-SAFC) 392 393 Packets from Higig Ports - (2 rules for every ingress Higig Port) 394 395 o Either IFP higher precedence rule for "SAFC allow" for devices 396 that don't have a SAFC-disabled link (Traffic with a specific TC 397 value will be unconditionally allowed to go to the outgoing 398 Higig-port), Or- IFP higher precedence rule for "SAFC block" for 399 devices that have a SAFC-disabled link. (Traffic with a specific 400 TC value will be unconditionally not allowed to go to the outgoing 401 Higig-port). 402 403 o IFP lower precedence rule for not allowing packet from a 404 specific "SRC_MOD_ID" to go to the outgoing Higig port. This rule 405 is to replace the current table driven SRC_MOD_ID block. The 406 specific SRC_MOD_ID that each node is blocking is dependent on the 407 relative position of the device in the ring. 408 NOTE: this rule is not used in this implementation. Instead, egress 409 masking is used. 410 411 For Front Panel Packets - (16 DST_MOD_ID based rules SAFC Unicast, 412 16 DST-MODID based rules for non-SAFC Unicast, 1 rule for SAFC 413 Non-Unicast, 1 rule for non-SAFC Non-Unicast) 414 415 o For SAFC- Unicast Traffic, block the local Higig Port that is 416 used for the Non-SAFC Distribution Tree. If, for the current node, 417 both SAFC and non-SAFC trees use the same local port, then this 418 rule has no effect. (For a specific TC, destined to a specific 419 MOD_ID, if the packet is Unicast, apply an "and-pbm" to block the 420 non-SAFC local port) 421 422 o For SAFC-Non-Unicast Traffic, allow the packet to be forwarded 423 to only SAFC -local Higig ports. 424 425 o For Non-SAFC- Unicast Traffic, block the local Higig Port that 426 is used for the SAFC Distribution Tree. If, for the current node, 427 both SAFC and non-SAFC trees use the same local port, then this 428 rule has no effect. (For a specific TC, destined to a specific 429 MOD_ID, if the packet is Unicast, apply an "and-pbm" to block the 430 SAFC local port) 431 432 o For Non-SAFC-Non-Unicast Traffic, allow the packet to be 433 forwarded to only non SAFC- local Higig ports. 434 435 For packets that are mirrored, SAFC distribution tree is selected by 436 mapping the DST_MODID to a local Port using the IM/EM_MOD_PORT_MAP 437 Table. Since IFP rules are not applied to mirror-copy the packet will 438 be forwarded through the ring back to the originating device where 439 it shall be dropped (as done today using the non-SAFC tree). 440 441 */ 442 443 typedef struct { 444 int found; /* true if group found */ 445 int priority; /* priority to search for */ 446 bcm_field_group_t group; /* group which matches priority */ 447 } group_info_t; 448 449 /* traverse function to find group matching a priority */ 450 STATIC int 451 _bcm_board_safc_find_group(int unit, bcm_field_group_t group, void *user) 452 { 453 group_info_t *gi; 454 int priority; 455 int rv; 456 457 gi = (group_info_t *)user; 458 rv = bcm_field_group_priority_get(unit, group, &priority); 459 if (BCM_SUCCESS(rv) && priority == gi->priority) { 460 gi->found = TRUE; 461 gi->group = group; 462 } 463 464 return BCM_E_NONE; 465 } 466 467 #define SAFC_DEBUG 1 468 469 #ifdef SAFC_DEBUG 470 471 /* create a debug counter */ 472 STATIC int 473 _bcm_board_safc_count_create(int unit, 474 bcm_field_group_t group, 475 bcm_field_entry_t entry, 476 const char *locus) 477 { 478 bcm_field_stat_t stat; 479 int id; 480 int rv; 481 482 stat = bcmFieldStatPackets; 483 484 rv = bcm_field_stat_create(unit, group, 1, &stat, &id); 485 BCM_IF_ERROR_RETURN(rv); 486 487 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 488 (BSL_META("counter %d@%s\n"), 489 id, locus)); 490 return 491 (bcm_field_entry_stat_attach(unit, entry, id)); 492 493 } 494 495 496 /* destroy a debug counter */ 497 STATIC int 498 _bcm_board_safc_count_destroy(int unit, bcm_field_entry_t entry) 499 { 500 int id; 501 int rv; 502 503 rv = bcm_field_entry_stat_get(unit, entry, &id); 504 BCM_IF_ERROR_RETURN(rv); 505 506 rv = bcm_field_entry_stat_detach(unit, entry, id); 507 BCM_IF_ERROR_RETURN(rv); 508 509 return 510 (bcm_field_stat_destroy(unit, id)); 511 512 } 513 514 #else 515 #define _bcm_board_safc_count_create(unit, group, entry, locus) (BCM_E_NONE) 516 #define _bcm_board_safc_count_destroy(unit, entry) (BCM_E_NONE) 517 #endif 518 519 /* Deallocate field group and entries */ 520 STATIC int 521 _bcm_board_safc_fp_destroy(int unit, bcm_field_group_t group) 522 { 523 int rv; 524 int i; 525 bcm_field_entry_t *entry; 526 int entry_count; 527 int entry_size; 528 529 rv = bcm_field_entry_multi_get(unit, group, 0, NULL, &entry_size); 530 if (BCM_SUCCESS(rv) && entry_size > 0) { 531 entry = sal_alloc(entry_size * sizeof(*entry), "safc_fp_destroy"); 532 if (entry) { 533 rv = bcm_field_entry_multi_get(unit, group, 534 entry_size, entry, &entry_count); 535 if (BCM_SUCCESS(rv)) { 536 for (i = 0; i < entry_count; i++) { 537 rv = _bcm_board_safc_count_destroy(unit, entry[i]); 538 if (BCM_FAILURE(rv)) { 539 break; 540 } 541 rv = bcm_field_entry_remove(unit, entry[i]); 542 if (BCM_FAILURE(rv)) { 543 break; 544 } 545 rv = bcm_field_entry_destroy(unit, entry[i]); 546 if (BCM_FAILURE(rv)) { 547 break; 548 } 549 } 550 } 551 sal_free(entry); 552 } else { 553 return BCM_E_MEMORY; 554 } 555 } 556 if (BCM_SUCCESS(rv)) { 557 rv = bcm_field_group_remove(unit, group); 558 } 559 if (BCM_SUCCESS(rv)) { 560 rv = bcm_field_group_destroy(unit, group); 561 } 562 563 return rv; 564 } 565 566 /* unconfigure SAFC field programming */ 567 STATIC int 568 _bcm_board_safc_unconfigure(int group_priority) 569 { 570 int rv; 571 int unit; 572 group_info_t gi; 573 574 gi.priority = group_priority; 575 gi.found = FALSE; 576 BCM_FOREACH_LOCAL_UNIT(unit) { 577 (void)bcm_field_group_traverse(unit, 578 _bcm_board_safc_find_group, 579 &gi); 580 if (gi.found) { 581 rv = _bcm_board_safc_fp_destroy(unit, gi.group); 582 if (BCM_FAILURE(rv)) { 583 break; 584 } 585 } 586 } 587 588 return BCM_E_NONE; 589 } 590 591 /* per-unit SAFC data initializer function */ 592 STATIC int 593 _bcm_board_safc_data_unit_init(safc_data_t *info, int unit) 594 { 595 int rv; 596 597 rv = bcm_port_config_get(unit, info->port_config + unit); 598 599 return rv; 600 } 601 602 /* 603 Collect the modids for SAFC topology. This is called recursively 604 starting from the links of the root node. 605 606 The 'visited flag' is used to prevent an infinite loop in case the 607 topology was calculated incorrectly. 608 609 */ 610 STATIC int 611 _bcm_board_safc_collect_modid(safc_data_t *info, 612 int src_spidx, 613 cpudb_entry_t *dst_entry, 614 int dst_idx) 615 { 616 int i, rx_idx; 617 cpudb_entry_t *rx_entry; 618 cpudb_key_t rx_key; 619 int rv; 620 621 /* already visited? */ 622 if (SHR_BITGET(info->s_visit, dst_entry->topo_idx)) { 623 /* If the visit bit is set, then we've already been here, 624 which should not happen because if this was really a 625 spanning tree we are traversing, then there should be no 626 loops. */ 627 return BCM_E_INTERNAL; 628 } 629 630 /* mark visited */ 631 SHR_BITSET(info->s_visit, dst_entry->topo_idx); 632 633 /* descend on any remaining edges */ 634 for (i = 0; i < dst_entry->base.num_stk_ports; i++) { 635 /* skip dst_idx because it points back to the source */ 636 if (i == dst_idx) { 637 continue; 638 } 639 640 /* skip obvious non-stack ports, or stacking cut ports */ 641 if ((dst_entry->sp_info[i].flags & 642 (CPUDB_SPF_ETHERNET|CPUDB_SPF_NO_LINK| 643 CPUDB_SPF_INACTIVE|CPUDB_SPF_CUT_PORT))) { 644 continue; 645 } 646 647 /* skip ports with no obvious partner */ 648 if (!(dst_entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED)) { 649 continue; 650 } 651 652 /* Get the remote RX CPUDB entry and and stack port index */ 653 CPUDB_KEY_COPY(rx_key, dst_entry->sp_info[i].rx_cpu_key); 654 rx_entry = NULL; 655 CPUDB_KEY_SEARCH(info->db_ref, rx_key, rx_entry); 656 if (!rx_entry) { 657 return BCM_E_NOT_FOUND; 658 } 659 rx_idx = dst_entry->sp_info[i].rx_stk_idx; 660 if (!((rx_idx >= 0) && (rx_idx < CPUDB_CXN_MAX))) { 661 return BCM_E_NOT_FOUND; 662 } 663 rv = _bcm_board_safc_collect_modid(info, src_spidx, rx_entry, rx_idx); 664 BCM_IF_ERROR_RETURN(rv); 665 } 666 667 /* mark modids found in this entry as being reachable via 668 the base port related to src_spidx */ 669 670 for (i=0; i<dst_entry->base.num_units; i++) { 671 int j; 672 673 for (j=0; j<dst_entry->base.mod_ids_req[i]; j++) { 674 info->s_idx[dst_entry->mod_ids[i] + j] = info->t_idx[src_spidx]; 675 } 676 } 677 return BCM_E_NONE; 678 } 679 680 /* return true if the stack ports a and b are sources and sunk to 681 identical units 682 */ 683 STATIC int 684 _bcm_board_safc_same_link(cpudb_ref_t db_ref, int a, int b) 685 { 686 cpudb_entry_t *entry, *tx_entry; 687 cpudb_stk_port_t *sp_a, *sp_b; 688 cpudb_unit_port_t *txup; 689 int tx_a, tx_b; 690 691 entry = db_ref->local_entry; 692 sp_a = entry->sp_info + a; 693 sp_b = entry->sp_info + b; 694 tx_a = sp_a->tx_stk_idx; 695 tx_b = sp_b->tx_stk_idx; 696 tx_entry = NULL; 697 698 if (entry->base.stk_ports[a].unit != entry->base.stk_ports[b].unit) { 699 /* not on the same local unit */ 700 return FALSE; 701 } 702 703 if ((tx_a < 0) || (tx_a >= CPUDB_CXN_MAX)) { 704 /* index out of range */ 705 return FALSE; 706 } 707 708 if ((tx_b < 0) || (tx_b >= CPUDB_CXN_MAX)) { 709 /* index out of range */ 710 return FALSE; 711 } 712 713 if (!CPUDB_KEY_EQUAL(sp_a->tx_cpu_key, sp_b->tx_cpu_key)) { 714 /* not connected to the same remote system */ 715 return FALSE; 716 } 717 718 CPUDB_KEY_SEARCH(db_ref, sp_a->tx_cpu_key, tx_entry); 719 if (tx_entry == NULL) { 720 /* can't even find the key */ 721 return FALSE; 722 } 723 724 txup = tx_entry->base.stk_ports; 725 726 if (txup[tx_a].unit != txup[tx_b].unit) { 727 /* units on the far end are different */ 728 return FALSE; 729 } 730 731 return TRUE; 732 } 733 734 /* determin stack ports that may be a member of a trunk group */ 735 STATIC int 736 _bcm_board_safc_trunk_idx_add(safc_data_t *info, int idx) 737 { 738 int i, unit, port; 739 cpudb_entry_t *entry; 740 741 if (SHR_BITGET(info->trunked, idx)) { 742 /* already added */ 743 return BCM_E_NONE; 744 } 745 746 BCM_PBMP_CLEAR(info->trunk[idx]); 747 748 /* check if this stack port idx is associated with other stack 749 ports connected to the same remote system and same unit. If so, 750 assume it is a member of a trunk and add it to the given stack 751 set. Do not assume that trunks are formed at this point, so do 752 not use the trunk API to make this determination. */ 753 754 entry = info->db_ref->local_entry; 755 756 /* 757 get TX key and remote unit of this port 758 */ 759 760 for (i = 0; i < entry->base.num_stk_ports; i++) { 761 762 if ((entry->sp_info[i].flags & 763 (CPUDB_SPF_ETHERNET|CPUDB_SPF_NO_LINK|CPUDB_SPF_INACTIVE))) { 764 continue; 765 } 766 767 if (idx == i) { 768 /* looking at this port, so skip */ 769 continue; 770 } 771 772 /* 773 get TX key and remote unit of this port 774 */ 775 if (_bcm_board_safc_same_link(info->db_ref, idx, i)) { 776 unit = entry->base.stk_ports[i].unit; 777 port = entry->base.stk_ports[i].port; 778 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 779 (BSL_META("Trunk related spidx %d (%d,%d)\n"), 780 i, unit, port)); 781 SHR_BITSET(info->trunked, i); 782 BCM_PBMP_PORT_ADD(info->trunk[idx], port); 783 if (info->t_idx[i] >= 0) { 784 return BCM_E_INTERNAL; 785 } 786 info->t_idx[i] = idx; 787 } 788 } 789 790 unit = entry->base.stk_ports[idx].unit; 791 port = entry->base.stk_ports[idx].port; 792 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 793 (BSL_META("Trunk base spidx %d (%d,%d)\n"), 794 idx, unit, port)); 795 BCM_PBMP_PORT_ADD(info->trunk[idx], port); 796 SHR_BITSET(info->trunked, idx); 797 if (info->t_idx[i] >= 0) { 798 return BCM_E_INTERNAL; 799 } 800 info->t_idx[idx] = idx; 801 802 return BCM_E_NONE; 803 } 804 805 806 807 /* add stack port idx and any related ports to the stack set */ 808 STATIC int 809 _bcm_board_safc_stack_idx_add(safc_data_t *info, stkset_t stkset, int idx) 810 { 811 int i, related; 812 813 if (SHR_BITGET(stkset, idx)) { 814 /* already added */ 815 return BCM_E_NONE; 816 } 817 818 SHR_BITSET(stkset, idx); 819 820 /* now see if there are any related ports that need to be added */ 821 822 /* stack port index of the 'base' stack port */ 823 related = info->t_idx[idx]; 824 for (i = 0; i < CPUDB_CXN_MAX; i++) { 825 /* if this stack port index is related, then add it in */ 826 if (info->t_idx[i] == related) { 827 SHR_BITSET(stkset, i); 828 } 829 } 830 831 return BCM_E_NONE; 832 } 833 834 /* SAFC data initializer */ 835 STATIC int 836 _bcm_board_safc_data_set(safc_data_t *info, 837 topo_cpu_t *tp_cpu, 838 cpudb_ref_t db_ref, 839 topo_info_t *safc) 840 { 841 int num_cpu; 842 topo_info_t *normal; 843 int src; 844 int i, j, m, dst, idx, rx_idx; 845 cpudb_entry_t *entry; 846 int num_modids; 847 bcm_port_t port; 848 int unit; 849 int nhmod, nhport; 850 cpudb_entry_t *rx_entry; 851 cpudb_key_t rx_key; /* RX key, unit on master port to .. */ 852 int rx_unit; /* .. compare against */ 853 cpudb_key_t pkey; /* RX key, unit on other ports being ..*/ 854 int punit; /* .. compare to master port */ 855 topo_stk_port_t *tsp; 856 int rv; 857 858 if(NULL == db_ref) 859 { 860 return BCM_E_PARAM; 861 } 862 863 num_cpu = db_ref->num_cpus; 864 normal = (topo_info_t *)db_ref->topo_cookie; 865 src = db_ref->local_entry->topo_idx; 866 nhmod = -1; 867 entry = db_ref->local_entry; 868 info->tp_cpu = tp_cpu; 869 info->db_ref = db_ref; 870 info->safc_topo = safc; 871 872 BCM_PBMP_CLEAR(info->none_pbm_mask); 873 BCM_PBMP_NEGATE(info->all_pbm_mask, info->none_pbm_mask); 874 875 /* init t_idx to catch errors */ 876 for (i = 0; i < CPUDB_CXN_MAX; i++) { 877 info->t_idx[i] = -1; 878 } 879 880 /* collect information about stack ports that may be trunked */ 881 for (i = 0; i < entry->base.num_stk_ports; i++) { 882 883 if ((entry->sp_info[i].flags & 884 (CPUDB_SPF_ETHERNET|CPUDB_SPF_NO_LINK|CPUDB_SPF_INACTIVE))) { 885 continue; 886 } 887 rv = _bcm_board_safc_trunk_idx_add(info, i); 888 BCM_IF_ERROR_RETURN(rv); 889 } 890 891 /* Set which stack ports are in use based on the topology data */ 892 for (dst = 0; dst < num_cpu; dst++ ) { 893 if (src != dst) { 894 idx = TX_CXN(normal, src, dst); 895 if (idx != TOPO_CXN_UNKNOWN) { 896 rv = _bcm_board_safc_stack_idx_add(info, info->normal, idx); 897 BCM_IF_ERROR_RETURN(rv); 898 } 899 idx = TX_CXN(safc, src, dst); 900 if (idx != TOPO_CXN_UNKNOWN) { 901 rv = _bcm_board_safc_stack_idx_add(info, info->safc, idx); 902 BCM_IF_ERROR_RETURN(rv); 903 } 904 } 905 } 906 907 /* mixed system or safc only? */ 908 if (shr_bitop_range_eq(info->normal, info->safc, 0, CPUDB_CXN_MAX)) { 909 info->safc_only = TRUE; 910 } 911 912 /* init portidx */ 913 for (i = 0; i < TOPO_MODIDS_MAX; i++) { 914 info->n_idx[i] = -1; 915 info->s_idx[i] = -1; 916 } 917 918 /* logic from bcm_board_module_filter */ 919 num_modids = 0; 920 for (i = 0; i < entry->base.num_units; i++) { 921 num_modids += entry->base.mod_ids_req[i]; 922 } 923 924 for (i = 0; i < entry->base.num_stk_ports; i++) { 925 926 if ((entry->sp_info[i].flags & 927 (CPUDB_SPF_ETHERNET|CPUDB_SPF_NO_LINK|CPUDB_SPF_INACTIVE))) { 928 continue; 929 } 930 931 port = entry->base.stk_ports[i].port; 932 unit = entry->base.stk_ports[i].unit; 933 934 /* Every active port should be a member of the SAFC port set 935 or the normal port set. If it is not, then there is some 936 logic error. */ 937 if (SHR_BITGET(info->safc, i)) { 938 BCM_PBMP_PORT_ADD(info->safc_pbm[unit], port); 939 } else if (SHR_BITGET(info->normal, i)) { 940 BCM_PBMP_PORT_ADD(info->normal_pbm[unit], port); 941 } else { 942 return BCM_E_INTERNAL; 943 } 944 945 SHR_BITSET(info->units, unit); 946 /* If we're using a reserved NH modid, or there's no 947 nhmod defined for this stack port, or there was a nhmod 948 for this stack port but it was was less than zero, then get the 949 default */ 950 951 if (bcm_st_reserved_modid_enable_get()) { 952 nh_tx_src_mod_port_get(unit, port, &nhmod, &nhport); 953 } 954 955 if (nhmod >= 0 && nhmod < num_modids) { 956 /* add nexthop module */ 957 SHR_BITSET(info->modid[i], nhmod); 958 SHR_BITSET(info->all_modid, nhmod); 959 } 960 961 /* 962 * Get the remote RX CPU key and unit for the master port 963 */ 964 CPUDB_KEY_COPY(rx_key, entry->sp_info[i].rx_cpu_key); 965 rx_entry = NULL; 966 rx_unit = -1; 967 rx_idx = -1; 968 CPUDB_KEY_SEARCH(db_ref, rx_key, rx_entry); 969 if (rx_entry) { 970 rx_idx = entry->sp_info[i].rx_stk_idx; 971 if ((rx_idx >= 0) && (rx_idx < CPUDB_CXN_MAX)) { 972 rx_unit = rx_entry->base.stk_ports[rx_idx].unit; 973 } else { 974 return BCM_E_NOT_FOUND; 975 } 976 } else { 977 return BCM_E_NOT_FOUND; 978 } 979 980 /* 981 * Allow only mod IDs of those stack ports with same RX CPU key 982 * and same remote stack-port unit. 983 * 984 * Note: If stack-port information for remote CPU entries 985 * is not available, then check for CPU key only 986 * (old behavior). 987 */ 988 for (j = 0; j < entry->base.num_stk_ports; j++) { 989 if (entry->base.stk_ports[j].unit != unit) { 990 continue; 991 } 992 if (!(entry->sp_info[j].flags & CPUDB_SPF_RX_RESOLVED)) { 993 continue; 994 } 995 996 /* 997 * Get other stack port RX CPU key and unit to 998 * compare against master port 999 */ 1000 CPUDB_KEY_COPY(pkey, entry->sp_info[j].rx_cpu_key); 1001 punit = -1; 1002 if (rx_unit >= 0) { 1003 idx = entry->sp_info[j].rx_stk_idx; 1004 if ((idx >= 0) && (idx < CPUDB_CXN_MAX) && rx_entry) { 1005 punit = rx_entry->base.stk_ports[idx].unit; 1006 } 1007 } 1008 1009 /* Skip port if RX CPU key or unit are different */ 1010 if (!CPUDB_KEY_EQUAL(rx_key, pkey) || (rx_unit != punit)) { 1011 continue; 1012 } 1013 1014 /* Add modules that are rxable on this stack port. 1015 This is for normal topology. 1016 */ 1017 tsp = &tp_cpu->tp_stk_port[j]; 1018 for (m = 0; m < tsp->rx_mod_num; m++) { 1019 int modid = tsp->rx_mods[m]; 1020 /* modid on this port */ 1021 SHR_BITSET(info->modid[i], modid); 1022 /* all modids */ 1023 SHR_BITSET(info->all_modid, modid); 1024 /* modid to base stack port index */ 1025 info->n_idx[modid] = info->t_idx[i]; 1026 } 1027 } 1028 /* Now if this is not a cut port, that means this port will be 1029 used for SAFC traffic. Gather all the modids reachable in 1030 the SAFC topology. */ 1031 if (!(entry->sp_info[i].flags & (CPUDB_SPF_CUT_PORT))) { 1032 sal_memset(info->s_visit, 0, sizeof(stkset_t)); 1033 SHR_BITSET(info->s_visit, entry->topo_idx); 1034 rv = _bcm_board_safc_collect_modid(info, i, rx_entry, rx_idx); 1035 BCM_IF_ERROR_RETURN(rv); 1036 } 1037 } 1038 1039 /* set blocked modid map. This is a list of modids for each *normal* 1040 stack port that is not expected to be received on that port. */ 1041 for (i = 0; i < entry->base.num_stk_ports; i++) { 1042 for (j = 0; j < TOPO_MODIDS_MAX; j++) { 1043 if (SHR_BITGET(info->all_modid, j) && 1044 (!SHR_BITGET(info->modid[i], j))) { 1045 /* valid modid not on this port */ 1046 SHR_BITSET(info->blocked[i], j); 1047 } 1048 } 1049 } 1050 1051 rv = _bcm_board_safc_unit_iterate(info, _bcm_board_safc_data_unit_init); 1052 BCM_IF_ERROR_RETURN(rv); 1053 1054 return BCM_E_NONE; 1055 } 1056 1057 /* SAFC data allocator and initializer */ 1058 STATIC int 1059 _bcm_board_safc_data(safc_data_t **info_p, 1060 topo_cpu_t *tp_cpu, cpudb_ref_t db_ref, topo_info_t *safc) 1061 { 1062 safc_data_t *info; 1063 int rv; 1064 1065 info = sal_alloc(sizeof(*info), "info"); 1066 if (info) { 1067 sal_memset(info, 0, sizeof(*info)); 1068 rv = _bcm_board_safc_data_set(info, tp_cpu, db_ref, safc); 1069 if (BCM_FAILURE(rv)) { 1070 sal_free(info); 1071 info = NULL; 1072 } 1073 } else { 1074 rv = BCM_E_MEMORY; 1075 } 1076 if (info) { 1077 *info_p = info; 1078 } 1079 return rv; 1080 } 1081 1082 STATIC int 1083 _bcm_board_safc_only_higig_u_cos(safc_data_t *info, int unit, bcm_cos_t cos) 1084 { 1085 bcm_field_entry_t e1; 1086 int rv; 1087 1088 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1089 BCM_IF_ERROR_RETURN(rv); 1090 1091 rv = bcm_field_qualify_InPorts(unit, e1, 1092 info->safc_pbm[unit], 1093 info->all_pbm_mask); 1094 BCM_IF_ERROR_RETURN(rv); 1095 1096 rv = bcm_field_qualify_OuterVlan(unit, e1, 1097 BCM_VLAN_CTRL(cos, 0, 0), 1098 info->safc_vlan_mask); 1099 BCM_IF_ERROR_RETURN(rv); 1100 1101 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1102 FUNCTION_NAME()); 1103 BCM_IF_ERROR_RETURN(rv); 1104 1105 rv = bcm_field_entry_install(unit, e1); 1106 BCM_IF_ERROR_RETURN(rv); 1107 1108 return BCM_E_NONE; 1109 } 1110 1111 /* SAFC-only Higig unit programming */ 1112 STATIC int 1113 _bcm_board_safc_only_higig_u(safc_data_t *info, int unit) 1114 { 1115 return _bcm_board_safc_cos_iterate(info, unit, 1116 _bcm_board_safc_only_higig_u_cos); 1117 } 1118 1119 STATIC int 1120 _bcm_board_safc_drop_ingress_u_cos(safc_data_t *info, int unit, bcm_cos_t cos) 1121 { 1122 bcm_field_entry_t e1; 1123 int rv; 1124 1125 /* Drop SAFC traffic ingressing on normal HG ports */ 1126 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1127 BCM_IF_ERROR_RETURN(rv); 1128 1129 rv = bcm_field_qualify_InPorts(unit, e1, 1130 info->normal_pbm[unit], info->all_pbm_mask); 1131 BCM_IF_ERROR_RETURN(rv); 1132 1133 rv = bcm_field_qualify_OuterVlan(unit, e1, 1134 BCM_VLAN_CTRL(cos, 0, 0), 1135 info->safc_vlan_mask); 1136 BCM_IF_ERROR_RETURN(rv); 1137 1138 rv = bcm_field_action_add(unit, e1, bcmFieldActionDrop, 0, 0); 1139 BCM_IF_ERROR_RETURN(rv); 1140 1141 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1142 FUNCTION_NAME()); 1143 BCM_IF_ERROR_RETURN(rv); 1144 1145 rv = bcm_field_entry_install(unit, e1); 1146 BCM_IF_ERROR_RETURN(rv); 1147 1148 return BCM_E_NONE; 1149 } 1150 1151 /* Mixed unit programming */ 1152 STATIC int 1153 _bcm_board_safc_drop_ingress_u(safc_data_t *info, int unit) 1154 { 1155 return _bcm_board_safc_cos_iterate(info, unit, 1156 _bcm_board_safc_drop_ingress_u_cos); 1157 } 1158 1159 STATIC int 1160 _bcm_board_safc_block_egress_u_cos(safc_data_t *info, int unit, bcm_cos_t cos) 1161 { 1162 bcm_field_entry_t e1; 1163 int rv; 1164 1165 /* Block SAFC traffic from egressing normal HG ports */ 1166 1167 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1168 BCM_IF_ERROR_RETURN(rv); 1169 1170 rv = bcm_field_qualify_InPorts(unit, e1, 1171 info->safc_pbm[unit], info->all_pbm_mask); 1172 BCM_IF_ERROR_RETURN(rv); 1173 1174 rv = bcm_field_qualify_OuterVlan(unit, e1, 1175 BCM_VLAN_CTRL(cos, 0, 0), 1176 info->safc_vlan_mask); 1177 BCM_IF_ERROR_RETURN(rv); 1178 1179 rv = bcm_field_action_ports_add(unit, e1, 1180 bcmFieldActionEgressMask, 1181 info->normal_pbm[unit]); 1182 BCM_IF_ERROR_RETURN(rv); 1183 1184 rv = _bcm_board_safc_count_create(unit, info->group[unit], 1185 e1, FUNCTION_NAME()); 1186 BCM_IF_ERROR_RETURN(rv); 1187 1188 rv = bcm_field_entry_install(unit, e1); 1189 BCM_IF_ERROR_RETURN(rv); 1190 1191 return BCM_E_NONE; 1192 } 1193 1194 STATIC int 1195 _bcm_board_safc_block_egress_u(safc_data_t *info, int unit) 1196 { 1197 return _bcm_board_safc_cos_iterate(info, unit, 1198 _bcm_board_safc_block_egress_u_cos); 1199 } 1200 1201 STATIC int 1202 _bcm_board_mixed_higig_u(safc_data_t *info, int unit) 1203 { 1204 int rv; 1205 1206 rv = _bcm_board_safc_drop_ingress_u(info, unit); 1207 BCM_IF_ERROR_RETURN(rv); 1208 1209 rv = _bcm_board_safc_block_egress_u(info, unit); 1210 BCM_IF_ERROR_RETURN(rv); 1211 1212 return BCM_E_NONE; 1213 } 1214 1215 /* Per-port, per modid, UNDO src modid blocking */ 1216 1217 STATIC int 1218 _bcm_board_safc_undo_source_modid_block_p(safc_data_t *info, int spidx) 1219 { 1220 int m, unit, port; 1221 int rv; 1222 1223 unit = info->db_ref->local_entry->base.stk_ports[spidx].unit; 1224 port = info->db_ref->local_entry->base.stk_ports[spidx].port; 1225 1226 /* No ports on this unit may be actively participating in 1227 any topology. If so, then skip. */ 1228 if (!SHR_BITGET(info->units, unit)) { 1229 return BCM_E_NONE; 1230 } 1231 1232 for (m=0; m < TOPO_MODIDS_MAX; m++) { 1233 if (SHR_BITGET(info->blocked[spidx], m)) { 1234 /* this modid should be blocked */ 1235 1236 /* undo device table block */ 1237 rv = bcm_port_modid_enable_set(unit, port, m, TRUE); 1238 BCM_IF_ERROR_RETURN(rv); 1239 } 1240 } 1241 1242 return BCM_E_NONE; 1243 } 1244 1245 1246 1247 /* SAFC/normal unicast forwarding */ 1248 1249 STATIC int 1250 _bcm_board_safc_unicast_forward_cos(safc_data_t *info, 1251 int unit, int port, int modid, int dest, 1252 bcm_pbmp_t egress_mask, bcm_cos_t cos) 1253 { 1254 bcm_field_entry_t e1; 1255 int rv; 1256 1257 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1258 BCM_IF_ERROR_RETURN(rv); 1259 1260 rv = bcm_field_qualify_InPorts(unit, e1, 1261 info->port_config[unit].e, 1262 info->all_pbm_mask); 1263 BCM_IF_ERROR_RETURN(rv); 1264 1265 rv = bcm_field_qualify_L2DestHit(unit, e1, 1, 1); 1266 BCM_IF_ERROR_RETURN(rv); 1267 1268 if (dest) { 1269 rv = bcm_field_qualify_OuterVlan(unit, e1, 1270 BCM_VLAN_CTRL(cos, 0, 0), 1271 info->safc_vlan_mask); 1272 BCM_IF_ERROR_RETURN(rv); 1273 } 1274 1275 rv = bcm_field_qualify_DstPort(unit, e1, modid, 1276 BCM_FIELD_EXACT_MATCH_MASK, 0, 0); 1277 BCM_IF_ERROR_RETURN(rv); 1278 1279 rv = bcm_field_action_ports_add(unit, e1, 1280 bcmFieldActionEgressMask, egress_mask); 1281 BCM_IF_ERROR_RETURN(rv); 1282 1283 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1284 FUNCTION_NAME()); 1285 BCM_IF_ERROR_RETURN(rv); 1286 1287 rv = bcm_field_entry_install(unit, e1); 1288 BCM_IF_ERROR_RETURN(rv); 1289 1290 return BCM_E_NONE; 1291 1292 } 1293 1294 /* per-unit, per-dest-type unicast forwarding 1295 1296 dest=1 SAFC 1297 dest=0 normal 1298 1299 Standard board programming should already add the normal topology 1300 port to the modport map, so this function just adds the SAFC port. 1301 */ 1302 1303 #define TRUNK(n) (((n)>1) ? "trunk " : "") 1304 1305 /* Check if a stack unit has multi stack ports mapped to the same modid. */ 1306 STATIC int 1307 _bcm_board_safc_multi_modmap(safc_data_t *info, int unit, int *multi_map) 1308 { 1309 int modid; 1310 int rv, i, j; 1311 int port_max = 16, port_count = 0; 1312 bcm_port_t port_array[16]; 1313 1314 for (modid = 0; modid < TOPO_MODIDS_MAX; modid++) { 1315 if (SHR_BITGET(info->all_modid, modid)) { 1316 rv = bcm_stk_modport_get_all(unit, modid, port_max, 1317 port_array, &port_count); 1318 BCM_IF_ERROR_RETURN(rv); 1319 if (port_count > 1) { 1320 for (i = 0; i < (port_count - 1); i++) { 1321 for (j = (i + 1); j < port_count; j++) { 1322 if (port_array[i] != port_array[j]) { 1323 *multi_map = TRUE; 1324 return BCM_E_NONE; 1325 } 1326 } 1327 } 1328 } 1329 } 1330 } 1331 1332 *multi_map = FALSE; 1333 return BCM_E_NONE; 1334 } 1335 1336 STATIC int 1337 _bcm_board_safc_unicast_forward_port(safc_data_t *info, 1338 int unit, int modid, int dest) 1339 { 1340 int spidx, otidx; 1341 int spunit, otunit; 1342 int s_port, num_port; 1343 bcm_pbmp_t s_pbmp, o_pbmp; 1344 bcm_pbmp_t egress_mask; 1345 int rv; 1346 bcm_cos_t cos; 1347 1348 /* get stack port index appropriate for destination */ 1349 spidx = dest ? info->s_idx[modid] : info->n_idx[modid]; 1350 if (spidx < 0) { 1351 return BCM_E_NONE; 1352 } 1353 spunit = info->db_ref->local_entry->base.stk_ports[spidx].unit; 1354 1355 BCM_PBMP_ASSIGN(s_pbmp, info->trunk[spidx]); 1356 if (BCM_PBMP_IS_NULL(s_pbmp)) { 1357 return BCM_E_INTERNAL; 1358 } 1359 1360 /* get the other frame format stack port index */ 1361 otidx = dest ? info->n_idx[modid] : info->s_idx[modid]; 1362 if (otidx < 0) { 1363 return BCM_E_NONE; 1364 } 1365 otunit = info->db_ref->local_entry->base.stk_ports[otidx].unit; 1366 1367 BCM_PBMP_ASSIGN(o_pbmp, info->trunk[otidx]); 1368 if (BCM_PBMP_IS_NULL(o_pbmp)) { 1369 return BCM_E_INTERNAL; 1370 } 1371 1372 if (unit != spunit && unit != otunit) { 1373 /* modid is not forwarded off this unit, so skip */ 1374 return BCM_E_NONE; 1375 } 1376 1377 1378 /* set s_port to first port */ 1379 BCM_PBMP_ITER(s_pbmp, s_port) { 1380 break; 1381 } 1382 1383 BCM_PBMP_COUNT(s_pbmp, num_port); 1384 1385 /* mask out all ports for egress except for the ports appropriate 1386 for this packet type. */ 1387 BCM_PBMP_CLEAR(egress_mask); 1388 if (BCM_PBMP_NEQ(o_pbmp, s_pbmp)) { 1389 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1390 (BSL_META_U(unit, 1391 "%s: masking for modid %d egress to %s%d\n"), 1392 FUNCTION_NAME(), modid, TRUNK(num_port), s_port)); 1393 BCM_PBMP_ASSIGN(egress_mask, o_pbmp); 1394 } else { 1395 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1396 (BSL_META_U(unit, 1397 "%s: no mask for modid %d egress to %s%d\n"), 1398 FUNCTION_NAME(), modid, TRUNK(num_port), s_port)); 1399 } 1400 1401 if (dest) { 1402 /* if SAFC, add the first port to modport */ 1403 rv = bcm_stk_modport_add(unit, modid, s_port); 1404 BCM_IF_ERROR_RETURN(rv); 1405 } 1406 1407 /* forwarding rules for each port */ 1408 BCM_PBMP_ITER(s_pbmp, s_port) { 1409 for (cos = BCM_COS_MAX; cos >= BCM_COS_MIN; cos--) { 1410 1411 /* check each COS if SAFC dest */ 1412 if ((dest != 0) && ((info->safc_cos_map & (1<<cos)) == 0)) { 1413 continue; 1414 } 1415 rv = _bcm_board_safc_unicast_forward_cos(info, spunit, s_port, 1416 modid, dest, 1417 egress_mask, cos); 1418 BCM_IF_ERROR_RETURN(rv); 1419 1420 /* COS ignored if !SAFC, so quit */ 1421 if (dest == 0) { 1422 break; 1423 } 1424 } 1425 } 1426 1427 return BCM_E_NONE; 1428 } 1429 1430 1431 STATIC int 1432 _bcm_board_safc_unicast_ingress_lag(safc_data_t *info, int unit) 1433 { 1434 bcm_field_entry_t e1; 1435 bcm_pbmp_t egress_mask; 1436 int s_port, num_port; 1437 int rv, multi_map; 1438 1439 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1440 (BSL_META_U(unit, 1441 "%s(<>,%d)\n"), 1442 FUNCTION_NAME(), unit)); 1443 1444 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1445 BCM_IF_ERROR_RETURN(rv); 1446 1447 rv = bcm_field_qualify_L2DestHit(unit, e1, 1, 1); 1448 BCM_IF_ERROR_RETURN(rv); 1449 1450 /* It just needs to be a trunk; it doesn't matter what the trunk ID is */ 1451 rv = bcm_field_qualify_DstTrunk(unit, e1, 0, 0); 1452 BCM_IF_ERROR_RETURN(rv); 1453 1454 BCM_PBMP_COUNT(info->normal_pbm[unit], num_port); 1455 if (num_port != 0) { 1456 rv = bcm_field_action_ports_add(unit, e1, bcmFieldActionEgressMask, 1457 info->normal_pbm[unit]); 1458 } else { 1459 BCM_PBMP_CLEAR(egress_mask); 1460 BCM_PBMP_COUNT(info->safc_pbm[unit], num_port); 1461 rv = _bcm_board_safc_multi_modmap(info, unit, &multi_map); 1462 BCM_IF_ERROR_RETURN(rv); 1463 1464 if ((num_port > 1) && multi_map) { 1465 /* Simply pick a port from the safc_pbm and mask out egress */ 1466 BCM_PBMP_ITER(info->safc_pbm[unit], s_port) { 1467 break; 1468 } 1469 BCM_PBMP_PORT_ADD(egress_mask, s_port); 1470 } 1471 rv = bcm_field_action_ports_add(unit, e1, bcmFieldActionEgressMask, 1472 egress_mask); 1473 } 1474 BCM_IF_ERROR_RETURN(rv); 1475 1476 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1477 FUNCTION_NAME()); 1478 BCM_IF_ERROR_RETURN(rv); 1479 1480 rv = bcm_field_entry_install(unit, e1); 1481 BCM_IF_ERROR_RETURN(rv); 1482 1483 return BCM_E_NONE; 1484 } 1485 1486 STATIC int 1487 _bcm_board_safc_unicast_forwarding_u_d(safc_data_t *info, int unit, int dest) 1488 { 1489 int modid; 1490 int rv; 1491 1492 if (dest) { 1493 /* LAG handling */ 1494 rv = _bcm_board_safc_unicast_ingress_lag(info, unit); 1495 BCM_IF_ERROR_RETURN(rv); 1496 } 1497 1498 for (modid = 0; modid < TOPO_MODIDS_MAX; modid++) { 1499 if (SHR_BITGET(info->all_modid, modid)) { 1500 rv = _bcm_board_safc_unicast_forward_port(info, unit, 1501 modid, dest); 1502 BCM_IF_ERROR_RETURN(rv); 1503 } 1504 } 1505 1506 return BCM_E_NONE; 1507 } 1508 1509 /* per-unit SAFC unicast forwarding */ 1510 STATIC int 1511 _bcm_board_safc_unicast_forwarding_u(safc_data_t *info, int unit) 1512 { 1513 return _bcm_board_safc_unicast_forwarding_u_d(info, unit, 1); 1514 } 1515 1516 /* per-unit Normal unicast forwarding */ 1517 STATIC int 1518 _bcm_board_normal_unicast_forwarding_u(safc_data_t *info, int unit) 1519 { 1520 return _bcm_board_safc_unicast_forwarding_u_d(info, unit, 0); 1521 } 1522 1523 /* per-unit non-unicast egress blocking from Ethernet ports */ 1524 STATIC int 1525 _bcm_board_safc_nonunicast_egress_blocking_u_cos(safc_data_t *info, 1526 int unit, bcm_cos_t cos) 1527 { 1528 bcm_field_entry_t e1; 1529 int rv; 1530 1531 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1532 BCM_IF_ERROR_RETURN(rv); 1533 1534 rv = bcm_field_qualify_InPorts(unit, e1, info->port_config[unit].e, 1535 info->all_pbm_mask); 1536 BCM_IF_ERROR_RETURN(rv); 1537 1538 rv = bcm_field_qualify_L2DestHit(unit, e1, 0, 1); 1539 BCM_IF_ERROR_RETURN(rv); 1540 1541 /* Block all L2 misses instead of source modid blocking. */ 1542 rv = bcm_field_action_ports_add(unit, e1, bcmFieldActionEgressMask, 1543 info->normal_pbm[unit]); 1544 BCM_IF_ERROR_RETURN(rv); 1545 1546 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1547 FUNCTION_NAME()); 1548 BCM_IF_ERROR_RETURN(rv); 1549 1550 rv = bcm_field_entry_install(unit, e1); 1551 BCM_IF_ERROR_RETURN(rv); 1552 1553 return BCM_E_NONE; 1554 } 1555 1556 /* per-unit MH header egress blocking from SAFC Higig ports */ 1557 STATIC int 1558 _bcm_board_safc_hg_op_egress_blocking_u(safc_data_t *info, int unit, int op) 1559 { 1560 bcm_field_entry_t e1; 1561 int rv; 1562 1563 rv = bcm_field_entry_create(unit, info->group[unit], &e1); 1564 BCM_IF_ERROR_RETURN(rv); 1565 1566 rv = bcm_field_qualify_InPorts(unit, e1, 1567 info->safc_pbm[unit], 1568 info->all_pbm_mask); 1569 BCM_IF_ERROR_RETURN(rv); 1570 1571 rv = bcm_field_qualify_MHOpcode(unit, e1, op, 0x7); 1572 BCM_IF_ERROR_RETURN(rv); 1573 1574 /* Block all L2 misses instead of source modid blocking. */ 1575 rv = bcm_field_action_ports_add(unit, e1, bcmFieldActionEgressMask, 1576 info->normal_pbm[unit]); 1577 BCM_IF_ERROR_RETURN(rv); 1578 1579 rv = _bcm_board_safc_count_create(unit, info->group[unit], e1, 1580 FUNCTION_NAME()); 1581 BCM_IF_ERROR_RETURN(rv); 1582 1583 rv = bcm_field_entry_install(unit, e1); 1584 BCM_IF_ERROR_RETURN(rv); 1585 1586 return BCM_E_NONE; 1587 } 1588 1589 1590 STATIC int 1591 _bcm_board_safc_nonunicast_egress_blocking_u(safc_data_t *info, int unit) 1592 { 1593 int rv; 1594 1595 rv = _bcm_board_safc_cos_iterate(info, unit, 1596 _bcm_board_safc_nonunicast_egress_blocking_u_cos); 1597 BCM_IF_ERROR_RETURN(rv); 1598 1599 rv = _bcm_board_safc_hg_op_egress_blocking_u(info, unit, 1600 BCM_FIELD_MHOPCODE_BROADCAST_DLF); 1601 BCM_IF_ERROR_RETURN(rv); 1602 1603 rv = _bcm_board_safc_hg_op_egress_blocking_u(info, unit, 1604 BCM_FIELD_MHOPCODE_MULTICAST); 1605 BCM_IF_ERROR_RETURN(rv); 1606 1607 rv = _bcm_board_safc_hg_op_egress_blocking_u(info, unit, 1608 BCM_FIELD_MHOPCODE_IPMULTICAST); 1609 BCM_IF_ERROR_RETURN(rv); 1610 1611 return BCM_E_NONE; 1612 } 1613 1614 /* 1615 System level programming using iterators and per-unit or per-port 1616 programming functions. 1617 */ 1618 1619 /* SAFC only higig programming */ 1620 STATIC int 1621 _bcm_board_safc_only_higig(safc_data_t *info) 1622 { 1623 int rv; 1624 1625 rv =_bcm_board_safc_unit_iterate(info, _bcm_board_safc_only_higig_u); 1626 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1627 (BSL_META("%s()=%d\n"), 1628 FUNCTION_NAME(), rv)); 1629 1630 return rv; 1631 } 1632 1633 /* Mixed SAFC/normal higig programming */ 1634 STATIC int 1635 _bcm_board_mixed_higig(safc_data_t *info) 1636 { 1637 int rv; 1638 1639 rv = _bcm_board_safc_unit_iterate(info, _bcm_board_mixed_higig_u); 1640 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1641 (BSL_META("%s()=%d\n"), 1642 FUNCTION_NAME(), rv)); 1643 1644 return rv; 1645 } 1646 1647 /* UNDO Source modid blocking */ 1648 STATIC int 1649 _bcm_board_safc_undo_source_modid_block(safc_data_t *info) 1650 { 1651 int rv; 1652 1653 rv = _bcm_board_safc_stkport_iterate 1654 (info, _bcm_board_safc_undo_source_modid_block_p); 1655 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1656 (BSL_META("%s()=%d\n"), 1657 FUNCTION_NAME(), rv)); 1658 1659 return rv; 1660 } 1661 1662 /* SAFC unicast forwarding */ 1663 STATIC int 1664 _bcm_board_safc_unicast_forwarding(safc_data_t *info) 1665 { 1666 int rv; 1667 1668 rv = _bcm_board_safc_unit_iterate 1669 (info, _bcm_board_safc_unicast_forwarding_u); 1670 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1671 (BSL_META("%s()=%d\n"), 1672 FUNCTION_NAME(), rv)); 1673 1674 return rv; 1675 } 1676 1677 /* Normal unicast forwarding */ 1678 STATIC int 1679 _bcm_board_normal_unicast_forwarding(safc_data_t *info) 1680 { 1681 int rv; 1682 1683 rv = _bcm_board_safc_unit_iterate 1684 (info, _bcm_board_normal_unicast_forwarding_u); 1685 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1686 (BSL_META("%s()=%d\n"), 1687 FUNCTION_NAME(), rv)); 1688 1689 return rv; 1690 } 1691 1692 /* non-unicast egress blocking */ 1693 STATIC int 1694 _bcm_board_safc_nonunicast_egress_blocking(safc_data_t *info) 1695 { 1696 int rv; 1697 1698 rv = _bcm_board_safc_unit_iterate 1699 (info, _bcm_board_safc_nonunicast_egress_blocking_u); 1700 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1701 (BSL_META("%s()=%d\n"), 1702 FUNCTION_NAME(), rv)); 1703 1704 return rv; 1705 } 1706 1707 /* field programming group initialization */ 1708 STATIC int 1709 _bcm_board_safc_unit_init(safc_data_t *info, int unit) 1710 { 1711 info->group[unit] = -1; 1712 1713 return 1714 bcm_field_group_create(unit, 1715 info->qset, 1716 info->group_priority, info->group + unit); 1717 } 1718 1719 1720 /* field programming initialization */ 1721 STATIC int 1722 _bcm_board_safc_init(safc_data_t *info, 1723 uint32 safc_cos_map, 1724 int group_priority) 1725 { 1726 int rv; 1727 1728 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1729 (BSL_META("%s\n"), 1730 FUNCTION_NAME())); 1731 1732 info->safc_cos_map = safc_cos_map; 1733 info->safc_vlan_mask = BCM_VLAN_CTRL(BCM_COS_MAX,0,0); 1734 info->group_priority = group_priority; 1735 1736 BCM_FIELD_QSET_INIT(info->qset); 1737 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyInPorts); 1738 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyDstTrunk); 1739 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyDstPort); 1740 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyOuterVlan); 1741 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyStageIngress); 1742 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyL2DestHit); 1743 BCM_FIELD_QSET_ADD(info->qset,bcmFieldQualifyMHOpcode); 1744 1745 rv = _bcm_board_safc_unit_iterate(info, _bcm_board_safc_unit_init); 1746 1747 return rv; 1748 } 1749 1750 /* SAFC configuration */ 1751 STATIC int 1752 _bcm_board_safc_configure(topo_cpu_t *tp_cpu, 1753 cpudb_ref_t db_ref, 1754 uint32 safc_cos_map, 1755 int group_priority, 1756 topo_info_t *safc) 1757 { 1758 int rv; 1759 safc_data_t *info; 1760 1761 rv = BCM_E_PARAM; 1762 info = NULL; 1763 1764 if ((safc_cos_map & ~((1<<BCM_COS_COUNT)-1)) != 0) { 1765 /* should be no bits set from bit BCM_COS_COUNT and higher */ 1766 goto done; 1767 } 1768 1769 rv = _bcm_board_safc_data(&info, tp_cpu, db_ref, safc); 1770 if (BCM_FAILURE(rv)) { 1771 goto done; 1772 } 1773 1774 if (!info) { 1775 rv = BCM_E_MEMORY; 1776 goto done; 1777 } 1778 1779 rv = _bcm_board_safc_init(info, safc_cos_map, group_priority); 1780 if (BCM_FAILURE(rv)) { 1781 goto done; 1782 } 1783 1784 if (info->safc_only) { 1785 rv = _bcm_board_safc_only_higig(info); 1786 if (BCM_FAILURE(rv)) { 1787 goto done; 1788 } 1789 } else { 1790 rv = _bcm_board_mixed_higig(info); 1791 if (BCM_FAILURE(rv)) { 1792 goto done; 1793 } 1794 } 1795 1796 rv = _bcm_board_safc_unicast_forwarding(info); 1797 if (BCM_FAILURE(rv)) { 1798 goto done; 1799 } 1800 1801 rv = _bcm_board_normal_unicast_forwarding(info); 1802 if (BCM_FAILURE(rv)) { 1803 goto done; 1804 } 1805 1806 if (!info->safc_only) { 1807 rv = _bcm_board_safc_nonunicast_egress_blocking(info); 1808 if (BCM_FAILURE(rv)) { 1809 goto done; 1810 } 1811 } 1812 1813 rv = _bcm_board_safc_undo_source_modid_block(info); 1814 if (BCM_FAILURE(rv)) { 1815 goto done; 1816 } 1817 1818 done: 1819 if (info) { 1820 sal_free(info); 1821 } 1822 1823 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1824 (BSL_META("%s=%d\n"), 1825 FUNCTION_NAME(), rv)); 1826 return rv; 1827 } 1828 1829 /* 1830 * Function: 1831 * int bcm_board_safc_configure(topo_cpu_t *tp_cpu, 1832 * cpudb_ref_t db_ref, 1833 * uint32 safc_cos_map, 1834 * int group_priority, 1835 * topo_info_t *connection) 1836 * Purpose: 1837 * Program SAFC forwarding based on provided connection info 1838 * Parameters: 1839 * tp_cpu - (IN) CPU topology information 1840 * db_ref - (IN) CPU database 1841 * safc_cos_map - (IN) SAFC COS bitmap 1842 * group_priority - (IN) field group priority 1843 * connection - (IN) Connection matrix 1844 * Returns: 1845 * BCM_E_NONE - no errors 1846 * BCM_E_FAIL - topology calculation failed (CPUDB incomplete) 1847 * BCM_E_RESOURCE - not enough programming resources 1848 * Notes: 1849 * 1850 * Performs device programming. Assumes any necessary non-SAFC 1851 * programming is complete. 1852 * 1853 * Connection matrix is from bcm_stack_spanning_tree (for SAFC) 1854 * *and* db_ref (for non SAFC). 1855 * 1856 * This function will only use SDK APIs. Any register manipulation 1857 * required by the application must be managed outside this 1858 * function. 1859 * 1860 * Group priority must be higher than any application or system 1861 * field group priority, and must be unique for each different 1862 * SAFC topology. 1863 * 1864 * SAFC is unconfigured when connection is NULL. In this case, 1865 * group_priority is the only parameter that must be valid; tp_cpu, 1866 * db_ref, and safc_cos_map is ignored. 1867 */ 1868 1869 int 1870 bcm_board_safc_configure(topo_cpu_t *tp_cpu, 1871 cpudb_ref_t db_ref, 1872 uint32 safc_cos_map, 1873 int group_priority, 1874 topo_info_t *connection) 1875 { 1876 int rv; 1877 1878 rv = BCM_E_PARAM; 1879 1880 if (cpudb_valid(db_ref) && tp_cpu && connection) { 1881 (void) _bcm_board_safc_unconfigure(group_priority); 1882 rv = _bcm_board_safc_configure(tp_cpu, db_ref, 1883 safc_cos_map, group_priority, 1884 connection); 1885 if (BCM_FAILURE(rv)) { 1886 (void) _bcm_board_safc_unconfigure(group_priority); 1887 } 1888 } else if (connection == NULL) { 1889 rv = _bcm_board_safc_unconfigure(group_priority); 1890 } 1891 1892 return rv; 1893 } 1894 1895