program.c (30452B)
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: program.c 8 * Purpose: board stack programming 9 * 10 * 11 * 12 * Methodology: 13 * 14 * Create a connection list formed by the merger of the board's 15 * internal connections and external topology connections from the 16 * CPUDB. Create a tree driver from this connection list and the 17 * stack vertex and edge programming functions, and use 18 * board_tree_connect to program all the devices. 19 * 20 * The edge programmer programs any trunks found on local units, and 21 * adds the edge port to the "allowable" stack ports (by default, 22 * all stack ports are disallowed). 23 * 24 * The vertex programmer programs the modport map, modid enable, and 25 * topology map for every local unit. 26 * 27 * Note that the unit numbers for remote units are synthesized, and 28 * must not correspond to any local unit number. bcm_unit_local() 29 * must return FALSE for any such remote unit, and the unit number 30 * used must be usable by BCM_GPORT_DEVPORT. These remote units 31 * numbers are not used as a unit argument except to bcm_unit_local, 32 * and are are relatively small, as they are used as an index into 33 * board_stk_pgm_t.stk_unit. This requirement is driven by the use 34 * of a connection list to drive the tree programming. 35 * 36 * The topology map used for bcm_topo_port_get() is a two 37 * dimensional array constructed at stack programming time, and so 38 * is common for all systems. 39 * 40 * The methodology used here is a significant departure from that 41 * used by stktask, and is more data driven, rather than using hand 42 * coded interfaces for each board. 43 * 44 * Note that this subsystem, unlike stktask board programming, 45 * expects that internal stack connections between local devices 46 * have already been registered with BCM stack during local board 47 * initialization, so stack programming only has to deal with modid 48 * mapping on internal ports. 49 */ 50 51 #include <shared/bsl.h> 52 53 #include <bcm/error.h> 54 #include <bcm/port.h> 55 #include <bcm/stack.h> 56 #include <bcm/trunk.h> 57 #include <bcm/topo.h> 58 #if defined(INCLUDE_LIB_CPUDB) 59 #include <appl/cpudb/cpudb.h> 60 #endif 61 #if defined(INCLUDE_LIB_STKTASK) 62 #include <appl/stktask/topology.h> 63 #include <appl/stktask/stktask.h> /* bcm_st_reserved_modid_enable_get */ 64 #include <appl/cputrans/nh_tx.h> /* nh_tx_src_get */ 65 #endif 66 67 68 #include <board/manager.h> 69 #include <board/stack.h> 70 #include <board_int/support.h> 71 72 #if defined(INCLUDE_LIB_CPUDB) && defined(INCLUDE_LIB_STKTASK) 73 74 75 #ifndef BOARD_PGM_ABS_MAX_MODID 76 #define BOARD_PGM_ABS_MAX_MODID 32 77 #endif 78 79 typedef struct board_stk_unit_s { 80 int local; /* true if a local unit */ 81 int unit_id; /* unit identifier */ 82 int modid; /* modid for this unit */ 83 bcm_pbmp_t disports; /* inactive stack ports (ext only) */ 84 bcm_pbmp_t enaports; /* active stack ports (int+ext) */ 85 bcm_pbmp_t ethports; /* non-stack ports (ext only) */ 86 } board_stk_unit_t; 87 88 /* The topology map is a dynamically allocated 2D array indexed by 89 unit number and modid containing a port */ 90 91 typedef bcm_port_t board_topo_unit[BOARD_PGM_ABS_MAX_MODID]; 92 93 94 /* Persistant data used by the stacking board programming subsystem */ 95 typedef struct board_stk_info_s { 96 int topo_valid; /* true if this entry is valid */ 97 int max_modid; /* maximum modid in the maps */ 98 int topo_units; /* number of topo_map entries */ 99 board_topo_unit *topo_map; /* topo map */ 100 } board_stk_info_t; 101 102 /* Transient programming data */ 103 typedef struct board_stk_pgm_s { 104 void *alloc; /* memory buffer */ 105 int unit_last; /* last unit_id + 1 */ 106 board_stk_unit_t *stk_unit; /* per unit data */ 107 int *ru_offset; /* indexed by topo_idx */ 108 int max_conn; /* maximum number of connections managed */ 109 board_tree_driver_t td; /* tree driver used */ 110 } board_stk_pgm_t; 111 112 STATIC board_stk_info_t _board_stack_info; 113 114 /* 115 * Function: 116 * _board_topo_port_get 117 * Purpose: 118 * Topology mapping function registered with BCM 119 * Parameters: 120 * unit - (IN) unit to map 121 * dest_modid - (IN) modid to map 122 * exit_port - (OUT) physical port (unit,modid) egresses 123 * Returns: 124 * BCM_E_NONE - success 125 * BCM_E_XXX - failed 126 */ 127 STATIC int 128 _board_topo_port_get(int unit, int dest_modid, bcm_port_t *exit_port) 129 { 130 int rv = BCM_E_PARAM; 131 132 if (_board_stack_info.topo_map == NULL ||!_board_stack_info.topo_valid) { 133 rv = BCM_E_UNAVAIL; 134 } else if (unit >= 0 && unit < _board_stack_info.topo_units && 135 dest_modid >= 0 && dest_modid < _board_stack_info.max_modid) { 136 *exit_port = _board_stack_info.topo_map[unit][dest_modid]; 137 rv = BCM_E_NONE; 138 } 139 140 return rv; 141 } 142 143 /* 144 * Function: 145 * _board_program_info 146 * Purpose: 147 * Tree Programmer 'info' function. 148 * Sets modid/trunk info for given unit 149 * Parameters: 150 * unit - (IN) current unit (see notes above) 151 * modid - (OUT) modid for this unit 152 * ti - (OUT) trunk info for this unit (local only) 153 * user_data - (IN) user data registered 154 * Returns: 155 * BCM_E_NONE - success 156 * BCM_E_XXX - failed 157 */ 158 STATIC int 159 _board_program_info(int unit, int *modid, bcm_trunk_chip_info_t *ti, 160 void *user_data) 161 { 162 board_stk_pgm_t *pgm = (board_stk_pgm_t *)user_data; 163 int rv = BCM_E_NONE; 164 165 /* Copy modid out. Modid assignments have already been made 166 available via the CPUDB, so this function just copies out the 167 result of that analysis. */ 168 *modid = pgm->stk_unit[unit].modid; 169 if (pgm->stk_unit[unit].local) { 170 /* get chip info for local units */ 171 rv = bcm_trunk_chip_info_get(unit, ti); 172 } 173 174 return rv; 175 } 176 177 /* 178 * Function: 179 * _board_program_edge 180 * Purpose: 181 * Tree Programmer 'edge' function. 182 * Program trunk if needed and add port to 'enable' list. 183 * Parameters: 184 * unit - (IN) current unit (see notes above) 185 * ti - (IN) trunk info for this unit (local only) 186 * ta - (OUT) trunk add info for this unit (local only) 187 * user_data - (IN) user data registered 188 * Returns: 189 * BCM_E_NONE - success 190 * BCM_E_XXX - failed 191 */ 192 STATIC int 193 _board_program_edge(int unit, bcm_trunk_chip_info_t *ti, 194 bcm_trunk_add_info_t *ta, void *user_data) 195 { 196 /* program trunk if needed */ 197 int i, rv, tid; 198 bcm_trunk_member_t *member_array = NULL; 199 bcm_trunk_info_t tinfo; 200 201 rv = BCM_E_INTERNAL; 202 203 if (ta->num_ports > 1) { 204 tid = ti->trunk_fabric_id_max; 205 if (tid >= ti->trunk_fabric_id_min) { 206 ta->psc = -1; /* Default hash algorithm */ 207 ta->dlf_index = -1; 208 ta->mc_index = -1; 209 ta->ipmc_index = -1; 210 rv = bcm_trunk_create(unit, BCM_TRUNK_FLAG_WITH_ID, &tid); 211 if (BCM_SUCCESS(rv)) { 212 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 213 (BSL_META_U(unit, 214 "Board trunk u:%d tid:%d\n"), 215 unit, tid)); 216 member_array = sal_alloc(ta->num_ports * 217 sizeof(bcm_trunk_member_t), "trunk member array"); 218 if (NULL == member_array) { 219 return BCM_E_MEMORY; 220 } 221 for (i = 0; i < ta->num_ports; i++) { 222 bcm_trunk_member_t_init(&member_array[i]); 223 if (BCM_GPORT_IS_SET(ta->tp[i])) { 224 member_array[i].gport = ta->tp[i]; 225 } else { 226 BCM_GPORT_LOCAL_SET(member_array[i].gport, ta->tp[i]); 227 } 228 } 229 bcm_trunk_info_t_init(&tinfo); 230 tinfo.flags = ta->flags; 231 tinfo.psc = ta->psc; 232 tinfo.dlf_index = ta->dlf_index; 233 tinfo.mc_index = ta->mc_index; 234 tinfo.ipmc_index = ta->ipmc_index; 235 rv = bcm_trunk_set(unit, tid, &tinfo, ta->num_ports, 236 member_array); 237 if (BCM_SUCCESS(rv)) { 238 ti->trunk_fabric_id_max--; 239 } 240 sal_free(member_array); 241 } 242 } else { 243 /* No more trunks */ 244 rv = BCM_E_FULL; 245 } 246 } 247 248 if (BCM_SUCCESS(rv)) { 249 for (i=0; i<ta->num_ports; i++) { 250 /* Add port to enable list */ 251 252 rv = BCM_E_UNAVAIL; 253 } 254 } 255 256 return rv; 257 258 } 259 260 /* 261 * Function: 262 * _board_program_vertex 263 * Purpose: 264 * Tree Programmer 'vertex' function. 265 * Programs device modmap, modid enables, and topo map. 266 * Parameters: 267 * unit - (IN) current unit (see notes above) 268 * modid - (IN) modid for this unit 269 * port - (IN) egressing stack port on this vertex 270 * user_data - (IN) user data registered 271 * Returns: 272 * BCM_E_NONE - success 273 * BCM_E_XXX - failed 274 */ 275 276 STATIC int 277 _board_program_vertex(int unit, int modid, bcm_gport_t port, void *user_data) 278 { 279 board_stk_pgm_t *pgm = (board_stk_pgm_t *)user_data; 280 int rv; 281 282 rv = BCM_E_NONE; 283 284 do { 285 if (!pgm->stk_unit[unit].local) { 286 break; 287 } 288 289 if (modid < 0) { 290 break; 291 } 292 293 /* modmap modid to port */ 294 LOG_VERBOSE(BSL_LS_BOARD_COMMON, 295 (BSL_META_U(unit, 296 "Board modmap mod=%d u:%d,%d\n"), 297 modid, unit, port)); 298 rv = bcm_stk_modport_set(unit, modid, port); 299 if (BCM_FAILURE(rv)) { 300 break; 301 } 302 303 /* allow modid on port */ 304 rv = bcm_port_modid_enable_set(unit, port, modid, TRUE); 305 if (BCM_FAILURE(rv)) { 306 break; 307 } 308 309 /* add port to topo map */ 310 _board_stack_info.topo_map[unit][modid] = 311 BCM_GPORT_DEVPORT_PORT_GET(port); 312 313 } while (0); 314 315 return rv; 316 } 317 318 /* 319 * Function: 320 * _stk_gport 321 * Purpose: 322 * Return a DEVPORT for the given stack port. 323 * Parameters: 324 * sp - (IN) CPUDB stack port structure 325 * offset - (IN) synthetic remote unit offset 326 * Returns: 327 * DEVPORT 328 * Notes: 329 * Units for local stack ports are real, and units for remote 330 * stack ports are synthetic, and must not correspond to any local 331 * unit number. They could land up corresponding to a currently 332 * attached remote unit number, but that's OK, because they should 333 * never be used as an argument to a BCM API call. 334 */ 335 STATIC bcm_gport_t 336 _stk_gport(cpudb_unit_port_t *sp, int offset) 337 { 338 return BCM_GPORT_DEVPORT(sp->unit + offset, sp->port); 339 } 340 341 /* 342 * Function: 343 * _topo_port 344 * Purpose: 345 * Determine the egressing port for packets from src to dst. 346 * Parameters: 347 * db_ref - (IN) CPUDB 348 * src - (IN) source entry 349 * dst - (IN) destination entry 350 * ru_offset - (IN) remote unit offset array 351 * devport - (OUT) egress port 352 * Returns: 353 * BCM_E_NONE - success 354 * BCM_E_XXX - failed 355 * Notes: 356 * This is a deliberate alternative to using the TOPO_CPU construction. 357 * This will reduce the coupling to stktask, and eliminate such coupling 358 * if and when topology is moved to a separate module. 359 */ 360 STATIC int 361 _topo_port(cpudb_ref_t db_ref, 362 cpudb_entry_t *src, 363 cpudb_entry_t *dst, 364 int *ru_offset, 365 bcm_gport_t *devport) 366 { 367 int idx; 368 int rv; 369 int offset; 370 371 offset = ru_offset[src->topo_idx]; 372 rv = topo_tx_port_get(db_ref, src, dst, &idx); 373 if (BCM_SUCCESS(rv)) { 374 *devport = _stk_gport(&src->base.stk_ports[idx], offset); 375 } 376 return rv; 377 } 378 379 380 /* 381 * Function: 382 * _cpudb_connection 383 * Purpose: 384 * Returns a connection list from the CPUDB suitable for the 385 * stack Tree programmer. 386 * Parameters: 387 * db_ref - (IN) CPUDB 388 * max_connection - (IN) max size of connection list 389 * list - (OUT) connection list 390 * actual - (OUT) actual size of list 391 * ru_offset - (IN) ru_offset array 392 * Returns: 393 * BCM_E_NONE - success 394 * BCM_E_XXX - failed 395 */ 396 STATIC int 397 _cpudb_connection(cpudb_ref_t db_ref, 398 int max_connection, 399 board_connection_t *list, 400 int *actual, 401 int *ru_offset) 402 { 403 cpudb_entry_t *src, *dst; 404 board_connection_t conn; 405 int count = 0; 406 407 /* This gets *all* the connections in the topology, not just 408 the connections from the local system. 409 */ 410 CPUDB_FOREACH_ENTRY(db_ref, src) { 411 CPUDB_FOREACH_ENTRY(db_ref, dst) { 412 if (src == dst) { 413 /* only iterate across the lower triangle of the matrix 414 below the diagonal. */ 415 break; 416 } 417 BCM_IF_ERROR_RETURN 418 (_topo_port(db_ref, src, dst, ru_offset, &conn.from)); 419 BCM_IF_ERROR_RETURN 420 (_topo_port(db_ref, dst, src, ru_offset, &conn.to)); 421 if (max_connection > 0) { 422 *list++ = conn; 423 max_connection--; 424 count++; 425 } else { 426 return BCM_E_FULL; 427 } 428 } 429 } 430 431 if (actual) { 432 *actual = count; 433 } 434 435 return BCM_E_NONE; 436 } 437 438 /* 439 * Function: 440 * _pgm_unit_init 441 * Purpose: 442 * Initialize board_stk_pgm_t structure 443 * Parameters: 444 * db_ref - (IN) CPUDB 445 * pgm - (OUT) board_stk_pgm_t to initialize 446 * Returns: 447 * BCM_E_NONE - success 448 * BCM_E_XXX - failed 449 */ 450 STATIC int 451 _pgm_unit_init(cpudb_ref_t db_ref, board_stk_pgm_t *pgm) 452 { 453 int offset = board_num_devices(); 454 int i, unit_id_base, local, unit_id_last = 0; 455 cpudb_entry_t *entry; 456 board_stk_unit_t *stkunit; 457 458 CPUDB_FOREACH_ENTRY(db_ref, entry) { 459 /* local or remote */ 460 if (entry == db_ref->local_entry) { 461 unit_id_base = 0; 462 local = TRUE; 463 } else { 464 unit_id_base = offset; 465 offset += entry->base.num_units; 466 local = FALSE; 467 } 468 pgm->ru_offset[entry->topo_idx] = unit_id_base; 469 470 for (i=0; i<entry->base.num_units; i++) { 471 stkunit = &pgm->stk_unit[unit_id_base + i]; 472 stkunit->local = local; 473 stkunit->unit_id = unit_id_base + i; 474 stkunit->modid = entry->mod_ids[i]; 475 } 476 unit_id_last = unit_id_base + entry->base.num_units; 477 } 478 pgm->unit_last = unit_id_last; 479 return BCM_E_NONE; 480 } 481 482 #define NOT_DISABLED (BCM_STK_ENABLE|CPUDB_SPF_INACTIVE) 483 484 /* 485 * Function: 486 * _bcm_stk_port_change 487 * Purpose: 488 * Change stack port to given flags, avoiding unnecessary callbacks 489 * Parameters: 490 * unit - (IN) stack port unit 491 * port - (IN) stack port on unit 492 * flags - (IN) requested flags 493 * Returns: 494 * BCM_E_NONE - success 495 * BCM_E_XXX - failed 496 */ 497 STATIC int 498 _bcm_stk_port_change(int unit, int port, uint32 flags) 499 { 500 int changing; 501 uint32 cur_flags; 502 503 /* get the current flags */ 504 BCM_IF_ERROR_RETURN(bcm_stk_port_get(unit, port, &cur_flags)); 505 changing = FALSE; 506 507 /* If the stack port is going to be disabled and is currently 508 enabled, or the BCM_STK_ENABLE or CPUDB_SPF_INACTIVE flags are 509 changing state, then set the new stack port state. */ 510 511 512 513 if ((flags == 0 && (cur_flags & BCM_STK_ENABLE)) || 514 ((flags & NOT_DISABLED) != (cur_flags & NOT_DISABLED))) { 515 changing = TRUE; 516 } 517 518 if (changing) { 519 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, port, flags)); 520 } 521 522 return BCM_E_NONE; 523 } 524 525 /* 526 * Function: 527 * _pgm_stk_ports 528 * Purpose: 529 * Program stack ports in local CPUDB entry 530 * Parameters: 531 * db_ref - (IN) CPUDB 532 * Returns: 533 * BCM_E_NONE - success 534 * BCM_E_XXX - failed 535 */ 536 STATIC int 537 _pgm_stk_ports(cpudb_ref_t db_ref) 538 { 539 int rv, unit, port, i; 540 uint32 flags, spflags; 541 cpudb_entry_t *local; 542 543 local = db_ref->local_entry; 544 rv = BCM_E_NONE; 545 546 /* TO DO: Scan for ports that are no longer stack ports 547 * Foreach local device 548 * get current bitmap 549 * foreach port in bitmap 550 * search local entry stack ports for (unit, port) 551 * if found, continue 552 * otherwise, call bcm_stk_port_set with flags = 0 553 */ 554 555 /* Update stack ports */ 556 for (i = 0; i < local->base.num_stk_ports; i++) { 557 unit = local->base.stk_ports[i].unit; 558 port = local->base.stk_ports[i].port; 559 flags = BCM_STK_ENABLE; 560 spflags = local->sp_info[i].flags; 561 562 /* See if port is inactive (explicit, cut or no link) */ 563 if (spflags & CPUDB_SPF_ETHERNET) { 564 flags = 0; /* Disable - not a stack port anymore */ 565 } else if (spflags & CPUDB_SPF_NO_LINK) { 566 flags |= BCM_STK_INACTIVE | BCM_STK_NO_LINK; 567 } else if (spflags & CPUDB_SPF_INACTIVE) { 568 flags |= BCM_STK_INACTIVE; 569 } else if (spflags & CPUDB_SPF_CUT_PORT) { 570 flags |= BCM_STK_CUT; 571 } else { /* Port is active */ 572 /* Simplex/duplex: Only mark simplex if not duplex and resolved */ 573 if (spflags & CPUDB_SPF_DUPLEX) { 574 flags |= BCM_STK_DUPLEX; 575 } else { 576 if ((spflags & CPUDB_SPF_TX_RESOLVED) && 577 (spflags & CPUDB_SPF_RX_RESOLVED)) { 578 flags |= BCM_STK_SIMPLEX; 579 } 580 } /* Else, port is not yet resolved */ 581 } 582 583 rv = _bcm_stk_port_change(unit, port, flags); 584 if (BCM_FAILURE(rv)) { 585 break; 586 } 587 } 588 589 return rv; 590 } 591 592 /* 593 * Function: 594 * _stk_gport_enable 595 * Purpose: 596 * Adds given stack port to enable list 597 * Parameters: 598 * pgm - (INOUT) pgm structure 599 * gport - (IN) stack port 600 * Returns: 601 * void 602 */ 603 STATIC void 604 _stk_gport_enable(board_stk_pgm_t *pgm, bcm_gport_t gport) 605 { 606 int unit; 607 int port; 608 609 unit = BCM_GPORT_DEVPORT_DEVID_GET(gport); 610 port = BCM_GPORT_DEVPORT_PORT_GET(gport); 611 612 BCM_PBMP_PORT_ADD(pgm->stk_unit[unit].enaports, port); 613 } 614 615 /* 616 * Function: 617 * _pgm_internal_sp 618 * Purpose: 619 * Callback function to add connection as internal stack ports. 620 * Parameters: 621 * conn - (IN) internal stack port connection 622 * user_data - (INOUT) user data from callback registration 623 * Returns: 624 * BCM_E_NONE - success 625 * BCM_E_XXX - failed 626 */ 627 STATIC int 628 _pgm_internal_sp(board_connection_t *conn, void *user_data) 629 { 630 board_stk_pgm_t *pgm = (board_stk_pgm_t *)user_data; 631 632 /* add each port to enable list */ 633 _stk_gport_enable(pgm, conn->from); 634 _stk_gport_enable(pgm, conn->to); 635 636 return BCM_E_NONE; 637 } 638 639 /* 640 * Function: 641 * _manage_internal_stack_ports 642 * Purpose: 643 * Add all connection pairs in list as internal stack ports 644 * Parameters: 645 * pgm - (INOUT) pgm structure 646 * count - (IN) connection list length 647 * connection - (IN) connection list 648 * Returns: 649 * BCM_E_NONE - success 650 * BCM_E_XXX - failed 651 */ 652 STATIC int 653 _manage_internal_stack_ports(board_stk_pgm_t *pgm, 654 int count, 655 board_connection_t *connection) 656 { 657 return 658 board_connection_connected_stack_port_traverse(count, 659 connection, 660 _pgm_internal_sp, 661 pgm); 662 } 663 664 /* 665 * Function: 666 * _manage_external_stack_ports 667 * Purpose: 668 * Add CPUDB external ports to appropriate pgm members 669 * Parameters: 670 * pgm - (INOUT) pgm structure 671 * db_ref - (IN) CPUDB 672 * Returns: 673 * BCM_E_NONE - success 674 */ 675 STATIC int 676 _manage_external_stack_ports(board_stk_pgm_t *pgm, cpudb_ref_t db_ref) 677 { 678 cpudb_entry_t *local = db_ref->local_entry; 679 int unit, port, i; 680 uint32 spflags; 681 /* Update stack ports */ 682 683 for (i = 0; i < local->base.num_stk_ports; i++) { 684 unit = local->base.stk_ports[i].unit; 685 port = local->base.stk_ports[i].port; 686 spflags = local->sp_info[i].flags; 687 688 if ((spflags & CPUDB_SPF_TX_RESOLVED) && 689 (spflags & CPUDB_SPF_RX_RESOLVED)) { 690 /* rx/tx resolved -> enaports */ 691 BCM_PBMP_PORT_ADD(pgm->stk_unit[unit].enaports, port); 692 } else if (spflags & CPUDB_SPF_ETHERNET) { 693 /* not stacking -> ethports */ 694 BCM_PBMP_PORT_ADD(pgm->stk_unit[unit].ethports, port); 695 } else { 696 /* otherwise -> disports */ 697 BCM_PBMP_PORT_ADD(pgm->stk_unit[unit].disports, port); 698 } 699 } 700 701 return BCM_E_NONE; 702 } 703 704 /* 705 * Function: 706 * _pgm_conn_init 707 * Purpose: 708 * Initialize pgm structure connection data 709 * Parameters: 710 * pgm - (INOUT) pgm structure 711 * board - (IN) board driver 712 * db_ref - (IN) CPUDB 713 * Returns: 714 * BCM_E_NONE - success 715 * BCM_E_XXX - failed 716 */ 717 STATIC int 718 _pgm_conn_init(board_stk_pgm_t *pgm, board_driver_t *board, cpudb_ref_t db_ref) 719 { 720 int rv, added; 721 722 /* Get internal connections */ 723 724 rv = BCM_E_FULL; 725 if (board->num_connection < (pgm->max_conn - pgm->td.num_connection)) { 726 727 /* get the internal connections */ 728 sal_memcpy(pgm->td.connection, board->connection, 729 board->num_connection * sizeof(pgm->td.connection[0])); 730 pgm->td.num_connection += board->num_connection; 731 732 /* manage internal connections */ 733 BCM_IF_ERROR_RETURN 734 (_manage_internal_stack_ports(pgm, 735 board->num_connection, 736 board->connection)); 737 } 738 739 BCM_IF_ERROR_RETURN(_manage_external_stack_ports(pgm, db_ref)); 740 741 BCM_IF_ERROR_RETURN(_pgm_stk_ports(db_ref)); 742 743 /* Get external connections, and remote unit offset */ 744 rv = _cpudb_connection(db_ref, pgm->max_conn, 745 pgm->td.connection+pgm->td.num_connection, 746 &added, pgm->ru_offset); 747 if (BCM_SUCCESS(rv)) { 748 pgm->td.num_connection += added; 749 pgm->td.user_data = pgm; 750 pgm->td.info = _board_program_info; 751 pgm->td.edge = _board_program_edge; 752 pgm->td.vertex = _board_program_vertex; 753 } 754 755 return rv; 756 } 757 758 /* byte offset in allocation */ 759 #define OFFSET(m,offset) ((void *)(((uint8 *)(m)) + (int)(offset))) 760 761 /* 762 * Function: 763 * _stk_pgm_init 764 * Purpose: 765 * Initialze pgm structure 766 * Parameters: 767 * pgm - (OUT) pgm structure 768 * board - (IN) board driver 769 * db_ref - (IN) CPUDB 770 * Returns: 771 * BCM_E_NONE - success 772 * BCM_E_XXX - failed 773 */ 774 STATIC int 775 _stk_pgm_init(board_stk_pgm_t *pgm, board_driver_t *board, cpudb_ref_t db_ref) 776 { 777 int rv, units, entries, su_size, ru_size, cn_size; 778 cpudb_entry_t *entry; 779 780 /* 781 Count how many entries and units are going to be managed. Units 782 are in stk_unit by unit id. The unit id is equivalant to the SDK 783 unit number when the unit is local, and is offset by the number 784 of units on the board (to force such units to be recognized as 785 remote) for all remote units, so the total allocation needed is 786 the total number of units found in the CPUDB plus the number of 787 units on this board. 788 789 */ 790 791 rv = BCM_E_NONE; 792 units = entries = 0; 793 CPUDB_FOREACH_ENTRY(db_ref, entry) { 794 entries++; 795 units += entry->base.num_units; 796 } 797 units += board_num_devices(); 798 799 /* init struct */ 800 sal_memset(pgm, 0, sizeof(*pgm)); 801 802 /* allocate and init stk_unit */ 803 su_size = units * sizeof(pgm->stk_unit[0]); 804 ru_size = entries * sizeof(pgm->ru_offset[0]); 805 806 /* cn_size, at most, is the number of internal connections plus 807 the square of the number of CPUDB entries divided by two, as 808 there is only one topological connection between any given pair 809 of systems. 810 */ 811 pgm->max_conn = board->num_connection + (entries*entries/2); 812 pgm->td.num_connection = 0; 813 cn_size = pgm->max_conn * sizeof(pgm->td.connection[0]); 814 pgm->alloc = ALLOC(su_size + ru_size + cn_size); 815 if (pgm->alloc != NULL) { 816 sal_memset(pgm->alloc, 0, su_size + ru_size + cn_size); 817 pgm->stk_unit = OFFSET(pgm->alloc, 0); 818 pgm->ru_offset = OFFSET(pgm->alloc, su_size); 819 pgm->td.connection = OFFSET(pgm->alloc, su_size + ru_size); 820 rv = _pgm_unit_init(db_ref, pgm); 821 if (BCM_SUCCESS(rv)) { 822 rv = _pgm_conn_init(pgm, board, db_ref); 823 } 824 } 825 826 if (BCM_FAILURE(rv) && pgm->alloc != NULL) { 827 FREE(pgm->alloc); 828 } 829 830 return rv; 831 } 832 833 /* 834 * Function: 835 * _nh_reserved_modid_set 836 * Purpose: 837 * Gets the reserved Next Hop modid for the given unit and port 838 * Parameters: 839 * unit - (IN) stack unit 840 * port - (IN) port on stack unit 841 * Returns: 842 * BCM_E_NONE - success 843 * BCM_E_XXX - failed 844 */ 845 STATIC int 846 _nh_reserved_modid_set(int unit, bcm_port_t port) 847 { 848 int nhmod = -1; 849 int nhport; 850 int rv = BCM_E_NONE; 851 852 if (bcm_st_reserved_modid_enable_get()) { 853 rv = nh_tx_src_mod_port_get(unit, port, &nhmod, &nhport); 854 if (BCM_FAILURE(rv) || nhmod < 0) { 855 rv = nh_tx_src_get(&nhmod, &nhport); 856 } 857 if (BCM_SUCCESS(rv) && nhmod >= 0) { 858 rv = bcm_port_modid_enable_set(unit, port, nhmod, TRUE); 859 } 860 } 861 862 return rv; 863 } 864 865 /* 866 * Function: 867 * _stk_program_unit 868 * Purpose: 869 * Program the given unit for stacking 870 * Parameters: 871 * stkunit - (IN) programming data 872 * Returns: 873 * BCM_E_NONE - success 874 * BCM_E_XXX - failed 875 */ 876 STATIC int 877 _stk_program_unit(board_stk_unit_t *stkunit) 878 { 879 bcm_port_t from, to; 880 int rv = BCM_E_NONE; 881 882 BCM_PBMP_ITER(stkunit->disports, from) { 883 /* block all disports -> enaports */ 884 BCM_PBMP_ITER(stkunit->enaports, to) { 885 rv = bcm_port_flood_block_set(stkunit->unit_id, from, to, -1U); 886 if (BCM_FAILURE(rv)) { 887 return rv; 888 } 889 } 890 /* block all disports -> disports */ 891 BCM_PBMP_ITER(stkunit->disports, to) { 892 if (from == to) { 893 continue; 894 } 895 rv = bcm_port_flood_block_set(stkunit->unit_id, from, to, -1U); 896 if (BCM_FAILURE(rv)) { 897 return rv; 898 } 899 } 900 } 901 902 BCM_PBMP_ITER(stkunit->enaports, from) { 903 /* allow all enaports -> enaports */ 904 BCM_PBMP_ITER(stkunit->enaports, to) { 905 rv = bcm_port_flood_block_set(stkunit->unit_id, from, to, 0); 906 if (BCM_FAILURE(rv)) { 907 return rv; 908 } 909 } 910 /* block all enaports -> disports */ 911 BCM_PBMP_ITER(stkunit->enaports, to) { 912 rv = bcm_port_flood_block_set(stkunit->unit_id, from, to, -1U); 913 if (BCM_FAILURE(rv)) { 914 return rv; 915 } 916 } 917 } 918 919 /* reserved modid enabled on all enaports */ 920 BCM_PBMP_ITER(stkunit->enaports, from) { 921 rv = _nh_reserved_modid_set(stkunit->unit_id, from); 922 if (BCM_FAILURE(rv)) { 923 return rv; 924 } 925 } 926 927 /* all modids enabled on all ethports */ 928 BCM_PBMP_ITER(stkunit->ethports, from) { 929 rv = bcm_port_modid_enable_set(stkunit->unit_id, from, -1, TRUE); 930 if (BCM_FAILURE(rv)) { 931 return rv; 932 } 933 } 934 935 return rv; 936 } 937 938 /* 939 * Function: 940 * _stk_pgm_finish 941 * Purpose: 942 * Finish stack programming for all local devices 943 * Parameters: 944 * pgm - (IN) pgm structure 945 * Returns: 946 * BCM_E_NONE - success 947 * BCM_E_XXX - failed 948 */ 949 STATIC int 950 _stk_pgm_finish(board_stk_pgm_t *pgm) 951 { 952 int i, rv; 953 954 rv = BCM_E_NONE; 955 956 for (i=0; i<pgm->unit_last; i++) { 957 if (pgm->stk_unit[i].local) { 958 rv = _stk_program_unit(&pgm->stk_unit[i]); 959 if (BCM_FAILURE(rv)) { 960 break; 961 } 962 } 963 } 964 return rv; 965 } 966 967 /* 968 * Function: 969 * _stk_pgm_free 970 * Purpose: 971 * Free allocate pgm data 972 * Parameters: 973 * pgm - (IN) pgm structure 974 * Returns: 975 * void 976 */ 977 STATIC void 978 _stk_pgm_free(board_stk_pgm_t *pgm) 979 { 980 FREE(pgm->alloc); 981 } 982 983 /* 984 * Function: 985 * _stk_topo_map_init 986 * Purpose: 987 * Initializes board topology data 988 * Parameters: 989 * db_ref - (IN) CPUDB 990 * Returns: 991 * BCM_E_NONE - success 992 * BCM_E_XXX - failed 993 */ 994 STATIC int 995 _stk_topo_map_init(cpudb_ref_t db_ref) 996 { 997 int units; 998 int rv = BCM_E_FAIL; 999 void *map; 1000 1001 _board_stack_info.topo_valid = FALSE; 1002 map = _board_stack_info.topo_map; 1003 if (map) { 1004 /* Force current map to be unavailable */ 1005 _board_stack_info.topo_map = NULL; 1006 1007 /* now free the memory */ 1008 FREE(_board_stack_info.topo_map); 1009 } 1010 1011 /* Allocate topo map */ 1012 units = db_ref->local_entry->base.num_units; 1013 _board_stack_info.topo_map = 1014 ALLOC(units * sizeof(_board_stack_info.topo_map[0])); 1015 1016 if (_board_stack_info.topo_map) { 1017 _board_stack_info.topo_units = db_ref->local_entry->base.num_units; 1018 rv = BCM_E_NONE; 1019 } else { 1020 rv = BCM_E_MEMORY; 1021 } 1022 1023 return rv; 1024 } 1025 1026 /* 1027 * Function: 1028 * board_stack_program 1029 * Purpose: 1030 * Program the current board for stacking operation 1031 * Parameters: 1032 * db_ref - (IN) CPUDB 1033 * flags - (IN) flags 1034 * Returns: 1035 * BCM_E_NONE - success 1036 * BCM_E_XXX - failed 1037 */ 1038 int 1039 board_stack_program(cpudb_ref_t db_ref, uint32 flags) 1040 { 1041 board_stk_pgm_t pgm; 1042 board_driver_t *board; 1043 1044 board = board_driver(); 1045 1046 if (board == NULL) { 1047 return BCM_E_INIT; 1048 } 1049 1050 /* init pgm struct */ 1051 BCM_IF_ERROR_RETURN(_stk_pgm_init(&pgm, board, db_ref)); 1052 1053 /* init topo map */ 1054 BCM_IF_ERROR_RETURN(_stk_topo_map_init(db_ref)); 1055 1056 /* run tree programmer */ 1057 BCM_IF_ERROR_RETURN(board_tree_connect(&pgm.td)); 1058 1059 /* deal with enabled/disabled ports and flood blocking */ 1060 BCM_IF_ERROR_RETURN(_stk_pgm_finish(&pgm)); 1061 1062 /* set topo map, and make available */ 1063 BCM_IF_ERROR_RETURN(bcm_topo_map_set(_board_topo_port_get)); 1064 _board_stack_info.topo_valid = TRUE; 1065 1066 _stk_pgm_free(&pgm); 1067 1068 return BCM_E_NONE; 1069 } 1070 1071 #endif