tksdiag.c (95648B)
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: tksdiag.c 8 * Purpose: CPU transport, CPU DB, and Stacking functions 9 * Requires: 10 */ 11 12 #include <sal/types.h> 13 #include <sal/core/libc.h> 14 #include <sal/core/thread.h> 15 #include <sal/core/sync.h> 16 #include <sal/core/dpc.h> 17 #include <sal/appl/sal.h> 18 #include <sal/appl/io.h> 19 #include <shared/bsl.h> 20 #include <bcm/pkt.h> 21 #include <bcm/tx.h> 22 #include <bcm/topo.h> 23 #include <bcm/init.h> 24 #include <bcm/stg.h> 25 #include <bcm/vlan.h> 26 #include <bcm/stack.h> 27 #ifdef BCM_RPC_SUPPORT 28 #include <bcm_int/rpc/rpc.h> 29 #include <bcm_int/rpc/rlink.h> 30 #endif /* BCM_RPC_SUPPORT */ 31 #include <bcm_int/control.h> 32 #include <bcm/debug.h> 33 34 #include <appl/diag/shell.h> 35 #include <appl/diag/system.h> 36 #include <appl/diag/parse.h> 37 #include <appl/diag/ctrans.h> 38 39 #include <appl/cpudb/cpudb.h> 40 #include <appl/cputrans/cputrans.h> 41 #include <appl/cputrans/atp.h> 42 #include <appl/cputrans/next_hop.h> 43 44 #include <appl/discover/disc.h> 45 #include <appl/stktask/stktask.h> 46 #include <appl/stktask/topology.h> 47 #include <appl/stktask/topo_pkt.h> 48 #include <appl/stktask/topo_brd.h> 49 #include <appl/stktask/attach.h> 50 51 #if defined(INCLUDE_BOARD) 52 #include <board/board.h> 53 #endif 54 55 #include <bcmx/bcmx.h> 56 57 /* Event Logging */ 58 #include <appl/diag/evlog.h> 59 60 #if defined(INCLUDE_SHARED_EVLOG) 61 #define ST_EVLOG 62 #endif /* INCLUDE_SHARED_EVLOG */ 63 64 65 #if defined(BCM_FIELD_SUPPORT) && defined(BCM_FIREBOLT_SUPPORT) 66 #include <soc/drv.h> /* For MH Opcode-0 priority workaround */ 67 #endif 68 69 void topo_cpu_dump(topo_cpu_t *topo_cpu, char *prefix); 70 71 72 73 /* Parsing a CPU KEY is same as parsing a MAC for now */ 74 75 #if defined(INCLUDE_LIB_CPUDB) && defined(INCLUDE_LIB_CPUTRANS) && \ 76 defined(INCLUDE_LIB_DISCOVER) && defined(INCLUDE_LIB_STKTASK) 77 78 const bcm_mac_t _bcast_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 79 80 81 /**************************************************************** 82 * 83 * CPUDB control 84 */ 85 86 STATIC INLINE void 87 db_entry_show(const cpudb_entry_t *entry) 88 { 89 const cpudb_stk_port_t *sp_p; 90 int i; 91 char keybuf[CPUDB_KEY_STRING_LEN]; 92 const cpudb_unit_port_t *sp_base; 93 char pr_buf[80]; 94 cpudb_ref_t db_ref; 95 uint32 flags; 96 char *idstr = "unknown"; 97 98 db_ref = entry->db_ref; 99 100 cpudb_key_format(entry->base.key, keybuf, sizeof(keybuf)); 101 cli_out(" Key: %s MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 102 keybuf, 103 entry->base.mac[0], entry->base.mac[1], entry->base.mac[2], 104 entry->base.mac[3], entry->base.mac[4], entry->base.mac[5]); 105 cli_out(" Flags 0x%x:%s%s%s%s%s%s%s%s%s%s\n", 106 entry->flags, 107 entry->flags & CPUDB_F_IS_MASTER ? " master" : "", 108 entry->flags & CPUDB_F_IS_LOCAL ? " local" : "", 109 entry->flags & CPUDB_F_TX_KNOWN ? " tx-known" : "", 110 entry->flags & CPUDB_F_SYSID_KNOWN ? " sysid-known" : "", 111 entry->flags & CPUDB_F_DEST_KNOWN ? " dest-known" : "", 112 entry->flags & CPUDB_F_BASE_INIT_DONE ? " base-init" : "", 113 entry->flags & CPUDB_F_GLOBAL_COMPLETE ? " gcomp" : "", 114 entry->flags & CPUDB_F_INACTIVE_MARKED ? " inact" : "", 115 entry->flags & CPUDB_F_CONFIG_IN ? " cfg in" : "", 116 entry->flags & CPUDB_F_LOCAL_COMPLETE ? " lcomp" : ""); 117 118 /* Base board id and flags */ 119 cpudb_board_idstr_get(entry->base.board_id, &idstr); 120 cli_out(" Board ID: %d (%s)\n", entry->base.board_id, idstr); 121 flags = entry->base.flags; 122 cli_out(" Flags: %08x %s%s%s%s\n", flags, 123 flags & CPUDB_BASE_F_CHASSIS ? " chassis" : "", 124 flags & CPUDB_BASE_F_LOAD_BALANCE ? " load-bal" : "", 125 flags & CPUDB_BASE_F_CHASSIS_AST ? " ast" : "", 126 flags & CPUDB_BASE_F_CHASSIS_10SLOT ? " 10slot" : ""); 127 128 cli_out(" units %d. dest unit %d. base dest port %d. " 129 "dest mod %d dest port %d.\n", 130 entry->base.num_units, 131 entry->base.dest_unit, 132 entry->base.dest_port, 133 entry->dest_mod, 134 entry->dest_port); 135 for (i = 0; i < entry->base.num_units; i++) { 136 cli_out(" unit %d: mod id req %d; mod id pref %d\n", 137 i, entry->base.mod_ids_req[i], entry->base.pref_mod_id[i]); 138 } 139 cli_out(" master prio %d. slot id %d. discovery seq %d.\n", 140 entry->base.master_pri, 141 entry->base.slot_id, 142 entry->base.dseq_num); 143 cli_out(" dest mod,port %d,%d. tx unit,port %d,%d. num stk %d\n", 144 entry->dest_mod, 145 entry->dest_port, 146 entry->tx_unit, 147 entry->tx_port, 148 entry->base.num_stk_ports); 149 cli_out(" trans pointers %p.\n", (void *)entry->trans_ptr); 150 for (i = 0; i < entry->base.num_units; i++) { 151 cli_out(" unit %d: base mod id %d\n", i, entry->mod_ids[i]); 152 } 153 154 for (i = 0; i < entry->base.num_stk_ports; i++) { 155 sp_p = &entry->sp_info[i]; 156 sp_base = &entry->base.stk_ports[i]; 157 cli_out(" StkPort %d: Unit %d. Port %d. " 158 "Flags 0x%x:%s%s%s%s%s%s; \n", 159 i, sp_base->unit, sp_base->port, 160 sp_p->flags, 161 sp_p->flags & CPUDB_SPF_NO_LINK ? " nolink" : "", 162 sp_p->flags & CPUDB_SPF_INACTIVE ? " inactive" : "", 163 sp_p->flags & CPUDB_SPF_DUPLEX ? " duplex" : "", 164 sp_p->flags & CPUDB_SPF_CUT_PORT ? " cut_port" : "", 165 sp_p->flags & CPUDB_SPF_TX_RESOLVED ? " txok" : "", 166 sp_p->flags & CPUDB_SPF_RX_RESOLVED ? " rxok" : ""); 167 cli_out(" Weight %u. Base Flags 0x%x:%s.\n", 168 sp_base->weight, 169 sp_base->bflags, 170 sp_base->bflags & CPUDB_UPF_DISABLE_IF_CUT ? " dis_cut" : ""); 171 cpudb_key_format(sp_p->tx_cpu_key, keybuf, sizeof(keybuf)); 172 173 if (CPUDB_KEY_COMPARE(sp_p->tx_cpu_key, sp_p->rx_cpu_key) == 0 && 174 sp_p->tx_stk_idx == sp_p->rx_stk_idx) { 175 sal_sprintf(pr_buf, "TX/RX Key: %s", keybuf); 176 if (sp_p->tx_stk_idx >= 0) { 177 sal_sprintf(pr_buf + strlen(pr_buf), " (rmt-idx %d)", 178 sp_p->tx_stk_idx); 179 } 180 if (db_ref->local_entry->base.flags & CPUDB_BASE_F_CHASSIS) { 181 sal_sprintf(pr_buf + strlen(pr_buf), " to slot %d", 182 cpudb_sp_idx_to_slot(db_ref, entry, i, NULL)); 183 } 184 cli_out(" %s\n", pr_buf); 185 } else { 186 if (sp_p->tx_stk_idx >= 0) { 187 cli_out(" TX Key: %s (rmt-idx %d)\n", 188 keybuf, sp_p->tx_stk_idx); 189 } else { 190 cli_out(" TX Key: %s\n", 191 keybuf); 192 } 193 cpudb_key_format(sp_p->rx_cpu_key, keybuf, sizeof(keybuf)); 194 if (sp_p->rx_stk_idx >= 0) { 195 cli_out(" RX Key: %s (rmt-idx %d)\n", 196 keybuf, sp_p->rx_stk_idx); 197 } else { 198 cli_out(" RX Key: %s\n", 199 keybuf); 200 } 201 } 202 } 203 } 204 205 /* Skip to next digit or end of string (0) */ 206 207 STATIC char * 208 _next_digit(char *str) 209 { 210 if (str == NULL) { 211 return str; 212 } 213 214 while ((*str != 0) && !isdigit((unsigned)*str)) { 215 str++; 216 } 217 218 return str; 219 } 220 221 222 /* Parse unit/port pair from string. 223 * Returns NULL if fails. 224 * Otherwise, returns updated string pointer 225 * 226 * All non-digits are ignored, so the only requirement is that 227 * the numbers are in pairs. E.g.: 228 * "0 1 0 3 0 5" and "(0,1) (0,3) (0,5)" are equivalent. 229 */ 230 231 STATIC char * 232 unit_port_pair_parse(char *str, int *unit, bcm_port_t *port) 233 { 234 char *next; 235 char *orig_str; 236 237 orig_str = str; 238 str = _next_digit(str); 239 *unit = strtoul(str, &next, 0); 240 if (next == str) { 241 return NULL; 242 } 243 str = next; 244 str = _next_digit(str); 245 *port = strtoul(str, &next, 0); 246 if (next == str) { 247 cli_out("Error parsing unit/port in %s\n", orig_str); 248 return NULL; 249 } 250 251 return next; 252 } 253 254 STATIC INLINE int 255 port_str_parse(char *str, cpudb_entry_t *entry) 256 { 257 char *next; 258 int i; 259 260 if (str == NULL || *str == 0) { 261 return 0; 262 } 263 264 entry->base.num_stk_ports = strtoul(str, &next, 0); 265 if (next == str) { 266 return -1; 267 } 268 269 str = next; 270 for (i = 0; i < entry->base.num_stk_ports; i++) { 271 str = unit_port_pair_parse(str, &(entry->base.stk_ports[i].unit), 272 &(entry->base.stk_ports[i].port)); 273 274 if (str == NULL) { 275 return -1; 276 } 277 } 278 279 return 0; 280 } 281 282 STATIC void 283 db_dump(cpudb_ref_t db_ref) 284 { 285 int i, count; 286 cpudb_entry_t *entry; 287 char keybuf[CPUDB_KEY_STRING_LEN]; 288 289 if (cpudb_valid(db_ref)) { 290 count = cpudb_entry_count_get(db_ref); 291 cli_out(" DB is valid and contains %d entries\n", count); 292 if (db_ref->local_entry != NULL) { 293 cpudb_key_format(db_ref->local_entry->base.key, 294 keybuf, sizeof(keybuf)); 295 cli_out(" Local Key: %s\n", keybuf); 296 } 297 if (db_ref->master_entry != NULL) { 298 cpudb_key_format(db_ref->master_entry->base.key, 299 keybuf, sizeof(keybuf)); 300 cli_out(" Master Key: %s\n", keybuf); 301 } 302 cli_out("\n"); 303 i = 0; 304 CPUDB_FOREACH_ENTRY(db_ref, entry) { 305 i += 1; 306 cli_out(" Entry %d/%d: ", i, count); 307 db_entry_show(entry); 308 cli_out("\n"); 309 } 310 if (i != count) { 311 cli_out("WARNING: entry count is %d but %d entries actually found\n", 312 count, i); 313 } 314 } else { 315 cli_out("DB is not valid\n"); 316 } 317 } 318 319 #if defined(INCLUDE_BCMX) 320 /* stktask/bcmx glue */ 321 STATIC void 322 ct_attach_callback(int unit, int attach, cpudb_entry_t *cpuent, int cpuunit) 323 { 324 COMPILER_REFERENCE(cpuent); 325 COMPILER_REFERENCE(cpuunit); 326 LOG_VERBOSE(BSL_LS_BCM_STK, 327 (BSL_META_U(unit, 328 "STACK: Attach callback, unit %d. %s\n"), 329 unit, attach ? "attach" : "detach")); 330 if (attach) { 331 (void) bcmx_device_attach(unit); 332 } else { 333 (void) bcmx_device_detach(unit); 334 } 335 } 336 #endif 337 338 339 char ct_cpudb_usage[] = 340 "cpudb <subcmd> [options]\n" 341 #ifndef COMPILER_STRING_CONST_LIMIT 342 "Subcommands:\n" 343 " newdb | create\n" 344 " Create a new DB and indicate DB reference. By default, DB 0 is\n" 345 " created and used. Will not change current DB.\n" 346 " current <n>\n" 347 " Set the current DB reference to <n> (returned from new).\n" 348 " destroy | kill <n>\n" 349 " Delete the DB indicated\n" 350 " update KEY=<key> [MAC=<mac>] [TXUnit=<unit>] [TXPort=<port>]\n" 351 " [DMod=<mod>] [DPort=<port>] [ModidsReq=<n>] [MasterPri=<n>]\n" 352 " [NumUnits=<n>]\n" 353 " Update with the CPU entry with the given key using the\n" 354 " information provided. Negative parameters will be ignored.\n" 355 " find | lookup MAC=<mac>\n" 356 " Look up the given MAC address\n" 357 " show\n" 358 " Show contents of the current DB\n" 359 " remove KEY=<key>\n" 360 " Remove the given KEY\n" 361 " stackports PortString=\"<n> <unit0> <port0> ...\" [DBidx=<idx>]\n" 362 " Indicate stack ports for the local system; local entry\n" 363 " must exist for the given DB\n" 364 " add KEY=<key> Local=<T|F>\n" 365 " Create an entry in the current DB for the given KEY.\n" 366 " Will also add the CPU key to ATP.\n" 367 #endif 368 ; 369 370 cpudb_ref_t db_refs[MAX_DBS]; 371 int cur_db; 372 int num_db = 0; 373 374 cmd_result_t 375 ct_cpudb(int unit, args_t *args) 376 { 377 char *subcmd; 378 char *int_arg; 379 parse_table_t pt; 380 static bcm_mac_t mac; 381 int a_db; 382 int tx_port = -1; 383 int tx_unit = -1; 384 int dest_mod = -1; 385 int dest_port = -1; 386 int master_pri = -1; 387 int num_units = -1; 388 cpudb_entry_t *entry; 389 int slot_id = -1; 390 int dest_unit = -1; 391 int i; 392 #if defined(INCLUDE_BCMX) 393 static int bcmx_registered = FALSE; 394 #endif 395 cpudb_key_t key; 396 397 COMPILER_REFERENCE(unit); 398 #if defined(INCLUDE_BCMX) 399 if (!bcmx_registered) { 400 int rv; 401 if ((rv = bcm_stack_attach_register(ct_attach_callback)) < 0) { 402 cli_out("Could not register BCMX with stack attach: %s\n", 403 bcm_errmsg(rv)); 404 } else { 405 bcmx_registered = TRUE; 406 } 407 } 408 #endif 409 if ((subcmd = ARG_GET(args)) == NULL) { 410 cli_out("Current DB is %d and is%s valid\n", 411 cur_db, cpudb_valid(db_refs[cur_db]) ? "" : " NOT"); 412 return CMD_OK; 413 } 414 415 if ((sal_strcasecmp(subcmd, "NEWDB") == 0) || 416 (sal_strcasecmp(subcmd, "CREATE") == 0)) { 417 for (i = 0; i < MAX_DBS; i++) { 418 if (db_refs[i] == NULL) { 419 break; 420 } 421 } 422 if (i >= MAX_DBS) { 423 cli_out("Too many DBs\n"); 424 return CMD_FAIL; 425 } 426 if ((db_refs[i] = cpudb_create()) == NULL) { 427 cli_out("ERROR: cpudb %d create failed\n", i); 428 } else { 429 cli_out("cpudb %d created\n", i); 430 num_db++; 431 } 432 } else if (sal_strcasecmp(subcmd, "CURRENT") == 0) { 433 if ((int_arg = ARG_GET(args)) == NULL) { 434 cli_out("Current db is %d\n", cur_db); 435 return CMD_OK; 436 } 437 cur_db = strtoul(int_arg, NULL, 0); 438 cli_out("Current DB set to %d%s\n", cur_db, 439 cpudb_valid(db_refs[cur_db]) ? "" : 440 " (NOTE: Not currently valid)"); 441 442 } else if ((sal_strcasecmp(subcmd, "KILL") == 0) || 443 (sal_strcasecmp(subcmd, "DESTROY") == 0)) { 444 if ((int_arg = ARG_GET(args)) == NULL) { 445 cli_out("Destroy requires database refence\n"); 446 return CMD_USAGE; 447 } 448 a_db = strtoul(int_arg, NULL, 0); 449 if (db_refs[a_db] != NULL) { 450 cli_out("Destroy returns %d\n", cpudb_destroy(db_refs[a_db])); 451 db_refs[a_db] = NULL; 452 } else { 453 cli_out("DB %d does not exist\n", a_db); 454 } 455 } else if (sal_strcasecmp(subcmd, "STACKPORTS") == 0) { 456 int db_idx = cur_db; 457 char *port_str; 458 459 if (ARG_CUR(args) == NULL) { 460 cli_out("stack ports required\n"); 461 return CMD_FAIL; 462 } 463 parse_table_init(unit, &pt); 464 parse_table_add(&pt, "PortString", PQ_STRING, 0, &port_str, 0); 465 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 466 if (parse_arg_eq(args, &pt) < 0) { 467 parse_arg_eq_done(&pt); 468 return CMD_USAGE; 469 } 470 471 if (db_refs[db_idx] == CPUDB_REF_NULL) { 472 cli_out("Invalid DB index. Try cpudb create\n"); 473 parse_arg_eq_done(&pt); 474 return CMD_FAIL; 475 } 476 if (db_refs[db_idx]->local_entry == NULL) { 477 cli_out("No local DB entry in cpudb %d\n", db_idx); 478 parse_arg_eq_done(&pt); 479 return CMD_FAIL; 480 } 481 if (port_str_parse(port_str, db_refs[db_idx]->local_entry) < 0) { 482 cli_out("Bad port string specified: %s\n", port_str); 483 parse_arg_eq_done(&pt); 484 return CMD_FAIL; 485 } 486 parse_arg_eq_done(&pt); 487 } else if (sal_strcasecmp(subcmd, "ADD") == 0) { 488 int is_local = FALSE; 489 char keybuf[CPUDB_KEY_STRING_LEN]; 490 491 parse_table_init(unit, &pt); 492 parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0); 493 parse_table_add(&pt, "Local", PQ_DFL|PQ_BOOL, 0, &is_local, 0); 494 if (parse_arg_eq(args, &pt) < 0) { 495 parse_arg_eq_done(&pt); 496 return CMD_USAGE; 497 } 498 parse_arg_eq_done(&pt); 499 500 cpudb_key_format(key, keybuf, sizeof(keybuf)); 501 entry = cpudb_entry_create(db_refs[cur_db], key, is_local); 502 if (entry == NULL) { 503 cli_out("ERROR: cpudb entry %s create failed\n", keybuf); 504 } else { 505 cli_out("cpudb entry %s created\n", keybuf); 506 atp_key_add(key, is_local); 507 } 508 } else if ((sal_strcasecmp(subcmd, "UPDATE") == 0)) { 509 510 parse_table_init(unit, &pt); 511 sal_memcpy(mac, _bcast_mac, sizeof(bcm_mac_t)); 512 513 parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0); 514 parse_table_add(&pt, "MAC", PQ_DFL|PQ_MAC, 0, mac, 0); 515 parse_table_add(&pt, "TXUnit", PQ_DFL|PQ_INT, 0, &tx_unit, 0); 516 parse_table_add(&pt, "TXPort", PQ_DFL|PQ_INT, 0, &tx_port, 0); 517 parse_table_add(&pt, "DMod", PQ_DFL|PQ_INT, 0, &dest_mod, 0); 518 parse_table_add(&pt, "DPort", PQ_DFL|PQ_INT, 0, &dest_port, 0); 519 parse_table_add(&pt, "MasterPri", PQ_DFL|PQ_INT, 0, &master_pri, 0); 520 parse_table_add(&pt, "NumUnits", PQ_DFL|PQ_INT, 0, &num_units, 0); 521 parse_table_add(&pt, "SlotID", PQ_DFL|PQ_INT, 0, &slot_id, 0); 522 parse_table_add(&pt, "DestUnit", PQ_DFL|PQ_INT, 0, 523 &dest_unit, 0); 524 525 if (parse_arg_eq(args, &pt) < 0) { 526 parse_arg_eq_done(&pt); 527 return CMD_USAGE; 528 } 529 530 CPUDB_KEY_SEARCH(db_refs[cur_db], key, entry); 531 if (entry == NULL) { 532 cli_out("Could not find entry for key\n"); 533 parse_arg_eq_done(&pt); 534 return CMD_FAIL; 535 } 536 537 if (tx_unit >= 0) { 538 entry->tx_unit = tx_unit; 539 entry->flags |= CPUDB_F_TX_KNOWN; 540 } 541 if (tx_port >= 0) { 542 entry->tx_port = tx_port; 543 } 544 if (dest_mod >= 0) { 545 entry->dest_mod = dest_mod; 546 entry->flags |= CPUDB_F_DEST_KNOWN; 547 } 548 if (dest_port >= 0) { /* For now, set both base and entry port */ 549 entry->base.dest_port = dest_port; 550 entry->dest_port = dest_port; 551 } 552 if (num_units >= 0) { 553 entry->base.num_units = num_units; 554 } 555 if (dest_unit >= 0) { 556 entry->base.dest_unit = dest_unit; 557 } 558 if (slot_id >= 0) { 559 entry->base.slot_id = slot_id; 560 } 561 if (sal_memcmp(mac, _bcast_mac, sizeof(bcm_mac_t))) { 562 entry->flags |= CPUDB_F_BASE_INIT_DONE; 563 sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t)); 564 } 565 566 if ((tx_unit >= 0 && tx_port < 0) || (tx_port >= 0 && tx_unit < 0)) { 567 cli_out("Warning: Not properly initializing tx_unit (%d) and " 568 "tx_port (%d)\n", tx_unit, tx_port); 569 } 570 if ((dest_mod >= 0 && dest_port < 0) || 571 (dest_port >= 0 && dest_mod < 0)) { 572 cli_out("Warning: Not properly initializing dest_mode (%d) and " 573 "dest_port (%d)\n", dest_mod, dest_port); 574 } 575 576 parse_arg_eq_done(&pt); 577 } else if ((sal_strcasecmp(subcmd, "LOOKUP") == 0) || 578 (sal_strcasecmp(subcmd, "FIND") == 0)) { 579 const cpudb_entry_t *entry; 580 581 parse_table_init(unit, &pt); 582 parse_table_add(&pt, "MAC", PQ_DFL|PQ_MAC, 0, mac, 0); 583 if (parse_arg_eq(args, &pt) < 0) { 584 parse_arg_eq_done(&pt); 585 return CMD_USAGE; 586 } 587 parse_arg_eq_done(&pt); 588 589 if ((entry = cpudb_mac_lookup(db_refs[cur_db], mac)) != NULL) { 590 db_entry_show(entry); 591 } else { 592 cli_out("Entry not found in database %d\n", cur_db); 593 } 594 595 } else if (sal_strcasecmp(subcmd, "SHOW") == 0) { 596 int valid; 597 int db_idx; 598 599 cli_out("Current DB index is %d and is%s valid\n", cur_db, 600 cpudb_valid(db_refs[cur_db]) ? "" : " NOT"); 601 for (db_idx = 0; db_idx < MAX_DBS; db_idx++) { 602 valid = cpudb_valid(db_refs[db_idx]); 603 if (valid) { 604 cli_out("\nDB index %d:\n", db_idx); 605 db_dump(db_refs[db_idx]); 606 } 607 } 608 } else if (sal_strcasecmp(subcmd, "REMOVE") == 0) { 609 parse_table_init(unit, &pt); 610 parse_table_add(&pt, "KEY", PQ_DFL|PQ_KEY, 0, key.key, 0); 611 if (parse_arg_eq(args, &pt) < 0) { 612 parse_arg_eq_done(&pt); 613 return CMD_USAGE; 614 } 615 parse_arg_eq_done(&pt); 616 cli_out("Remove returns %d\n", 617 cpudb_entry_remove(db_refs[cur_db], key)); 618 } else if (sal_strcasecmp(subcmd, "UNREGISTER") == 0) { 619 #if defined(INCLUDE_BCMX) 620 if (bcmx_registered) { 621 int rv; 622 623 if ((rv = bcm_stack_attach_unregister(ct_attach_callback)) < 0) { 624 cli_out("Could not unregister BCMX with stack attach: %s\n", 625 bcm_errmsg(rv)); 626 } else { 627 cli_out("cpudb BCMX callback unregistered\n"); 628 bcmx_registered = FALSE; 629 } 630 } 631 #else 632 cli_out("cpudb: BCMX is not enabled\n"); 633 #endif 634 } else { 635 cli_out("Subcommand not found: %s\n", subcmd); 636 return CMD_USAGE; 637 } 638 639 return CMD_OK; 640 } 641 642 #if 0 643 /**************************************************************** 644 * 645 * TOPOLOGY callbacks 646 */ 647 648 static topo_cpu_t *tp_cpu; 649 650 #define TP_CPU_INIT \ 651 if (tp_cpu == NULL) { \ 652 tp_cpu = sal_alloc(sizeof(*tp_cpu), "tp_cpu"); \ 653 sal_memset(tp_cpu, 0, sizeof(*tp_cpu)); \ 654 } 655 656 #endif 657 658 /**************************************************************** 659 * 660 * StackTask thread 661 */ 662 663 /* 664 * Stack update callback function 665 * 666 * This function is registered with stk_port_set as a callback. 667 * Currently, it interprets the cookie as the COS on which 668 * stack (next hop) traffic flows and sets up the protocol priority 669 * on enabled, SL stack ports according to that value. 670 */ 671 672 STATIC void 673 _stk_port_update(int unit, bcm_port_t port, uint32 flags, void *cookie) 674 { 675 int stk_cos; 676 int rv; 677 678 if (flags & BCM_STK_ENABLE) { 679 if (flags & BCM_STK_SL) { 680 stk_cos = PTR_TO_INT(cookie); 681 LOG_VERBOSE(BSL_LS_BCM_STK, 682 (BSL_META_U(unit, 683 "STACK: port update: unit %d, port %d, flags 0x%x," 684 "stk_cos %d\n"), 685 unit, port, flags, stk_cos)); 686 687 rv = bcm_switch_control_port_set(unit, port, 688 bcmSwitchCpuProtocolPrio, 689 stk_cos); 690 if ((rv < 0) && (rv != BCM_E_UNAVAIL)) { 691 cli_out("STACK: Error setting CPU protocol priority" 692 " on unit %d, port %d: %s\n", unit, port, 693 bcm_errmsg(rv)); 694 } 695 } 696 } else { 697 /* Do any special processing needed for a port which is 698 * removed from stacking. 699 */ 700 } 701 } 702 703 704 /* 705 * Workaround for MH Opcode 0 Priority issue on devices, 706 * 5650x A0, A1 707 * 5630x A0, B0 708 * 5610x A0 709 */ 710 711 #define MH_OPCODE0_INIT 0 712 #define MH_OPCODE0_SELECT 1 713 #define MH_OPCODE0_CLEAR 2 714 715 #if defined(BCM_FIELD_SUPPORT) && defined(BCM_FIREBOLT_SUPPORT) 716 /* 717 * Function: 718 * mh_opcode0_priority_select 719 * Description: 720 * Creates FP rule to redirect incoming HiGig port packets with 721 * MH Opcode 0 to the CPU port. In addition, it clears the 722 * 'copy-to-cpu' in the icontrol_opcode_bitmap registers for the HiGig. 723 * 724 * Parameters: 725 * unit - BCM device number 726 * group_priority - Group priority within allowable range 727 * (see bcm_field_status_get), 728 * or BCM_FIELD_GROUP_PRIO_ANY to automatically assign a 729 * priority; each priority value may be used only once 730 * group - (OUT) New FP Group ID 731 * entry - (OUT) New FP Entry ID 732 * Returns: 733 * BCM_E_NONE Success 734 * BCM_E_XXX Failure, 735 * - NULL pointers 736 * - FP subsystem is not initialized 737 * - No more FP resources available 738 * Notes: 739 * FP subsystem must be initialized. 740 * This routine should only be executed on (local) 741 * 5650x A0, A1 742 * 5630x A0, B0 743 * 5610x A0 744 */ 745 746 STATIC int 747 mh_opcode0_priority_select(int unit, 748 int group_priority, 749 bcm_field_group_t *group, 750 bcm_field_entry_t *entry, 751 int *obm_reg_changed) 752 { 753 int valid_rev = FALSE; 754 bcm_port_t port; 755 uint32 obm_reg; 756 bcm_field_qset_t qset; 757 uint8 opcode; 758 uint8 opcode_mask; 759 uint32 action_param0; 760 bcm_pbmp_t in_ports; 761 bcm_pbmp_t in_ports_mask; 762 uint16 dev_id; 763 uint8 rev_id; 764 765 766 /* Check device type and revision */ 767 if ((!SOC_UNIT_VALID(unit))) { 768 return BCM_E_NONE; 769 } 770 771 /* Need to check the Revision ID of the device, not the driver */ 772 soc_cm_get_id(unit, &dev_id, &rev_id); 773 774 if (SOC_IS_FIREBOLT(unit) && 775 ((rev_id == BCM56504_A0_REV_ID) || 776 (rev_id == BCM56504_A1_REV_ID))) { 777 valid_rev = TRUE; 778 } else if (SOC_IS_HELIX(unit) && 779 ((rev_id == BCM56304_A0_REV_ID) || 780 (rev_id == BCM56304_B0_REV_ID))) { 781 valid_rev = TRUE; 782 } else if (SOC_IS_FELIX(unit) && 783 (rev_id == BCM56107_A0_REV_ID)) { 784 valid_rev = TRUE; 785 } 786 if (!valid_rev) { /* No error; not for this device */ 787 return BCM_E_NONE; 788 } 789 790 791 /* Valid devide type, revision */ 792 793 if ((group == NULL) || (entry == NULL)) { 794 return BCM_E_PARAM; 795 } 796 797 /* Set the HG ingress CPU Opcode map to NOT forward to CPU */ 798 PBMP_ST_ITER(unit, port) { 799 SOC_IF_ERROR_RETURN(READ_ICONTROL_OPCODE_BITMAPr(unit, port, 800 &obm_reg)); 801 soc_reg_field_set(unit, ICONTROL_OPCODE_BITMAPr, &obm_reg, BITMAPf, 802 0x0); 803 SOC_IF_ERROR_RETURN(WRITE_ICONTROL_OPCODE_BITMAPr(unit, port, 804 obm_reg)); 805 *obm_reg_changed = TRUE; 806 } 807 808 809 /* Select qualifiers: MHOpcode, Ingress Ports */ 810 BCM_FIELD_QSET_INIT(qset); 811 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyMHOpcode); 812 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyInPorts); 813 814 /* Create group */ 815 BCM_IF_ERROR_RETURN(bcm_field_group_create(unit, qset, 816 group_priority, group)); 817 /* Create entry */ 818 BCM_IF_ERROR_RETURN(bcm_field_entry_create(unit, *group, entry)); 819 820 /* Set qualifiers data, mask */ 821 /* MHOpcode */ 822 opcode = BCM_FIELD_MHOPCODE_CONTROL; 823 opcode_mask = 0x7; /* Match all bits */ 824 BCM_IF_ERROR_RETURN(bcm_field_qualify_MHOpcode(unit, *entry, 825 opcode, opcode_mask)); 826 /* Ingress Ports */ 827 BCM_PBMP_ASSIGN(in_ports, PBMP_ST_ALL(unit)); 828 BCM_PBMP_ASSIGN(in_ports_mask, PBMP_PORT_ALL(unit)); 829 BCM_IF_ERROR_RETURN(bcm_field_qualify_InPorts(unit, *entry, 830 in_ports, in_ports_mask)); 831 832 /* Set action to redirect to CPU port */ 833 action_param0 = SOC_PBMP_WORD_GET(PBMP_CMIC(unit), 0); 834 BCM_IF_ERROR_RETURN(bcm_field_action_add(unit, *entry, 835 bcmFieldActionRedirectPbmp, 836 action_param0, 0)); 837 838 return bcm_field_entry_install(unit, *entry); 839 } 840 841 842 /* 843 * Function: 844 * mh_opcode0_priority_clear 845 * Description: 846 * It destroys the FP rule for the given group ID and entry ID. 847 * In addition, it sets the 'copy-to-cpu' flag in the icontrol_opcode_bitmap 848 * registers for the HiGig. 849 * 850 * Parameters: 851 * unit - BCM device number 852 * group - FP Group ID 853 * entry - FP Entry ID 854 * Returns: 855 * BCM_E_NONE Success 856 * BCM_E_XXX Failure 857 * Notes: 858 * This routine is used in conjuction with mh_opcode0_priority_select. 859 * This should only be called on those units where the 860 * mh_opcode0_priority_select was successfully called. The FP group 861 * and entry IDs should have been saved earlier and passed in 862 * to this routine. 863 * 864 * Given the above, the device type and rev will NOT be validated. 865 */ 866 867 STATIC int 868 mh_opcode0_priority_clear(int unit, 869 bcm_field_group_t group, 870 bcm_field_entry_t entry, 871 int obm_reg_changed) 872 { 873 bcm_port_t port; 874 uint32 obm_reg; 875 876 /* Destroy entry */ 877 if (entry != -1) { 878 BCM_IF_ERROR_RETURN(bcm_field_entry_remove(unit, entry)); 879 BCM_IF_ERROR_RETURN(bcm_field_entry_destroy(unit, entry)); 880 } 881 882 /* Destroy group */ 883 if (group != -1) { 884 BCM_IF_ERROR_RETURN(bcm_field_group_destroy(unit, group)); 885 } 886 887 /* Set HG ingress CPU Opcode map to COPY to the CPU */ 888 if (obm_reg_changed) { 889 PBMP_ST_ITER(unit, port) { 890 SOC_IF_ERROR_RETURN(READ_ICONTROL_OPCODE_BITMAPr(unit, port, 891 &obm_reg)); 892 soc_reg_field_set(unit, ICONTROL_OPCODE_BITMAPr, &obm_reg, BITMAPf, 893 0x10); 894 SOC_IF_ERROR_RETURN(WRITE_ICONTROL_OPCODE_BITMAPr(unit, port, 895 obm_reg)); 896 } 897 } 898 899 return BCM_E_NONE; 900 } 901 902 typedef struct mh_opcode0_fp_s { 903 bcm_field_group_t group; 904 bcm_field_entry_t entry; 905 int obm_reg_changed; 906 } mh_opcode0_fp_t; 907 908 /* 909 * Function: 910 * mh_opcode0_priority 911 * Description: 912 * This routines performs the specified action for the MH Opcode 0 913 * priority. 914 * 915 * Parameters: 916 * action - Action to take, 917 * MH_OPCODE0_INIT Initializes static data; must 918 * be called first 919 * MH_OPCODE0_SELECT Calls 'priority_select' 920 * MH_OPCODE0_CLEAR Calls 'priority_clear' 921 * Returns: 922 * BCM_E_NONE Success 923 * BCM_E_XXX Failure 924 */ 925 926 STATIC int 927 mh_opcode0_priority(int action) 928 { 929 int i; 930 int rv; 931 static int init = FALSE; 932 static mh_opcode0_fp_t mh_opcode0_fp[SOC_MAX_NUM_DEVICES]; 933 934 if (!init && (action != MH_OPCODE0_INIT)) { 935 return BCM_E_INIT; 936 } 937 938 switch (action) { 939 case MH_OPCODE0_INIT: 940 for (i = 0; i < (sizeof(mh_opcode0_fp)/sizeof(mh_opcode0_fp_t)); i++) { 941 mh_opcode0_fp[i].group = -1; 942 mh_opcode0_fp[i].entry = -1; 943 mh_opcode0_fp[i].obm_reg_changed = FALSE; 944 } 945 init = TRUE; 946 break; 947 948 case MH_OPCODE0_SELECT: 949 for (i = 0; i < soc_ndev; i++) { 950 951 rv = mh_opcode0_priority_select(SOC_NDEV_IDX2DEV(i), 952 BCM_FIELD_GROUP_PRIO_ANY, 953 &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group, 954 &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry, 955 &mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed); 956 if (BCM_FAILURE(rv)) { 957 cli_out("ERROR: Failed to create FP rule to use HiGig packet " 958 "priority on unit %d.\n",SOC_NDEV_IDX2DEV(i)); 959 cli_out(" Stacking may not work properly.\n"); 960 return rv; 961 } 962 } 963 break; 964 965 case MH_OPCODE0_CLEAR: 966 /* Destroy created FP rule on units */ 967 for (i = 0; i < soc_ndev; i++) { 968 mh_opcode0_priority_clear(SOC_NDEV_IDX2DEV(i), 969 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group, 970 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry, 971 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed); 972 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].group = -1; 973 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].entry = -1; 974 mh_opcode0_fp[SOC_NDEV_IDX2DEV(i)].obm_reg_changed = FALSE; 975 } 976 break; 977 978 default: 979 break; 980 } 981 982 return BCM_E_NONE; 983 } 984 985 #else 986 987 STATIC int 988 mh_opcode0_priority(int action) 989 { 990 COMPILER_REFERENCE(action); 991 return BCM_E_NONE; 992 } 993 994 #endif /* BCM_FIELD_SUPPORT && BCM_FIREBOLT_SUPPORT */ 995 996 997 #define TKS_STK_DEFAULT_THREAD_PRIORITY 100 998 static int st_pri = TKS_STK_DEFAULT_THREAD_PRIORITY; 999 static sal_thread_t st_tid = SAL_THREAD_ERROR; 1000 static sal_sem_t st_done_sem; 1001 1002 #define TOPO_ATP_FLAGS (ATP_F_NEXT_HOP | ATP_F_REASSEM_BUF) 1003 1004 STATIC void 1005 tks_st_thread(void *cookie) 1006 { 1007 bcm_st_config_t *cfg; 1008 int rv, unit, i; 1009 sal_usecs_t attach_timeout; 1010 1011 /* The following call is needed as a workaround for 1012 * the MHOpcode 0 priority issue in FB, HX, and FX devices 1013 */ 1014 mh_opcode0_priority(MH_OPCODE0_INIT); 1015 rv = mh_opcode0_priority(MH_OPCODE0_SELECT); 1016 if (BCM_FAILURE(rv)) { 1017 mh_opcode0_priority(MH_OPCODE0_CLEAR); 1018 } 1019 1020 cfg = (bcm_st_config_t *)cookie; 1021 1022 if ((rv=topo_pkt_handle_init(TOPO_ATP_FLAGS)) != BCM_E_NONE) { 1023 cli_out("WARNING: topo_pkt_handle_init returned %s\n", bcm_errmsg(rv)); 1024 } 1025 1026 if ((rv=bcm_stack_attach_init()) != BCM_E_NONE) { 1027 cli_out("WARNING: bcm_stack_attach_init returned %s\n", bcm_errmsg(rv)); 1028 } 1029 1030 rv = bcm_st_start(cfg, TRUE); 1031 cli_out("ST thread exited with value %d (%s)\n", rv, bcm_errmsg(rv)); 1032 st_tid = SAL_THREAD_ERROR; 1033 1034 cli_out("ST: Stopping RPC and rlink\n"); 1035 1036 /* Detach all remote units from BCMX */ 1037 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 1038 if (BCM_CONTROL(unit) == NULL) { 1039 continue; 1040 } 1041 #if defined(INCLUDE_BCMX) 1042 if (BCM_IS_REMOTE(unit)) { 1043 (void)bcmx_device_detach(unit); 1044 } 1045 #endif /* INCLUDE_BCMX */ 1046 } 1047 1048 #define TKS_STK_THREAD_POLL_FRACTION 100 1049 /* Make sure an attach thread is not running before stopping RPC */ 1050 if (bcm_st_timeout_get(BCM_STS_ATTACH, 1051 &attach_timeout) == BCM_E_NONE) { 1052 /* Wait twice the attach timeout for stktask to stop */ 1053 for (i=0; i<2*TKS_STK_THREAD_POLL_FRACTION; i++) { 1054 if (!bcm_stack_attach_running()) { 1055 break; 1056 } 1057 sal_usleep(attach_timeout/TKS_STK_THREAD_POLL_FRACTION); 1058 } 1059 1060 if (bcm_stack_attach_running()) { 1061 cli_out("Attach thread failed to signal completion\n"); 1062 } 1063 1064 } else { 1065 cli_out("Could not get attach timeout\n"); 1066 } 1067 1068 #ifdef BCM_RPC_SUPPORT 1069 /* Stop RLINK and RPC */ 1070 (void)bcm_rlink_stop(); 1071 (void)bcm_rpc_stop(); 1072 #endif 1073 1074 mh_opcode0_priority(MH_OPCODE0_CLEAR); 1075 sal_sem_give(st_done_sem); 1076 sal_thread_exit(rv); 1077 } 1078 1079 typedef struct { 1080 int timeout; 1081 int rv; 1082 } tks_st_stop_thread_arg_t; 1083 1084 STATIC void 1085 tks_st_stop_thread(void *cookie) 1086 { 1087 tks_st_stop_thread_arg_t *arg = (tks_st_stop_thread_arg_t *)cookie; 1088 1089 arg->rv = bcm_st_stop(arg->timeout); 1090 1091 sal_thread_exit(0); 1092 } 1093 1094 static int 1095 null_attach(cpudb_ref_t db_ref) 1096 { 1097 int ismaster = db_ref->local_entry == db_ref->master_entry; 1098 char master[CPUDB_KEY_STRING_LEN]; 1099 char slave[CPUDB_KEY_STRING_LEN]; 1100 1101 master[0] = 0; 1102 slave[0] = 0; 1103 if (db_ref->master_entry) { 1104 cpudb_key_format(db_ref->master_entry->base.key, 1105 master, sizeof(master)); 1106 } 1107 cpudb_key_format(db_ref->local_entry->base.key, slave, sizeof(slave)); 1108 1109 if (ismaster) { 1110 cli_out("STACK: master on %s (%d cpu%s)\n", 1111 master, 1112 db_ref->num_cpus, db_ref->num_cpus == 1 ? "" : "s"); 1113 } else { 1114 cli_out("STACK: slave on %s (%d cpus, master %s)\n", 1115 slave, db_ref->num_cpus, master); 1116 } 1117 1118 bcm_st_event_send(BCM_STE_ATTACH_SUCCESS); 1119 return BCM_E_NONE; 1120 } 1121 1122 1123 #if defined(ST_EVLOG) 1124 1125 STATIC int 1126 evlog_start(void) 1127 { 1128 int args = 4; 1129 int entries = 100; 1130 1131 /* Create log of size 100 entries with 4 arguments */ 1132 if (st_log == NULL) { 1133 if ((st_log = diag_evlog_create(args, entries)) == NULL) { 1134 return BCM_E_MEMORY; 1135 } 1136 } 1137 1138 SHARED_EVLOG_ENABLE_ALL(st_log); 1139 return BCM_E_NONE; 1140 } 1141 1142 STATIC int 1143 evlog_stop(void) 1144 { 1145 if (st_log == NULL) { 1146 cli_out("No event log\n"); 1147 } else { 1148 diag_evlog_destroy(st_log); 1149 st_log = NULL; 1150 } 1151 1152 return BCM_E_NONE; 1153 } 1154 1155 STATIC int 1156 evlog_clear(void) 1157 { 1158 if (st_log == NULL) { 1159 cli_out("No event log\n"); 1160 } else { 1161 evlog_stop(); 1162 evlog_start(); 1163 } 1164 1165 return BCM_E_NONE; 1166 } 1167 1168 STATIC void 1169 evlog_show(args_t *args) 1170 { 1171 int i; 1172 int count; 1173 uint32 flags; 1174 char *option; 1175 int summary = FALSE; 1176 int start, end; 1177 sal_usecs_t elapsed_t; 1178 char *from = NULL; /* Previous Stack task state */ 1179 char *to = NULL; /* New Stack task state */ 1180 char *event = NULL; /* Event that triggered state transition */ 1181 1182 1183 if (st_log == NULL) { 1184 cli_out("No event log\n"); 1185 return; 1186 } 1187 1188 if ((option = ARG_GET(args)) != NULL) { 1189 if (parse_cmp("Summary", option, '\0')) { 1190 summary = TRUE; 1191 } 1192 } 1193 1194 /* Disable logging */ 1195 flags = SHARED_EVLOG_ENABLE_GET(st_log); 1196 SHARED_EVLOG_ENABLE_SET(st_log, 0); 1197 1198 /* Get log count and check for rollover */ 1199 count = SHARED_EVLOG_COUNT(st_log); 1200 if (st_log->cur_idx < count) { 1201 count = st_log->max_entries; 1202 } 1203 1204 cli_out("Stack Task State Change Event Log"); 1205 if (summary) { 1206 cli_out(" - Summary"); 1207 } 1208 cli_out("\n"); 1209 cli_out(" Flags : 0x%x\n", flags); 1210 cli_out(" Count : %d\n", count); 1211 cli_out("\n"); 1212 if (count <= 0) { 1213 SHARED_EVLOG_ENABLE_SET(st_log, flags); /* Restore flags */ 1214 return; 1215 } 1216 1217 1218 /* 1219 * Summary: Display total time elapsed time for each state 1220 */ 1221 if (summary) { 1222 cli_out(" Entry Elapsed Time Stack Task State On\n"); 1223 cli_out(" Start End (usecs) From ==> To Event\n"); 1224 cli_out(" ----------------------------------------------------\n"); 1225 1226 /* 1227 * The display for the summary option assumes the following 1228 * log sequence for getting the elapsed time between two log entries: 1229 * Stack starts -> start of Stack state 1230 * Start of Stack state -> End of Stack state 1231 */ 1232 1233 start = end = -1; 1234 for (i = 0; i < count; i++) { 1235 /* Look for start of stack task */ 1236 if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "stack start") 1237 == 0) { 1238 start = i++; 1239 end = start; 1240 /* Look for the start of a state */ 1241 for (; i < count; i++) { 1242 if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "start")) { 1243 continue; 1244 } 1245 end = i; 1246 1247 from = "(Start)"; 1248 to = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, 1249 i, 0)]; 1250 event = "---"; 1251 break; 1252 } 1253 } else { 1254 1255 /* Look for the start of a state */ 1256 if (start < 0) { 1257 if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "start")) { 1258 continue; 1259 } 1260 start = i++; 1261 } 1262 1263 /* Look for the end of a state change */ 1264 if (sal_strcasecmp(SHARED_EVLOG_STR(st_log, i), "end")) { 1265 continue; 1266 } 1267 1268 end = i; 1269 from = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 0)]; 1270 to = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 1)]; 1271 event = bcm_st_event_strings[SHARED_EVLOG_ARG(st_log, i, 2)]; 1272 } 1273 1274 if (start == end) { 1275 continue; 1276 } 1277 1278 elapsed_t = SHARED_EVLOG_TIMESTAMP(st_log, end) - 1279 SHARED_EVLOG_TIMESTAMP(st_log, start); 1280 cli_out(" %3d %3d %12d %-8s %-8s %-15s\n", 1281 start, end, 1282 elapsed_t, 1283 from, to, event); 1284 1285 start = end; 1286 } 1287 cli_out("\n"); 1288 1289 } else { 1290 /* 1291 * Detail: Display time elapsed time for each state broken into, 1292 * 1) Start of state to Event notification to transition 1293 * to new state 1294 * 2) Transitition to new state 1295 */ 1296 1297 cli_out(" Entry Time(usecs) Description Stack Task State " 1298 "On\n"); 1299 cli_out(" From ==> To " 1300 "Event\n"); 1301 cli_out(" -------------------------------------------------------" 1302 "----\n"); 1303 for (i = 0; i < count; i++) { 1304 if (SHARED_EVLOG_ARG(st_log, i, 0) == BCM_STS_INVALID) { 1305 from = to = event = "---"; 1306 } else { 1307 from = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 0)]; 1308 to = bcm_st_state_strings[SHARED_EVLOG_ARG(st_log, i, 1)]; 1309 event = bcm_st_event_strings[SHARED_EVLOG_ARG(st_log, i, 2)]; 1310 } 1311 1312 cli_out(" %3d %12d %-11s %-8s %-8s %-15s\n", 1313 i, 1314 SHARED_EVLOG_TIMESTAMP(st_log, i), 1315 SHARED_EVLOG_STR(st_log, i), 1316 from, to, event); 1317 } 1318 cli_out("\n"); 1319 } 1320 1321 SHARED_EVLOG_ENABLE_SET(st_log, flags); /* Restore flags */ 1322 1323 return; 1324 } 1325 #endif /* ST_EVLOG */ 1326 1327 /* Multiblock packet allocator */ 1328 1329 #define MAX_NUM_BLKS 50 1330 1331 STATIC int 1332 tks_pkt_alloc(int unit, int num_blks, int length, uint32 flags, bcm_pkt_t **pkt) 1333 { 1334 int i; 1335 int rv; 1336 int alength; 1337 bcm_pkt_t *pkta[MAX_NUM_BLKS]; 1338 bcm_pkt_blk_t *blk = NULL; 1339 1340 if ((num_blks <= 0) || (num_blks >= MAX_NUM_BLKS)) { 1341 return BCM_E_PARAM; 1342 } 1343 1344 if (num_blks > 1) { 1345 blk = sal_alloc(num_blks * sizeof(bcm_pkt_blk_t), "tks_pkt_alloc"); 1346 } 1347 1348 alength = length/num_blks; 1349 1350 for (i=0; i<num_blks; i++) { 1351 1352 /* calculate length needed */ 1353 if (num_blks != 1 && i <= num_blks-2) { 1354 /* not the last block, so use alength for allocation, and 1355 subtract from length, so lenggth will be how much is 1356 needed for the final allocation. */ 1357 length = length - alength; 1358 } else { 1359 /* last block, which could also be the first and only block */ 1360 alength = length; 1361 } 1362 1363 /* Get a pkt */ 1364 rv = bcm_pkt_alloc(unit, alength, flags, &pkta[i]); 1365 1366 if (i == 0) { 1367 if (num_blks > 1) { 1368 blk[i] = *pkta[i]->pkt_data; 1369 pkta[i]->pkt_data = blk; 1370 } 1371 } else { 1372 /* not the first packet */ 1373 1374 /* Accumulate data segments into first packet */ 1375 pkta[0]->pkt_data[i] = pkta[i]->pkt_data[0]; 1376 pkta[0]->blk_count += 1; 1377 1378 /* Just needed the packet for its data */ 1379 pkta[i]->blk_count -= 1; 1380 rv = bcm_pkt_free(unit, pkta[i]); 1381 if (BCM_FAILURE(rv)) { 1382 return rv; 1383 } 1384 } 1385 } 1386 1387 *pkt = pkta[0]; 1388 1389 return BCM_E_NONE; 1390 } 1391 1392 STATIC int 1393 tks_pkt_free(int unit, bcm_pkt_t *pkt) 1394 { 1395 int rv, num_blks; 1396 bcm_pkt_blk_t *blk; 1397 1398 num_blks = pkt->blk_count; 1399 blk = pkt->pkt_data; 1400 rv = bcm_pkt_free(unit, pkt); 1401 if (num_blks > 1) { 1402 sal_free(blk); 1403 } 1404 return rv; 1405 } 1406 1407 STATIC void 1408 tks_list_callback(int unit, bcm_pkt_t *pkt, void *cookie) 1409 { 1410 bcm_pkt_t *next; 1411 int rv; 1412 1413 cli_out("tks_list_callback(%d,%p,%p)\n",unit,(void *)pkt,cookie); 1414 while(pkt) { 1415 next = pkt->next; 1416 rv = tks_pkt_free(pkt->unit, pkt); 1417 if (BCM_FAILURE(rv)) { 1418 cli_out("tks_list_callback: tks_pkt_free()=%d\n",rv); 1419 } 1420 pkt = next; 1421 } 1422 } 1423 1424 STATIC void 1425 tks_array_callback(int unit, bcm_pkt_t *pkt, void *cookie) 1426 { 1427 tks_list_callback(unit,pkt, (void *)3); 1428 sal_free(cookie); 1429 } 1430 1431 STATIC void 1432 tks_pkt_callback(int unit, bcm_pkt_t *pkt, void *cookie) 1433 { 1434 int rv; 1435 sal_vaddr_t ctl = PTR_TO_UINTPTR(cookie); 1436 void *pktp = (void *)pkt; 1437 1438 if (ctl == 1) { 1439 rv = tks_pkt_free(unit, pkt); 1440 /* Coverity will complain if 'pkt' is printed because a function 1441 is passed a de-allocated resource */ 1442 cli_out("tks_pkt_callback(%d,%p,%p)=%d\n",unit,pktp,cookie,rv); 1443 } else { 1444 cli_out("tks_pkt_callback [list]\n"); 1445 } 1446 } 1447 1448 static bcm_st_config_t st_cfg = { 1449 disc_start, 1450 disc_abort, 1451 NULL, /* Use default master election routine */ 1452 1453 NULL, /* Use default topology update function */ 1454 NULL, /* Use default attach update function */ 1455 NULL, /* Use default transition notify function */ 1456 1457 /* Base is filled in from current db */ 1458 {{{0}}}, 1459 }; 1460 1461 static char *event_list[] = { EVENT_LIST_NAMES }; 1462 1463 char tks_stk_task_usage[] = 1464 "StkTask START [RETRX=<n>] [CfgTimeout=<n>] [TimeOut=<n>] [DBidx=<n>]\n" 1465 " [COS=<n>] [VLAN=<n>] [DiscFallBack=<T|F>]\n" 1466 #ifndef COMPILER_STRING_CONST_LIMIT 1467 " Start the stack task (if not running).\n" 1468 "StkTask EVENT Event=<UNBlock | BLock | LINKUP | LINKDOWN | PKT |\n" 1469 " DRestart | DSuccess | DFailure | TSuccess | TFailure |\n" 1470 " ASuccess | AFailure | TimeOut >\n" 1471 " Send the indicated event to the stack task (to be implemented)\n" 1472 "StkTask UPDATE DBidx=<n> [REStart=<T|F>] [MasterPri=n]\n" 1473 " Update the stack task base configuration with that of the\n" 1474 " given CPU database\n" 1475 "StkTask TIMEOUT State=<state> TimeOut=<usec>\n" 1476 " Set the timeout for the given state\n" 1477 "StkTask INIT\n" 1478 " Init stack task without starting it\n" 1479 "StkTask DISC [Version=<n>] [FallBack=<T|F>]\n" 1480 " Set or display the current discovery version and fallback setting\n" 1481 "StkTask STOP\n" 1482 " Stop the stack task (if running).\n" 1483 "StkTask TOPO\n" 1484 " Dump the topology database\n" 1485 #if defined(ST_EVLOG) 1486 "StkTask EVLOG {CLEAR | SHOW [summary]}\n" 1487 " Stack task event logging\n" 1488 #endif /* ST_EVLOG */ 1489 #endif 1490 ; 1491 1492 extern bcm_st_state_t st_state; 1493 extern volatile uint32 st_blocked_events; 1494 extern volatile uint32 st_pending_events; 1495 extern volatile sal_usecs_t st_transition_time; 1496 extern uint32 st_stk_port_flags[CPUDB_CXN_MAX]; 1497 extern sal_usecs_t stk_port_last_event_us[CPUDB_CXN_MAX]; 1498 extern uint32 bcm_st_flags; 1499 extern int _topo_hw_linkscan; 1500 1501 1502 cmd_result_t 1503 tks_stk_task(int unit, args_t *args) 1504 { 1505 parse_table_t pt; 1506 int rv; 1507 char *subcmd; 1508 cpudb_ref_t db_ref; 1509 1510 if ((subcmd = ARG_GET(args)) == NULL) { 1511 int i; 1512 1513 cli_out("Stack Task thread is%s running, state %s, flags 0x%x\n", 1514 st_tid == SAL_THREAD_ERROR ? " not" : "", 1515 bcm_st_state_strings[st_state], 1516 bcm_st_flags); 1517 for (i = 0; i < 32; i++) { 1518 if (bcm_st_flags & (1 << i)) { 1519 if (i < BCM_STF_MAX) { 1520 cli_out(" %s\n", bcm_st_flags_strings[i]); 1521 } else { 1522 cli_out(" Unknown flag 0x%x\n", bcm_st_flags & (1 << i)); 1523 } 1524 } 1525 } 1526 cli_out("ST pending ev 0x%x; blocked 0x%x; last trans %u\n", 1527 st_blocked_events, st_pending_events, 1528 st_transition_time); 1529 cli_out("Stk ports with link:\n"); 1530 for (i = 0; i < CPUDB_CXN_MAX; i++) { 1531 if (st_stk_port_flags[i] != 0) { 1532 cli_out(" %d%s: Last event %u. Link %s; Last link %s\n", 1533 i, st_stk_port_flags[i] & ST_SPF_DISABLED ? 1534 " (disabled)" : "", 1535 stk_port_last_event_us[i], 1536 st_stk_port_flags[i] & ST_SPF_LINK_UP ? 1537 "up" : "down", 1538 st_stk_port_flags[i] & ST_SPF_LAST_EVENT_UP ? 1539 "up" : "down"); 1540 } 1541 } 1542 1543 if (st_state == BCM_STS_BLOCKED || st_state == BCM_STS_READY) { 1544 cpudb_ref_t disc = NULL; 1545 cpudb_ref_t cur = NULL; 1546 1547 if (!cpudb_valid((disc = bcm_st_discovery_db_get()))) { 1548 cli_out("Stack task discovery DB is not valid\n"); 1549 } else { 1550 cli_out("Stack task discovery DB:\n"); 1551 db_dump(disc); 1552 } 1553 if (!cpudb_valid((cur = bcm_st_current_db_get()))) { 1554 cli_out("Stack task current DB is not valid\n"); 1555 } else { 1556 cli_out("Stack task current DB:\n"); 1557 db_dump(cur); 1558 } 1559 (void)cpudb_destroy(disc); 1560 (void)cpudb_destroy(cur); 1561 } else { 1562 cli_out("Disc DB %p; Cur DB %p\n", 1563 (void *)bcm_st_disc_db, (void *)bcm_st_cur_db); 1564 cli_out("Not dumping DBs due to current state\n"); 1565 } 1566 return CMD_OK; 1567 } 1568 1569 if (sal_strcasecmp(subcmd, "START") == 0) { 1570 static int retrx_us = -1; 1571 static int cfg_to_us = -1; 1572 static int timeout_us = -1; 1573 int disc_vlan = -1; 1574 int disc_cos = -1; 1575 int disc_fallback = FALSE; 1576 int auto_trunk = -1; 1577 int load_balance = -1; 1578 char *board_id_str = NULL; 1579 int reserved_modid = -1; 1580 int db_idx = cur_db; 1581 uint32 modid_init = 0; 1582 bcm_st_config_t *cfg = &st_cfg; 1583 int i; 1584 bcm_pbmp_t vports, vports_untag; 1585 int hw_linkscan = TRUE; 1586 int topo_dly = -1; 1587 int topo_master_dly = -1; 1588 int need_board_handler = TRUE; 1589 1590 if (st_tid != SAL_THREAD_ERROR) { 1591 cli_out("Stack Task is already running\n"); 1592 return CMD_OK; 1593 } 1594 1595 parse_table_init(unit, &pt); 1596 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 1597 parse_table_add(&pt, "RETRX", PQ_DFL|PQ_INT, 0, &retrx_us, 0); 1598 parse_table_add(&pt, "TimeOut", PQ_DFL|PQ_INT, 0, &timeout_us, 0); 1599 parse_table_add(&pt, "CfgTimeout", PQ_DFL|PQ_INT, 0, &cfg_to_us, 0); 1600 parse_table_add(&pt, "Priority", PQ_DFL|PQ_INT, 0, &st_pri, 0); 1601 parse_table_add(&pt, "COS", PQ_DFL|PQ_INT, 0, &disc_cos, 0); 1602 parse_table_add(&pt, "VLAN", PQ_DFL|PQ_INT, 0, &disc_vlan, 0); 1603 parse_table_add(&pt, "rsvdmodidbmp", PQ_DFL|PQ_INT, 0, &modid_init, 0); 1604 parse_table_add(&pt, "AutoTrunk", PQ_DFL|PQ_INT, 0, &auto_trunk, 0); 1605 parse_table_add(&pt, "ReservedModId", PQ_DFL|PQ_INT, 0, 1606 &reserved_modid, 0); 1607 parse_table_add(&pt, "LoadBalance", PQ_DFL|PQ_INT, 0, 1608 &load_balance, 0); 1609 parse_table_add(&pt, "Board", PQ_DFL|PQ_STRING, 0, 1610 &board_id_str, 0); 1611 parse_table_add(&pt, "DiscFallBack", PQ_DFL|PQ_BOOL, 0, 1612 &disc_fallback, 0); 1613 parse_table_add(&pt, "HWLINKscan", PQ_DFL|PQ_BOOL, 0, 1614 &hw_linkscan, 0); 1615 parse_table_add(&pt, "TopoDelay", PQ_DFL|PQ_INT, 0, 1616 &topo_dly, 0); 1617 parse_table_add(&pt, "TopoMasterDelay", PQ_DFL|PQ_INT, 0, 1618 &topo_master_dly, 0); 1619 1620 if (parse_arg_eq(args, &pt) < 0) { 1621 parse_arg_eq_done(&pt); 1622 return CMD_USAGE; 1623 } 1624 disc_timeout_set(timeout_us, cfg_to_us, retrx_us); 1625 if (disc_cos >= 0) { 1626 disc_cos_set(disc_cos); 1627 rv = bcm_stk_update_callback_register(0, _stk_port_update, 1628 INT_TO_PTR(disc_cos)); 1629 if (rv < 0) { 1630 cli_out("ST: Could not set stack callback: %s\n", 1631 bcm_errmsg(rv)); 1632 } 1633 } 1634 if (disc_vlan >= 0) { 1635 disc_vlan_set(disc_vlan); 1636 } 1637 if (disc_fallback) { 1638 disc_fallback_set(TRUE); 1639 } 1640 1641 if (modid_init != 0) { 1642 topo_reserved_modid_set(modid_init, TRUE); 1643 } 1644 1645 /* Do not allow HW linkscan mode to be set by Stack task */ 1646 if (hw_linkscan == 0) { 1647 _topo_hw_linkscan = 0; 1648 } 1649 1650 if (auto_trunk >= 0) { 1651 bcm_board_auto_trunk_set(auto_trunk); 1652 } 1653 1654 if (reserved_modid >= 0) { 1655 bcm_st_reserved_modid_enable_set(reserved_modid); 1656 } 1657 1658 if (topo_dly >= 0) { 1659 topo_delay_set(topo_dly); 1660 } 1661 1662 if (topo_master_dly >= 0) { 1663 topo_master_delay_set(topo_master_dly); 1664 } 1665 1666 if (!cpudb_valid(db_refs[db_idx]) || 1667 db_refs[db_idx]->local_entry == NULL) { 1668 cfg = NULL; 1669 } else { 1670 1671 db_ref = db_refs[db_idx]; 1672 disc_vlan_get(&disc_vlan); 1673 BCM_PBMP_CLEAR(vports_untag); 1674 1675 /* Set application flags */ 1676 if (load_balance > 0) { 1677 db_ref->local_entry->base.flags |= CPUDB_BASE_F_LOAD_BALANCE; 1678 } 1679 if (load_balance > 1) { 1680 db_ref->local_entry->base.flags |= CPUDB_BASE_F_CHASSIS_AST; 1681 } 1682 #if defined(INCLUDE_BOARD) 1683 if (board_name() != NULL) { 1684 need_board_handler = FALSE; 1685 } 1686 #endif 1687 if (need_board_handler) { 1688 rv = topo_board_register(topo_board_default_board_program, 1689 NULL); 1690 if (rv < 0) { 1691 cli_out("Could not register board programming\n"); 1692 return CMD_FAIL; 1693 } 1694 } 1695 1696 if (board_id_str != NULL) { 1697 rv = cpudb_board_id_get(board_id_str, 1698 &db_ref->local_entry->base.board_id); 1699 if (BCM_FAILURE(rv)) { 1700 cli_out("ERROR: Could not find board id for '%s'\n", 1701 board_id_str); 1702 return CMD_FAIL; 1703 } else { 1704 /* Initialize board */ 1705 rv = topo_board_initialize(db_ref); 1706 if (BCM_FAILURE(rv)) { 1707 cli_out("ERROR: Could not initialize board '%s'\n", 1708 board_id_str); 1709 return CMD_FAIL; 1710 } else { 1711 cli_out("Initialized board %s\n", board_id_str); 1712 } 1713 } 1714 } else { 1715 cli_out("ERROR: No board id\n"); 1716 return CMD_FAIL; 1717 } 1718 /* Put CPU in VLAN for all devices */ 1719 for (i = 0; i < db_ref->local_entry->base.num_units; i++) { 1720 rv = bcm_vlan_create(i, disc_vlan); 1721 if (rv < 0 && rv != BCM_E_EXISTS) { 1722 cli_out("ERROR: vlan %d create failed: %s\n", 1723 disc_vlan, bcm_errmsg(rv)); 1724 return CMD_FAIL; 1725 } 1726 BCM_PBMP_CLEAR(vports); 1727 BCM_PBMP_PORT_ADD(vports, CMIC_PORT(i)); 1728 rv = bcm_vlan_port_add(i, disc_vlan, 1729 vports, vports_untag); 1730 if (rv < 0) { 1731 cli_out("ERROR: vlan %d CPU port add unit %d failed: %s\n", 1732 disc_vlan, unit, bcm_errmsg(rv)); 1733 return CMD_FAIL; 1734 } 1735 } 1736 /* 1737 * For each local stack port, if SL, set DISABLE_IF_CUT; 1738 * Set the weight inversely to the speed 1739 */ 1740 for (i = 0; i < db_ref->local_entry->base.num_stk_ports; i++) { 1741 int speed; 1742 cpudb_unit_port_t *sp = 1743 &db_ref->local_entry->base.stk_ports[i]; 1744 1745 if (bcm_port_speed_get(sp->unit, sp->port, &speed) < 0) { 1746 cli_out("Error getting port speed unit %d, port %d\n", 1747 sp->unit, sp->port); 1748 return CMD_FAIL; 1749 } 1750 if (speed > 0) { 1751 if (speed < 2500) { /* Assume SL port */ 1752 sp->bflags |= CPUDB_UPF_DISABLE_IF_CUT; 1753 } 1754 sp->weight = 1000000/speed; 1755 } else { 1756 /* The port speed is less than or equal to zero, 1757 so set to the highest weight. */ 1758 sp->weight = 1000000; 1759 } 1760 } 1761 sal_memcpy(&st_cfg.base, &db_ref->local_entry->base, 1762 sizeof(cpudb_base_t)); 1763 } 1764 1765 if (st_done_sem == NULL) { 1766 1767 st_done_sem = sal_sem_create("STDoneSem", sal_sem_BINARY, 0); 1768 1769 if (st_done_sem == NULL) { 1770 cli_out("Could not create semaphore\n"); 1771 return CMD_FAIL; 1772 } 1773 1774 } 1775 1776 st_tid = sal_thread_create("bcmSTACK", 1777 SAL_THREAD_STKSZ, 1778 st_pri, 1779 tks_st_thread, 1780 cfg); 1781 #if defined(ST_EVLOG) 1782 /* Start event logging for Stack task */ 1783 if (st_log != NULL) { 1784 evlog_stop(); 1785 } 1786 rv = evlog_start(); 1787 if (rv < 0) { 1788 cli_out("Cannot start event logging\n"); 1789 } else { 1790 SHARED_EVENT_LOG(st_log, "STACK START", 1791 BCM_STS_INVALID, BCM_STS_INVALID, 0, 0); 1792 } 1793 #endif /* ST_EVLOG */ 1794 1795 parse_arg_eq_done(&pt); 1796 1797 return CMD_OK; 1798 } else if (sal_strcasecmp(subcmd, "UPDATE") == 0) { 1799 int db_idx = cur_db; 1800 int restart = FALSE; 1801 int master_pri = -1; 1802 1803 parse_table_init(unit, &pt); 1804 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 1805 parse_table_add(&pt, "REStart", PQ_DFL|PQ_BOOL, 0, &restart, 0); 1806 parse_table_add(&pt, "MasterPri", PQ_DFL|PQ_INT, 0, &master_pri, 0); 1807 if (parse_arg_eq(args, &pt) < 0) { 1808 parse_arg_eq_done(&pt); 1809 return CMD_USAGE; 1810 } 1811 parse_arg_eq_done(&pt); 1812 if (!cpudb_valid(db_refs[db_idx]) || 1813 db_refs[db_idx]->local_entry == NULL) { 1814 cli_out("Invalid DB index. Try cpudb create\n"); 1815 return CMD_FAIL; 1816 } 1817 1818 if (master_pri >= 0) { 1819 db_refs[db_idx]->local_entry->base.master_pri = master_pri; 1820 } 1821 1822 rv = bcm_st_base_update(&db_refs[db_idx]->local_entry->base, 1823 restart); 1824 if (rv < 0) { 1825 cli_out("ST base update ERROR %d: %s\n", rv, bcm_errmsg(rv)); 1826 return CMD_FAIL; 1827 } 1828 1829 } else if (sal_strcasecmp(subcmd, "DISC") == 0) { 1830 int ver = -1; 1831 int disc_fallback = -1; 1832 int rv; 1833 1834 if (ARG_CNT(args) == 0) { 1835 if ((rv = disc_version_get(&ver)) < 0) { 1836 cli_out("Failed to get current discovery version: %s\n", 1837 bcm_errmsg(rv)); 1838 return CMD_FAIL; 1839 } else { 1840 cli_out("Current discovery version: %d\n", ver); 1841 } 1842 if ((rv = disc_fallback_get(&disc_fallback)) < 0) { 1843 cli_out("Failed to get discovery fallback setting: %s\n", 1844 bcm_errmsg(rv)); 1845 return CMD_FAIL; 1846 } else { 1847 cli_out("Fallback is %s\n", 1848 disc_fallback ? "enable" : "disable"); 1849 } 1850 return CMD_OK; 1851 } 1852 1853 parse_table_init(unit, &pt); 1854 parse_table_add(&pt, "Version", PQ_DFL|PQ_INT, 0, &ver, 0); 1855 parse_table_add(&pt, "FallBack", PQ_DFL|PQ_BOOL, 0, &disc_fallback, 0); 1856 if (parse_arg_eq(args, &pt) < 0) { 1857 parse_arg_eq_done(&pt); 1858 return CMD_USAGE; 1859 } 1860 parse_arg_eq_done(&pt); 1861 1862 if (ver != -1) { 1863 if ((rv = disc_version_set(ver)) < 0) { 1864 cli_out("Failed to set discovery version %d: %s\n", ver, 1865 bcm_errmsg(rv)); 1866 return CMD_FAIL; 1867 } 1868 } 1869 if (disc_fallback != -1) { 1870 if ((rv = disc_fallback_set(disc_fallback)) < 0) { 1871 cli_out("Failed to %s discovery version fallback: %s\n", 1872 disc_fallback ? "enable" : "disable", 1873 bcm_errmsg(rv)); 1874 return CMD_FAIL; 1875 } 1876 } 1877 1878 return CMD_OK; 1879 } else if (sal_strcasecmp(subcmd, "INIT") == 0) { 1880 int rv; 1881 int db_idx = cur_db; 1882 1883 parse_table_init(unit, &pt); 1884 parse_table_add(&pt, "DBidx", PQ_DFL|PQ_INT, 0, &db_idx, 0); 1885 if (parse_arg_eq(args, &pt) < 0) { 1886 parse_arg_eq_done(&pt); 1887 return CMD_USAGE; 1888 } 1889 if (!cpudb_valid(db_refs[db_idx]) || 1890 db_refs[db_idx]->local_entry == NULL) { 1891 cli_out("Invalid DB index. Try cpudb create\n"); 1892 parse_arg_eq_done(&pt); 1893 return CMD_FAIL; 1894 } 1895 db_ref = db_refs[db_idx]; 1896 sal_memcpy(&st_cfg.base, &db_ref->local_entry->base, 1897 sizeof(cpudb_base_t)); 1898 rv = bcm_st_config_load(&st_cfg); 1899 cli_out("bcm_st_config_load returned %d\n", rv); 1900 parse_arg_eq_done(&pt); 1901 return CMD_OK; 1902 } else if (sal_strcasecmp(subcmd, "TOPO") == 0) { 1903 topo_cpu_t *topo; 1904 1905 if (bcm_board_topo_get(&topo) == BCM_E_NONE && topo != NULL) { 1906 topo_cpu_dump(topo, ""); 1907 } else { 1908 sal_printf("No Topology\n"); 1909 } 1910 } else if (sal_strcasecmp(subcmd, "TIMEOUT") == 0) { 1911 int state = -1; 1912 sal_usecs_t timeout = 0; 1913 int rv; 1914 1915 assert(sizeof (timeout) == sizeof (int)); 1916 1917 parse_table_init(unit, &pt); 1918 parse_table_add(&pt, "State", PQ_DFL|PQ_MULTI, 0, &state, 1919 bcm_st_state_strings); 1920 parse_table_add(&pt, "TimeOut", PQ_DFL|PQ_INT, 0, &timeout, 0); 1921 if (parse_arg_eq(args, &pt) < 0) { 1922 parse_arg_eq_done(&pt); 1923 return CMD_USAGE; 1924 } 1925 parse_arg_eq_done(&pt); 1926 if (state < 0) { 1927 for (state = BCM_STS_BLOCKED; state < BCM_STS_MAX; state++) { 1928 bcm_st_timeout_get((bcm_st_state_t)state, &timeout); 1929 cli_out("Timeout for %s is %d\n", bcm_st_state_strings[state], 1930 timeout); 1931 } 1932 return CMD_OK; 1933 } 1934 rv = bcm_st_timeout_set((bcm_st_state_t)state, timeout); 1935 cli_out("Set timeout for %s to %d; returns %d\n", 1936 bcm_st_state_strings[state], timeout, rv); 1937 return CMD_OK; 1938 } else if (sal_strcasecmp(subcmd, "STOP") == 0) { 1939 /* Use stktask attach timeout as a proxy for stop timeouts. 1940 The should make this work in simulation and real modes. */ 1941 tks_st_stop_thread_arg_t stop_arg; 1942 sal_thread_t st_stop_tid = SAL_THREAD_ERROR; 1943 sal_usecs_t attach_timeout; 1944 int i; 1945 1946 if (bcm_st_timeout_get(BCM_STS_ATTACH, 1947 &attach_timeout) != BCM_E_NONE) { 1948 cli_out("Could not get attach timeout\n"); 1949 return CMD_FAIL; 1950 } 1951 1952 stop_arg.timeout = attach_timeout/50; 1953 stop_arg.rv = BCM_E_INTERNAL; 1954 1955 if (st_tid == SAL_THREAD_ERROR) { 1956 cli_out("Stack Task is not running\n"); 1957 return CMD_OK; 1958 } 1959 1960 st_stop_tid = sal_thread_create("STSTOP", 1961 SAL_THREAD_STKSZ, 1962 st_pri, 1963 tks_st_stop_thread, 1964 (void *)&stop_arg); 1965 1966 if (st_stop_tid == SAL_THREAD_ERROR) { 1967 cli_out("Could not create stack stop thread\n"); 1968 return CMD_FAIL; 1969 } 1970 1971 /* Wait for the stack thread to signal completion */ 1972 if (sal_sem_take(st_done_sem, attach_timeout*3) < 0) { 1973 cli_out("Stack thread failed to signal completion\n"); 1974 return CMD_FAIL; 1975 } else { 1976 /* Wait for twice the bcm_st_stop timeout for the stop 1977 thread to complete */ 1978 1979 #define TKS_STOP_THREAD_POLL_FRACTION 10 1980 1981 for ( i=0; i<2*TKS_STOP_THREAD_POLL_FRACTION; i++ ) { 1982 if (stop_arg.rv == BCM_E_INTERNAL) { 1983 sal_usleep(stop_arg.timeout/TKS_STOP_THREAD_POLL_FRACTION); 1984 } else { 1985 break; 1986 } 1987 } 1988 } 1989 1990 if (stop_arg.rv == BCM_E_INTERNAL) { 1991 cli_out("Stack stop thread failed to signal completion\n"); 1992 return CMD_FAIL; 1993 } 1994 1995 cli_out("bcm_st_stop returns %d: %s\n", 1996 stop_arg.rv, bcm_errmsg(stop_arg.rv)); 1997 1998 1999 } else if (sal_strcasecmp(subcmd, "EVENT") == 0) { 2000 bcm_st_event_t event = BCM_STE_DISC_RESTART; 2001 parse_table_init(unit, &pt); 2002 parse_table_add(&pt, "Event", PQ_DFL | PQ_MULTI, 0, &event, 2003 event_list); 2004 if (parse_arg_eq(args, &pt) < 0) { 2005 parse_arg_eq_done(&pt); 2006 return CMD_USAGE; 2007 } 2008 rv = bcm_st_event_send(event); 2009 if (rv < 0) { 2010 cli_out("bcm_st_send_event ERROR: %s\n", bcm_errmsg(rv)); 2011 } 2012 parse_arg_eq_done(&pt); 2013 } else if (sal_strcasecmp(subcmd, "NOATTACH") == 0) { 2014 st_cfg.st_attach = null_attach; 2015 #if defined(INCLUDE_ATPTRANS_SOCKET) && defined(INCLUDE_CHASSIS) 2016 } else if (sal_strcasecmp(subcmd, "CHASSIS_ATPTRANS_SOCKET") == 0) { 2017 st_cfg.st_transition = bcm_board_chassis_atptrans_socket_transition; 2018 #endif 2019 #if defined(ST_EVLOG) 2020 } else if (sal_strcasecmp(subcmd, "EVLOG") == 0) { 2021 if ((subcmd = ARG_GET(args)) == NULL) { 2022 return CMD_USAGE; 2023 } 2024 if (sal_strcasecmp(subcmd, "CLEAR") == 0) { 2025 evlog_clear(); 2026 } else if (sal_strcasecmp(subcmd, "SHOW") == 0) { 2027 evlog_show(args); 2028 } 2029 #endif /* ST_EVLOG */ 2030 } else if (sal_strcasecmp(subcmd, "TX") == 0) { 2031 /* params */ 2032 int op = BCM_HG_OPCODE_CPU; 2033 int blk = 1; 2034 bcm_pbmp_t dest; 2035 int dmod = 0; 2036 int dport = 0; 2037 int tagged = 1; 2038 int length = 68; 2039 int reply=0; 2040 int async=0; /* 0=sync 1=async per list 2=async per packet*/ 2041 int list=0; 2042 int array=0; 2043 int ether=0; 2044 int crc=1; 2045 int txunit=-1; 2046 /* vars */ 2047 uint32 flags = 0; 2048 bcm_pkt_t *pkt = NULL; 2049 bcm_pkt_t *cur_pkt = NULL; 2050 bcm_pkt_t *prev_pkt = NULL; 2051 bcm_pkt_t **pkt_array = NULL; 2052 int i; 2053 uint8 *buf = NULL; 2054 int packets; 2055 int cmd_rv = CMD_FAIL; 2056 2057 BCM_PBMP_CLEAR(dest); 2058 parse_table_init(unit, &pt); 2059 parse_table_add(&pt, "Op", PQ_DFL|PQ_INT, 0, &op, 0); 2060 parse_table_add(&pt, "Blk", PQ_DFL|PQ_INT, 0, &blk, 0); 2061 parse_table_add(&pt, "PortBitMap", PQ_DFL|PQ_PBMP, 0, &dest, 0); 2062 parse_table_add(&pt, "DMod", PQ_DFL|PQ_INT, 0, &dmod, 0); 2063 parse_table_add(&pt, "DPort", PQ_DFL|PQ_INT, 0, &dport, 0); 2064 parse_table_add(&pt, "Tagged", PQ_DFL|PQ_INT, 0, &tagged, 0); 2065 parse_table_add(&pt, "Length", PQ_DFL|PQ_INT, 0, &length, 0); 2066 parse_table_add(&pt, "Reply", PQ_DFL|PQ_INT, 0, &reply, 0); 2067 parse_table_add(&pt, "Async", PQ_DFL|PQ_INT, 0, &async, 0); 2068 parse_table_add(&pt, "LIst", PQ_DFL|PQ_INT, 0, &list, 0); 2069 parse_table_add(&pt, "ARray", PQ_DFL|PQ_INT, 0, &array, 0); 2070 parse_table_add(&pt, "Ether", PQ_DFL|PQ_INT, 0, ðer, 0); 2071 parse_table_add(&pt, "Crc", PQ_DFL|PQ_INT, 0, &crc, 0); 2072 parse_table_add(&pt, "TXUnit", PQ_DFL|PQ_INT, 0, &txunit, 0); 2073 2074 if (parse_arg_eq(args, &pt) < 0) { 2075 parse_arg_eq_done(&pt); 2076 return CMD_USAGE; 2077 } 2078 2079 parse_arg_eq_done(&pt); 2080 2081 if (blk < 1) { 2082 cli_out("blk must be greater than 0\n"); 2083 return CMD_USAGE; 2084 } 2085 2086 if (ether) { 2087 flags |= BCM_TX_ETHER; 2088 } 2089 2090 if (crc) { 2091 flags |= BCM_TX_CRC_APPEND; 2092 } 2093 2094 if (tagged) { 2095 length += 4; 2096 buf = sal_alloc(length, "sttx"); 2097 if (!buf) { 2098 cli_out("no memory\n"); 2099 goto done; 2100 } 2101 for (i=0; i<12; i++) { 2102 buf[i] = i; 2103 } 2104 buf[12] = 0x81; 2105 buf[13] = 0x00; 2106 buf[14] = 0x00; 2107 buf[15] = 0x01; 2108 for (i=16; i<length; i++) { 2109 buf[i] = i-4; 2110 } 2111 } else { 2112 buf = sal_alloc(length, "sttx"); 2113 if (!buf) { 2114 cli_out("no memory\n"); 2115 cmd_rv = CMD_FAIL; 2116 goto done; 2117 } 2118 for (i=0; i<length; i++) { 2119 buf[i] = i; 2120 } 2121 } 2122 2123 if (reply) { 2124 int tmp; 2125 /* swap SA/DA */ 2126 if (length < 12) { 2127 cli_out("length %d too short\n", length); 2128 cmd_rv = CMD_FAIL; 2129 goto done; 2130 } 2131 for (i=0; i<6; i++) { 2132 tmp = buf[i]; 2133 buf[i] = buf[i+6]; 2134 buf[i+6] = tmp; 2135 } 2136 } 2137 2138 if (array > 0 && list > 0) { 2139 cli_out("Cannot specify array and list at the same time\n"); 2140 cmd_rv = CMD_FAIL; 2141 goto done; 2142 } 2143 2144 packets = array ? array : (list ? list : 1); 2145 2146 if (array) { 2147 pkt_array = sal_alloc(packets * sizeof(bcm_pkt_t *), "sttx"); 2148 } 2149 2150 if (txunit < 0) { 2151 txunit = unit; 2152 } 2153 2154 for (i=0; i < packets; i++) { 2155 rv = tks_pkt_alloc(txunit, blk, length, flags, &cur_pkt); 2156 if (BCM_FAILURE(rv)) { 2157 cli_out("tks_pkt_alloc: %s %d\n", bcm_errmsg(rv),rv); 2158 cmd_rv = CMD_FAIL; 2159 goto done; 2160 } 2161 cur_pkt->dest_mod = dmod; 2162 cur_pkt->dest_port = dport; 2163 cur_pkt->opcode = op; 2164 BCM_PBMP_ASSIGN(cur_pkt->tx_pbmp, dest); 2165 if (tagged) { 2166 BCM_PBMP_CLEAR(cur_pkt->tx_upbmp); 2167 } else { 2168 cur_pkt->_vtag[0] = 0x81; 2169 cur_pkt->_vtag[1] = 0x00; 2170 cur_pkt->_vtag[2] = 0x00; 2171 cur_pkt->_vtag[3] = 0x01; 2172 BCM_PBMP_ASSIGN(cur_pkt->tx_upbmp, dest); 2173 BCM_PKT_NO_VTAG_REQUIRE(cur_pkt); 2174 } 2175 rv = bcm_pkt_memcpy(cur_pkt, 0, buf, length); 2176 if (BCM_FAILURE(rv)) { 2177 cli_out("bcm_pkt_memcpy: %s %d\n", bcm_errmsg(rv),rv); 2178 cmd_rv = CMD_FAIL; 2179 goto done; 2180 } 2181 if ((array > 0 || list > 0) && async > 1) { 2182 /* For tx_list() and async > 1, use per packet callback */ 2183 cur_pkt->call_back = tks_pkt_callback; 2184 } 2185 2186 /* Keep linked list for packet free */ 2187 if (pkt == NULL) { 2188 pkt = cur_pkt; 2189 } 2190 if (prev_pkt != NULL) { 2191 prev_pkt->next = cur_pkt; 2192 } 2193 prev_pkt = cur_pkt; 2194 2195 if (array) { 2196 pkt_array[i] = cur_pkt; 2197 } 2198 } 2199 2200 if (async) { 2201 if (list) { 2202 cli_out("async tx list:\n"); 2203 for (cur_pkt = pkt; cur_pkt; cur_pkt=cur_pkt->next) { 2204 cli_out(" %p\n", (void *)cur_pkt); 2205 } 2206 rv = bcm_tx_list(txunit, pkt, tks_list_callback, (void *)2); 2207 } else if (array) { 2208 cli_out("async tx array:\n"); 2209 for (i = 0; i < packets; i++) { 2210 cli_out(" %p\n", (void *)pkt_array[i]); 2211 } 2212 rv = bcm_tx_array(txunit, pkt_array, packets, 2213 tks_array_callback, (void *)pkt_array); 2214 if (BCM_SUCCESS(rv)) { 2215 pkt_array = NULL; /* Freed by callback */ 2216 } 2217 } else { 2218 cli_out("async tx pkt %p\n", (void *)pkt); 2219 pkt->call_back = tks_pkt_callback; 2220 rv = bcm_tx(txunit, pkt, (void *)1); 2221 } 2222 } else { 2223 if (list) { 2224 rv = bcm_tx_list(txunit, pkt, NULL, NULL); 2225 } else if (array) { 2226 rv = bcm_tx_array(txunit, pkt_array, packets, NULL, NULL); 2227 } else { 2228 rv = bcm_tx(txunit, pkt, NULL); 2229 } 2230 } 2231 if (BCM_FAILURE(rv)) { 2232 cli_out("bcm tx: %s %d\n", bcm_errmsg(rv),rv); 2233 cmd_rv = CMD_FAIL; 2234 goto done; 2235 } 2236 if (!async) { 2237 bcm_pkt_t *next_pkt; 2238 for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt=next_pkt) { 2239 next_pkt = cur_pkt->next; 2240 rv = tks_pkt_free(txunit, cur_pkt); 2241 if (BCM_FAILURE(rv)) { 2242 cli_out("tks_pkt_free: %s %d\n", bcm_errmsg(rv),rv); 2243 cmd_rv = CMD_FAIL; 2244 goto done; 2245 } 2246 } 2247 } 2248 cmd_rv = CMD_OK; 2249 2250 done: 2251 if (buf) { 2252 sal_free(buf); 2253 } 2254 if (pkt_array) { 2255 sal_free(pkt_array); 2256 } 2257 2258 return cmd_rv; 2259 } else if (sal_strcasecmp(subcmd, "MODPORT") == 0) { 2260 /* params */ 2261 int modid = 0; 2262 int dest; 2263 2264 parse_table_init(unit, &pt); 2265 parse_table_add(&pt, "Modid", PQ_DFL|PQ_INT, 0, &modid, 0); 2266 parse_table_add(&pt, "Port", PQ_DFL|PQ_INT, 0, &dest, 0); 2267 if (parse_arg_eq(args, &pt) < 0) { 2268 parse_arg_eq_done(&pt); 2269 return CMD_USAGE; 2270 } 2271 parse_arg_eq_done(&pt); 2272 rv = bcm_stk_modport_set(unit, modid, dest); 2273 if (BCM_FAILURE(rv)) { 2274 cli_out("bcm_stk_modport_set: %s %d\n", bcm_errmsg(rv),rv); 2275 return CMD_FAIL; 2276 } 2277 return CMD_OK; 2278 } else if (sal_strcasecmp(subcmd, "MODID") == 0) { 2279 /* params */ 2280 int modid = 0; 2281 parse_table_init(unit, &pt); 2282 parse_table_add(&pt, "Modid", PQ_DFL|PQ_INT, 0, &modid, 0); 2283 if (parse_arg_eq(args, &pt) < 0) { 2284 parse_arg_eq_done(&pt); 2285 return CMD_USAGE; 2286 } 2287 parse_arg_eq_done(&pt); 2288 rv = bcm_stk_my_modid_set(unit, modid); 2289 if (BCM_FAILURE(rv)) { 2290 cli_out("bcm_stk_my_modid_set: %s %d\n", bcm_errmsg(rv),rv); 2291 return CMD_FAIL; 2292 } 2293 return CMD_OK; 2294 } else { 2295 cli_out("Subcommand not found: %s\n", subcmd); 2296 return CMD_USAGE; 2297 } 2298 2299 return CMD_OK; 2300 } 2301 2302 2303 /**************************************************************** 2304 * 2305 * CPUDB DUMP AND PARSE ROUTINES 2306 * 2307 * DB dump and parse routines work in tandem. After configuration, 2308 * the current stack task DB can be dumped. This creates a script 2309 * (a list of dbparse commands) that can be read in on a different 2310 * system to recreate the DB and topology information. 2311 * 2312 * The parsing is stateful and the order of the dbparse commands 2313 * is very important. For example, 'dbparse object=cpudb_stk_port...' 2314 * gives info about a stack port; but which stack port is implied 2315 * in the current state of the parsing (what was the last DB 2316 * entry created and which stack ports were added previously). 2317 * 2318 * The DB parse routines will install the data into the current 2319 * CPU DB (from cpudb create) and into parse_tp_cpu. 2320 */ 2321 2322 static topo_cpu_t *parse_tp_cpu; 2323 2324 #define PARSE_TP_CPU_INIT \ 2325 if (parse_tp_cpu == NULL) { \ 2326 parse_tp_cpu = sal_alloc(sizeof(*parse_tp_cpu), "parse_tp_cpu"); \ 2327 sal_memset(parse_tp_cpu, 0, sizeof(*parse_tp_cpu)); \ 2328 } 2329 2330 /* Dump a CPUDB entry's stack port */ 2331 void 2332 stk_ports_dump(cpudb_entry_t *entry, char *prefix) 2333 { 2334 cpudb_stk_port_t *sp; 2335 int i; 2336 2337 for (i = 0; i < entry->base.num_stk_ports; i++) { 2338 sp = &entry->sp_info[i]; 2339 sal_printf("%s object=cpudb_stk_port \\\n" 2340 " weight=0x%x \\\n" 2341 " base_flags=0x%x \\\n" 2342 " flags=0x%x \\\n" 2343 " unit=%d \\\n" 2344 " port=%d \\\n" 2345 " tx_cpu_key=%x:%x:%x:%x:%x:%x \\\n" 2346 " tx_stk_idx=%d \\\n" 2347 " rx_cpu_key=%x:%x:%x:%x:%x:%x \\\n" 2348 " rx_stk_idx=%d\n", 2349 prefix, 2350 entry->base.stk_ports[i].weight, 2351 entry->base.stk_ports[i].bflags, 2352 sp->flags, 2353 entry->base.stk_ports[i].unit, 2354 entry->base.stk_ports[i].port, 2355 MAC_ADDR_LIST(sp->tx_cpu_key.key), 2356 sp->tx_stk_idx, 2357 MAC_ADDR_LIST(sp->rx_cpu_key.key), 2358 sp->rx_stk_idx); 2359 } 2360 } 2361 2362 /* Dump a CPUDB entry's stack port */ 2363 void 2364 cpudb_units_dump(cpudb_entry_t *entry, char *prefix) 2365 { 2366 int i; 2367 2368 for (i = 0; i < entry->base.num_units; i++) { 2369 sal_printf("%s object=cpudb_unit_mod_ids \\\n" 2370 " mod_ids_req=%d \\\n" 2371 " pref_mod_id=%d \\\n" 2372 " mod_id=%d\n", 2373 prefix, 2374 entry->base.mod_ids_req[i], 2375 entry->base.pref_mod_id[i], 2376 entry->mod_ids[i]); 2377 } 2378 } 2379 2380 /* Dump a CPUDB entry */ 2381 2382 void 2383 cpudb_entry_dump(cpudb_entry_t *entry, char *prefix) 2384 { 2385 cpudb_base_t *base; 2386 2387 base = &entry->base; 2388 sal_printf("%s object=cpudb_entry key=%x:%x:%x:%x:%x:%x \\\n" 2389 " mac=%x:%x:%x:%x:%x:%x \\\n" 2390 " master_pri=%d \\\n" 2391 " slot_id=%d \\\n" 2392 " dest_unit=%d \\\n" 2393 " base_dest_port=%d \\\n" 2394 " flags=0x%x \\\n" 2395 " tx_unit=%d \\\n" 2396 " tx_port=%d \\\n" 2397 " dest_mod=%d \\\n" 2398 " dest_port=%d \\\n" 2399 " topo_idx=%d\n", 2400 prefix, 2401 MAC_ADDR_LIST(base->key.key), 2402 MAC_ADDR_LIST(base->mac), 2403 base->master_pri, 2404 base->slot_id, 2405 base->dest_unit, 2406 base->dest_port, 2407 entry->flags, 2408 entry->tx_unit, 2409 entry->tx_port, 2410 entry->dest_mod, 2411 entry->dest_port, 2412 entry->topo_idx); 2413 stk_ports_dump(entry, prefix); 2414 cpudb_units_dump(entry, prefix); 2415 } 2416 2417 /* Dump topology mod id lists for a stack port */ 2418 2419 void 2420 topo_stk_port_dump(topo_stk_port_t *sp, char *prefix) 2421 { 2422 int i; 2423 2424 sal_printf("%s object=topo_stk_port flags=0x%x\n", 2425 prefix, 2426 sp->flags); 2427 for (i = 0; i < sp->tx_mod_num; i++) { 2428 sal_printf("%s object=topo_tx_mod mod_id=%d\n", 2429 prefix, 2430 sp->tx_mods[i]); 2431 } 2432 for (i = 0; i < sp->rx_mod_num; i++) { 2433 sal_printf("%s object=topo_rx_mod mod_id=%d\n", 2434 prefix, 2435 sp->rx_mods[i]); 2436 } 2437 } 2438 2439 /* Dump a topology CPU structure */ 2440 2441 void 2442 topo_cpu_dump(topo_cpu_t *topo_cpu, char *prefix) 2443 { 2444 int i; 2445 2446 sal_printf("%s object=topo_cpu \\\n", prefix); 2447 sal_printf(" key=%x:%x:%x:%x:%x:%x \\\n", 2448 MAC_ADDR_LIST(topo_cpu->local_entry.base.key.key)); 2449 sal_printf(" version=%d \\\n" 2450 " master_seq_num=%d \\\n" 2451 " flags=0x%x\n", 2452 topo_cpu->version, 2453 topo_cpu->master_seq_num, 2454 topo_cpu->flags); 2455 for (i = 0; i < topo_cpu->local_entry.base.num_stk_ports; i++) { 2456 topo_stk_port_dump(&(topo_cpu->tp_stk_port[i]), prefix); 2457 } 2458 sal_printf("\n# End of topology dump.\n\n"); 2459 } 2460 2461 /* Dump a CPUDB including topology info */ 2462 2463 void 2464 cpudb_dump(cpudb_ref_t db, char *prefix) 2465 { 2466 cpudb_entry_t *entry; 2467 2468 if (!cpudb_valid(db)) { 2469 cli_out("DB is not valid\n"); 2470 return; 2471 } 2472 2473 sal_printf("# Dump CPU DB\n"); 2474 sal_printf("# WARNING: DB parsing is stateful and order specific.\n"); 2475 sal_printf("# WARNING: Changing the order of dbparse commands\n"); 2476 sal_printf("# WARNING: will change or break the resulting parse\n\n"); 2477 CPUDB_FOREACH_ENTRY(db, entry) { 2478 cpudb_entry_dump(entry, prefix); 2479 } 2480 2481 if (db->master_entry != NULL) { 2482 sal_printf("%s object=master_key key=%x:%x:%x:%x:%x:%x\n", 2483 prefix, 2484 MAC_ADDR_LIST(db->master_entry->base.key.key)); 2485 } 2486 2487 if (db->local_entry != NULL) { 2488 sal_printf("%s object=local_key key=%x:%x:%x:%x:%x:%x\n", 2489 prefix, 2490 MAC_ADDR_LIST(db->local_entry->base.key.key)); 2491 } 2492 sal_printf("\n# End of CPUDB dump.\n"); 2493 } 2494 2495 char cmd_st_db_dump_usage[] = 2496 "Dump the current stack task CPUDB in a parsable format\n"; 2497 2498 cmd_result_t 2499 cmd_st_db_dump(int ignored_unit, args_t *args) 2500 { 2501 if (!cpudb_valid(bcm_st_cur_db)) { 2502 cli_out("Stack task current DB is not valid\n"); 2503 return CMD_OK; 2504 } 2505 2506 sal_printf("\n# Dumping current stack task CPUDB\n\n"); 2507 cpudb_dump(bcm_st_cur_db, "dbparse"); 2508 sal_printf("\n\n# Clear topology info before parsing\n"); 2509 sal_printf("dbparse object=topo_clear\n"); 2510 2511 return CMD_OK; 2512 } 2513 2514 static char *parse_object_list[] = { PARSE_OBJECT_NAMES }; 2515 2516 char cmd_cpudb_parse_usage[] = 2517 "Parse a CPUDB object command generated by CPUDB dump\n"; 2518 2519 static cpudb_key_t current_key; 2520 static int current_topo_sp_idx; 2521 2522 #define CHECK_SET(dest, val) if ((val) >= 0) (dest) = (val) 2523 2524 /* Add stack port to the given entry */ 2525 STATIC int _stk_port_add(cpudb_entry_t *entry, int unit, bcm_port_t port, 2526 int weight, int base_flags, 2527 int flags, int tx_stk_idx, int rx_stk_idx, 2528 cpudb_key_t tx_cpu_key, cpudb_key_t rx_cpu_key) 2529 { 2530 int cur_sp; 2531 cpudb_stk_port_t *sp; 2532 2533 if (entry->base.num_stk_ports >= CPUDB_STK_PORTS_MAX) { 2534 cli_out("ERROR: failed to add stack port unit=%d port=%d to cpudb " 2535 "(max=%d)\n", unit, port, CPUDB_STK_PORTS_MAX); 2536 return BCM_E_FAIL; 2537 } 2538 2539 cur_sp = entry->base.num_stk_ports++; 2540 entry->base.stk_ports[cur_sp].weight = weight; 2541 entry->base.stk_ports[cur_sp].bflags = base_flags; 2542 entry->base.stk_ports[cur_sp].unit = unit; 2543 entry->base.stk_ports[cur_sp].port = port; 2544 sp = &entry->sp_info[cur_sp]; 2545 sp->flags = flags; 2546 CPUDB_KEY_COPY(sp->tx_cpu_key, tx_cpu_key); 2547 sp->tx_stk_idx = tx_stk_idx; 2548 CPUDB_KEY_COPY(sp->rx_cpu_key, rx_cpu_key); 2549 sp->rx_stk_idx = rx_stk_idx; 2550 2551 return BCM_E_NONE; 2552 } 2553 2554 /* 2555 * Parse a port specification string of unit, port pairs, adding each 2556 * as a stack port to the given entry. See notes at unit_port_pair_parse. 2557 */ 2558 2559 STATIC cmd_result_t 2560 _port_string_parse(cpudb_entry_t *entry, char *port_str) 2561 { 2562 int unit; 2563 bcm_port_t port; 2564 static cpudb_key_t empty_key; /* Initialized to 0 in BSS */ 2565 2566 if (port_str == NULL) { 2567 return CMD_FAIL; 2568 } 2569 2570 port_str = _next_digit(port_str); 2571 do { 2572 port_str = unit_port_pair_parse(port_str, &unit, &port); 2573 if (port_str != NULL) { 2574 if (BCM_FAILURE(_stk_port_add(entry, unit, port, 0, 0, 0, 2575 -1, -1, empty_key, empty_key))) { 2576 return CMD_FAIL; 2577 } 2578 port_str = _next_digit(port_str); 2579 } else { 2580 cli_out("Error parsing port string: %s\n", port_str); 2581 } 2582 } while ((port_str != NULL) && (*port_str != 0)); 2583 2584 return port_str == NULL ? CMD_FAIL : CMD_OK; 2585 } 2586 2587 /* 2588 * Requires the notion of a "current DB" (fixed for entire parsing) 2589 * and "current DB entry" (updated by parsing routine) 2590 */ 2591 2592 cmd_result_t 2593 cmd_cpudb_parse(int ignored_unit, args_t *args) 2594 { 2595 parse_table_t pt; 2596 int object; 2597 int base_dest_port = -1, 2598 dest_mod = -1, 2599 dest_port = -1, 2600 dest_unit = -1, 2601 flags = 0, 2602 weight = 0, 2603 base_flags = 0, 2604 master_pri = -1, 2605 master_seq_num = -1, 2606 mod_id = -1, 2607 mod_ids_req = -1, 2608 num_stk_ports = -1, 2609 port = -1, 2610 pref_mod_id = -1, 2611 rx_stk_idx = -1, 2612 slot_id = -1, 2613 topo_idx = -1, 2614 tx_port = -1, 2615 tx_stk_idx = -1, 2616 tx_unit = -1, 2617 unit = -1, 2618 version = -1; 2619 cpudb_key_t key, rx_cpu_key, tx_cpu_key; 2620 bcm_mac_t mac; 2621 cpudb_ref_t db_ref; 2622 cpudb_entry_t *entry; 2623 cpudb_base_t *base; 2624 topo_stk_port_t *topo_sp; 2625 cmd_result_t cmd_rv = CMD_OK; 2626 int cur_unit; 2627 int db_idx = cur_db; 2628 char *sp_string; 2629 int rv; 2630 2631 sal_memset(&key, 0, sizeof(cpudb_key_t)); 2632 sal_memset(&rx_cpu_key, 0, sizeof(cpudb_key_t)); 2633 sal_memset(&tx_cpu_key, 0, sizeof(cpudb_key_t)); 2634 sal_memset(mac, 0, sizeof(bcm_mac_t)); 2635 2636 parse_table_init(unit, &pt); 2637 parse_table_add(&pt, "OBJECT", PQ_DFL | PQ_MULTI, 0, &object, 2638 parse_object_list); 2639 parse_table_add(&pt, "DB_IDX", PQ_DFL | PQ_INT, 0, &db_idx, 0); 2640 parse_table_add(&pt, "BASE_DEST_PORT", PQ_DFL | PQ_INT, 0, &base_dest_port, 0); 2641 parse_table_add(&pt, "BASE_FLAGS", PQ_DFL | PQ_INT, 0, &base_flags, 0); 2642 parse_table_add(&pt, "DEST_MOD", PQ_DFL | PQ_INT, 0, &dest_mod, 0); 2643 parse_table_add(&pt, "DEST_PORT", PQ_DFL | PQ_INT, 0, &dest_port, 0); 2644 parse_table_add(&pt, "DEST_UNIT", PQ_DFL | PQ_INT, 0, &dest_unit, 0); 2645 parse_table_add(&pt, "FLAGS", PQ_DFL | PQ_INT, 0, &flags, 0); 2646 parse_table_add(&pt, "KEY", PQ_DFL | PQ_KEY, 0, key.key, 0); 2647 parse_table_add(&pt, "MAC", PQ_DFL | PQ_MAC, 0, mac, 0); 2648 parse_table_add(&pt, "MASTER_PRI", PQ_DFL | PQ_INT, 0, &master_pri, 0); 2649 parse_table_add(&pt, "MASTER_SEQ_NUM", PQ_DFL | PQ_INT, 0, &master_seq_num, 0); 2650 parse_table_add(&pt, "MOD_ID", PQ_DFL | PQ_INT, 0, &mod_id, 0); 2651 parse_table_add(&pt, "MOD_IDS_REQ", PQ_DFL | PQ_INT, 0, &mod_ids_req, 0); 2652 parse_table_add(&pt, "NUM_STK_PORTS", PQ_DFL | PQ_INT, 0, &num_stk_ports, 0); 2653 parse_table_add(&pt, "PORT", PQ_DFL | PQ_INT, 0, &port, 0); 2654 parse_table_add(&pt, "PREF_MOD_ID", PQ_DFL | PQ_INT, 0, &pref_mod_id, 0); 2655 parse_table_add(&pt, "RX_CPU_KEY", PQ_DFL | PQ_KEY, 0, rx_cpu_key.key, 0); 2656 parse_table_add(&pt, "RX_STK_IDX", PQ_DFL | PQ_INT, 0, &rx_stk_idx, 0); 2657 parse_table_add(&pt, "SLOT_ID", PQ_DFL | PQ_INT, 0, &slot_id, 0); 2658 parse_table_add(&pt, "SP_STRING", PQ_STRING, 0, &sp_string, 0); 2659 parse_table_add(&pt, "TOPO_IDX", PQ_DFL | PQ_INT, 0, &topo_idx, 0); 2660 parse_table_add(&pt, "TX_CPU_KEY", PQ_DFL | PQ_KEY, 0, tx_cpu_key.key, 0); 2661 parse_table_add(&pt, "TX_PORT", PQ_DFL | PQ_INT, 0, &tx_port, 0); 2662 parse_table_add(&pt, "TX_STK_IDX", PQ_DFL | PQ_INT, 0, &tx_stk_idx, 0); 2663 parse_table_add(&pt, "TX_UNIT", PQ_DFL | PQ_INT, 0, &tx_unit, 0); 2664 parse_table_add(&pt, "UNIT", PQ_DFL | PQ_INT, 0, &unit, 0); 2665 parse_table_add(&pt, "VERSION", PQ_DFL | PQ_INT, 0, &version, 0); 2666 parse_table_add(&pt, "WEIGHT", PQ_DFL | PQ_INT, 0, &weight, 0); 2667 2668 if (parse_arg_eq(args, &pt) < 0) { 2669 parse_arg_eq_done(&pt); 2670 return CMD_USAGE; 2671 } 2672 2673 if (db_idx < 0 || db_idx >= MAX_DBS) { 2674 parse_arg_eq_done(&pt); 2675 sal_printf("Bad db index %d\n", db_idx); 2676 return CMD_USAGE; 2677 } 2678 db_ref = db_refs[db_idx]; 2679 if (!cpudb_valid(db_ref)) { 2680 parse_arg_eq_done(&pt); 2681 sal_printf("DB reference %d is not valid\n", db_idx); 2682 return CMD_USAGE; 2683 } 2684 2685 switch (object) { 2686 case PARSE_OBJ_CPUDB_ENTRY : /* Sets current key */ 2687 CPUDB_KEY_SEARCH(db_ref, key, entry); 2688 if (entry != NULL) { 2689 sal_printf("CPUDB PARSE ENTRY: WARNING key already in DB " 2690 CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key)); 2691 } 2692 CPUDB_KEY_COPY(current_key, key); 2693 entry = cpudb_entry_create(db_ref, key, FALSE); 2694 if (entry == NULL) { 2695 sal_printf("CPUDB PARSE ENTRY: ERROR failed to create entry for " 2696 CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key)); 2697 cmd_rv = CMD_FAIL; 2698 break; 2699 } 2700 base = &entry->base; 2701 sal_memcpy(entry->base.mac, mac, sizeof(bcm_mac_t)); 2702 2703 CHECK_SET(entry->flags, flags); 2704 CHECK_SET(base->master_pri, master_pri); 2705 CHECK_SET(base->slot_id, slot_id); 2706 CHECK_SET(base->dest_unit, dest_unit); 2707 CHECK_SET(base->dest_port, base_dest_port); 2708 CHECK_SET(entry->tx_unit, tx_unit); 2709 CHECK_SET(entry->tx_port, tx_port); 2710 CHECK_SET(entry->dest_mod, dest_mod); 2711 CHECK_SET(entry->dest_port, dest_port); 2712 CHECK_SET(entry->topo_idx, topo_idx); 2713 entry->base.num_units = 0; 2714 entry->base.num_stk_ports = 0; 2715 break; 2716 2717 case PARSE_OBJ_CPUDB_UNIT_MOD_IDS : 2718 CPUDB_KEY_SEARCH(db_ref, current_key, entry); 2719 if (entry == NULL) { 2720 sal_printf("CPUDB PARSE UNIT_MOD_IDS: Current DB key not found\n"); 2721 cmd_rv = CMD_FAIL; 2722 break; 2723 } 2724 if (entry->base.num_units >= CPUDB_UNITS_MAX) { 2725 sal_printf("CPUDB PARSE UNIT_MOD_IDS: Cannot exceed %d units\n", 2726 CPUDB_UNITS_MAX); 2727 cmd_rv = CMD_FAIL; 2728 break; 2729 } 2730 cur_unit = entry->base.num_units++; 2731 entry->mod_ids[cur_unit] = mod_id; 2732 entry->base.pref_mod_id[cur_unit] = pref_mod_id; 2733 entry->base.mod_ids_req[cur_unit] = mod_ids_req; 2734 break; 2735 2736 case PARSE_OBJ_CPUDB_STK_PORT : 2737 CPUDB_KEY_SEARCH(db_ref, current_key, entry); 2738 if (entry == NULL) { 2739 sal_printf("CPUDB PARSE STK_PORT: Current DB key not found\n"); 2740 cmd_rv = CMD_FAIL; 2741 break; 2742 } 2743 if (BCM_FAILURE(_stk_port_add(entry, unit, port, weight, base_flags, 2744 flags, tx_stk_idx, rx_stk_idx, 2745 tx_cpu_key, rx_cpu_key))) { 2746 cmd_rv = CMD_FAIL; 2747 } 2748 break; 2749 2750 case PARSE_OBJ_CPUDB_STK_PORT_STR : 2751 CPUDB_KEY_SEARCH(db_ref, current_key, entry); 2752 if (entry == NULL) { 2753 sal_printf("CPUDB PARSE STK_PORT_STR: " 2754 "Current DB key not found\n"); 2755 cmd_rv = CMD_FAIL; 2756 break; 2757 } 2758 cmd_rv = _port_string_parse(entry, sp_string); 2759 break; 2760 2761 case PARSE_OBJ_MASTER_KEY : 2762 CPUDB_KEY_SEARCH(db_ref, key, entry); 2763 if (entry == NULL) { 2764 sal_printf("CPUDB PARSE MASTER KEY: Entry not found: " 2765 CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key)); 2766 cmd_rv = CMD_FAIL; 2767 break; 2768 } 2769 db_ref->master_entry = entry; 2770 break; 2771 2772 case PARSE_OBJ_LOCAL_KEY : 2773 CPUDB_KEY_SEARCH(db_ref, key, entry); 2774 if (entry == NULL) { 2775 sal_printf("CPUDB PARSE LOCAL KEY: Entry not found: " 2776 CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key)); 2777 cmd_rv = CMD_FAIL; 2778 break; 2779 } 2780 db_ref->local_entry = entry; 2781 break; 2782 2783 case PARSE_OBJ_TOPO_CPU : 2784 CPUDB_KEY_SEARCH(db_ref, key, entry); 2785 if (entry == NULL) { 2786 sal_printf("CPUDB PARSE LOCAL KEY: Entry not found: " 2787 CPUDB_KEY_FMT_EOLN, CPUDB_KEY_DISP(key)); 2788 cmd_rv = CMD_FAIL; 2789 break; 2790 } 2791 PARSE_TP_CPU_INIT; 2792 cpudb_entry_copy(&parse_tp_cpu->local_entry, entry); 2793 CHECK_SET(parse_tp_cpu->version, version); 2794 CHECK_SET(parse_tp_cpu->master_seq_num, master_seq_num); 2795 CHECK_SET(parse_tp_cpu->flags, flags); 2796 current_topo_sp_idx = -1; 2797 break; 2798 2799 case PARSE_OBJ_TOPO_STK_PORT : 2800 current_topo_sp_idx++; 2801 if (current_topo_sp_idx >= CPUDB_STK_PORTS_MAX) { 2802 sal_printf("CPUDB PARSE TOPO_STK_PORT: Cannot exceed %d stack " 2803 "ports\n", CPUDB_STK_PORTS_MAX); 2804 cmd_rv = CMD_FAIL; 2805 break; 2806 } 2807 PARSE_TP_CPU_INIT; 2808 topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx]; 2809 CHECK_SET(topo_sp->flags, flags); 2810 break; 2811 case PARSE_OBJ_TOPO_TX_MOD : 2812 PARSE_TP_CPU_INIT; 2813 topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx]; 2814 if (topo_sp->tx_mod_num >= TOPO_MODIDS_MAX) { 2815 sal_printf("CPUDB PARSE TOPO_TX_MOD: Cannot exceed %d mod ids\n", 2816 TOPO_MODIDS_MAX); 2817 cmd_rv = CMD_FAIL; 2818 break; 2819 } 2820 topo_sp->tx_mods[(topo_sp->tx_mod_num)++] = mod_id; 2821 break; 2822 case PARSE_OBJ_TOPO_RX_MOD : 2823 PARSE_TP_CPU_INIT; 2824 topo_sp = &parse_tp_cpu->tp_stk_port[current_topo_sp_idx]; 2825 if (topo_sp->rx_mod_num >= TOPO_MODIDS_MAX) { 2826 sal_printf("CPUDB PARSE TOPO_RX_MOD: Cannot exceed %d mod ids\n", 2827 TOPO_MODIDS_MAX); 2828 cmd_rv = CMD_FAIL; 2829 break; 2830 } 2831 topo_sp->rx_mods[(topo_sp->rx_mod_num)++] = mod_id; 2832 break; 2833 2834 case PARSE_OBJ_TOPO_CLEAR : /* Clear parse topology */ 2835 PARSE_TP_CPU_INIT; 2836 sal_memset(parse_tp_cpu, 0, sizeof(*parse_tp_cpu)); 2837 break; 2838 2839 case PARSE_OBJ_TOPO_INSTALL : 2840 /* not supported */ 2841 break; 2842 2843 case PARSE_OBJ_STACK_INSTALL : 2844 rv = atp_db_update(db_ref); 2845 if (rv < 0) { 2846 cli_out("WARNING: ATP DB update failed %d: %s\n", 2847 rv, bcm_errmsg(rv)); 2848 } 2849 rv = bcm_stack_attach_update(db_ref); 2850 if (rv < 0) { 2851 cli_out("ERROR: stack attach returned %d: %s\n", 2852 rv, bcm_errmsg(rv)); 2853 } 2854 break; 2855 case PARSE_OBJ_LOCAL_ENTRY : 2856 /* Make a few parameters settable for local entry */ 2857 if (db_ref->local_entry == NULL) { 2858 cli_out("ERROR: DB parse. Local entry not set\n"); 2859 cmd_rv = CMD_FAIL; 2860 break; 2861 } 2862 entry = db_ref->local_entry; 2863 base = &entry->base; 2864 CHECK_SET(entry->flags, flags); 2865 CHECK_SET(base->master_pri, master_pri); 2866 CHECK_SET(base->slot_id, slot_id); 2867 CHECK_SET(base->dest_unit, dest_unit); 2868 CHECK_SET(base->dest_port, base_dest_port); 2869 CHECK_SET(entry->tx_unit, tx_unit); 2870 CHECK_SET(entry->tx_port, tx_port); 2871 CHECK_SET(entry->dest_mod, dest_mod); 2872 CHECK_SET(entry->dest_port, dest_port); 2873 CHECK_SET(entry->topo_idx, topo_idx); 2874 break; 2875 default: 2876 sal_printf("Unknown object parse\n"); 2877 cmd_rv = CMD_USAGE; 2878 break; 2879 } 2880 2881 parse_arg_eq_done(&pt); 2882 return cmd_rv; 2883 } 2884 2885 2886 #endif /* INCLUDE_LIB_CPUDB */