topo_pkt.c (33306B)
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_pkt.c 8 * Purpose: All functions related to topo packet generation and 9 * handling. 10 * 11 * This file contains code related to topology packet generation 12 * and handling. It provides default functions that are used by 13 * stack task if customer applications do not provide alternatives. 14 * In addition, it provides some building blocks that customers 15 * may integrate with their own code. 16 * 17 * Here's how the sample topology stack task code works: 18 * 19 * 1. stk task enters DISC mode: Application should call 20 * topo_pkt_expect_set(TRUE) to indicate topo pkts 21 * should be expected. 22 * 23 * 2. stk task enters TOPO mode: Stack task calls 24 * bcm_stack_topo_update (as programmed into st_config). 25 * 26 * 3. topology packet is received: 27 * If both 1 and 2 have occurred, process packet. 28 * If only 1 has occurred, bank packet and wait for (2). 29 * If only 2 has occurred, it's an error. 30 * 31 * If stack task exits TOPO mode, or whenever it goes into blocked 32 * mode, the application should call topo_pkt_expect_set(FALSE). 33 */ 34 35 #include <shared/bsl.h> 36 37 #include <sdk_config.h> 38 #include <shared/alloc.h> 39 40 #include <bcm/error.h> 41 #include <bcm/types.h> 42 #include <bcm/port.h> 43 #include <bcm/stack.h> 44 45 #include <appl/cpudb/cpudb.h> 46 47 #include <appl/cputrans/cputrans.h> 48 #include <appl/cputrans/atp.h> 49 #include <appl/cputrans/nh_tx.h> 50 51 #include <appl/stktask/stktask.h> 52 #include <appl/stktask/topology.h> 53 #include <appl/stktask/topo_pkt.h> 54 #include <appl/stktask/topo_brd.h> 55 56 #include "topo_int.h" 57 #include "brd_chassis_int.h" 58 59 static sal_mutex_t st_topo_lock; /* Serves as init done indication */ 60 static volatile int topo_enabled; /* Accept topo packets; control w/ expect */ 61 62 static cpudb_ref_t topo_current_db = CPUDB_REF_NULL; 63 static uint8 topo_pkt_buf[TOPO_PKT_BYTES_MAX]; 64 static int topo_pkt_len; /* Also signals pkt is present */ 65 66 #define TOPO_PKT_CLEAR topo_pkt_len = 0 67 #define TOPO_PKT_SET(_pkt, _len, _src_key) do { \ 68 sal_memcpy(topo_pkt_buf, (_pkt), (_len)); \ 69 topo_pkt_len = (_len); \ 70 } while (0) 71 #define TOPO_PKT_PRESENT (topo_pkt_len > 0) 72 73 #define ST_TOPO_LOCK sal_mutex_take(st_topo_lock, sal_mutex_FOREVER) 74 #define ST_TOPO_UNLOCK sal_mutex_give(st_topo_lock) 75 76 /* Process topo pkts when current DB is non NULL */ 77 #define TOPO_ACTIVE (topo_current_db != CPUDB_REF_NULL) 78 79 #ifndef TOPO_THREAD_STACK 80 #define TOPO_THREAD_STACK SAL_THREAD_STKSZ 81 #endif 82 #ifndef TOPO_THREAD_PRIO 83 #define TOPO_THREAD_PRIO 50 84 #endif 85 86 87 #define TOPO_DEFERRED 1 88 89 /**************************************************************** 90 * 91 * Default topology update callback function 92 */ 93 94 STATIC void topo_pkt_process(void); 95 STATIC int topo_pkt_send(cpudb_ref_t db_ref, cpudb_entry_t *entry); 96 STATIC int topo_pkt_send_depth_first(cpudb_ref_t db_ref, cpudb_entry_t *entry); 97 98 int 99 bcm_stack_topo_update(cpudb_ref_t db_ref) 100 { 101 int rv = BCM_E_NONE; 102 cpudb_entry_t *entry; 103 104 if (st_topo_lock == NULL) { /* Not initialized */ 105 return BCM_E_INIT; 106 } 107 108 ST_TOPO_LOCK; 109 if (!topo_enabled) { /* Not enabled */ 110 ST_TOPO_UNLOCK; 111 return BCM_E_INIT; 112 } 113 if (TOPO_ACTIVE) { 114 ST_TOPO_UNLOCK; 115 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 116 (BSL_META("TOPO: Activated twice\n"))); 117 return BCM_E_FAIL; 118 } 119 120 topo_current_db = db_ref; 121 122 #if !defined(TOPO_PROCESSING_LOCAL) /* Send out topo info from master */ 123 if (db_ref->local_entry == db_ref->master_entry) { /* Local is master */ 124 /* Generate the topology and send out topo packets */ 125 if ((rv = topology_mod_ids_assign(db_ref)) < 0) { 126 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 127 (BSL_META("Could not assign all mod ids: %s\n"), 128 bcm_errmsg(rv))); 129 } else if ((rv = topology_create(db_ref)) < 0) { 130 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 131 (BSL_META("Failed to create topology: %s\n"), 132 bcm_errmsg(rv))); 133 } else if ((rv = topo_pkt_send_depth_first(db_ref, 134 db_ref->master_entry)) < 0) { 135 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 136 (BSL_META("Failed to send topo pkt: %s\n"), 137 bcm_errmsg(rv))); 138 } 139 140 /* 141 * Clear topo visited flags for all cpus 142 */ 143 CPUDB_FOREACH_ENTRY(db_ref, entry) { 144 CPUDB_TOPO_NOT_VISITED_SET(entry); 145 } 146 } else { /* Not master */ 147 if (TOPO_PKT_PRESENT) { /* Ready to process packet */ 148 topo_pkt_process(); 149 } 150 } 151 #else 152 /* To do: Implement local topology processing */ 153 #endif 154 155 /* Check rv == BCM_E_NONE before doing anything else */ 156 ST_TOPO_UNLOCK; 157 158 return rv; 159 } 160 161 STATIC int 162 _topo_handle_init(void) 163 { 164 if (st_topo_lock == NULL) { 165 st_topo_lock = sal_mutex_create("topo_handle"); 166 if (st_topo_lock == NULL) { 167 return BCM_E_MEMORY; 168 } 169 } 170 171 return BCM_E_NONE; 172 } 173 174 /**************************************************************** 175 * 176 * Application to topology interface API functions 177 * 178 * topo_pkt_handle_init: 179 * Register w/ ATP to get topo pkts. 180 * topo_pkt_expect_set(int enable) 181 * Indicate if topology packet should be expected and 182 * processed. 183 * 184 * topo_stack_topo_update 185 * Normally called by stack task on transition to 186 * TOPO state. 187 */ 188 189 STATIC bcm_rx_t topo_pkt_handler(cpudb_key_t src_key, 190 int client_id, 191 bcm_pkt_t *pkt, 192 uint8 *payload, 193 int payload_len, 194 void *cookie); 195 196 /* 197 * (Re-)Initialize the topo packet handler subsystem. 198 * Creates lock and registers with ATP with given flags 199 */ 200 201 int 202 topo_pkt_handle_init(uint32 topo_atp_flags) 203 { 204 int rv = BCM_E_NONE; 205 206 if (st_topo_lock == NULL) { 207 rv = _topo_handle_init(); 208 if (rv < 0) { 209 return rv; 210 } 211 } 212 213 /* Handle ATP-NH registration to receive topo packets from ATP */ 214 atp_unregister(BCM_ST_TOPO_CLIENT_ID); 215 rv = atp_register(BCM_ST_TOPO_CLIENT_ID, topo_atp_flags, 216 topo_pkt_handler, NULL, -1, -1); 217 218 return rv; 219 } 220 221 /* 222 * Indicate to topo processing whether to expect topo pkts. 223 * This should be enabled at the transition into DISC. It 224 * should be disabled at the transition to BLOCKED. 225 * 226 * This will always clear the local DB pointer. That pointer 227 * is set when stack task calls with "start topo processing". 228 * It must not be changed by stack task until after 229 * topo_pkt_handle_enable_set(FALSE) is called. 230 */ 231 232 int 233 topo_pkt_expect_set(int enable) 234 { 235 int rv = BCM_E_NONE; 236 237 if (st_topo_lock == NULL) { 238 return BCM_E_INIT; 239 } 240 241 ST_TOPO_LOCK; 242 topo_enabled = enable; 243 topo_current_db = CPUDB_REF_NULL; 244 ST_TOPO_UNLOCK; 245 246 return rv; 247 } 248 249 250 /* 251 * _nh_src_modid_enable 252 * 253 * Enables the mod ID that will be used by the given destination 254 * CPU when sending NH packets. 255 */ 256 STATIC int 257 _nh_src_modid_enable(cpudb_ref_t db_ref, cpudb_entry_t *entry) 258 { 259 int i; 260 int nh_mod_id = -1; 261 cpudb_entry_t *l_entry; 262 cpudb_unit_port_t *sp; 263 uint32 flags; 264 265 /* 266 * If a reserved mod ID is used for NH, 267 * nothing to do. This reserved mod ID 268 * should never be blocked. 269 */ 270 if (bcm_st_reserved_modid_enable_get()) { 271 return BCM_E_NONE; 272 } 273 274 l_entry = db_ref->local_entry; 275 276 /* If not using the reserved modid feature, 277 * enable remote mod ID since remote CPU will 278 * be transmitting NH packets using its local mod ID. 279 */ 280 281 /* 282 * Get first mod ID in CPU entry 283 */ 284 for (i = 0; i < entry->base.num_units; i++) { 285 if (entry->mod_ids[i] >= 0) { 286 nh_mod_id = entry->mod_ids[i]; 287 break; /* Found a local mod ID */ 288 } 289 } 290 291 if (nh_mod_id < 0) { 292 return BCM_E_NOT_FOUND; 293 } 294 295 for (i = 0; i < l_entry->base.num_stk_ports; i++) { 296 sp = &l_entry->base.stk_ports[i]; 297 BCM_IF_ERROR_RETURN(bcm_stk_port_get(sp->unit, sp->port, &flags)); 298 if (!(flags & BCM_STK_SL) && 299 l_entry->sp_info[i].flags & CPUDB_SPF_RX_RESOLVED) { 300 bcm_port_modid_enable_set(sp->unit, sp->port, nh_mod_id, TRUE); 301 } 302 } 303 304 return BCM_E_NONE; 305 } 306 307 #if !defined(TOPO_PROCESSING_LOCAL) 308 309 STATIC int 310 topo_pkt_send(cpudb_ref_t db_ref, cpudb_entry_t *entry) 311 { 312 uint8 *buf, *start_buf; 313 int len = 0; 314 int rv = BCM_E_NONE; 315 316 /* Now send out the packets */ 317 buf = start_buf = atp_tx_data_alloc(TOPO_PKT_BYTES_MAX); 318 if (buf == NULL) { 319 return BCM_E_MEMORY; 320 } 321 322 buf += CPUTRANS_HEADER_BYTES; 323 324 topo_pkt_gen(db_ref, entry, buf, TOPO_PKT_BYTES_MAX, &len); 325 326 /* 327 * Enable mod ID that remote CPU will be using for NH packets 328 */ 329 _nh_src_modid_enable(db_ref, entry); 330 331 /* 332 * Send topo packet requesting an immediate ACK back. 333 * 334 * This is necessary to avoid topo ACKs to travel 335 * back with a NH mod-ID (as a result of the topo packet 336 * processing) that the rest of the systems are not ready 337 * to accept (such as the 32-mod ID support). 338 */ 339 rv = atp_tx(entry->base.key, 340 BCM_ST_TOPO_CLIENT_ID, 341 start_buf, 342 CPUTRANS_HEADER_BYTES + len, 343 CPUTRANS_NO_HEADER_ALLOC | CPUTRANS_IMMEDIATE_ACK, 344 NULL, 345 NULL); 346 if (rv < 0) { 347 LOG_WARN(BSL_LS_TKS_TOPOLOGY, 348 (BSL_META("topo send %d: %s. Failed to tx pkt to " 349 CPUDB_KEY_FMT_EOLN), 350 rv, bcm_errmsg(rv), 351 CPUDB_KEY_DISP(entry->base.key))); 352 } 353 354 atp_tx_data_free(start_buf); 355 return rv; 356 } 357 358 /* 359 * Send topo pkts in depth first 360 * order - to avoid src mod blocking 361 */ 362 STATIC int 363 topo_pkt_send_depth_first(cpudb_ref_t db_ref, cpudb_entry_t *entry) 364 { 365 cpudb_stk_port_t *sp = NULL; 366 cpudb_entry_t *other_end; 367 int i, rv; 368 369 if (CPUDB_TOPO_VISITED(entry)) { 370 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 371 (BSL_META("TOPO ERROR: recursing infinitely"))); 372 return -1; 373 } 374 375 CPUDB_TOPO_VISITED_SET(entry); 376 377 for (i = 0; i < entry->base.num_stk_ports; i++) { 378 sp = &entry->sp_info[i]; 379 380 if (entry->sp_info[i].flags & CPUDB_SPF_TX_RESOLVED) { 381 CPUDB_KEY_SEARCH(db_ref, sp->tx_cpu_key, other_end); 382 383 if (other_end != NULL) { 384 if (CPUDB_TOPO_VISITED(other_end)) { 385 continue; 386 } 387 388 /* depth-first traversal */ 389 topo_pkt_send_depth_first(db_ref, other_end); 390 } 391 } 392 } 393 394 #ifdef TOPO_PKT_SEND_CONFIG_IN_SET 395 /* Only send a topo packet to an entry if CPUDB_F_CONFIG_IN is 396 set. 397 398 Normally, on the master, Discovery will have CONFIG_IN set for 399 each slave entry that has participated in discovery. 400 401 If #define TOPO_PKT_SEND_CONFIG_IN_SET is set and CPUDB entry flag 402 CPUDB_F_CONFIG_IN is clear, then do not send a topo pkt to the 403 entry. 404 405 An application can clear CPUDB_F_CONFIG_IN before calling 406 bcm_stack_topo_update() to suppress the transmission of a topo 407 pkt to that entry. The entry will still be used for topology 408 calculation and modid assignment. 409 410 This could allow a system to change stacking software from a 411 'stktask' based topo pkt protocol to something not using topo 412 pkt by leaving those entries that need a topo pkt_send with 413 CONFIG_IN set, and clearing CONFIG_IN from those that don't. 414 415 The master is still responsible for ensuring that those systems 416 with CONFIG_IN clear can still forward packets as needed for 417 the systems with CONFIG_IN set. 418 419 */ 420 if (entry != db_ref->master_entry && !entry->flags & CPUDB_F_CONFIG_IN) { 421 return BCM_E_NONE; 422 } 423 #endif 424 425 rv = topo_pkt_send(db_ref, entry); 426 return rv; 427 } 428 429 #ifndef TOPO_DELAY_DEFAULT 430 #define TOPO_DELAY_DEFAULT 500000 /* 0.5 second, for master only */ 431 #endif 432 433 434 static int topo_delay_us = 0; 435 static int topo_master_delay_us = TOPO_DELAY_DEFAULT; 436 437 int 438 topo_delay_set(int delay_us) 439 { 440 topo_delay_us = delay_us; 441 return BCM_E_NONE; 442 } 443 444 int 445 topo_delay_get(int *delay_us) 446 { 447 if (delay_us != NULL) { 448 *delay_us = topo_delay_us; 449 } 450 return BCM_E_NONE; 451 } 452 453 int 454 topo_master_delay_set(int delay_us) 455 { 456 topo_master_delay_us = delay_us; 457 return BCM_E_NONE; 458 } 459 460 int 461 topo_master_delay_get(int *delay_us) 462 { 463 if (delay_us != NULL) { 464 *delay_us = topo_master_delay_us; 465 } 466 return BCM_E_NONE; 467 } 468 469 /* 470 * Process current topo packet 471 */ 472 473 STATIC void 474 _topo_pkt_process_thread(void *cookie) 475 { 476 int rv; 477 static topo_cpu_t topo_cpu; /* Pretty big, so keep off the stack */ 478 479 COMPILER_REFERENCE(cookie); 480 481 ST_TOPO_LOCK; 482 /* Note that a previous invocation may have cleared a packet 483 between the time the lock was released after calling 484 topo_pkt_process(), and aquired above, so check if packet is 485 still present. */ 486 if (TOPO_ACTIVE && TOPO_PKT_PRESENT) { 487 /* Calculate local CPU connection information; call board programming */ 488 sal_memset(&topo_cpu, 0, sizeof(topo_cpu)); 489 rv = topo_pkt_parse(topo_current_db, 490 topo_current_db->local_entry, 491 topo_pkt_buf, 492 topo_pkt_len, 493 &topo_cpu, 494 NULL); 495 496 if (rv < 0) { 497 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 498 (BSL_META("TOPO PKT ERROR: parse failure: %s\n"), 499 bcm_errmsg(rv))); 500 } else if ((rv = topo_board_program(topo_current_db, &topo_cpu)) < 0) { 501 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 502 (BSL_META("TOPO PKT ERROR: appl fail: %s\n"), 503 bcm_errmsg(rv))); 504 } 505 506 TOPO_PKT_CLEAR; /* Discard packet once processed */ 507 508 if (rv == BCM_E_NONE) { 509 int delay; 510 511 /* Defer topology processing allowing all devices to update */ 512 delay = topo_delay_us; 513 if (topo_current_db->local_entry == 514 topo_current_db->master_entry) { 515 delay = topo_master_delay_us; 516 } 517 518 if ((topo_current_db->num_cpus > 1) && (delay > 0)) { 519 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 520 (BSL_META("TOPO: Sleeping for %d us\n"), 521 delay)); 522 sal_usleep(delay); 523 } 524 /* Successfully processed topo pkt; signal stack task */ 525 bcm_st_event_send(BCM_STE_TOPO_SUCCESS); 526 } 527 } 528 ST_TOPO_UNLOCK; 529 sal_thread_exit(0); 530 } 531 532 STATIC void 533 topo_pkt_process(void) 534 { 535 (void) sal_thread_create("topoDPC", 536 TOPO_THREAD_STACK, 537 TOPO_THREAD_PRIO, 538 _topo_pkt_process_thread, 539 NULL); 540 } 541 542 543 /* 544 * This routine needs to handle the case where the local machine 545 * hasn't realized it's ready for a topo pkt, but the master 546 * has sent one. This is done by queuing any topo packet received. 547 */ 548 549 STATIC bcm_rx_t 550 topo_pkt_handler(cpudb_key_t src_key, 551 int client_id, 552 bcm_pkt_t *pkt, 553 uint8 *payload, 554 int payload_len, 555 void *cookie) 556 { 557 COMPILER_REFERENCE(client_id); 558 COMPILER_REFERENCE(cookie); 559 COMPILER_REFERENCE(pkt); 560 561 if (st_topo_lock == NULL) { /* Not active */ 562 return BCM_RX_HANDLED; 563 } 564 565 ST_TOPO_LOCK; /* Synchronize with topo_update call */ 566 if (!topo_enabled) { 567 ST_TOPO_UNLOCK; 568 return BCM_RX_HANDLED; 569 } 570 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 571 (BSL_META("ST TOPO: pkt len %d in from " 572 CPUDB_KEY_FMT_EOLN), 573 payload_len, CPUDB_KEY_DISP(src_key))); 574 575 /* Record this info - this may overwrite a previous packet that 576 hasn't been processed yet. */ 577 TOPO_PKT_SET(payload, payload_len, src_key); 578 if (TOPO_ACTIVE) { /* Topo is active meaning ready to process topo pkt */ 579 topo_pkt_process(); 580 } 581 582 ST_TOPO_UNLOCK; 583 return BCM_RX_HANDLED; 584 } 585 586 #endif /* not topology generated locally */ 587 588 #if 1 589 #define CHECK_PACK(_buf, _len, _cnt, _data) \ 590 if (_cnt + 1 > _len) return -1; else (_buf)[(_cnt)++] = _data 591 #else /* Debug version of the function */ 592 #define CHECK_PACK(_buf, _len, _cnt, _data) do { \ 593 LOG_INFO(BSL_LS_TKS_TOPOLOGY, \ 594 (BSL_META(\ \ 595 (BSL_META"Packing mod %d\n")), 596 _data)); \ \ 597 if (_cnt + 1 > _len) return -1; else (_buf)[(_cnt)++] = _data; \ 598 } while (0) 599 #endif 600 601 #if defined(INCLUDE_CHASSIS) 602 603 /**************************************************************** 604 * 605 * CHASSIS SPECIFIC CODE 606 */ 607 608 609 610 /* 611 * The following generate the chassis topology based on 612 * conventions. This is done by overriding the generation 613 * of the TX and RX module-ID lists per stack port. 614 */ 615 616 /* Pack mod IDs for an LM on an external LM stack port; sp_idx is active */ 617 STATIC int 618 tp_chassis_lm_pack_mods( 619 int cfm_count, /* How many CFMs active in the system? */ 620 /* The rest follow tp_pack_mods semantics */ 621 cpudb_ref_t db_ref, cpudb_entry_t *entry, 622 uint8 *pkt_data, int len, int sp_idx, int tx) 623 { 624 int slot_id; /* This slot ID */ 625 int cnt = 0; /* byte count */ 626 int cfm_slot; 627 int slot, mod; 628 629 slot_id = entry->base.slot_id; 630 if ((cfm_slot = cpudb_sp_idx_to_slot(db_ref, entry, sp_idx, NULL)) < 0) { 631 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 632 (BSL_META("TOPO: LM %d no cxn on %d\n"), 633 slot_id, sp_idx)); 634 return 0; 635 } 636 637 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 638 (BSL_META("Packing LM slot %d, sp idx %d to slot %d, %s; %d cfms\n"), 639 slot_id, sp_idx, cfm_slot, tx ? "tx" : "rx", cfm_count)); 640 641 if (!tx) { /* RX: Expect any mod ID on any active stack port */ 642 CHECK_PACK(pkt_data, len, cnt, CFM_MODID(cfm_slot)); 643 FOREACH_OTHER_MODID(slot_id, slot, mod) { 644 CHECK_PACK(pkt_data, len, cnt, mod); 645 } 646 return cnt; 647 } 648 649 /* TX: Pack mod IDs for transmitting to other LMs */ 650 CHECK_PACK(pkt_data, len, cnt, CFM_MODID(cfm_slot)); 651 if (cfm_count == 1) { /* Only one CFM in system */ 652 FOREACH_OTHER_MODID(slot_id, slot, mod) { 653 CHECK_PACK(pkt_data, len, cnt, mod); 654 } 655 } else { /* assume cfm_count is 2; (if 0, sp is not active) */ 656 FOREACH_OTHER_MODID(slot_id, slot, mod) { 657 if (cfm_slot % 2 == mod % 2) { 658 CHECK_PACK(pkt_data, len, cnt, mod); 659 } 660 } 661 } 662 663 return cnt; 664 } 665 666 /* Pack mod IDs for a CFM on an external LM stack port; sp_idx is active */ 667 STATIC int 668 tp_chassis_cfm_pack_mods( 669 int cfm_count, /* How many CFMs active in the system; > 0 */ 670 /* The rest follow tp_pack_mods semantics */ 671 cpudb_ref_t db_ref, cpudb_entry_t *entry, 672 uint8 *pkt_data, int len, int sp_idx, int tx) 673 { 674 int slot_id; /* local slot ID */ 675 int cnt = 0; /* byte count */ 676 int lm_slot; /* To which LM slot does sp_idx connect? */ 677 int mod; 678 679 slot_id = entry->base.slot_id; 680 if ((lm_slot = cpudb_sp_idx_to_slot(db_ref, entry, sp_idx, NULL)) < 0) { 681 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 682 (BSL_META("TOPO: CFM %d no cxn on %d\n"), 683 slot_id, sp_idx)); 684 return 0; 685 } 686 687 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 688 (BSL_META("Packing CFM slot %d sp idx %d to slot %d, %s; %d cfms\n"), 689 slot_id, sp_idx, lm_slot, tx ? "tx" : "rx", cfm_count)); 690 691 if (!tx) { /* If one CFM or "parity" matches, expect mod id */ 692 /* Expect other CFMs mod ID */ 693 CHECK_PACK(pkt_data, len, cnt, CFM_MODID(1-slot_id)); 694 FOREACH_MODID(lm_slot, mod) { 695 if ((cfm_count == 1) || ((slot_id % 2) == (mod % 2))) { 696 CHECK_PACK(pkt_data, len, cnt, mod); 697 } 698 } 699 return cnt; 700 } 701 702 CHECK_PACK(pkt_data, len, cnt, CFM_MODID(1-slot_id)); 703 FOREACH_MODID(lm_slot, mod) { /* Send to all slot's mod ids */ 704 CHECK_PACK(pkt_data, len, cnt, mod); 705 } 706 707 return cnt; 708 } 709 710 STATIC int 711 tp_chassis_pack_mods( 712 cpudb_ref_t db_ref, cpudb_entry_t *entry, 713 uint8 *pkt_data, int len, int sp_idx, int tx) 714 { 715 int cfm_count = 0; 716 cpudb_entry_t *db_ent; 717 718 /* If not resolved or enabled, no activity on the port */ 719 if ((entry->sp_info[sp_idx].flags & CPUDB_SPF_NO_LINK) || 720 (entry->sp_info[sp_idx].flags & CPUDB_SPF_INACTIVE) || 721 (entry->sp_info[sp_idx].flags & CPUDB_SPF_ETHERNET)) { 722 return 0; 723 } 724 725 /* Count CFMs in DB */ 726 CPUDB_FOREACH_ENTRY(db_ref, db_ent) { 727 if (db_ent->base.slot_id < 2) { 728 ++cfm_count; 729 } 730 } 731 732 if (entry->base.slot_id < 2) { /* This is a CFM card */ 733 return tp_chassis_cfm_pack_mods(cfm_count, db_ref, entry, 734 pkt_data, len, sp_idx, tx); 735 } 736 737 return tp_chassis_lm_pack_mods(cfm_count, db_ref, entry, pkt_data, len, 738 sp_idx, tx); 739 } 740 741 #else 742 743 #define tp_chassis_pack_mods(a, b, c, d, e, f) 0 744 745 #endif /* INCLUDE_CHASSIS */ 746 747 748 /**************************************************************** 749 * 750 * Topology packet generation and parsing. 751 */ 752 753 STATIC int 754 tp_pack_mods(cpudb_ref_t db_ref, cpudb_entry_t *entry, 755 uint8 *pkt_data, int len, int sp_idx, int tx) 756 { 757 int i, nmod, mod; 758 int entry_idx, cpu_idx; 759 int cnt; 760 cpudb_entry_t *cpu_entry; 761 762 #if defined(INCLUDE_CHASSIS) 763 if (CHASSIS_SM(db_ref->local_entry->base.flags)) { 764 return tp_chassis_pack_mods(db_ref, entry, pkt_data, 765 len, sp_idx, tx); 766 } 767 #endif 768 769 entry_idx = entry->topo_idx; 770 cnt = 0; 771 CPUDB_FOREACH_ENTRY(db_ref, cpu_entry) { 772 cpu_idx = cpu_entry->topo_idx; 773 if (cpu_idx == entry_idx) { 774 continue; 775 } 776 777 if (tx) { 778 if (TP_TX_CXN(db_ref, entry_idx, cpu_idx) != sp_idx) { 779 continue; 780 } 781 } else { 782 if (TP_RX_CXN(db_ref, entry_idx, cpu_idx) != sp_idx) { 783 continue; 784 } 785 } 786 787 for (i = 0; i < cpu_entry->base.num_units; i++) { 788 mod = cpu_entry->mod_ids[i]; 789 for (nmod = 0; nmod < cpu_entry->base.mod_ids_req[i]; nmod++) { 790 CHECK_PACK(pkt_data, len, cnt, (mod + nmod)); 791 } 792 } 793 } 794 795 return cnt; 796 } 797 798 /* 799 * Function: 800 * topo_pkt_gen 801 * Purpose: 802 * Generate a topology packet for the given CPU entry 803 * Parameters: 804 * db_ref - DB to use 805 * entry - Packet is destined for this entry's CPU 806 * pkt_data - Packet buffer to use 807 * len - Bytes available in the buffer 808 * packed_bytes - (OUT) bytes put in buffer 809 * Returns: 810 * BCM_E_XXX 811 * Notes: 812 * The base mod ID must be set for all entries before this is called. 813 * Assumes pkt_data points to the start of the topology payload 814 * (topo version) following the CPUTRANS header. 815 */ 816 817 int 818 topo_pkt_gen(cpudb_ref_t db_ref, cpudb_entry_t *entry, 819 uint8 *pkt_data, int len, int *packed_bytes) 820 { 821 int sp_ofs; /* Start of stack port entry */ 822 int rx_count_ofs; /* Where count of rx mods goes */ 823 int cnt, sp_idx; 824 cpudb_entry_t *db_ent; 825 int i; 826 uint8 *cur_ptr; 827 int tot_bytes; 828 829 if (TOPO_HEADER_BYTES(entry->base.num_units) > len) { 830 return BCM_E_RESOURCE; 831 } 832 833 cur_ptr = &pkt_data[TOPO_VER_OFS]; 834 PACK_LONG(cur_ptr, TOPO_PKT_VERSION); 835 cur_ptr += sizeof(uint32); 836 PACK_LONG(cur_ptr, 0); /* Reserved: TOPO_RSVD_OFS */ 837 cur_ptr += sizeof(uint32); 838 PACK_LONG(cur_ptr, db_ref->master_entry->base.dseq_num); 839 cur_ptr += sizeof(uint32); 840 cur_ptr += sizeof(uint32); /* BASE_LEN_OFS: Base length is set later */ 841 PACK_LONG(cur_ptr, 0); /* FLAGS TOPO_FLAGS_OFS */ 842 cur_ptr += sizeof(uint32); 843 844 /* Pack up module IDs per unit for this entry */ 845 for (i = 0; i < entry->base.num_units; i++) { 846 PACK_LONG(cur_ptr, entry->mod_ids[i]); 847 cur_ptr += sizeof(uint32); 848 } 849 850 tot_bytes = TOPO_HEADER_BYTES(entry->base.num_units); 851 sp_ofs = TOPO_MOD_IDS_OFS + sizeof(uint32) * entry->base.num_units; 852 /* Pack up stack info for this entry */ 853 for (sp_idx = 0; sp_idx < entry->base.num_stk_ports; sp_idx++) { 854 pkt_data[sp_ofs] = 0; /* FLAGS */ 855 if (entry->sp_info[sp_idx].flags & CPUDB_SPF_CUT_PORT) { 856 pkt_data[sp_ofs] |= TOPO_CUT_PORT; 857 } 858 859 cnt = tp_pack_mods(db_ref, entry, &pkt_data[sp_ofs + 2], 860 len - (sp_ofs + 2), sp_idx, TRUE); 861 if (cnt < 0) { 862 return BCM_E_RESOURCE; 863 } 864 pkt_data[sp_ofs + 1] = cnt; 865 tot_bytes += cnt + 2; /* FLAGS + num tx mods */ 866 867 rx_count_ofs = sp_ofs + cnt + 2; 868 cnt = tp_pack_mods(db_ref, entry, &pkt_data[rx_count_ofs + 1], 869 len - (rx_count_ofs + 1), sp_idx, FALSE); 870 if (cnt < 0) { 871 return BCM_E_RESOURCE; 872 } 873 pkt_data[rx_count_ofs] = cnt; 874 tot_bytes += cnt + 1; /* num rx mods */ 875 876 sp_ofs = rx_count_ofs + 1 + cnt; 877 } 878 879 /* After the stack ports, add the dest mod ids, dest port per CPU */ 880 pkt_data[tot_bytes++] = db_ref->num_cpus; 881 if (tot_bytes + (db_ref->num_cpus * (CPUDB_KEY_BYTES + 2)) > len) { 882 return -1; 883 } 884 CPUDB_FOREACH_ENTRY(db_ref, db_ent) { 885 CPUDB_KEY_PACK(&pkt_data[tot_bytes], db_ent->base.key); 886 tot_bytes += CPUDB_KEY_BYTES; 887 pkt_data[tot_bytes++] = db_ent->mod_ids[db_ent->base.dest_unit]; 888 /* Dest port may change with mod id remapping */ 889 pkt_data[tot_bytes++] = db_ent->base.dest_port; 890 } 891 892 if (tot_bytes + 4 > len) { 893 return -1; 894 } 895 896 /* Clear app cookie; add to cur_ofs */ 897 pkt_data[tot_bytes++] = 0; 898 pkt_data[tot_bytes++] = 0; 899 pkt_data[tot_bytes++] = 0; 900 pkt_data[tot_bytes++] = 0; 901 902 /* Pack the length of the packet, from mod IDs thru ap cookie */ 903 PACK_LONG(&pkt_data[TOPO_BASE_LEN_OFS], tot_bytes - TOPO_FLAGS_OFS); 904 905 if (packed_bytes != NULL) { 906 *packed_bytes = tot_bytes; 907 } 908 909 return BCM_E_NONE; 910 } 911 912 913 /* 914 * Function: 915 * topo_pkt_parse 916 * Purpose: 917 * Parse a topology packet; checks data against DB ref 918 * Parameters: 919 * db_ref - DB to use 920 * entry - (IN/OUT) The local entry (see notes) 921 * topo_data - Packet buffer to use 922 * len - Length of buffer 923 * tp_cpu - (OUT) Where to place results 924 * ap_data_ofs - (OUT) offset of application data relative 925 * to topo_data 926 * Returns: 927 * BCM_E_FAIL if any mismatch is detected or buffer is too short. 928 * Notes: 929 * Checks against local entry. Length of buffer is only used 930 * for checking if there's not enough data in the packet. 931 * 932 * Note that the local MOD IDs are recorded (taken from the packet) 933 * into entry->mod_ids (as well as into tp_cpu->mod_ids). 934 */ 935 936 int 937 topo_pkt_parse( 938 cpudb_ref_t db_ref, 939 cpudb_entry_t *entry, 940 uint8 *topo_data, 941 int len, 942 topo_cpu_t *tp_cpu, 943 int *ap_data_ofs) 944 { 945 int cur_ofs; /* Index into topo_data */ 946 cpudb_base_t *l_base; /* Local base info */ 947 int sp_idx; /* Index of stack port */ 948 topo_stk_port_t *tp_sp; /* Topology stk port info */ 949 int i; 950 cpudb_entry_t *db_ent; 951 int cpu_count; 952 cpudb_key_t db_key; 953 int cpu_idx; 954 uint8 *cur_ptr; 955 int num_modids; 956 957 if (entry == NULL || 958 db_ref == CPUDB_REF_NULL || 959 topo_data == NULL || 960 tp_cpu == NULL) { 961 return BCM_E_PARAM; 962 } 963 964 l_base = &entry->base; 965 966 if (len < TOPO_HEADER_BYTES(db_ref->num_cpus) + 5) { 967 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 968 (BSL_META("TOPO PARSE ERROR: Packet too short (%d<%d)[#%d]\n"), 969 len, 970 (int)TOPO_HEADER_BYTES(db_ref->num_cpus) + 5, 971 db_ref->num_cpus)); 972 return BCM_E_FAIL; 973 } 974 cur_ptr = &topo_data[TOPO_VER_OFS]; 975 UNPACK_LONG(cur_ptr, tp_cpu->version); /* TOPO_VER_OFS */ 976 cur_ptr += sizeof(uint32); 977 cur_ptr += sizeof(uint32); /* Reserved: TOPO_RSVD_OFS */ 978 UNPACK_LONG(cur_ptr, tp_cpu->master_seq_num); /* TOPO_MSEQ_NUM_OFS */ 979 cur_ptr += sizeof(uint32); 980 /* skip TOPO_BASE_LEN_OFS */ 981 cur_ptr += sizeof(uint32); 982 UNPACK_LONG(cur_ptr, tp_cpu->flags); /* TOPO_FLAGS_OFS */ 983 cur_ptr += sizeof(uint32); 984 985 /* Pull the local device module IDs off of the packet */ 986 for (i = 0; i < entry->base.num_units; i++) { 987 UNPACK_LONG(cur_ptr, entry->mod_ids[i]); 988 cur_ptr += sizeof(uint32); 989 } 990 991 /* Now parse the mod id lists per local stack port */ 992 cur_ofs = TOPO_MOD_IDS_OFS + sizeof(uint32) * entry->base.num_units; 993 for (sp_idx = 0; sp_idx < l_base->num_stk_ports; sp_idx++) { 994 tp_sp = &tp_cpu->tp_stk_port[sp_idx]; 995 996 tp_sp->flags = topo_data[cur_ofs++]; 997 998 /* Check cut port flag */ 999 if (tp_sp->flags & TOPO_CUT_PORT) { 1000 entry->sp_info[sp_idx].flags |= CPUDB_SPF_CUT_PORT; 1001 } else { 1002 entry->sp_info[sp_idx].flags &= ~CPUDB_SPF_CUT_PORT; 1003 } 1004 1005 /* Get TX modid count and check database limit */ 1006 num_modids = topo_data[cur_ofs++]; 1007 if (num_modids > TOPO_MODIDS_MAX) { 1008 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1009 (BSL_META("TOPO PARSE ERROR: TX mod id count %d exceeds DB limit " 1010 "%d\n"), num_modids, TOPO_MODIDS_MAX)); 1011 return BCM_E_FAIL; 1012 } 1013 tp_sp->tx_mod_num = num_modids; 1014 for (i = 0; i < tp_sp->tx_mod_num; i++) { 1015 tp_sp->tx_mods[i] = topo_data[cur_ofs++]; 1016 LOG_INFO(BSL_LS_TKS_TOPOLOGY, 1017 (BSL_META("ST TOPO: Map TX mod %d to stk idx %d\n"), 1018 tp_sp->tx_mods[i], sp_idx)); 1019 } 1020 1021 /* Get RX modid count and check database limit */ 1022 num_modids = topo_data[cur_ofs++]; 1023 if (num_modids > TOPO_MODIDS_MAX) { 1024 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1025 (BSL_META("TOPO PARSE ERROR: RX mod id count %d exceeds DB limit " 1026 "%d\n"), num_modids, TOPO_MODIDS_MAX)); 1027 return BCM_E_FAIL; 1028 } 1029 tp_sp->rx_mod_num = num_modids; 1030 for (i = 0; i < tp_sp->rx_mod_num; i++) { 1031 tp_sp->rx_mods[i] = topo_data[cur_ofs++]; 1032 LOG_INFO(BSL_LS_TKS_TOPOLOGY, 1033 (BSL_META("ST TOPO: Map RX mod %d to stk idx %d\n"), 1034 tp_sp->rx_mods[i], sp_idx)); 1035 } 1036 1037 if (cur_ofs + 2 > len) { 1038 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1039 (BSL_META("TOPO PARSE ERROR: Packet too short at %d\n"), 1040 cur_ofs)); 1041 return BCM_E_FAIL; 1042 } 1043 } 1044 1045 /* Now that mod ids are unpacked, copy local entry info to tp_cpu */ 1046 cpudb_entry_copy(&tp_cpu->local_entry, entry); 1047 1048 /* The base mod ids per CPU follow stack port info */ 1049 cpu_count = topo_data[cur_ofs++]; 1050 if (cur_ofs + cpu_count * (CPUDB_KEY_BYTES + 1) > len) { 1051 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1052 (BSL_META("TOPO PARSE ERROR: Packet too short at %d\n"), 1053 cur_ofs)); 1054 return BCM_E_FAIL; 1055 } 1056 for (cpu_idx = 0; cpu_idx < cpu_count; cpu_idx++) { 1057 CPUDB_KEY_UNPACK(&topo_data[cur_ofs], db_key); 1058 cur_ofs += CPUDB_KEY_BYTES; 1059 CPUDB_KEY_SEARCH(db_ref, db_key, db_ent); 1060 if (db_ent == NULL) { 1061 LOG_ERROR(BSL_LS_TKS_TOPOLOGY, 1062 (BSL_META("TOPO PARSE ERROR: Could not find DB key " 1063 CPUDB_KEY_FMT_EOLN), 1064 CPUDB_KEY_DISP(db_key))); 1065 return BCM_E_FAIL; 1066 } 1067 db_ent->dest_mod = topo_data[cur_ofs++]; 1068 db_ent->dest_port = topo_data[cur_ofs++]; 1069 db_ent->flags |= CPUDB_F_DEST_KNOWN; 1070 LOG_VERBOSE(BSL_LS_TKS_TOPOLOGY, 1071 (BSL_META("TOPO: Mapped " CPUDB_KEY_FMT " to (%d, %d)\n"), 1072 CPUDB_KEY_DISP(db_key), db_ent->dest_mod, 1073 db_ent->dest_port)); 1074 } 1075 1076 UNPACK_LONG(&topo_data[cur_ofs], tp_cpu->ap_cookie); 1077 cur_ofs += sizeof(uint32); 1078 if (ap_data_ofs != NULL) { 1079 *ap_data_ofs = cur_ofs; 1080 } 1081 1082 return BCM_E_NONE; 1083 }