topo_brd.c (37593B)
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: topo_brd.c 8 * Purpose: 9 * Requires: 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <bcm/error.h> 15 #include <bcm/types.h> 16 #include <bcm/topo.h> 17 #include <bcm/stack.h> 18 #include <bcm/link.h> 19 #include <bcm/port.h> 20 #include <bcm/switch.h> 21 #ifdef BCM_RPC_SUPPORT 22 #include <bcm_int/rpc/rpc.h> 23 #endif /* BCM_RPC_SUPPORT */ 24 25 #include <appl/stktask/stktask.h> 26 #include <appl/stktask/topology.h> 27 #include <appl/stktask/topo_brd.h> 28 #include <appl/stktask/topo_pkt.h> 29 #include <appl/stktask/attach.h> 30 #include <appl/cpudb/cpudb.h> 31 #include <appl/cputrans/nh_tx.h> 32 #include <appl/cputrans/cpu2cpu.h> 33 #include <appl/cputrans/atp.h> 34 #include <appl/discover/disc.h> 35 36 37 #include <soc/drv.h> 38 39 #include "topo_int.h" 40 #include "brd_chassis_int.h" 41 42 int topo_board_op(topo_board_control_t op, 43 cpudb_ref_t db_ref, topo_cpu_t *topo_cpu); 44 45 static sal_mutex_t topo_data_lock; /* Serves as init done indication */ 46 #define TD_INIT (topo_data_lock != NULL) 47 48 #define TOPO_DATA_LOCK sal_mutex_take(topo_data_lock, sal_mutex_FOREVER) 49 #define TOPO_DATA_UNLOCK sal_mutex_give(topo_data_lock) 50 51 /* Manage the system topology information here */ 52 topo_cpu_t bcm_board_topo_data; 53 volatile int topo_data_set; 54 55 /* Indicates whether stack ports can be set to HW linkscan mode */ 56 int _topo_hw_linkscan = 1; 57 58 59 /* 60 * Rapid Recovery 61 * 62 * The following data structure stores information for local stack ports 63 * used for rapid recovery. 64 * 65 * Note: The stack port index correspond to the same index used 66 * for stack port in databases such as cpudb, topo, and stacking. 67 * This convention has been used throughout the stacking code. 68 */ 69 typedef struct topo_sp_info_s { 70 int unit; /* Stack port unit */ 71 bcm_port_t port; /* Stack port */ 72 bcm_trunk_t tid; /* Stack port trunk ID */ 73 } topo_sp_info_t; 74 75 static topo_sp_info_t topo_sp[CPUDB_STK_PORTS_MAX]; 76 77 #define TOPO_SP_TID_GET(_idx) (topo_sp[_idx].tid) 78 #define TOPO_SP_TID_SET(_idx, _tid) (topo_sp[_idx].tid = _tid) 79 80 STATIC int topo_sp_idx_find(int unit, bcm_port_t port); 81 STATIC int topo_sp_init(cpudb_entry_t *entry); 82 STATIC int topo_sp_info_update(cpudb_entry_t *entry); 83 84 85 /* 86 * Set/get the current topology CPU information. 87 * 88 * Should be set to NULL when in transition or invalid 89 * 90 * This is exposed inside this library, but shouldn't be used 91 * above that level. 92 */ 93 94 int 95 bcm_board_topo_set(topo_cpu_t *tp_cpu) 96 { 97 topo_data_set = FALSE; 98 if (!TD_INIT) { 99 if ((topo_data_lock = sal_mutex_create("topo_data_lock")) == NULL) { 100 return BCM_E_MEMORY; 101 } 102 } 103 104 TOPO_DATA_LOCK; 105 if (tp_cpu != NULL) { 106 if (tp_cpu != &bcm_board_topo_data) { 107 /* Only copy if not the default */ 108 sal_memcpy(&bcm_board_topo_data, tp_cpu, sizeof(topo_cpu_t)); 109 } 110 topo_data_set = TRUE; 111 } else { 112 topo_data_set = FALSE; 113 } 114 TOPO_DATA_UNLOCK; 115 116 return BCM_E_NONE; 117 } 118 119 int 120 bcm_board_topo_get(topo_cpu_t **tp_cpu) 121 { 122 if (topo_data_set) { 123 *tp_cpu = &bcm_board_topo_data; 124 } else { 125 *tp_cpu = NULL; 126 } 127 return BCM_E_NONE; 128 } 129 130 131 /* 132 * Function: 133 * topo_cpu_trans_purge 134 * Purpose: 135 * Clears any pending transactions for given remote destination CPU. 136 * Parameters: 137 * entry - Entry for remote CPU 138 * Returns: 139 * N/A 140 */ 141 142 STATIC void 143 topo_cpu_trans_purge(cpudb_entry_t *entry) 144 { 145 atp_key_purge(entry->base.key); 146 #ifdef BCM_RPC_SUPPORT 147 bcm_rpc_cleanup(entry->base.key); 148 #endif /* BCM_RPC_SUPPORT */ 149 } 150 151 152 /* 153 * Function: 154 * topo_cpu_trans_flush 155 * Purpose: 156 * Checks and clears pending transactions for remote CPUs where 157 * a different local stack port is now used to transmit to. 158 * Parameters: 159 * db_ref - Database of current system configuration 160 * Returns: 161 * BCM_E_NONE Success 162 * Notes: 163 * This routine should be called before a new topology is 164 * set for the system. 165 */ 166 167 STATIC int 168 topo_cpu_trans_flush(cpudb_ref_t db_ref) 169 { 170 cpudb_ref_t prev_db; 171 cpudb_entry_t *entry; 172 cpudb_entry_t *l_entry; 173 cpudb_entry_t *prev_entry; 174 175 if ((prev_db = db_ref->old_db) == NULL) { 176 return BCM_E_NONE; 177 } 178 179 l_entry = db_ref->local_entry; 180 181 /* Check if path to get to this remote CPU has changed */ 182 CPUDB_FOREACH_ENTRY(db_ref, entry) { 183 if (entry == l_entry) { 184 continue; 185 } 186 187 CPUDB_KEY_SEARCH(prev_db, entry->base.key, prev_entry); 188 if (prev_entry != NULL) { 189 if ((prev_entry->tx_unit == entry->tx_unit) && 190 (prev_entry->tx_port == entry->tx_port)) { 191 continue; 192 } 193 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 194 (BSL_META("TX path changed to CPU " CPUDB_KEY_FMT_EOLN), 195 CPUDB_KEY_DISP(entry->base.key))); 196 topo_cpu_trans_purge(entry); 197 } 198 } 199 200 return BCM_E_NONE; 201 } 202 203 /* 204 * Function: 205 * topo_board_setup 206 * Purpose: 207 * Program a board according to the given CPUDB 208 * Parameters: 209 * db_ref - Data base with system info 210 * Returns: 211 * BCM_E_XXX 212 * Notes: 213 * Currently supports 24 Gig, 48 Gig and 48 FE stacking 214 * reference designs. 215 * 216 * If CPUDB contains one entry, set up the topo CPU structure directly. 217 * Otherwise, (for now) call the topo packet generate and parse 218 * routines to generate the topo CPU structure. 219 * 220 * This routine clears "topo_data_set" and will only set it back to true 221 * if the data is successfully generated. 222 */ 223 224 int 225 topo_board_setup(cpudb_ref_t db_ref) 226 { 227 int rv = BCM_E_NONE; 228 229 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 230 (BSL_META("Topology board setup\n"))); 231 232 topo_data_set = FALSE; 233 if (!TD_INIT) { 234 if ((topo_data_lock = sal_mutex_create("topo_data_lock")) == NULL) { 235 return BCM_E_MEMORY; 236 } 237 } 238 239 if (db_ref->local_entry == NULL || db_ref->num_cpus <= 0 || 240 db_ref->num_cpus > CPUDB_CPU_MAX) { 241 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 242 (BSL_META("TOPO SETUP: Local entry %p, num cpus %d\n"), 243 db_ref->local_entry, db_ref->num_cpus)); 244 return BCM_E_PARAM; 245 } 246 247 TOPO_DATA_LOCK; 248 /* Clear current topo data */ 249 sal_memset(&bcm_board_topo_data, 0, sizeof(topo_cpu_t)); 250 if (db_ref->num_cpus == 1) { 251 252 /* All local external stack ports have 0 mod id associations. */ 253 if ((rv = cpudb_entry_copy(&bcm_board_topo_data.local_entry, 254 db_ref->local_entry)) < 0) { 255 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 256 (BSL_META("TOPO SETUP: Failed to copy entry\n"))); 257 } else { 258 bcm_board_topo_data.num_cpus = 1; 259 topo_data_set = TRUE; 260 261 if ((rv = topo_board_program(db_ref, &bcm_board_topo_data)) < 0) { 262 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 263 (BSL_META("TOPO SETUP: Failed topo brd program: %s\n"), 264 bcm_errmsg(rv))); 265 } 266 } 267 } else { 268 /* For now, use packet generate/parse */ 269 static uint8 _pkt_buf[TOPO_PKT_BYTES_MAX]; 270 int len; 271 272 /* Generate topo pkt; then parse it to get topo cpu struct */ 273 if ((rv = topo_pkt_gen(db_ref, db_ref->local_entry, 274 _pkt_buf, TOPO_PKT_BYTES_MAX, &len)) < 0) { 275 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 276 (BSL_META("TOPO SETUP: Failed pkt gen\n"))); 277 } else if ((rv = topo_pkt_parse(db_ref, db_ref->local_entry, _pkt_buf, 278 len, &bcm_board_topo_data, NULL)) < 0) { 279 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 280 (BSL_META("TOPO SETUP: Failed pkt parse\n"))); 281 } else { 282 bcm_board_topo_data.num_cpus = db_ref->num_cpus; 283 topo_data_set = TRUE; 284 } 285 } 286 /* Set master seq num if present */ 287 if (topo_data_set && db_ref->master_entry != NULL) { 288 bcm_board_topo_data.master_seq_num = 289 db_ref->master_entry->base.dseq_num; 290 } 291 TOPO_DATA_UNLOCK; 292 293 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 294 (BSL_META("TOPO SETUP: Exit rv %d, data set %d\n"), 295 rv, topo_data_set)); 296 return rv; 297 } 298 299 /* Set stack ports */ 300 301 STATIC int 302 _topo_stk_ports_update(cpudb_ref_t db_ref, topo_cpu_t *topo_cpu) 303 { 304 int unit, port; 305 uint32 flags, spflags; 306 cpudb_entry_t *l_entry; 307 int i; 308 309 l_entry = db_ref->local_entry; 310 311 /* TO DO: Scan for ports that are no longer stack ports 312 * Foreach local device 313 * get current bitmap 314 * foreach port in bitmap 315 * search local entry stack ports for (unit, port) 316 * if found, continue 317 * otherwise, call bcm_stk_port_set with flags = 0 318 */ 319 320 /* Update stack ports */ 321 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 322 unit = l_entry->base.stk_ports[i].unit; 323 port = l_entry->base.stk_ports[i].port; 324 flags = BCM_STK_ENABLE; 325 spflags = l_entry->sp_info[i].flags; 326 327 328 #if !defined(TOPO_BRD_UPDATE_ALL_PORTS) 329 /* See if stack port flags have changed since the old db. 330 This is an optimization that depends on the old CPUDB being 331 propagated. Applications that require pre SDK-5.6.3 332 behavior can define TOPO_BRD_UPDATE_ALL_PORTS. 333 */ 334 if ((cpudb_valid(db_ref->old_db)) && 335 (db_ref->old_db->local_entry->base.num_stk_ports == 336 l_entry->base.num_stk_ports) && 337 (db_ref->old_db->local_entry->base.stk_ports[i].unit == unit) && 338 (db_ref->old_db->local_entry->base.stk_ports[i].port == port) && 339 (db_ref->old_db->local_entry->sp_info[i].flags == spflags)) { 340 continue; 341 } 342 #endif 343 344 /* See if port is inactive (explicit, cut or no link) */ 345 if (spflags & CPUDB_SPF_ETHERNET) { 346 flags = 0; /* Disable - not a stack port anymore */ 347 } else if (spflags & CPUDB_SPF_NO_LINK) { 348 flags |= BCM_STK_INACTIVE | BCM_STK_NO_LINK; 349 } else if (spflags & CPUDB_SPF_INACTIVE) { 350 flags |= BCM_STK_INACTIVE; 351 } else if (spflags & CPUDB_SPF_CUT_PORT) { 352 flags |= BCM_STK_CUT; 353 } else { /* Port is active */ 354 /* Simplex/duplex: Only mark simplex if not duplex and resolved */ 355 if (spflags & CPUDB_SPF_DUPLEX) { 356 flags |= BCM_STK_DUPLEX; 357 } else { 358 if ((spflags & CPUDB_SPF_TX_RESOLVED) && 359 (spflags & CPUDB_SPF_RX_RESOLVED)) { 360 flags |= BCM_STK_SIMPLEX; 361 } 362 } /* Else, port is not yet resolved */ 363 } 364 BCM_IF_ERROR_RETURN(bcm_stk_port_set(unit, port, flags)); 365 } 366 367 return BCM_E_NONE; 368 } 369 370 371 /* 372 * Function: 373 * topo_board_program 374 * Purpose: 375 * Program a board given local topology info 376 * Parameters: 377 * db_ref - Data base of current configuration 378 * topo_cpu - Info for local board programming 379 * Returns: 380 * BCM_E_XXX 381 * Notes: 382 * Currently supports 24 Gig, 48 Gig and 48 FE stacking 383 * reference designs. 384 */ 385 386 STATIC int 387 _topo_board_default_program(cpudb_ref_t db_ref, topo_cpu_t *topo_cpu) 388 { 389 int i, j; 390 int done; 391 cpudb_entry_t *entry; 392 cpudb_entry_t *l_entry; 393 int rv_tmp, rv = BCM_E_FAIL; 394 cpudb_unit_port_t *sp; 395 uint32 flags; 396 397 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 398 (BSL_META("Topology board programming db_ref %p. old_db %p\n"), 399 db_ref, db_ref->old_db)); 400 401 l_entry = db_ref->local_entry; 402 403 /* First, handle some things for the local entry */ 404 l_entry->flags |= CPUDB_F_TX_KNOWN; 405 406 /* If not using the reserved modid feature, set the NH source 407 modid on each resolved stack port */ 408 if (!bcm_st_reserved_modid_enable_get()) { 409 int loc_mod_id = -1; 410 411 /* 412 * Program NH TX source module to a local mod ID; 413 * First, find a local mod ID, if present 414 */ 415 for (i = 0; i < l_entry->base.num_units; i++) { 416 if (l_entry->mod_ids[i] >= 0) { 417 loc_mod_id = l_entry->mod_ids[i]; 418 break; /* Found a local mod ID */ 419 } 420 } /* for each unit */ 421 422 /* Even if loc_mod_id < 0, that's what we want to use */ 423 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 424 sp = &l_entry->base.stk_ports[i]; 425 BCM_IF_ERROR_RETURN(bcm_stk_port_get(sp->unit, sp->port, &flags)); 426 if (!(flags & BCM_STK_SL) && 427 l_entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED) { 428 rv_tmp = nh_tx_src_mod_port_set(sp->unit, sp->port, 429 loc_mod_id, -1); 430 if (rv_tmp < 0) { 431 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 432 (BSL_META("TOPOLOGY WARNING: " 433 "Could not set NH mod/port for (%d, %d): %s\n"), 434 sp->unit, sp->port, bcm_errmsg(rv_tmp))); 435 } 436 } else { 437 /* Allow default NH source mod id */ 438 rv_tmp = nh_tx_src_mod_port_set(sp->unit, sp->port, -1, -1); 439 if (rv_tmp < 0) { 440 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 441 (BSL_META("TOPOLOGY WARNING: " 442 "Could not clear NH mod/port for (%d, %d): " 443 "%s\n"), 444 sp->unit, sp->port, bcm_errmsg(rv_tmp))); 445 } 446 } 447 } 448 } 449 450 /* Set up the tx unit/port for each other destination in the system */ 451 452 CPUDB_FOREACH_ENTRY(db_ref, entry) { 453 if (entry == l_entry) { 454 continue; 455 } 456 457 done = FALSE; 458 /* Find the stack port to get to this CPU */ 459 for (i = 0; i < l_entry->base.num_stk_ports && !done; i++) { 460 for (j = 0; j < topo_cpu->tp_stk_port[i].tx_mod_num && !done; j++) { 461 if (entry->dest_mod == topo_cpu->tp_stk_port[i].tx_mods[j]) { 462 entry->tx_unit = l_entry->base.stk_ports[i].unit; 463 entry->tx_port = l_entry->base.stk_ports[i].port; 464 done = TRUE; 465 } 466 } 467 } 468 if (!done) { 469 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 470 (BSL_META("TOPOLOGY WARNING: Did not find tx stack port for " 471 CPUDB_KEY_FMT " mod %d\n"), CPUDB_KEY_DISP(entry->base.key), 472 entry->dest_mod)); 473 } 474 /* This amounts to ignoring the warning */ 475 entry->flags |= CPUDB_F_TX_KNOWN; 476 } 477 478 479 /* Check and clear transactions for remote CPUs with a different path */ 480 topo_cpu_trans_flush(db_ref); 481 482 /* Set new topology information */ 483 bcm_board_topo_set(topo_cpu); 484 485 /* Initialize topology stack port info */ 486 topo_sp_init(l_entry); 487 488 #if defined(TOPO_BRD_UPDATE_BEFORE_PROGRAM) 489 /* Currently, stack port status is updated after the rest of board 490 programming. The behavior before SDK-5.6.3 was to update the 491 stack ports before board programming. In principle, the order 492 should not matter. Define TOPO_BRD_UPDATE_BEFORE_PROGRAM to 493 restore the older behavior if it is needed. */ 494 BCM_IF_ERROR_RETURN(_topo_stk_ports_update(db_ref, topo_cpu)); 495 #endif 496 497 /* Set up the board based on device detection. */ 498 if (soc_ndev == 1 && 499 SOC_IS_HERCULES15(0)) { 500 rv = bcm_board_topo_cfm_xgs2(topo_cpu, db_ref); 501 } else if (soc_ndev == 1 && 502 SOC_IS_XGS12_FABRIC(0)) { 503 rv = bcm_board_topo_8h(topo_cpu, db_ref); 504 } else if (soc_ndev == 1 && 505 SOC_IS_RAPTOR(0)) { 506 rv = bcm_board_topo_xgs3_48g5g(topo_cpu, db_ref); 507 } else if (soc_ndev == 1 && 508 SOC_IS_FB_FX_HX(0)) { 509 rv = bcm_board_topo_sdk_xgs3_24g(topo_cpu, db_ref); 510 } else { 511 512 switch (db_ref->local_entry->base.board_id) { 513 case cpudb_board_id_sdk_xgs3_24g: 514 rv = bcm_board_topo_sdk_xgs3_24g(topo_cpu, db_ref); 515 break; 516 case cpudb_board_id_sdk_xgs3_20x: 517 rv = bcm_board_topo_xgs3_20x(topo_cpu, db_ref); 518 break; 519 case cpudb_board_id_cfm_xgs3: 520 rv = bcm_board_topo_cfm_xgs3(topo_cpu, db_ref); 521 break; 522 case cpudb_board_id_lm_56800_12x: 523 rv = bcm_board_topo_lm_56800_12x(topo_cpu, db_ref); 524 break; 525 case cpudb_board_id_sdk_xgs3_48g: 526 rv = bcm_board_topo_xgs3_48g(topo_cpu, db_ref); 527 break; 528 case cpudb_board_id_sdk_xgs3_48f: 529 rv = bcm_board_topo_xgs3_48f(topo_cpu, db_ref); 530 break; 531 case cpudb_board_id_lm_xgs3_48g: 532 rv = bcm_board_topo_lm_xgs3_48g(topo_cpu, db_ref); 533 break; 534 case cpudb_board_id_sdk_xgs3_48g5g: 535 rv = bcm_board_topo_xgs3_48g5g(topo_cpu, db_ref); 536 break; 537 case cpudb_board_id_sdk_xgs3_48g2: 538 rv = bcm_board_topo_xgs3_48g2(topo_cpu, db_ref); 539 break; 540 default: 541 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 542 (BSL_META("TOPOLOGY ERROR: Unknown board\n"))); 543 rv = BCM_E_NOT_FOUND; 544 break; 545 } 546 } 547 return rv; 548 } 549 550 int 551 topo_board_program(cpudb_ref_t db_ref, topo_cpu_t *topo_cpu) 552 { 553 int i, j; 554 int done; 555 cpudb_entry_t *entry; 556 cpudb_entry_t *l_entry; 557 int rv_tmp, rv = BCM_E_FAIL; 558 cpudb_unit_port_t *sp; 559 uint32 flags; 560 int nh_vlan; 561 562 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 563 (BSL_META("Topology board programming db_ref %p. old_db %p\n"), 564 db_ref, db_ref->old_db)); 565 566 l_entry = db_ref->local_entry; 567 568 /* First, handle some things for the local entry */ 569 l_entry->flags |= CPUDB_F_TX_KNOWN; 570 571 /* If not using the reserved modid feature, set the NH source 572 modid on each resolved stack port */ 573 if (!bcm_st_reserved_modid_enable_get()) { 574 int loc_mod_id = -1; 575 576 /* 577 * Program NH TX source module to a local mod ID; 578 * First, find a local mod ID, if present 579 */ 580 for (i = 0; i < l_entry->base.num_units; i++) { 581 if (l_entry->mod_ids[i] >= 0) { 582 loc_mod_id = l_entry->mod_ids[i]; 583 break; /* Found a local mod ID */ 584 } 585 } /* for each unit */ 586 587 /* Even if loc_mod_id < 0, that's what we want to use */ 588 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 589 sp = &l_entry->base.stk_ports[i]; 590 BCM_IF_ERROR_RETURN(bcm_stk_port_get(sp->unit, sp->port, &flags)); 591 if (!(flags & BCM_STK_SL) && 592 l_entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED) { 593 rv_tmp = nh_tx_src_mod_port_set(sp->unit, sp->port, 594 loc_mod_id, -1); 595 if (rv_tmp < 0) { 596 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 597 (BSL_META("TOPOLOGY WARNING: " 598 "Could not set NH mod/port for (%d, %d): %s\n"), 599 sp->unit, sp->port, bcm_errmsg(rv_tmp))); 600 } 601 } else { 602 /* Allow default NH source mod id */ 603 rv_tmp = nh_tx_src_mod_port_set(sp->unit, sp->port, -1, -1); 604 if (rv_tmp < 0) { 605 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 606 (BSL_META("TOPOLOGY WARNING: " 607 "Could not clear NH mod/port for (%d, %d): " 608 "%s\n"), 609 sp->unit, sp->port, bcm_errmsg(rv_tmp))); 610 } 611 } 612 } 613 } 614 615 /* Set up the tx unit/port for each other destination in the system */ 616 617 CPUDB_FOREACH_ENTRY(db_ref, entry) { 618 if (entry == l_entry) { 619 continue; 620 } 621 622 done = FALSE; 623 /* Find the stack port to get to this CPU */ 624 for (i = 0; i < l_entry->base.num_stk_ports && !done; i++) { 625 for (j = 0; j < topo_cpu->tp_stk_port[i].tx_mod_num && !done; j++) { 626 if (entry->dest_mod == topo_cpu->tp_stk_port[i].tx_mods[j]) { 627 entry->tx_unit = l_entry->base.stk_ports[i].unit; 628 entry->tx_port = l_entry->base.stk_ports[i].port; 629 done = TRUE; 630 } 631 } 632 } 633 if (!done) { 634 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 635 (BSL_META("TOPOLOGY WARNING: Did not find tx stack port for " 636 CPUDB_KEY_FMT " mod %d\n"), CPUDB_KEY_DISP(entry->base.key), 637 entry->dest_mod)); 638 } 639 /* This amounts to ignoring the warning */ 640 entry->flags |= CPUDB_F_TX_KNOWN; 641 } 642 643 644 /* Check and clear transactions for remote CPUs with a different path */ 645 topo_cpu_trans_flush(db_ref); 646 647 /* Set new topology information */ 648 bcm_board_topo_set(topo_cpu); 649 650 /* Initialize topology stack port info */ 651 topo_sp_init(l_entry); 652 653 rv = topo_board_op(topoBoardProgram, db_ref, topo_cpu); 654 655 #if !defined(TOPO_BRD_UPDATE_BEFORE_PROGRAM) 656 BCM_IF_ERROR_RETURN(_topo_stk_ports_update(db_ref, topo_cpu)); 657 #endif 658 /* 659 * Re-install NH TX destination mac address since mod ID 660 * for local CPU could be different after a topology run 661 */ 662 next_hop_vlan_get(&nh_vlan); 663 nh_tx_dest_install(TRUE, nh_vlan); 664 665 if (rv < 0) { 666 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 667 (BSL_META("TOPO board prg: Board programming failed: %s\n"), 668 bcm_errmsg(rv))); 669 bcm_board_topo_set(NULL); 670 } else { 671 rv = topo_sp_info_update(l_entry); 672 } 673 674 return rv; 675 } 676 677 /* 678 * Set HW linkscan when this is allowed by flag '_topo_hw_linkscan' 679 * and Stack Trunk Failover is supported by device. 680 */ 681 STATIC int 682 _topo_linkscan_mode_set(cpudb_entry_t *entry) 683 { 684 int i; 685 int unit; 686 int port; 687 int trunk_failover; 688 689 if (!_topo_hw_linkscan) { 690 return BCM_E_NONE; 691 } 692 693 /* Using CPUDB same stack port index */ 694 for (i = 0; i < entry->base.num_stk_ports; i++) { 695 unit = entry->base.stk_ports[i].unit; 696 port = entry->base.stk_ports[i].port; 697 698 if (BCM_SUCCESS(bcm_switch_control_get(unit, 699 bcmSwitchFailoverStackTrunk, 700 &trunk_failover))) { 701 if (trunk_failover) { 702 BCM_IF_ERROR_RETURN 703 (bcm_linkscan_mode_set(unit, port, BCM_LINKSCAN_MODE_HW)); 704 } 705 } 706 } 707 708 return BCM_E_NONE; 709 } 710 711 /* 712 * Some devices have restrictions on what the allowable modid 713 * may be, such as the modid must be even when the device requires 714 * two modids. This isn't true for all such devices, so we just test 715 * for that property 716 */ 717 718 STATIC int 719 _topo_set_unit_modid_preference(int unit, int num_modid, int *preference) 720 { 721 int current_modid, new_modid; 722 723 if (num_modid == 2) { 724 725 /* If the device requires two modids and the modid is even, 726 see if the modid can be odd. */ 727 728 BCM_IF_ERROR_RETURN(bcm_stk_my_modid_get(unit, ¤t_modid)); 729 if ((current_modid & 1) == 0) { 730 int rv; 731 732 new_modid = current_modid+1; 733 rv = bcm_stk_my_modid_set(unit, new_modid); 734 if (rv == BCM_E_BADID) { 735 *preference = CPUDB_TOPO_MODID_EVEN; 736 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 737 (BSL_META_U(unit, 738 "unit %d modid preference is even\n"), 739 unit)); 740 } 741 BCM_IF_ERROR_RETURN(bcm_stk_my_modid_set(unit, current_modid)); 742 } 743 } 744 return BCM_E_NONE; 745 } 746 747 748 /* 749 * Update the CPU database module ID parameters based on actual device 750 * configuration. 751 */ 752 753 STATIC int 754 _topo_set_modid_parameters(cpudb_entry_t *entry) 755 { 756 int unit; 757 int *preference, *required, num_modid; 758 759 for ( unit=0; unit<entry->base.num_units; unit++ ) { 760 required = &entry->base.mod_ids_req[unit]; 761 762 if (*required > 0) { 763 764 preference = &entry->base.pref_mod_id[unit]; 765 766 if (*preference == CPUDB_TOPO_MODID_ANY) { 767 768 BCM_IF_ERROR_RETURN(bcm_stk_modid_count(unit, &num_modid)); 769 770 /* 771 If the number of modids the device needs is more 772 than what is requested, then update the number of 773 required modids to what the device supports. 774 775 This is intended to support devices that are 776 configurable to use one or more modids. 777 */ 778 779 if (num_modid > *required) { 780 *required = num_modid; 781 } 782 783 BCM_IF_ERROR_RETURN 784 (_topo_set_unit_modid_preference(unit, 785 num_modid, preference)); 786 } 787 } 788 } 789 return BCM_E_NONE; 790 } 791 792 static int 793 _topo_board_default_initialize(cpudb_ref_t db_ref) 794 { 795 switch (db_ref->local_entry->base.board_id) { 796 case cpudb_board_id_cfm_xgs2: 797 case cpudb_board_id_cfm_xgs3: 798 case cpudb_board_id_lm_xgs2_6x: 799 case cpudb_board_id_lm_xgs2_48g: 800 case cpudb_board_id_lm_xgs3_12x: 801 case cpudb_board_id_lm_xgs3_48g: 802 case cpudb_board_id_lm_56800_12x: 803 #if defined(INCLUDE_CHASSIS) 804 805 #define CHASSIS_C2C_SRC_MODID 31 /* Src mod ID for c2c */ 806 807 db_ref->local_entry->base.flags |= CPUDB_BASE_F_CHASSIS; 808 if (db_ref->local_entry->base.board_id == cpudb_board_id_cfm_xgs3) { 809 db_ref->local_entry->base.flags |= CPUDB_BASE_F_CHASSIS_10SLOT; 810 } 811 if (CHASSIS_SM(db_ref->local_entry->base.flags)) { 812 /* Set c2c src modid for for SM load balancing only */ 813 c2c_src_mod_set(CHASSIS_C2C_SRC_MODID); 814 /* Use special modid assignment */ 815 topology_mod_id_assign_function(topo_chassis_modids_assign); 816 } 817 /* Don't touch discovery minimum TTL; set maximum TTL to 2 */ 818 disc_ttl_max_set(2); 819 bcm_board_chassis_setup(db_ref); 820 #endif 821 break; 822 case cpudb_board_id_sdk_xgs3_48f: 823 case cpudb_board_id_sdk_xgs3_48g: 824 case cpudb_board_id_sdk_xgs3_24g: 825 case cpudb_board_id_sdk_xgs3_20x: 826 case cpudb_board_id_sdk_xgs3_48g5g: 827 case cpudb_board_id_sdk_xgs3_48g2: 828 disc_ttl_max_set(2); 829 break; 830 default: 831 break; 832 } 833 834 return BCM_E_NONE; 835 } 836 837 int 838 topo_board_initialize(cpudb_ref_t db_ref) 839 { 840 BCM_IF_ERROR_RETURN(topo_board_op(topoBoardInit, db_ref, NULL)); 841 842 /* Set stack ports linkscan mode */ 843 _topo_linkscan_mode_set(db_ref->local_entry); 844 845 _topo_set_modid_parameters(db_ref->local_entry); 846 847 return BCM_E_NONE; 848 } 849 850 851 /* 852 * Rapid Recovery 853 */ 854 855 /* 856 * Function: 857 * topo_sp_idx_find 858 * Purpose: 859 * Looks up given stack unit/port in local topology stack information 860 * and returns database index. 861 * Parameters: 862 * unit - Unit of stack port 863 * port - Stack port 864 * Returns: 865 * >= 0 Stack port index 866 * < 0 Cannot find given stack port in local topology information 867 * Note: 868 * Caller must apply LOCK. 869 */ 870 871 STATIC int 872 topo_sp_idx_find(int unit, bcm_port_t port) 873 { 874 int i; 875 876 for (i = 0; i < COUNTOF(topo_sp); i++) { 877 if ((topo_sp[i].unit == unit) && (topo_sp[i].port == port)) { 878 return i; 879 } 880 } 881 882 return BCM_E_NOT_FOUND; 883 } 884 885 886 /* 887 * Function: 888 * topo_sp_init 889 * Purpose: 890 * Initializes topology stack port information and 891 * set HW linkscan mode for stack ports on devices with 892 * stack port trunk failover support. 893 * Parameters: 894 * entry - Local CPUDB entry 895 * Returns: 896 * BCM_E_NONE - Success 897 * BCM_E_XXX - Number of given stack ports is larger than local db 898 */ 899 900 STATIC int 901 topo_sp_init(cpudb_entry_t *entry) 902 { 903 int i; 904 int topo_sp_max = COUNTOF(topo_sp); 905 906 907 TOPO_DATA_LOCK; 908 for (i = 0; i < topo_sp_max; i++) { 909 topo_sp[i].unit = -1; 910 topo_sp[i].port = -1; 911 topo_sp[i].tid = -1; 912 } 913 914 if (entry->base.num_stk_ports > topo_sp_max) { 915 TOPO_DATA_UNLOCK; 916 return BCM_E_FAIL; 917 } 918 919 /* Using CPUDB same stack port index */ 920 for (i = 0; i < entry->base.num_stk_ports; i++) { 921 topo_sp[i].unit = entry->base.stk_ports[i].unit; 922 topo_sp[i].port = entry->base.stk_ports[i].port; 923 } 924 925 TOPO_DATA_UNLOCK; 926 return BCM_E_NONE; 927 } 928 929 930 /* 931 * Function: 932 * topo_sp_info_update 933 * Purpose: 934 * Updates the topology stack port database with the system's 935 * current configuration. Currently, only trunk information 936 * is being stored. 937 * Parameters: 938 * entry - Local CPUDB entry 939 * Returns: 940 * BCM_E_NONE - Success 941 * BCM_E_XXX - Error obtaining system's information 942 */ 943 944 STATIC int 945 topo_sp_info_update(cpudb_entry_t *entry) 946 { 947 int i; 948 int unit; 949 bcm_port_t port; 950 bcm_trunk_t tid; 951 bcm_module_t modid = -1; 952 int topo_sp_max = COUNTOF(topo_sp); 953 954 /* Load information from current system configuration */ 955 TOPO_DATA_LOCK; 956 for (i = 0; i < topo_sp_max; i++) { 957 unit = topo_sp[i].unit; 958 port = topo_sp[i].port; 959 960 if ((unit < 0) || (port < 0)) { 961 continue; 962 } 963 964 if (BCM_SUCCESS(bcm_trunk_find(unit, modid, 965 BCM_GPORT_DEVPORT(unit, port), &tid))) { 966 topo_sp[i].tid = tid; 967 } else { 968 topo_sp[i].tid = -1; 969 } 970 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 971 (BSL_META_U(unit, 972 "Stack port %d: unit %d, port %d, tid %d\n"), 973 i, unit, port, topo_sp[i].tid)); 974 } 975 TOPO_DATA_UNLOCK; 976 977 return BCM_E_NONE; 978 } 979 980 981 /* 982 * Function: 983 * topo_sp_tx_cpu_replace 984 * Purpose: 985 * Replaces the TX stack port if the failed port is used to 986 * reach a destination in the system. The routine will: 987 * - replace port in CPU database, 988 * - update C2C database, 989 * - clear any pending transaction to destination CPU 990 * Parameters: 991 * db_ref - (IN/OUT) Current CPU database 992 * unit - Unit of failed stack port 993 * fail_sp - Failed stack port to replace 994 * repl_sp - Replacing stack port 995 * Returns: 996 * N/A 997 * NOTE: 998 * Assumes that the failed and replacing ports are in the same unit. 999 */ 1000 1001 STATIC void 1002 topo_sp_tx_cpu_replace(cpudb_ref_t db_ref, int unit, 1003 bcm_port_t fail_sp, bcm_port_t repl_sp) 1004 { 1005 cpudb_entry_t *entry; 1006 1007 CPUDB_FOREACH_ENTRY(db_ref, entry) { 1008 if (entry == db_ref->local_entry) { 1009 continue; 1010 } 1011 /* Replace if failed port is being used */ 1012 if ((entry->tx_unit == unit) && (entry->tx_port == fail_sp)) { 1013 entry->tx_port = repl_sp; 1014 topo_cpu_trans_purge(entry); 1015 c2c_cpu_add(entry); 1016 /* 1017 * Inform ATP that the db entry has been modified 1018 * so that in-flight tx pkts are handled gracefully 1019 */ 1020 atp_db_update_notify(); 1021 } 1022 } 1023 1024 } 1025 1026 1027 /* 1028 * Function: 1029 * topo_board_rapid_recovery 1030 * Purpose: 1031 * Performs a rapid recovery of the local system for 1032 * the following defined cases: 1033 * 1034 * a) Trunk link failure 1035 * When the failure occurs on a stack port that is a member 1036 * of a trunk. Trunk should contain at least one more additional 1037 * stack port. 1038 * 1039 * Any other cases not defined above will return failure. 1040 * 1041 * Parameters: 1042 * db_ref - (IN/OUT) Current CPU database 1043 * unit - Unit of failed stack port 1044 * fail_sp - Failed stack port 1045 * Returns: 1046 * BCM_E_NONE - Success 1047 * BCM_E_XXX - System cannot perform rapid recovery 1048 */ 1049 1050 int 1051 topo_board_rapid_recovery(cpudb_ref_t db_ref, int unit, bcm_port_t fail_sp) 1052 { 1053 topo_cpu_t *topo_cpu; /* Current topology */ 1054 int fail_sp_idx; /* Failed stack port index */ 1055 bcm_trunk_t tid; /* Trunk ID of failed stack port */ 1056 int rv = BCM_E_UNAVAIL; 1057 1058 TOPO_DATA_LOCK; 1059 1060 /* Get current topology */ 1061 bcm_board_topo_get(&topo_cpu); 1062 if (topo_cpu == NULL) { 1063 TOPO_DATA_UNLOCK; 1064 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1065 (BSL_META_U(unit, 1066 "Current topology is null\n"))); 1067 return BCM_E_FAIL; 1068 } 1069 1070 1071 /* 1072 * Trunk Link Failure 1073 * 1074 * Note: The topology database is currently NOT being updated for now. 1075 * The original information created by topology after 1076 * a full discovery cycle remains unchanged. 1077 */ 1078 if ((fail_sp_idx = topo_sp_idx_find(unit, fail_sp)) < 0) { 1079 TOPO_DATA_UNLOCK; 1080 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1081 (BSL_META_U(unit, 1082 "Stack port unit %d, port %d, not found\n"), 1083 unit, fail_sp)); 1084 return BCM_E_NOT_FOUND; 1085 } 1086 1087 tid = TOPO_SP_TID_GET(fail_sp_idx); 1088 if (tid >= 0) { 1089 int i, j; 1090 bcm_trunk_info_t t_info; 1091 bcm_port_t repl_sp; /* Replacing port */ 1092 int member_count; 1093 bcm_trunk_member_t member_array[BCM_TRUNK_FABRIC_MAX_PORTCNT]; 1094 bcm_port_t local_port; 1095 1096 /* Get current trunk information and remove failed port */ 1097 rv = bcm_trunk_get(unit, tid, &t_info, BCM_TRUNK_FABRIC_MAX_PORTCNT, 1098 member_array, &member_count); 1099 if (BCM_FAILURE(rv)) { 1100 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1101 (BSL_META_U(unit, 1102 "Cannot get trunk information for unit %d, tid %d\n"), 1103 unit, tid)); 1104 TOPO_DATA_UNLOCK; 1105 return rv; 1106 } 1107 1108 /* Setup new trunk information with failed port removed */ 1109 j = 0; 1110 for (i = 0; i < member_count; i++) { 1111 BCM_IF_ERROR_RETURN(bcm_port_local_get(unit, member_array[i].gport, 1112 &local_port)); 1113 if (local_port == fail_sp) { 1114 continue; 1115 } 1116 sal_memcpy(&member_array[j], &member_array[i], 1117 sizeof(bcm_trunk_member_t)); 1118 j++; 1119 } 1120 member_count = j; 1121 1122 /* Trunk failover requires at least one port left in trunk */ 1123 if (member_count < 1) { 1124 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1125 (BSL_META_U(unit, 1126 "Link failure on unit %d, port %d, is not a " 1127 "trunk failover case\n"), unit, fail_sp)); 1128 TOPO_DATA_UNLOCK; 1129 return BCM_E_FAIL; 1130 } 1131 1132 /* Get first active port of trunk to replace failed port */ 1133 BCM_IF_ERROR_RETURN(bcm_port_local_get(unit, member_array[0].gport, 1134 &repl_sp)); 1135 1136 /* Board programming */ 1137 rv = bcm_board_topo_trunk_failover(topo_cpu, unit, 1138 fail_sp, fail_sp_idx, 1139 tid, &t_info, member_count, 1140 member_array); 1141 if (BCM_FAILURE(rv)) { 1142 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1143 (BSL_META_U(unit, 1144 "Fail to reconfigure system for trunk failover\n"))); 1145 TOPO_DATA_UNLOCK; 1146 return BCM_E_FAIL; 1147 } 1148 1149 /* Update CPU transport */ 1150 topo_sp_tx_cpu_replace(db_ref, unit, fail_sp, repl_sp); 1151 1152 /* Update internal information */ 1153 TOPO_SP_TID_SET(fail_sp_idx, -1); 1154 } 1155 1156 TOPO_DATA_UNLOCK; 1157 1158 return rv; 1159 } 1160 1161 /* Registration interface */ 1162 int 1163 topo_board_default_board_program(topo_board_control_t op, 1164 cpudb_ref_t db_ref, 1165 topo_cpu_t *topo_cpu, 1166 void *user_data) 1167 { 1168 int rv = BCM_E_PARAM; 1169 1170 switch (op) { 1171 case topoBoardInit: 1172 rv = _topo_board_default_initialize(db_ref); 1173 break; 1174 1175 case topoBoardProgram: 1176 rv = _topo_board_default_program(db_ref, topo_cpu); 1177 break; 1178 1179 default: 1180 break; 1181 1182 } 1183 1184 return rv; 1185 } 1186 1187 1188 1189 static topo_board_callback_t _topo_board_handler; 1190 static void *_topo_board_user_data; 1191 1192 int 1193 topo_board_register(topo_board_callback_t func, void *user_data) 1194 { 1195 _topo_board_handler = func; 1196 _topo_board_user_data = user_data; 1197 1198 return BCM_E_NONE; 1199 } 1200 1201 int 1202 topo_board_unregister(topo_board_callback_t func, void *user_data) 1203 { 1204 int rv = BCM_E_NOT_FOUND; 1205 1206 if (_topo_board_handler == func && _topo_board_user_data == user_data) { 1207 _topo_board_handler = NULL; 1208 _topo_board_user_data = NULL; 1209 rv = BCM_E_NONE; 1210 } 1211 1212 return rv; 1213 } 1214 1215 int 1216 topo_board_op(topo_board_control_t op, 1217 cpudb_ref_t db_ref, topo_cpu_t *topo_cpu) 1218 { 1219 return _topo_board_handler ? 1220 _topo_board_handler(op, db_ref, topo_cpu, _topo_board_user_data) 1221 : BCM_E_UNAVAIL; 1222 }