link.c (207665B)
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 * Link Scan 8 * 9 * Linkscan should always run for all chips in a system. It manages 10 * the current chip LINK state (EPC_LINK or equivalent), and programs 11 * MACs to match auto-negotiated links. 12 * 13 * Linkscan is also responsible for determining the link up/down 14 * status for a port. Since link down events signaled by most PHYs are 15 * latched low and cleared on read, it is important that accesses to 16 * to the PHY itself be managed carefully. Linkscan is intended to be 17 * the only process that reads the actual PHY (using 18 * _bcm_port_link_get). All other calls to retrieve link status 19 * results in calls to _bcm_link_get which returns the linkscan view 20 * of the link status. This ensures linkscan is the only process that 21 * reads the actual PHYs. 22 * 23 * All modifications to the linkscan state are protected by LC_LOCK. 24 * 25 * Linkscan maintains the following port bitmaps 26 * 27 * lc_pbm_link: 28 * Current physical link up/down status. When a bit 29 * in this mask is set, a link up or link down event 30 * is recognized and signaled to any registered 31 * handlers. 32 * 33 * lc_pbm_link_change: 34 * Mask of ports that need to recognize a link 35 * down event. Ports are added to this mask by the 36 * function bcm_link_change. 37 * 38 * lc_pbm_override_ports: 39 * Bit map of ports that are currently 40 * being explicitly set to a value. These actual value 41 * is determined by lb_pbm_override_link. Ports are 42 * added and removed from this mode by the routine 43 * _bcm_link_force. 44 * 45 * Ports that are forced to an UP state do NOT result 46 * in a call to bcm_port_update. It is the 47 * responsibility of the caller to configure the 48 * correct MAC and PHY state. 49 * 50 * lc_pbm_override_link: 51 * Bit map indicating the link-up/link-down 52 * status for those ports with override set. 53 * 54 * lc_pbm_sgmii_autoneg_port: 55 * Port that is configured in SGMII autoneg mode based 56 * on spn_PHY_SGMII_AUTONEG. Maintaining this bitmap 57 * avoids the overhead of the soc_property_port_get call. 58 * 59 * lc_pbm_linkdown_tx: 60 * Ports configured with linkdown TX result in 61 * leaving the MAC enabled when link is down. This allows 62 * packets to egress without link being established. 63 * 64 * Calls to _bcm_link_get always returns the current status as 65 * indicated by lc_pbm_link. 66 * 67 * For 10G+ ports, the an additional bitmap is used: 68 * 69 * lc_pbm_remote_fault: 70 * Bit map indicating the fault (local or remote) status of 71 * a link-up port. 72 * 73 * To track valid fault status, the physical link must be up and 74 * the port configured so that symbols reach the MAC. Thus, physical 75 * port configuration is tracked by the lc_pbm_link state. However, 76 * if the port is receiving a fault indication, we do not want 77 * to allow packet traffic. Thus, the logical port is not yet up. 78 * The logical port up is what we want to return to _bcm_link_get, 79 * so we fold these two states together. Tracking the fault 80 * state requires a bit more work in the _bcm_esw_linkscan_update_port 81 * logic. 82 * 83 * If LAG failover capability is configured through the trunk module, 84 * then three more bitmaps are used: 85 * 86 * lc_pbm_failover: 87 * Bit map of ports configured for LAG failover. 88 * 89 * lc_pbm_failed: 90 * Bit map of ports configured for LAG failover which 91 * have experienced a link down or fault and 92 * are now in BCM_PORT_LINK_STATUS_FAILED state. These 93 * ports require application intervention to leave 94 * the FAILED state. 95 * 96 * lc_pbm_failed_clear: 97 * Bit map of ports which were previously in FAILED state 98 * but have been cleared by application intervention and 99 * are now in DOWN state (due to link down or fault). 100 * A port remains in this set until the next link up 101 * without fault, at which point the hardware 102 * sequence to remove the failover state may complete. 103 * 104 * Accelerated linkscan: 105 * 106 * The accelerated linkscan mode allows the linkscan thread to 107 * run at a faster interval of time where a set of ports (lc_pbm_accel) 108 * are scanned in the faster rate. 109 * A port is placed under the accelerated mode under the following conditions: 110 * - Linkscan mode is HW 111 * - Fast RX LOS is enabled. This can be enabled with the 112 * SOC property 'fast_sw_rx_los_pbmp' or the port control 113 * bcmPortControlRxFastLOS. 114 * - State is down and hw link indicates an UP state 115 116 * For the Accelerated linkscan mode, the following bitmaps are used: 117 * lc_pbm_fast: 118 * Bit map of ports with Fast RX LOS property enabled. 119 * When enabled, a port may be placed under the accelerated 120 * linkscan mode during a link state transition from 121 * down to up. Note that the port linkscan mode 122 * needs to be HW. 123 * lc_pbm_accel: 124 * Bit map of ports currently under accelerated linkscan 125 * mode. 126 */ 127 128 #include <shared/bsl.h> 129 130 #include <shared/alloc.h> 131 #include <sal/core/spl.h> 132 #include <soc/debug.h> 133 #include <soc/drv.h> 134 #include <soc/scache.h> 135 #include <soc/phyctrl.h> 136 137 #include <bcm/error.h> 138 #include <bcm/link.h> 139 140 /* #include <bcm_int/common/link.h> */ 141 #include <bcm_int/esw/link.h> 142 #include <bcm_int/esw/port.h> 143 #include <bcm_int/esw/trunk.h> 144 #include <bcm_int/common/lock.h> 145 146 #include <bcm_int/api_xlate_port.h> 147 #include <bcm_int/esw_dispatch.h> 148 149 #if defined(BCM_KATANA2_SUPPORT) 150 #include <bcm_int/esw/katana2.h> 151 #include <soc/katana2.h> 152 #endif /* BCM_KATANA2_SUPPORT */ 153 154 #if defined(BCM_SABER2_SUPPORT) 155 #include <bcm_int/esw/saber2.h> 156 #include <soc/saber2.h> 157 #endif /* BCM_SABER2_SUPPORT */ 158 159 #ifdef BCM_TRIUMPH3_SUPPORT 160 #include <bcm_int/esw/triumph3.h> 161 #endif /* BCM_TRIUMPH3_SUPORT */ 162 163 #if defined(BCM_KATANA2_SUPPORT) 164 #include <bcm_int/esw/katana2.h> 165 #include <soc/katana2.h> 166 #endif /* BCM_KATANA2_SUPPORT */ 167 168 #if defined(BCM_PREEMPTION_SUPPORT) 169 #include <bcm_int/esw/preemption.h> 170 #endif /* BCM_PREEMPTION_SUPPORT */ 171 172 #ifdef BCM_WARM_BOOT_SUPPORT 173 #include <bcm_int/esw/switch.h> 174 #endif /* BCM_WARM_BOOT_SUPPORT */ 175 #include <bcm_int/esw/portctrl.h> 176 177 #if defined(INCLUDE_UC_ULINK) 178 #include <soc/uc_msg.h> 179 #endif 180 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 181 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 182 #include <soc/phy/phyctrl.h> 183 #endif 184 185 #ifdef PORTMOD_SUPPORT 186 #include <soc/portmod/portmod.h> 187 #endif 188 189 typedef struct ls_handler_s { 190 struct ls_handler_s *lh_next; 191 bcm_linkscan_handler_t lh_f; 192 } ls_handler_t; 193 194 typedef struct ls_errstate_s { 195 int limit; /* # errors to enter error state */ 196 int delay; /* Length of error state in seconds */ 197 int count; /* # of errors so far */ 198 int wait; /* Boolean, TRUE when in error state */ 199 sal_usecs_t time; /* Time error state was entered */ 200 } ls_errstate_t; 201 202 typedef struct ls_cntl_s { 203 char lc_taskname[16]; 204 sal_mutex_t lc_lock; /* Synchronization */ 205 pbmp_t lc_pbm_hw; /* Hardware link scan ports */ 206 pbmp_t lc_pbm_sw; /* Software link scan ports */ 207 pbmp_t lc_pbm_sgmii_autoneg_port; /* Ports with 208 SGMII autoneg */ 209 pbmp_t lc_pbm_info_skip; /* Ports to skip info during 210 linkdown */ 211 pbmp_t lc_pbm_fast; /* Ports eligible for accel mode */ 212 pbmp_t lc_pbm_accel; /* Active fast link scan ports */ 213 int lc_hw_change; /* HW Link state has changed */ 214 int lc_warm_boot; /* A Warm Boot occured */ 215 ls_handler_t *lc_handler; /* List of handlers */ 216 VOL int lc_us; /* Time between scans (us) */ 217 VOL sal_thread_t lc_thread; /* Link scan thread */ 218 sal_sem_t lc_sema; /* Link scan semaphore */ 219 ls_errstate_t lc_error[SOC_MAX_NUM_PORTS]; /* Link error state */ 220 bcm_linkscan_port_handler_t lc_f[SOC_MAX_NUM_PORTS]; /* Handler for 221 link fn */ 222 int lc_accel_us; /* Accel mode time scan interval */ 223 int lc_accel_poll_max; /* Max polls for accel mode */ 224 int lc_accel_poll_count; /* Accel poll count */ 225 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 226 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 227 sal_time_t lc_up_time[SOC_MAX_NUM_PORTS]; /* Link up time*/ 228 #endif /* BCM_HURRICANE_SUPPORT || BCM_HAWKEYE_SUPORT || BCM_TRIDENT_SUPPORT */ 229 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 230 uint32 lc_up_proc_state[SOC_MAX_NUM_PORTS]; /* Link up procedure 231 status */ 232 #endif 233 #if defined(BCM_HAWKEYE_SUPPORT) 234 uint32 lc_ibppktsetlimit[SOC_MAX_NUM_PORTS]; /* Link up time */ 235 uint32 lc_ibpcelsetlimit[SOC_MAX_NUM_PORTS]; /* Link up time */ 236 #endif /* BCM_HAWKEYE_SUPORT */ 237 } ls_cntl_t; 238 239 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 240 #define LC_LINK_UP_STATE_NONE (0) 241 #define LC_LINK_UP_STATE_START (1) 242 #define LC_LINK_UP_STATE_DONE (2) 243 #endif 244 245 /* 246 * Define: 247 * LC_LOCK/LC_UNLOCK 248 * Purpose: 249 * Serialization Macros for access to lc_cntl structure. 250 */ 251 252 #define LC_LOCK(unit) \ 253 if(SOC_IS_TRIUMPH3(unit) || SOC_IS_SABER2(unit) || \ 254 SOC_IS_TRIDENT(unit) || SOC_IS_TD2_TT2(unit) || \ 255 SOC_IS_KATANA2(unit) || SOC_IS_HURRICANEX(unit) || \ 256 SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit)) { \ 257 /* To avoid deadlock between port and linkscan mutexes */ \ 258 BCM_LOCK(unit); \ 259 } \ 260 sal_mutex_take(link_control[unit]->lc_lock, sal_mutex_FOREVER); 261 262 #define LC_UNLOCK(unit) \ 263 sal_mutex_give(link_control[unit]->lc_lock); \ 264 if(SOC_IS_TRIUMPH3(unit) || SOC_IS_SABER2(unit) || \ 265 SOC_IS_TRIDENT(unit) || SOC_IS_TD2_TT2(unit) || \ 266 SOC_IS_KATANA2(unit) || SOC_IS_HURRICANEX(unit) || \ 267 SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit)) { \ 268 BCM_UNLOCK(unit); \ 269 } 270 271 #define LC_CHECK_INIT(unit) \ 272 if (link_control[unit] == NULL) { \ 273 return(BCM_E_INIT); \ 274 } 275 276 /* Define this if you want to know the time take to prcess link up/down event. 277 * This is *not* the time between actual HW link up/down and software link 278 * up/down event. 279 */ 280 #define BCM_LINK_CHANGE_BENCHMARK 281 282 /* Return On error with link mutex unlocked */ 283 #define _BCM_LINK_IF_ERROR_RETURN(op) \ 284 do { \ 285 int __rv__; \ 286 if (((__rv__ = (op)) < 0)) { \ 287 LC_UNLOCK(unit); \ 288 return(__rv__); \ 289 } \ 290 } while(0) 291 292 293 /* 294 * Variable: 295 * link_control 296 * Purpose: 297 * Hold per-unit global status for linkscan 298 */ 299 300 STATIC ls_cntl_t *link_control[BCM_MAX_NUM_UNITS]; 301 302 #if defined(BCM_HAWKEYE_SUPPORT) 303 #define PHY_AN_TX_PAUSE_CAP (0x01) 304 #define PHY_AN_RX_PAUSE_CAP (0x02) 305 #define HK_PAUSE_WAR_PHY_REG (0x19) 306 #endif /* BCM_HAWKEYE_SUPPORT */ 307 308 /* 309 * Accelerated Linkscan Defaults 310 * - Time interval during fast/accelerated mode. 311 * - Max number of accelerated interval polls before clearing 312 * the accelerated bitmap. 313 */ 314 #define ACCELERATED_INTERVAL_USEC 100000 /* 100 msecs */ 315 #define ACCELERATED_POLL_COUNT_MAX 10 316 317 static sal_usecs_t last_time_hw_link_up[BCM_MAX_NUM_UNITS]; /* Debug */ 318 #ifdef BCM_TRIUMPH3_SUPPORT 319 extern int _bcm_esw_ibod_syn_port_down(int unit, int port); 320 #endif 321 322 #if defined(INCLUDE_UC_ULINK) 323 uint8 soc_cmic_uc_link_change_flag; 324 #endif 325 326 /* 327 * Function: 328 * _bcm_esw_link_port_info_skip_set 329 * Purpose: 330 * Adds/Removes given port to skip_info pbmp to indicate if 331 * skip port_info_get 332 * during link down event notification or not 333 * Parameters: 334 * unit - StrataSwitch unit #. 335 * gport - Port to set/remove 336 * skip - Identificator to set or remove 337 * Returns: 338 * BCM_E_XXX 339 */ 340 int 341 _bcm_esw_link_port_info_skip_set(int unit, bcm_port_t port, int skip) 342 { 343 ls_cntl_t *lc = link_control[unit]; 344 bcm_port_t local_port; 345 346 if (BCM_GPORT_IS_SET(port)) { 347 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 348 } else { 349 local_port = port; 350 } 351 if (!SOC_PORT_VALID(unit, local_port) || !IS_PORT(unit, local_port)) { 352 return BCM_E_PORT; 353 } 354 355 LC_LOCK(unit); 356 357 if (skip) { 358 BCM_PBMP_PORT_ADD(lc->lc_pbm_info_skip, local_port); 359 } else { 360 BCM_PBMP_PORT_REMOVE(lc->lc_pbm_info_skip, local_port); 361 } 362 LC_UNLOCK(unit); 363 364 return BCM_E_NONE; 365 } 366 367 368 /* 369 * Function: 370 * _bcm_esw_link_port_info_skip_get 371 * Purpose: 372 * Get status of given port to indicate if to skip port_info_get 373 * during link down event notification or not 374 * Parameters: 375 * unit - StrataSwitch unit #. 376 * gport - Port to set/remove 377 * skip - [OUT] Identificator if set or not 378 * Returns: 379 * BCM_E_XXX 380 */ 381 int 382 _bcm_esw_link_port_info_skip_get(int unit, bcm_port_t port, int *skip) 383 { 384 ls_cntl_t *lc = link_control[unit]; 385 bcm_port_t local_port; 386 387 if (BCM_GPORT_IS_SET(port)) { 388 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &local_port)); 389 } else { 390 local_port = port; 391 } 392 if (!SOC_PORT_VALID(unit, local_port) || !IS_PORT(unit, local_port)) { 393 return BCM_E_PORT; 394 } 395 if (!skip) { 396 return BCM_E_PARAM; 397 } 398 399 *skip = (BCM_PBMP_MEMBER(lc->lc_pbm_info_skip, local_port)) ? 1 : 0; 400 401 return BCM_E_NONE; 402 } 403 404 /* 405 * Function: 406 * _lc_pbm_init 407 * Purpose: 408 * Initialize the port bitmaps in the link_control structure 409 * Parameters: 410 * unit - StrataSwitch unit #. 411 */ 412 static void 413 _lc_pbm_init(int unit) 414 { 415 soc_persist_t *sop = SOC_PERSIST(unit); 416 417 /* 418 * Force initial scan by setting link change while pretending link 419 * was initially up. 420 */ 421 BCM_PBMP_ASSIGN(sop->lc_pbm_link, PBMP_ALL(unit)); 422 #ifdef BCM_KATANA2_SUPPORT 423 if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) { 424 (void)_bcm_kt2_flexio_pbmp_update(unit, &sop->lc_pbm_link); 425 } 426 #endif 427 428 /* If we set sop->lc_pbm_link_change as PBMP_PORT_ALL(unit), 429 * MAC of all ports will be reset, and traffic will be disrupted. 430 */ 431 /* BCM_PBMP_ASSIGN(sop->lc_pbm_link_change, PBMP_PORT_ALL(unit)); */ 432 BCM_PBMP_CLEAR(sop->lc_pbm_override_ports); 433 BCM_PBMP_CLEAR(sop->lc_pbm_override_link); 434 BCM_PBMP_CLEAR(sop->lc_pbm_remote_fault); 435 BCM_PBMP_CLEAR(sop->lc_pbm_failover); 436 BCM_PBMP_CLEAR(sop->lc_pbm_failed); 437 BCM_PBMP_CLEAR(sop->lc_pbm_failed_clear); 438 BCM_PBMP_CLEAR(sop->lc_pbm_linkdown_tx); 439 BCM_PBMP_CLEAR(sop->lc_pbm_fc); 440 BCM_PBMP_CLEAR(sop->lc_pbm_eth_buffer_mode); 441 442 #ifdef BCM_RCPU_SUPPORT 443 if (SOC_IS_RCPU_ONLY(unit) && SOC_PORT_VALID(unit, RCPU_PORT(unit))) { 444 /* Do not update link status for rcpu port. */ 445 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_ports, RCPU_PORT(unit)); 446 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_link, RCPU_PORT(unit)); 447 } 448 #endif /* BCM_RCPU_SUPPORT */ 449 450 } 451 452 #ifdef BCM_WARM_BOOT_SUPPORT 453 454 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 455 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 456 #define BCM_WB_VERSION_1_2 SOC_SCACHE_VERSION(1,2) 457 #define BCM_WB_VERSION_1_3 SOC_SCACHE_VERSION(1,3) 458 #define BCM_WB_VERSION_1_4 SOC_SCACHE_VERSION(1,4) 459 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_4 460 461 /* 462 * Number of pbmp's to save: 463 * From ls_ctrl_t above - 3: 464 * lc_pbm_hw 465 * lc_pbm_sw 466 * lc_pbm_info_skip 467 * 468 * From soc_persist_t - 8: 469 * link_fwd 470 * lc_pbm_override_ports 471 * lc_pbm_override_link 472 * lc_pbm_linkdown_tx 473 * lc_pbm_remote_fault 474 * lc_pbm_failover 475 * lc_pbm_failed 476 * lc_pbm_failed_clear 477 * 478 * Constructed in sync - 1: 479 * disabled_pbmp - bitmap of disabled PHYs (internal state) 480 * 481 * If any are added, that must be updated here. 482 * 483 * Note that lc_pbm_link and lc_pbm_link_change are not included, since 484 * they should be derived from the current HW state, not that existing 485 * at the save point. 486 */ 487 488 #define BCM_LINK_PBMP_SCACHE_NUM_WB_1_0 12 489 #define BCM_LINK_PBMP_SCACHE_NUM_WB_1_1 13 490 #define BCM_LINK_PBMP_SCACHE_NUM_WB_1_2 14 491 #define BCM_LINK_PBMP_SCACHE_NUM_WB_1_3 15 492 493 #define BCM_LINK_PBMP_SCACHE_NUM BCM_LINK_PBMP_SCACHE_NUM_WB_1_3 494 495 496 #define _LINK_PBMP_BYTE_MAX (SOC_PBMP_WORD_MAX * sizeof(uint32)) 497 498 #define _BCM_LINK_PBMP_SCACHE_COPY(_pbmp_) \ 499 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { \ 500 fldbuf[i] = SOC_PBMP_WORD_GET(_pbmp_, i); \ 501 } \ 502 sal_memcpy(link_scache_ptr, fldbuf, _LINK_PBMP_BYTE_MAX); \ 503 link_scache_ptr += _LINK_PBMP_BYTE_MAX; 504 505 #define _BCM_LINK_PBMP_SCACHE_RECOVER(_pbmp_) \ 506 sal_memset(fldbuf, 0, _LINK_PBMP_BYTE_MAX); \ 507 sal_memcpy(fldbuf, link_scache_ptr, _LINK_PBMP_BYTE_MAX); \ 508 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { \ 509 SOC_PBMP_WORD_SET(_pbmp_, i, fldbuf[i]); \ 510 } \ 511 link_scache_ptr += _LINK_PBMP_BYTE_MAX; 512 513 /* 514 * Function: 515 * _bcm_esw_link_sync 516 * Purpose: 517 * Record Link module persisitent info for Level 2 Warm Boot 518 * 519 * Warm Boot Version Map: 520 * Fields for previous version to be documented 521 * BCM_WB_VERSION_1_0 522 * ... 523 * BCM_WB_VERSION_1_1 524 * ... 525 * BCM_WB_VERSION_1_2 526 * lc_pbm_fast Port bitmap for fast linkscan property (accel mode) 527 * 528 * Parameters: 529 * unit - StrataSwitch unit number. 530 * Returns: 531 * BCM_E_XXX 532 */ 533 int 534 _bcm_esw_link_sync(int unit) 535 { 536 int alloc_size; 537 soc_scache_handle_t scache_handle; 538 uint8 *link_scache, *link_scache_ptr; 539 ls_cntl_t *lc = link_control[unit]; 540 soc_persist_t *sop = SOC_PERSIST(unit); 541 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 542 int i, enable; 543 bcm_port_t port; 544 bcm_pbmp_t pbmp, disabled_pbmp; 545 int lc_us; 546 547 SOC_SCACHE_HANDLE_SET(scache_handle, 548 unit, BCM_MODULE_LINKSCAN, 0); 549 550 alloc_size = BCM_LINK_PBMP_SCACHE_NUM * _LINK_PBMP_BYTE_MAX; 551 552 #if defined(BCM_HAWKEYE_SUPPORT) 553 if (SOC_IS_HAWKEYE(unit) && soc_feature(unit, soc_feature_eee)) { 554 /* For lc_ibppktsetlimit and lc_ibpcelsetlimit */ 555 alloc_size += (SOC_MAX_NUM_PORTS * 2 * sizeof(uint32)); 556 } 557 #endif /* BCM_HAWKEYE_SUPPORT */ 558 559 /* For lc_us */ 560 alloc_size += sizeof(int); 561 562 BCM_IF_ERROR_RETURN 563 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 564 alloc_size, 565 &link_scache, BCM_WB_DEFAULT_VERSION, NULL)); 566 567 link_scache_ptr = link_scache; 568 569 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 570 SOC_PBMP_CLEAR(disabled_pbmp); 571 572 #if defined(BCM_SABER2_SUPPORT) 573 if(SOC_IS_SABER2(unit)){ 574 int oamp_enable; 575 (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable); 576 /* Skip OAMP port for saber2 device */ 577 if(oamp_enable) { 578 SOC_PBMP_PORT_REMOVE(pbmp, 579 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 580 } 581 } 582 #endif 583 584 PBMP_ITER(pbmp, port) { 585 BCM_IF_ERROR_RETURN 586 (bcm_esw_port_enable_get(unit, port, &enable)); 587 if (!enable) { 588 SOC_PBMP_PORT_ADD(disabled_pbmp, port); 589 } 590 } 591 592 /* Copy out the required persistent PBMP's */ 593 _BCM_LINK_PBMP_SCACHE_COPY(lc->lc_pbm_hw); 594 _BCM_LINK_PBMP_SCACHE_COPY(lc->lc_pbm_sw); 595 _BCM_LINK_PBMP_SCACHE_COPY(lc->lc_pbm_info_skip); 596 597 _BCM_LINK_PBMP_SCACHE_COPY(sop->link_fwd); 598 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_override_ports); 599 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_override_link); 600 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_linkdown_tx); 601 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_remote_fault); 602 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_failover); 603 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_failed); 604 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_failed_clear); 605 _BCM_LINK_PBMP_SCACHE_COPY(disabled_pbmp); 606 607 /* Introduced fc bitmap sync/recovery with WB ver 1.1 */ 608 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_fc); 609 610 #if defined(BCM_HAWKEYE_SUPPORT) 611 if (SOC_IS_HAWKEYE(unit) && soc_feature(unit, soc_feature_eee)) { 612 for (i = 0 ; i < SOC_MAX_NUM_PORTS ; i++) { 613 sal_memcpy(link_scache_ptr, 614 &(lc->lc_ibppktsetlimit[i]), sizeof(uint32)); 615 link_scache_ptr += sizeof(uint32); 616 sal_memcpy(link_scache_ptr, 617 &(lc->lc_ibpcelsetlimit[i]), sizeof(uint32)); 618 link_scache_ptr += sizeof(uint32); 619 } 620 } 621 #endif /* BCM_HAWKEYE_SUPPORT */ 622 623 /* Introduced accel mode bitmap sync/recovery with WB ver 1.2 */ 624 _BCM_LINK_PBMP_SCACHE_COPY(lc->lc_pbm_fast); 625 626 lc_us = lc->lc_us; 627 sal_memcpy(link_scache_ptr, &(lc_us), sizeof(int)); 628 link_scache_ptr += sizeof(int); 629 630 /* Introduced ethernet buffer mode port bitmap sync/recovery with WB ver 1.4 */ 631 _BCM_LINK_PBMP_SCACHE_COPY(sop->lc_pbm_eth_buffer_mode); 632 633 return BCM_E_NONE; 634 } 635 636 STATIC int 637 _bcm_esw_link_reload(int unit) 638 { 639 soc_port_t port; 640 int loopback; 641 int alloc_size; 642 int realloc_size = 0; 643 uint16 recovered_ver; 644 soc_scache_handle_t scache_handle; 645 uint8 *link_scache, *link_scache_ptr; 646 ls_cntl_t *lc = link_control[unit]; 647 soc_persist_t *sop = SOC_PERSIST(unit); 648 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 649 int i, rv, link=0; 650 bcm_pbmp_t pbmp_port, disabled_pbmp; 651 int lc_us; 652 653 /* Only toggle if we need to */ 654 SOC_PBMP_CLEAR(sop->lc_pbm_link_change); 655 656 SOC_SCACHE_HANDLE_SET(scache_handle, 657 unit, BCM_MODULE_LINKSCAN, 0); 658 659 alloc_size = BCM_LINK_PBMP_SCACHE_NUM * _LINK_PBMP_BYTE_MAX; 660 661 #if defined(BCM_HAWKEYE_SUPPORT) 662 if (SOC_IS_HAWKEYE(unit) && soc_feature(unit, soc_feature_eee)) { 663 /* For lc_ibppktsetlimit and lc_ibpcelsetlimit */ 664 alloc_size += (SOC_MAX_NUM_PORTS * 2 * sizeof(uint32)); 665 } 666 #endif /* BCM_HAWKEYE_SUPPORT */ 667 668 SOC_PBMP_ASSIGN(pbmp_port, PBMP_PORT_ALL(unit)); 669 #if defined(BCM_SABER2_SUPPORT) 670 if(SOC_IS_SABER2(unit)){ 671 int oamp_enable; 672 (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable); 673 /* Skip OAMP port for saber2 device */ 674 if(oamp_enable) { 675 SOC_PBMP_PORT_REMOVE(pbmp_port, 676 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 677 } 678 } 679 #endif 680 681 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 682 alloc_size, &link_scache, 683 BCM_WB_DEFAULT_VERSION, &recovered_ver); 684 if (BCM_SUCCESS(rv)) { 685 link_scache_ptr = link_scache; 686 687 /* Recover out the required persistent PBMP's */ 688 _BCM_LINK_PBMP_SCACHE_RECOVER(lc->lc_pbm_hw); 689 _BCM_LINK_PBMP_SCACHE_RECOVER(lc->lc_pbm_sw); 690 _BCM_LINK_PBMP_SCACHE_RECOVER(lc->lc_pbm_info_skip); 691 692 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->link_fwd); 693 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_override_ports); 694 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_override_link); 695 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_linkdown_tx); 696 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_remote_fault); 697 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_failover); 698 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_failed); 699 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_failed_clear); 700 _BCM_LINK_PBMP_SCACHE_RECOVER(disabled_pbmp); 701 702 /* mask2 needs to be restored before using it in */ 703 BCM_PBMP_ASSIGN(SOC_CONTROL(unit)->link_mask2, sop->link_fwd); 704 705 /* Introduced fc bitmap sync/recovery with WB ver 1.1 */ 706 if (recovered_ver >= BCM_WB_VERSION_1_1) { 707 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_fc); 708 } else { 709 /* 710 * Allocate extra scache space to recover fc bitmap for 711 * syncing this info to scache in subsequent warm reloads 712 */ 713 realloc_size += ((BCM_LINK_PBMP_SCACHE_NUM_WB_1_1 - 714 BCM_LINK_PBMP_SCACHE_NUM_WB_1_0) * 715 _LINK_PBMP_BYTE_MAX); 716 } 717 #if defined(BCM_HAWKEYE_SUPPORT) 718 if (SOC_IS_HAWKEYE(unit) && soc_feature(unit, soc_feature_eee)) { 719 for (i = 0 ; i < SOC_MAX_NUM_PORTS ; i++) { 720 sal_memcpy(&(lc->lc_ibppktsetlimit[i]), 721 link_scache_ptr, sizeof(uint32)); 722 link_scache_ptr += sizeof(uint32); 723 sal_memcpy(&(lc->lc_ibpcelsetlimit[i]), 724 link_scache_ptr, sizeof(uint32)); 725 link_scache_ptr += sizeof(uint32); 726 } 727 } 728 #endif /* BCM_HAWKEYE_SUPPORT */ 729 730 /* Introduced accel mode bitmap sync/recovery with WB ver 1.2 */ 731 if (recovered_ver >= BCM_WB_VERSION_1_2) { 732 _BCM_LINK_PBMP_SCACHE_RECOVER(lc->lc_pbm_fast); 733 } else { 734 realloc_size += ((BCM_LINK_PBMP_SCACHE_NUM_WB_1_2 - 735 BCM_LINK_PBMP_SCACHE_NUM_WB_1_1) * 736 _LINK_PBMP_BYTE_MAX); 737 } 738 739 if (recovered_ver >= BCM_WB_VERSION_1_3) { 740 sal_memcpy(&lc_us, link_scache_ptr, sizeof(int)); 741 link_scache_ptr += sizeof(int); 742 lc->lc_us = lc_us; 743 } else { 744 realloc_size += sizeof(int); 745 } 746 747 /* Introduced eth buffer_mode bitmap sync/recovery with WB ver 1.4 */ 748 if (recovered_ver >= BCM_WB_VERSION_1_4) { 749 _BCM_LINK_PBMP_SCACHE_RECOVER(sop->lc_pbm_eth_buffer_mode); 750 } else { 751 realloc_size += ((BCM_LINK_PBMP_SCACHE_NUM_WB_1_3 - 752 BCM_LINK_PBMP_SCACHE_NUM_WB_1_2) * 753 _LINK_PBMP_BYTE_MAX); 754 } 755 756 /* 757 * Allocate extra scache space 758 */ 759 if (realloc_size > 0) { 760 SOC_IF_ERROR_RETURN 761 (soc_scache_realloc(unit, scache_handle, realloc_size)); 762 } 763 764 /* Recover port enable state */ 765 PBMP_ITER(pbmp_port, port) { 766 if (SOC_PBMP_MEMBER(disabled_pbmp, port)) { 767 /* MAC reg writes are suppressed, but this will set 768 * the SW PHY flag as disabled. */ 769 BCM_IF_ERROR_RETURN 770 (bcm_esw_port_enable_set(unit, port, FALSE)); 771 } 772 } 773 774 /* Best guess, based on link foward state (subset of up ports) */ 775 SOC_PBMP_ASSIGN(sop->lc_pbm_link, sop->link_fwd); 776 /* Also remote fault, since link must be up to detect it */ 777 SOC_PBMP_OR(sop->lc_pbm_link, sop->lc_pbm_remote_fault); 778 /* Already in fault, toggle link status to see if it's cleared */ 779 SOC_PBMP_OR(sop->lc_pbm_link_change, sop->lc_pbm_remote_fault); 780 } else if (BCM_E_NOT_FOUND == rv) { 781 /* Can't recover forced ports without persistent storage, 782 * but we can check for ports in loopback and put them as 783 * forced with link up. 784 */ 785 PBMP_ITER(pbmp_port, port) { 786 BCM_IF_ERROR_RETURN 787 (bcm_esw_port_loopback_get(unit, port, &loopback)); 788 LOG_VERBOSE(BSL_LS_BCM_LINK, 789 (BSL_META_U(unit, 790 "Linkscan init loopback recovery, " 791 "unit %d, port %d, lb=%d\n"), 792 unit, port, loopback)); 793 if (loopback != BCM_PORT_LOOPBACK_NONE) { 794 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_link, port); 795 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_ports, port); 796 } 797 } 798 /* 799 * Force initial scan by setting link change while pretending link 800 * was initially up. We'll pull out the expected link up ports 801 * below. 802 */ 803 SOC_PBMP_ASSIGN(sop->lc_pbm_link, PBMP_ALL(unit)); 804 #ifdef BCM_KATANA2_SUPPORT 805 if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) { 806 (void)_bcm_kt2_flexio_pbmp_update(unit, &sop->lc_pbm_link); 807 } 808 #endif 809 #if defined(BCM_SABER2_SUPPORT) 810 if(SOC_IS_SABER2(unit)){ 811 int oamp_enable; 812 (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable); 813 /* Skip OAMP port for saber2 device */ 814 if(oamp_enable) { 815 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link, 816 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 817 } 818 } 819 #endif 820 } else { 821 return rv; 822 } 823 824 PBMP_ITER(pbmp_port, port) { 825 if (SOC_PBMP_MEMBER(sop->lc_pbm_override_ports, port)) { 826 continue; 827 } 828 829 /* Retrieve link status from CMIC_MIIM_LINK_STATUS register for 830 * ports configured in Hardware Linkscan mode and from LATCH_DOWN 831 * register in Software Linkscan mode. This approach ensures that 832 * Link status is reliably retrieved as Latch down status register 833 * is getting cleared when toggling ports in Hardware linkscan mode 834 */ 835 /* link variable is filled up here, so it is valid */ 836 if (SOC_PBMP_MEMBER(lc->lc_pbm_hw, port)) { 837 /* coverity[uninit_use_in_call] : FALSE */ 838 /* 839 * COVERITY 840 * 841 * The iterator above PBMP_ITER will protect the port variable 842 * from overrun. 843 */ 844 /* coverity[overrun-call] */ 845 BCM_IF_ERROR_RETURN 846 (_bcm_port_link_get(unit, port, 1, &link)); 847 } else { 848 /* coverity[uninit_use_in_call] : FALSE */ 849 /* 850 * COVERITY 851 * The iterator above PBMP_ITER will protect the port variable 852 * from overrun. 853 */ 854 /* coverity[overrun-call] */ 855 BCM_IF_ERROR_RETURN 856 (_bcm_port_link_get(unit, port, 0, &link)); 857 } 858 if ((!link && SOC_PBMP_MEMBER(sop->lc_pbm_link, port)) || 859 (link && !SOC_PBMP_MEMBER(sop->lc_pbm_link, port))) { 860 /* Link status changed from expectation, process */ 861 SOC_PBMP_PORT_ADD(sop->lc_pbm_link_change, port); 862 } 863 } 864 865 /* Enable loopback on disabled port */ 866 BCM_IF_ERROR_RETURN 867 (_bcm_esw_link_force_for_disabled_loopback_port(unit)); 868 869 /* Note Warm Boot occurred for linkscan thread start */ 870 lc->lc_warm_boot = TRUE; 871 872 return BCM_E_NONE; 873 } 874 #endif /* BCM_WARM_BOOT_SUPPORT */ 875 876 /* 877 * Function: 878 * bcm_esw_linkscan_enable_port_get 879 * Purpose: 880 * Determine whether or not linkscan is managing a given port. 881 * Parameters: 882 * unit - StrataSwitch unit #. 883 * port - Port to check. 884 * Returns: 885 * BCM_E_NONE - port being scanned 886 * BCM_E_DISABLED - port not being scanned 887 */ 888 int 889 bcm_esw_linkscan_enable_port_get(int unit, bcm_port_t port) 890 { 891 soc_persist_t *sop = SOC_PERSIST(unit); 892 ls_cntl_t *lc = link_control[unit]; 893 894 if (BCM_GPORT_IS_SET(port)) { 895 BCM_IF_ERROR_RETURN( 896 bcm_esw_port_local_get(unit, port, &port)); 897 } 898 899 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 900 return BCM_E_PORT; 901 } 902 if (lc == NULL || lc->lc_us == 0 || 903 (!BCM_PBMP_MEMBER(lc->lc_pbm_sw, port) && 904 !BCM_PBMP_MEMBER(lc->lc_pbm_hw, port) && 905 !BCM_PBMP_MEMBER(sop->lc_pbm_override_ports, port))) { 906 return (BCM_E_DISABLED); 907 } 908 909 return (BCM_E_NONE); 910 } 911 912 #if defined(BCM_TRIDENT_SUPPORT) 913 /* 914 * Function: 915 * _bcm_trident_linkscan_update_asf 916 * Purpose: 917 * Update Alternate Store and Forward parameters for a port on Trident. 918 * Parameters: 919 * unit - device 920 * port - port 921 * linkup - port link state (0=down, 1=up) 922 * speed - port speed 923 * duplex - port duplex (0=half, 1=full) 924 * Returns: 925 * BCM_E_XXX 926 * Notes: 927 * This routine is the same as _bcm_esw_linkscan_update_asf but Trident 928 * has a different mapping table for speeds. 929 */ 930 STATIC int 931 _bcm_trident_linkscan_update_asf(int unit, bcm_port_t port, int linkup, 932 int speed, int duplex) 933 { 934 int no_10_100, asf_speed; 935 936 if (!linkup || IS_CPU_PORT(unit, port)) { 937 speed = 0; 938 } 939 no_10_100 = soc_feature(unit, soc_feature_asf_no_10_100); 940 switch (speed) { 941 case 0: 942 asf_speed = 0; 943 break; 944 case 10: 945 if (no_10_100) { 946 asf_speed = 0; 947 } else { 948 asf_speed = duplex ? 3 : 2; 949 } 950 break; 951 case 100: 952 if (no_10_100) { 953 asf_speed = 0; 954 } else { 955 asf_speed = duplex ? 5 : 4; 956 } 957 break; 958 case 1000: 959 asf_speed = duplex ? 7 : 6; 960 break; 961 case 2500: 962 asf_speed = duplex ? 9 : 8; 963 break; 964 case 10000: 965 asf_speed = 12; 966 break; 967 case 12000: 968 asf_speed = 13; 969 break; 970 case 13000: 971 asf_speed = 14; 972 break; 973 case 15000: 974 asf_speed = 15; 975 break; 976 case 16000: 977 asf_speed = 16; 978 break; 979 case 20000: 980 asf_speed = 18; 981 break; 982 case 24000: 983 asf_speed = 20; 984 break; 985 case 30000: 986 asf_speed = 24; 987 break; 988 case 40000: 989 asf_speed = 28; 990 break; 991 default: 992 asf_speed = 0; 993 break; 994 } 995 996 return soc_reg_field32_modify(unit, ASF_PORT_SPEEDr, port, 997 ASF_PORT_SPEEDf, asf_speed); 998 } 999 #endif /* BCM_TRIDENT_SUPPORT */ 1000 1001 #if defined(BCM_GREYHOUND2_SUPPORT) 1002 /* 1003 * Function: 1004 * _bcm_gh2_linkscan_update_asf 1005 * Purpose: 1006 * Update Alternate Store and Forward destination ports. 1007 * Parameters: 1008 * unit - device 1009 * port - port 1010 * linkup - port link state (0=down, 1=up) 1011 * speed - port speed 1012 * duplex - port duplex (0=half, 1=full) 1013 * Returns: 1014 * BCM_E_XXX 1015 */ 1016 STATIC int 1017 _bcm_gh2_linkscan_update_asf(int unit, bcm_port_t port, int linkup, 1018 int speed, int duplex) 1019 { 1020 int dst_port; 1021 int dst_port_speed; 1022 int dst_mmu_port = 0; 1023 bcm_pbmp_t pbmp; 1024 uint32 old_val0, old_val1, old_val2; 1025 uint32 new_val0, new_val1, new_val2; 1026 soc_info_t *si = &SOC_INFO(unit); 1027 1028 if (IS_CPU_PORT(unit, port)) { 1029 /* Cut-through mode not supported on CPU port, skip it */ 1030 return BCM_E_NONE; 1031 } 1032 1033 BCM_IF_ERROR_RETURN( 1034 READ_ASF_PORT_SPEED_MATCH_BMP0r(unit, port, &old_val0)); 1035 BCM_IF_ERROR_RETURN( 1036 READ_ASF_PORT_SPEED_MATCH_BMP1r(unit, port, &old_val1)); 1037 BCM_IF_ERROR_RETURN( 1038 READ_ASF_PORT_SPEED_MATCH_BMP2r(unit, port, &old_val2)); 1039 1040 SOC_PBMP_ASSIGN(pbmp, PBMP_E_ALL(unit)); 1041 new_val0 = 0; 1042 new_val1 = 0; 1043 new_val2 = 0; 1044 PBMP_ITER(pbmp, dst_port) { 1045 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, dst_port, 1046 &dst_port_speed)); 1047 if (dst_port_speed <= speed) { 1048 dst_mmu_port = si->port_p2m_mapping[si->port_l2p_mapping[dst_port]]; 1049 if (dst_mmu_port < 32) { 1050 new_val0 |= 1 << (dst_mmu_port % 32); 1051 } else if ((dst_mmu_port >=32) && (dst_mmu_port < 64)) { 1052 new_val1 |= 1 << (dst_mmu_port % 32); 1053 } else { /* dst_mmu_port >= 64 */ 1054 new_val2 |= 1 << (dst_mmu_port % 32); 1055 } 1056 } 1057 } 1058 if (old_val0 != new_val0) { 1059 BCM_IF_ERROR_RETURN( 1060 WRITE_ASF_PORT_SPEED_MATCH_BMP0r(unit, port, new_val0)); 1061 } 1062 if (old_val1 != new_val1) { 1063 BCM_IF_ERROR_RETURN( 1064 WRITE_ASF_PORT_SPEED_MATCH_BMP1r(unit, port, new_val1)); 1065 } 1066 if (old_val2 != new_val2) { 1067 BCM_IF_ERROR_RETURN( 1068 WRITE_ASF_PORT_SPEED_MATCH_BMP2r(unit, port, new_val2)); 1069 } 1070 return BCM_E_NONE; 1071 } 1072 #endif /* BCM_GREYHOUND2_SUPPORT */ 1073 1074 /* 1075 * Function: 1076 * _bcm_esw_linkscan_update_asf 1077 * Purpose: 1078 * Update Alternate Store and Forward parameters for a port. 1079 * Parameters: 1080 * unit - device 1081 * port - port 1082 * linkup - port link state (0=down, 1=up) 1083 * speed - port speed 1084 * duplex - port duplex (0=half, 1=full) 1085 * Returns: 1086 * BCM_E_XXX 1087 */ 1088 1089 STATIC int 1090 _bcm_esw_linkscan_update_asf(int unit, bcm_port_t port, int linkup, 1091 int speed, int duplex) 1092 { 1093 if (SOC_REG_IS_VALID(unit, ASFPORTSPEEDr)) { 1094 uint32 asf_reg, oasf_reg, asf_speed; 1095 int no_10_100; 1096 1097 SOC_IF_ERROR_RETURN(READ_ASFPORTSPEEDr(unit, port, &asf_reg)); 1098 oasf_reg = asf_reg; 1099 if (!linkup || IS_CPU_PORT(unit, port)) { 1100 speed = 0; 1101 } 1102 no_10_100 = soc_feature(unit, soc_feature_asf_no_10_100); 1103 switch (speed) { 1104 case 0: 1105 asf_speed = 0; 1106 break; 1107 case 10: 1108 if (no_10_100) { 1109 asf_speed = 0; 1110 } else { 1111 asf_speed = duplex ? 2 : 1; 1112 } 1113 break; 1114 case 100: 1115 if (no_10_100) { 1116 asf_speed = 0; 1117 } else { 1118 asf_speed = duplex ? 4 : 3; 1119 } 1120 break; 1121 case 1000: 1122 asf_speed = 5; 1123 break; 1124 case 10000: 1125 asf_speed = 6; 1126 break; 1127 case 12000: 1128 asf_speed = 7; 1129 break; 1130 default: 1131 asf_speed = 0; 1132 break; 1133 } 1134 soc_reg_field_set(unit, ASFPORTSPEEDr, &asf_reg, 1135 PORTSPEEDf, asf_speed); 1136 if (asf_reg != oasf_reg) { 1137 SOC_IF_ERROR_RETURN(WRITE_ASFPORTSPEEDr(unit, port, asf_reg)); 1138 } 1139 return BCM_E_NONE; 1140 } 1141 #if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_SCORPION_SUPPORT) 1142 /* Trident has a very different speed to ASF mapping */ 1143 /* coverity[result_independent_of_operands] */ 1144 if (SOC_REG_IS_VALID(unit, ASF_PORT_SPEEDr) && !SOC_IS_TD_TT(unit)) { 1145 uint32 asf_reg, oasf_reg, asf_speed; 1146 int no_10_100; 1147 1148 SOC_IF_ERROR_RETURN(READ_ASF_PORT_SPEEDr(unit, port, &asf_reg)); 1149 oasf_reg = asf_reg; 1150 if (!linkup || IS_CPU_PORT(unit, port)) { 1151 speed = 0; 1152 } 1153 no_10_100 = soc_feature(unit, soc_feature_asf_no_10_100); 1154 switch (speed) { 1155 case 0: 1156 asf_speed = 0; 1157 break; 1158 case 10: 1159 if (no_10_100) { 1160 asf_speed = 0; 1161 } else { 1162 asf_speed = duplex ? 3 : 2; 1163 } 1164 break; 1165 case 100: 1166 if (no_10_100) { 1167 asf_speed = 0; 1168 } else { 1169 asf_speed = duplex ? 5 : 4; 1170 } 1171 break; 1172 case 1000: 1173 asf_speed = duplex ? 7 : 6; 1174 break; 1175 case 2500: 1176 asf_speed = duplex ? 9 : 8; 1177 break; 1178 case 10000: 1179 asf_speed = 21; 1180 break; 1181 case 12000: 1182 case 13000: 1183 asf_speed = 25; 1184 break; 1185 case 16000: 1186 asf_speed = 27; 1187 break; 1188 case 20000: 1189 case 21000: 1190 asf_speed = 29; 1191 break; 1192 default: 1193 asf_speed = 0; 1194 break; 1195 } 1196 soc_reg_field_set(unit, ASF_PORT_SPEEDr, &asf_reg, 1197 ASF_PORT_SPEEDf, asf_speed); 1198 if (asf_reg != oasf_reg) { 1199 SOC_IF_ERROR_RETURN(WRITE_ASF_PORT_SPEEDr(unit, port, asf_reg)); 1200 } 1201 return BCM_E_NONE; 1202 } 1203 #endif /* BCM_BRADLEY_SUPPORT || BCM_SCORPION_SUPPORT */ 1204 #if defined(BCM_TRIDENT_SUPPORT) 1205 /* ASF_PORT_SPEED register should always be there for Trident */ 1206 /* this check is to protect against some future variants to avoid crashes */ 1207 /* coverity[result_independent_of_operands] */ 1208 if (SOC_IS_TD_TT(unit) && SOC_REG_IS_VALID(unit, ASF_PORT_SPEEDr) ) { 1209 return _bcm_trident_linkscan_update_asf(unit, port, linkup, 1210 speed, duplex); 1211 } 1212 #endif 1213 #if defined(BCM_GREYHOUND2_SUPPORT) 1214 if (SOC_IS_GREYHOUND2(unit)) { 1215 return _bcm_gh2_linkscan_update_asf(unit, port, linkup, 1216 speed, duplex); 1217 } 1218 #endif 1219 return BCM_E_NONE; 1220 } 1221 1222 #if defined(BCM_HERCULES15_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT) 1223 /* 1224 * Function: 1225 * _bcm_esw_link_fault_get 1226 * Purpose: 1227 * Check for remote and local fault on 10G+ link which is already up. 1228 * Parameters: 1229 * unit - StrataSwitch unit #. 1230 * port - Port to process. 1231 * fault - (IN/OUT) Fault status 1232 * Returns: 1233 * BCM_E_XXX 1234 */ 1235 1236 STATIC int 1237 _bcm_esw_link_fault_get(int unit, int port, int *fault) 1238 { 1239 uint64 lss; 1240 int rmt_fault, lcl_fault, speed; 1241 soc_reg_t reg; 1242 soc_field_t rmt_fault_field, lcl_fault_field; 1243 soc_reg_t clr_reg; 1244 soc_persist_t *sop = SOC_PERSIST(unit); 1245 bcm_port_ability_t port_ability; 1246 int ln_rmt_fault = 0; 1247 int ln_lcl_fault = 0; 1248 1249 if (SOC_PBMP_MEMBER(sop->lc_pbm_eth_buffer_mode, port)) { 1250 *fault = FALSE; 1251 if (!IS_GE_PORT(unit, port)) { 1252 SOC_IF_ERROR_RETURN(soc_phyctrl_linkfault_get(unit, port, fault)); 1253 } 1254 if (*fault & BCM_PORT_FAULT_LOCAL) { 1255 ln_lcl_fault = TRUE; 1256 } 1257 if (*fault & BCM_PORT_FAULT_REMOTE) { 1258 ln_rmt_fault = TRUE; 1259 } 1260 if (ln_lcl_fault || ln_rmt_fault) { 1261 *fault = TRUE; 1262 } 1263 } 1264 1265 if (SOC_PBMP_MEMBER(sop->lc_pbm_fc, port)) { 1266 if (!(SOC_USE_PORTCTRL(unit))) { 1267 SOC_IF_ERROR_RETURN(soc_phyctrl_linkfault_get(unit, port, fault)); 1268 return BCM_E_NONE; 1269 } 1270 } 1271 1272 if (IS_HG_PORT(unit, port) || IS_XE_PORT(unit, port) || 1273 IS_CE_PORT(unit, port) || IS_CDE_PORT(unit, port)) { 1274 1275 sal_memset(&port_ability, 0, sizeof(bcm_port_ability_t)); 1276 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed)); 1277 1278 /* CD PORTS (PM8x50) do not support the below check */ 1279 if (!IS_CD_PORT(unit, port)) { 1280 BCM_IF_ERROR_RETURN(bcm_esw_port_ability_local_get(unit, 1281 port, &port_ability)); 1282 1283 /* check if the port has no fault status to retrieve */ 1284 if (port_ability.speed_full_duplex & BCM_PORT_ABILITY_5000MB && 1285 speed < 5000) { 1286 return BCM_E_NONE; 1287 } else if (speed < 5000) { 1288 return BCM_E_NONE; 1289 } 1290 } 1291 1292 if (SOC_USE_PORTCTRL(unit)) { 1293 BCM_IF_ERROR_NOT_UNAVAIL_RETURN 1294 (bcmi_esw_portctrl_link_fault_get(unit, port, 1295 &lcl_fault, &rmt_fault)); 1296 if (rmt_fault || lcl_fault) { 1297 *fault = TRUE; 1298 } 1299 bcmi_esw_portctrl_clear_rx_lss_status_set(unit, port, 1, 1); 1300 bcmi_esw_portctrl_clear_rx_lss_status_set(unit, port, 0, 0); 1301 return BCM_E_NONE; 1302 } 1303 1304 clr_reg = INVALIDr; 1305 if (soc_feature(unit, soc_feature_clmac) && 1306 (IS_CL_PORT(unit, port) || IS_CLG2_PORT(unit, port))) { 1307 /* Tomahawk Front panel port is using CL MAC - thus we should check CL port instead of speed here */ 1308 reg = CLMAC_RX_LSS_STATUSr; 1309 rmt_fault_field = REMOTE_FAULT_STATUSf; 1310 lcl_fault_field = LOCAL_FAULT_STATUSf; 1311 clr_reg = CLMAC_CLEAR_RX_LSS_STATUSr; 1312 } else if (soc_feature(unit, soc_feature_cmac) && 1313 IS_CL_PORT(unit, port) && 1314 (IS_CE_PORT(unit, port) || 1315 SOC_INFO(unit).port_speed_max[port] >= 100000)) { 1316 reg = CMAC_RX_LSS_STATUSr; 1317 rmt_fault_field = REMOTE_FAULT_STATUSf; 1318 lcl_fault_field = LOCAL_FAULT_STATUSf; 1319 clr_reg = CMAC_CLEAR_RX_LSS_STATUSr; 1320 } else if (soc_feature(unit, soc_feature_xmac)) { 1321 reg = XMAC_RX_LSS_STATUSr; 1322 rmt_fault_field = REMOTE_FAULT_STATUSf; 1323 lcl_fault_field = LOCAL_FAULT_STATUSf; 1324 clr_reg = XMAC_CLEAR_RX_LSS_STATUSr; 1325 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_SABER2_SUPPORT) 1326 } else if (soc_feature(unit, soc_feature_xlmac)) { 1327 /* Tomahawk management port is taking XLMAC, so processed here */ 1328 reg = XLMAC_RX_LSS_STATUSr; 1329 rmt_fault_field = REMOTE_FAULT_STATUSf; 1330 lcl_fault_field = LOCAL_FAULT_STATUSf; 1331 clr_reg = XLMAC_CLEAR_RX_LSS_STATUSr; 1332 #endif 1333 } else { 1334 rmt_fault_field = REMOTEFAULTSTATf; 1335 lcl_fault_field = LOCALFAULTSTATf; 1336 reg = MAC_RXLSSSTATr; 1337 } 1338 1339 SOC_IF_ERROR_RETURN 1340 (soc_reg_get(unit, reg, port, 0, &lss)); 1341 rmt_fault = soc_reg64_field32_get(unit, reg, lss, rmt_fault_field); 1342 lcl_fault = soc_reg64_field32_get(unit, reg, lss, lcl_fault_field); 1343 1344 if (rmt_fault || lcl_fault) { 1345 *fault = TRUE; 1346 } 1347 1348 if (clr_reg != INVALIDr) { 1349 COMPILER_64_ZERO(lss); 1350 soc_reg64_field32_set(unit, clr_reg, &lss, 1351 CLEAR_REMOTE_FAULT_STATUSf, 1); 1352 soc_reg64_field32_set(unit, clr_reg, &lss, 1353 CLEAR_LOCAL_FAULT_STATUSf, 1); 1354 SOC_IF_ERROR_RETURN 1355 (soc_reg_set(unit, clr_reg, 1356 port, 0, lss)); 1357 1358 soc_reg64_field32_set(unit, clr_reg, &lss, 1359 CLEAR_REMOTE_FAULT_STATUSf, 0); 1360 soc_reg64_field32_set(unit, clr_reg, &lss, 1361 CLEAR_LOCAL_FAULT_STATUSf, 0); 1362 SOC_IF_ERROR_RETURN 1363 (soc_reg_set(unit, clr_reg, port, 0, lss)); 1364 } 1365 } 1366 1367 return BCM_E_NONE; 1368 } 1369 #endif /* HERC15, FIREBOLT */ 1370 1371 1372 #if defined(BCM_TRX_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) 1373 STATIC int 1374 _bcm_esw_link_lag_failover_loopback_get(int unit, int port, int* value) 1375 { 1376 uint64 lag_fail_status; 1377 soc_reg_t lag_failover_status_reg; 1378 if (SOC_USE_PORTCTRL(unit)) { 1379 return bcmi_esw_portctrl_lag_failover_loopback_get(unit, 1380 port, 1381 value); 1382 } 1383 1384 if (SOC_REG_IS_VALID(unit, LAG_FAILOVER_STATUSr)) { 1385 lag_failover_status_reg = LAG_FAILOVER_STATUSr; 1386 } else if (SOC_REG_IS_VALID(unit, GXPORT_LAG_FAILOVER_STATUSr)) { 1387 lag_failover_status_reg = GXPORT_LAG_FAILOVER_STATUSr; 1388 } else { 1389 if (SOC_IS_TOMAHAWKX(unit)) { 1390 lag_failover_status_reg = CLMAC_LAG_FAILOVER_STATUSr; 1391 } else { 1392 lag_failover_status_reg = XLMAC_LAG_FAILOVER_STATUSr; 1393 } 1394 } 1395 1396 /* Has this port failed? */ 1397 BCM_IF_ERROR_RETURN 1398 (soc_reg_get(unit, lag_failover_status_reg, 1399 port, 0, &lag_fail_status)); 1400 1401 *value = soc_reg64_field32_get(unit, lag_failover_status_reg, 1402 lag_fail_status, 1403 LAG_FAILOVER_LOOPBACKf); 1404 return BCM_E_NONE; 1405 } 1406 1407 STATIC int 1408 _bcm_esw_link_failover_link_up_with_portmod(int unit, int port) { 1409 int failed = TRUE; 1410 int retries = 5; 1411 int failover_loopback_usec = 5000; 1412 soc_timeout_t to; 1413 1414 /* Unimac may take several tries before clearing the loopback state. */ 1415 while (retries--) { 1416 BCM_IF_ERROR_RETURN( 1417 bcmi_esw_portctrl_lag_remove_failover_lpbk_set(unit, port, 0)); 1418 BCM_IF_ERROR_RETURN( 1419 bcmi_esw_portctrl_lag_remove_failover_lpbk_set(unit, port, 1)); 1420 1421 soc_timeout_init(&to, failover_loopback_usec, 0); 1422 while (!soc_timeout_check(&to)) { 1423 int rv = BCM_E_NONE; 1424 rv = _bcm_esw_link_lag_failover_loopback_get(unit, port, &failed); 1425 if (BCM_SUCCESS(rv) && !failed) { 1426 break; 1427 } 1428 } 1429 if (!failed) { 1430 break; 1431 } 1432 } 1433 1434 if (failed) { 1435 return BCM_E_TIMEOUT; 1436 } 1437 1438 /* Disable LAG failover until port is returned to trunk */ 1439 BCM_IF_ERROR_RETURN(bcmi_esw_portctrl_lag_failover_disable(unit, port)); 1440 BCM_IF_ERROR_RETURN(bcmi_esw_portctrl_trunk_hwfailover_set(unit, port, 0)); 1441 1442 /* Flush any flow control status to guarantee normal traffic goes 1443 * to the port first. */ 1444 if (SOC_IS_HELIX5(unit)) { 1445 uint64 zero64; 1446 COMPILER_64_ZERO(zero64); 1447 BCM_IF_ERROR_RETURN(WRITE_XPORT_TO_MMU_BKP_64r(unit, port, zero64)); 1448 } 1449 1450 else if (!SOC_IS_TOMAHAWK3(unit)) { 1451 BCM_IF_ERROR_RETURN(WRITE_XPORT_TO_MMU_BKPr(unit, port, 0)); 1452 } 1453 1454 LOG_VERBOSE(BSL_LS_BCM_LINK, 1455 (BSL_META_U(unit, 1456 "Unit %d: LAG Failed port %d status completed\n"), 1457 unit, port)); 1458 1459 return BCM_E_NONE; 1460 } 1461 1462 /* 1463 * Function: 1464 * _bcm_esw_link_failover_link_up 1465 * Purpose: 1466 * Perform the recovery sequence to restore a previously failed port 1467 * when link up occurs. 1468 * Parameters: 1469 * unit - StrataSwitch unit #. 1470 * port - Port to process. 1471 * Returns: 1472 * BCM_E_XXX 1473 */ 1474 STATIC int 1475 _bcm_esw_link_failover_link_up(int unit, int port) 1476 { 1477 int failed = TRUE, retries; 1478 uint64 lag_fail_config, lag_fail_status, rx_lss_ctrl; 1479 int failover_loopback_usec; 1480 soc_timeout_t to; 1481 soc_reg_t lag_failover_config_reg; 1482 soc_reg_t lag_failover_status_reg; 1483 1484 if (SOC_USE_PORTCTRL(unit)) { 1485 return _bcm_esw_link_failover_link_up_with_portmod(unit, port); 1486 } 1487 1488 failover_loopback_usec = 5000; 1489 retries = 5; 1490 1491 if (SOC_IS_SABER2(unit) && SOC_REG_PORT_VALID(unit, 1492 XLPORT_LAG_FAILOVER_CONFIGr, port)) { 1493 lag_failover_config_reg = XLPORT_LAG_FAILOVER_CONFIGr; 1494 } else if (SOC_REG_IS_VALID(unit, LAG_FAILOVER_CONFIGr)) { 1495 lag_failover_config_reg = LAG_FAILOVER_CONFIGr; 1496 } else if (SOC_REG_IS_VALID(unit, GXPORT_LAG_FAILOVER_CONFIGr)) { 1497 lag_failover_config_reg = GXPORT_LAG_FAILOVER_CONFIGr; 1498 } else { 1499 /* The LAG_FAILOVER_EN and REMOVE_FAILOVER_LPBK fields 1500 * moved to XLMAC_CTRL register in Trident2, CLMAC_CTRL register in TH 1501 */ 1502 if (SOC_IS_TOMAHAWKX(unit)) { 1503 lag_failover_config_reg = CLMAC_CTRLr; 1504 } else { 1505 lag_failover_config_reg = XLMAC_CTRLr; 1506 } 1507 } 1508 1509 if (SOC_REG_IS_VALID(unit, LAG_FAILOVER_STATUSr)) { 1510 lag_failover_status_reg = LAG_FAILOVER_STATUSr; 1511 } else if (SOC_REG_IS_VALID(unit, GXPORT_LAG_FAILOVER_STATUSr)) { 1512 lag_failover_status_reg = GXPORT_LAG_FAILOVER_STATUSr; 1513 } else { 1514 if (SOC_IS_TOMAHAWKX(unit)) { 1515 lag_failover_status_reg = CLMAC_LAG_FAILOVER_STATUSr; 1516 } else { 1517 lag_failover_status_reg = XLMAC_LAG_FAILOVER_STATUSr; 1518 } 1519 } 1520 1521 BCM_IF_ERROR_RETURN 1522 (soc_reg_get(unit, lag_failover_config_reg, port, 0, 1523 &lag_fail_config)); 1524 1525 /* Unimac may take several tries before clearing the loopback state. */ 1526 while (retries--) { 1527 soc_reg64_field32_set(unit, lag_failover_config_reg, 1528 &lag_fail_config, REMOVE_FAILOVER_LPBKf, 0); 1529 BCM_IF_ERROR_RETURN 1530 (soc_reg_set(unit, lag_failover_config_reg, 1531 port, 0, lag_fail_config)); 1532 soc_reg64_field32_set(unit, lag_failover_config_reg, 1533 &lag_fail_config, REMOVE_FAILOVER_LPBKf, 1); 1534 BCM_IF_ERROR_RETURN 1535 (soc_reg_set(unit, lag_failover_config_reg, 1536 port, 0, lag_fail_config)); 1537 1538 soc_timeout_init(&to, failover_loopback_usec, 0); 1539 while (!soc_timeout_check(&to)) { 1540 BCM_IF_ERROR_RETURN 1541 (soc_reg_get(unit, lag_failover_status_reg, 1542 port, 0, &lag_fail_status)); 1543 failed = 1544 soc_reg64_field32_get(unit, lag_failover_status_reg, 1545 lag_fail_status, LAG_FAILOVER_LOOPBACKf); 1546 if (!failed) { 1547 break; 1548 } 1549 } 1550 if (!failed) { 1551 break; 1552 } 1553 } 1554 1555 if (failed) { 1556 return BCM_E_TIMEOUT; 1557 } 1558 1559 /* Disable LAG failover until port is returned to trunk */ 1560 soc_reg64_field32_set(unit, lag_failover_config_reg, 1561 &lag_fail_config, REMOVE_FAILOVER_LPBKf, 0); 1562 soc_reg64_field32_set(unit, lag_failover_config_reg, 1563 &lag_fail_config, LAG_FAILOVER_ENf, 0); 1564 if (soc_reg_field_valid(unit, lag_failover_config_reg, 1565 LINK_STATUS_SELECTf)) { 1566 soc_reg64_field32_set(unit, lag_failover_config_reg, 1567 &lag_fail_config, LINK_STATUS_SELECTf, 0); 1568 } 1569 BCM_IF_ERROR_RETURN 1570 (soc_reg_set(unit, lag_failover_config_reg, port, 0, lag_fail_config)); 1571 1572 if (SOC_REG_IS_VALID(unit, XLMAC_RX_LSS_CTRLr)) { 1573 SOC_IF_ERROR_RETURN 1574 (soc_reg_get(unit, XLMAC_RX_LSS_CTRLr, port, 0, &rx_lss_ctrl)); 1575 soc_reg64_field32_set(unit, XLMAC_RX_LSS_CTRLr, &rx_lss_ctrl, 1576 RESET_FLOW_CONTROL_TIMERS_ON_LINK_DOWNf, 0); 1577 SOC_IF_ERROR_RETURN 1578 (soc_reg_set(unit, XLMAC_RX_LSS_CTRLr, port, 0, rx_lss_ctrl)); 1579 } 1580 1581 /* Flush any flow control status to guarantee normal traffic goes 1582 * to the port first. */ 1583 if (SOC_IS_HELIX5(unit)) { 1584 uint64 zero64; 1585 COMPILER_64_ZERO(zero64); 1586 BCM_IF_ERROR_RETURN(WRITE_XPORT_TO_MMU_BKP_64r(unit, port, zero64)); 1587 } else { 1588 BCM_IF_ERROR_RETURN(WRITE_XPORT_TO_MMU_BKPr(unit, port, 0)); 1589 } 1590 1591 LOG_VERBOSE(BSL_LS_BCM_LINK, 1592 (BSL_META_U(unit, 1593 "Unit %d: LAG Failed port %d status completed\n"), 1594 unit, port)); 1595 1596 return BCM_E_NONE; 1597 } 1598 1599 /* 1600 * Function: 1601 * _bcm_esw_link_failover_link_down_force 1602 * Purpose: 1603 * Force a link down event on a LAG failover enabled port when 1604 * a fault is detected. This will engage the HW failover 1605 * mechanism. 1606 * Parameters: 1607 * unit - StrataSwitch unit #. 1608 * port - Port to process. 1609 * Returns: 1610 * BCM_E_XXX 1611 */ 1612 STATIC int 1613 _bcm_esw_link_failover_link_down_force(int unit, int port) 1614 { 1615 int failed = FALSE; 1616 int failover_loopback_usec; 1617 soc_timeout_t to; 1618 int rv; 1619 1620 PORT_LOCK(unit); 1621 if (SOC_USE_PORTCTRL(unit)) { 1622 rv = bcmi_esw_portctrl_phy_enable_set(unit, port, FALSE); 1623 } else { 1624 rv = soc_phyctrl_enable_set(unit, port, FALSE); 1625 } 1626 PORT_UNLOCK(unit); 1627 BCM_IF_ERROR_RETURN(rv); 1628 1629 failover_loopback_usec = 5000; 1630 soc_timeout_init(&to, failover_loopback_usec, 0); 1631 while (!soc_timeout_check(&to)) { 1632 rv = _bcm_esw_link_lag_failover_loopback_get(unit, port, &failed); 1633 if (BCM_SUCCESS(rv) && failed) { 1634 break; 1635 } 1636 } 1637 1638 if (!failed) { 1639 return BCM_E_TIMEOUT; 1640 } 1641 1642 /* Turn PHY back on now that we've entered failed state */ 1643 PORT_LOCK(unit); 1644 if (SOC_USE_PORTCTRL(unit)) { 1645 rv = bcmi_esw_portctrl_phy_enable_set(unit, port, TRUE); 1646 } else { 1647 rv = soc_phyctrl_enable_set(unit, port, TRUE); 1648 } 1649 PORT_UNLOCK(unit); 1650 BCM_IF_ERROR_RETURN(rv); 1651 1652 return BCM_E_NONE; 1653 } 1654 1655 /* 1656 * Function: 1657 * _bcm_esw_link_failover_port_disable 1658 * Purpose: 1659 * When a port enters failed state, disable the RX path and 1660 * flush the TX FIFO. 1661 * Parameters: 1662 * unit - StrataSwitch unit #. 1663 * port - Port to process. 1664 * Returns: 1665 * BCM_E_XXX 1666 */ 1667 STATIC int 1668 _bcm_esw_link_failover_port_disable(int unit, int port) 1669 { 1670 if (IS_HG_PORT(unit, port) || IS_XE_PORT(unit, port)) { 1671 /* disable rx path of (unit, port) */ 1672 BCM_IF_ERROR_RETURN 1673 (_bcm_esw_port_mac_failover_notify(unit,port)); 1674 1675 if (!SOC_USE_PORTCTRL(unit)) { 1676 if (SOC_REG_IS_VALID(unit, MAC_TXCTRLr)) { 1677 /* Flush BigMAC TX FIFO */ 1678 BCM_IF_ERROR_RETURN 1679 (soc_reg_field32_modify(unit, MAC_TXCTRLr, port, 1680 TXFIFO_RESETf, 1)); 1681 BCM_IF_ERROR_RETURN 1682 (soc_reg_field32_modify(unit, MAC_TXCTRLr, port, 1683 TXFIFO_RESETf, 0)); 1684 } 1685 } 1686 } 1687 1688 return BCM_E_NONE; 1689 } 1690 #endif /* BCM_TRX_SUPPORT || BCM_BRADLEY_SUPPORT */ 1691 1692 #if defined(BCM_HAWKEYE_SUPPORT) 1693 STATIC int 1694 _hawkeye_new_link_check(int unit, int port) 1695 { 1696 uint32 val; 1697 bcm_port_medium_t medium; 1698 bcm_port_ability_t local_advert; 1699 bcm_port_ability_t remote_advert; 1700 uint32 mac_data = 0, phy_data = 0; 1701 int speed = 0, duplex = 0, an = 0; 1702 int tx_pause = 0, rx_pause = 0; 1703 int rv; 1704 1705 BCM_IF_ERROR_RETURN(bcm_esw_port_autoneg_get(unit, port, &an)); 1706 BCM_IF_ERROR_RETURN(bcm_esw_port_medium_get(unit, port, &medium)); 1707 if (medium == BCM_PORT_MEDIUM_COPPER){ 1708 /* medium is copper */ 1709 BCM_IF_ERROR_RETURN 1710 (bcm_esw_port_phy_get(unit, port, 0, 1711 HK_PAUSE_WAR_PHY_REG, &phy_data)); 1712 if (phy_data & PHY_AN_TX_PAUSE_CAP) { 1713 tx_pause = 1; 1714 } else { 1715 tx_pause = 0; 1716 } 1717 1718 if (phy_data & PHY_AN_RX_PAUSE_CAP) { 1719 rx_pause = 1; 1720 } else { 1721 rx_pause = 0; 1722 } 1723 } else { 1724 /* medium is fiber */ 1725 1726 sal_memset(&local_advert, 0, sizeof(bcm_port_ability_t)); 1727 rv = bcm_esw_port_ability_advert_get(unit, port, &local_advert); 1728 if (BCM_FAILURE(rv)) { 1729 LOG_WARN(BSL_LS_BCM_LINK, 1730 (BSL_META_U(unit, 1731 "p=%d soc_phyctrl_adv_local_get rv=%d\n"), 1732 port, rv)); 1733 return rv; 1734 } 1735 1736 sal_memset(&remote_advert, 0, sizeof(bcm_port_ability_t)); 1737 rv = bcm_esw_port_ability_remote_get(unit, port, &remote_advert); 1738 if (BCM_FAILURE(rv)) { 1739 LOG_WARN(BSL_LS_BCM_LINK, 1740 (BSL_META_U(unit, 1741 "p=%d soc_phyctrl_adv_remote_get rv=%d\n"), 1742 port, rv)); 1743 return rv; 1744 } 1745 1746 /* 1747 * IEEE 802.3 Flow Control Resolution. 1748 * Please see $SDK/doc/pause-resolution.txt 1749 * for more information. 1750 */ 1751 1752 tx_pause = 1753 ((remote_advert.pause & SOC_PA_PAUSE_RX) && 1754 (local_advert.pause & SOC_PA_PAUSE_RX)) || 1755 ((remote_advert.pause & SOC_PA_PAUSE_RX) && 1756 !(remote_advert.pause & SOC_PA_PAUSE_TX) && 1757 (local_advert.pause & SOC_PA_PAUSE_TX)); 1758 1759 rx_pause = 1760 ((remote_advert.pause & SOC_PA_PAUSE_RX) && 1761 (local_advert.pause & SOC_PA_PAUSE_RX)) || 1762 ((local_advert.pause & SOC_PA_PAUSE_RX) && 1763 (remote_advert.pause & SOC_PA_PAUSE_TX) && 1764 !(local_advert.pause & SOC_PA_PAUSE_TX)); 1765 } 1766 1767 if(soc_feature(unit, soc_feature_hawkeye_a0_war)) { 1768 /* QSGMII Pause Work aroud for HAWKEYE A0*/ 1769 /* coverity[result_independent_of_operands] */ 1770 SOC_IF_ERROR_RETURN(READ_CMIC_TX_PAUSE_CAPABILITYr(unit, &mac_data)); 1771 1772 if (tx_pause) { 1773 mac_data |= (1 << (port-1)); 1774 } else { 1775 mac_data &= ~(1 << (port-1)); 1776 } 1777 /* coverity[result_independent_of_operands] */ 1778 SOC_IF_ERROR_RETURN(WRITE_CMIC_TX_PAUSE_CAPABILITYr(unit, mac_data)); 1779 1780 /* coverity[result_independent_of_operands] */ 1781 SOC_IF_ERROR_RETURN(READ_CMIC_RX_PAUSE_CAPABILITYr(unit, &mac_data)); 1782 1783 if (rx_pause) { 1784 mac_data |= (1 << (port-1)); 1785 } else { 1786 mac_data &= ~(1 << (port-1)); 1787 } 1788 /* coverity[result_independent_of_operands] */ 1789 SOC_IF_ERROR_RETURN(WRITE_CMIC_RX_PAUSE_CAPABILITYr(unit, mac_data)); 1790 1791 PORT_LOCK(unit); 1792 /* Toggle ENA_EXT_CONFIG of command_config register */ 1793 rv = READ_COMMAND_CONFIGr(unit, port, &mac_data); 1794 if (BCM_SUCCESS(rv)) { 1795 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1796 ENA_EXT_CONFIGf, 0); 1797 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1798 } 1799 if (BCM_SUCCESS(rv)) { 1800 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1801 ENA_EXT_CONFIGf, 1); 1802 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1803 } 1804 1805 if (BCM_SUCCESS(rv)) { 1806 sal_udelay(10000); 1807 } 1808 if (!an) { 1809 if (BCM_SUCCESS(rv)) { 1810 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1811 ENA_EXT_CONFIGf, 0); 1812 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1813 } 1814 } 1815 PORT_UNLOCK(unit); 1816 BCM_IF_ERROR_RETURN(rv); 1817 } else { 1818 /* QSGMII Pause Work aroud for NON HAWKEYE A0*/ 1819 /* coverity[result_independent_of_operands] */ 1820 SOC_IF_ERROR_RETURN(READ_CMIC_TX_PAUSE_CAPABILITYr(unit, &mac_data)); 1821 1822 if (tx_pause) { 1823 mac_data |= (1 << port); 1824 } else { 1825 mac_data &= ~(1 << port); 1826 } 1827 /* coverity[result_independent_of_operands] */ 1828 SOC_IF_ERROR_RETURN(WRITE_CMIC_TX_PAUSE_CAPABILITYr(unit, mac_data)); 1829 1830 /* coverity[result_independent_of_operands] */ 1831 SOC_IF_ERROR_RETURN(READ_CMIC_RX_PAUSE_CAPABILITYr(unit, &mac_data)); 1832 1833 if (rx_pause) { 1834 mac_data |= (1 << port); 1835 } else { 1836 mac_data &= ~(1 << port); 1837 } 1838 /* coverity[result_independent_of_operands] */ 1839 SOC_IF_ERROR_RETURN(WRITE_CMIC_RX_PAUSE_CAPABILITYr(unit, mac_data)); 1840 1841 PORT_LOCK(unit); 1842 /* Toggle ENA_EXT_CONFIG of command_config register */ 1843 rv = READ_COMMAND_CONFIGr(unit, port, &mac_data); 1844 if (BCM_SUCCESS(rv)) { 1845 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1846 ENA_EXT_CONFIGf, 0); 1847 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1848 } 1849 if (BCM_SUCCESS(rv)) { 1850 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1851 ENA_EXT_CONFIGf, 1); 1852 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1853 } 1854 if (BCM_SUCCESS(rv)) { 1855 sal_udelay(10000); 1856 } 1857 if (!an) { 1858 if (BCM_SUCCESS(rv)) { 1859 soc_reg_field_set(unit, COMMAND_CONFIGr, &mac_data, 1860 ENA_EXT_CONFIGf, 0); 1861 rv = WRITE_COMMAND_CONFIGr(unit, port, mac_data); 1862 } 1863 } 1864 PORT_UNLOCK(unit); 1865 BCM_IF_ERROR_RETURN(rv); 1866 /* 1867 * In HK A0, the back-pressure is disabled 1868 * when the bit HD_FC_ENA is cleared (binary 0). 1869 * In other revision of HK, the back-pressure is disabled 1870 * when the bit HD_FC_ENA is set (binary 1). 1871 * To avoid confusion with HK A0, 1872 * S/W set the bit HD_FC_ENA to 1 in other revision of HK. 1873 * P.S. Because the value of register IPG_HD_BKP_CNTL 1874 * is set to default on link up, S/W needs to 1875 * set the value again for every link-up. 1876 */ 1877 SOC_IF_ERROR_RETURN(READ_IPG_HD_BKP_CNTLr(unit, port, &val)); 1878 soc_reg_field_set(unit, IPG_HD_BKP_CNTLr, 1879 &val, HD_FC_ENAf, 0x1); 1880 SOC_IF_ERROR_RETURN(WRITE_IPG_HD_BKP_CNTLr(unit, port, val)); 1881 } 1882 /* Issue : 1883 * 1. Port link flapping during 10/100M half duplex flow control 1884 * 2. Fiber port will lose packet when use 156.2Mhz clock 1885 * 3. Packet loss on 2 HK systems cascade test 1886 * Solution : 1887 * 1. Set HD_FC_BKOFF_OK=1 for 10/100M half duplex 1888 * 2. Set HD_FC_BKOFF_OK=0(default value) for 1000M 1889 * 3. Set IPG_CONFIG_RX=0xA for 10/100M and 1890 * IPG_CONFIG_RX=0x5(default value) for 1000M 1891 * 1892 * P.S. Because the value of register IPG_HD_BKP_CNTL is set to 1893 * default on link up, S/W needs to set the value 1894 * again for every link-up. 1895 */ 1896 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed)); 1897 BCM_IF_ERROR_RETURN(bcm_esw_port_duplex_get(unit, port, &duplex)); 1898 SOC_IF_ERROR_RETURN(READ_IPG_HD_BKP_CNTLr(unit, port, &val)); 1899 if(speed < 1000) { 1900 soc_reg_field_set(unit, IPG_HD_BKP_CNTLr, &val, 1901 IPG_CONFIG_RXf, 0xa); 1902 if(duplex == SOC_PORT_DUPLEX_HALF) { 1903 soc_reg_field_set(unit, IPG_HD_BKP_CNTLr, &val, 1904 HD_FC_BKOFF_OKf, 0x1); 1905 } 1906 } 1907 SOC_IF_ERROR_RETURN(WRITE_IPG_HD_BKP_CNTLr(unit, port, val)); 1908 1909 if(soc_feature(unit, soc_feature_eee)) { 1910 uint32 eee_duration_timer_pulse; 1911 soc_timeout_t to_time; 1912 int need_uni_sw_reset = FALSE; 1913 int need_pau_eee_war = FALSE; 1914 int eee_en; 1915 ls_cntl_t *lc = link_control[unit]; 1916 _bcm_port_info_t *port_info; 1917 1918 /* Each GPORT uses the GMII_Tx_clk from its second port 1919 * to count Tx/Rx LPI Duration . 1920 * Hence SW needs to program EEE_DURATION_TIMER_PULSE based 1921 * on the speed of only GE9 of gport1 & GE17 of gport2. 1922 */ 1923 SOC_IF_ERROR_RETURN 1924 (bcm_esw_port_control_get(unit, port, 1925 bcmPortControlEEEEnable, &eee_en)); 1926 1927 if (eee_en && ((port == 10) || (port == 18))) { 1928 if (speed == 10){ 1929 eee_duration_timer_pulse = 0x18; 1930 } else if (speed == 100) { 1931 eee_duration_timer_pulse = 0xF9; 1932 } else { 1933 /* restore default value in chip */ 1934 eee_duration_timer_pulse = 0x4E1; 1935 } 1936 1937 if (soc_feature(unit, soc_feature_unified_port)) { 1938 SOC_IF_ERROR_RETURN 1939 (READ_PORT_EEE_DURATION_TIMER_PULSEr(unit, port, &val)); 1940 soc_reg_field_set(unit, PORT_EEE_DURATION_TIMER_PULSEr, &val, 1941 CNT_VALUEf, eee_duration_timer_pulse); 1942 SOC_IF_ERROR_RETURN 1943 (WRITE_PORT_EEE_DURATION_TIMER_PULSEr(unit, port, val)); 1944 } else { 1945 if (SOC_REG_IS_VALID(unit,GE0_EEE_CONFIGr)) { 1946 SOC_IF_ERROR_RETURN 1947 (READ_GE0_EEE_CONFIGr(unit, port, &val)); 1948 soc_reg_field_set 1949 (unit, GE0_EEE_CONFIGr, &val, 1950 EEE_DURATION_TIMER_PULSEf, eee_duration_timer_pulse); 1951 SOC_IF_ERROR_RETURN 1952 (WRITE_GE0_EEE_CONFIGr(unit, port, val)); 1953 SOC_IF_ERROR_RETURN 1954 (WRITE_GE1_EEE_CONFIGr(unit, port, val)); 1955 SOC_IF_ERROR_RETURN 1956 (WRITE_GE2_EEE_CONFIGr(unit, port, val)); 1957 SOC_IF_ERROR_RETURN 1958 (WRITE_GE3_EEE_CONFIGr(unit, port, val)); 1959 SOC_IF_ERROR_RETURN 1960 (WRITE_GE4_EEE_CONFIGr(unit, port, val)); 1961 SOC_IF_ERROR_RETURN 1962 (WRITE_GE5_EEE_CONFIGr(unit, port, val)); 1963 SOC_IF_ERROR_RETURN 1964 (WRITE_GE6_EEE_CONFIGr(unit, port, val)); 1965 SOC_IF_ERROR_RETURN 1966 (WRITE_GE7_EEE_CONFIGr(unit, port, val)); 1967 } 1968 need_uni_sw_reset = TRUE; 1969 } 1970 } 1971 1972 /* EEE-Pause WAR */ 1973 /* step 1. Program IBPPKTSETLIMIT and IBPCELLSETLIMIT */ 1974 /* step 2. Poll IBPBKPSTATUS register in MMU */ 1975 /* step 3. COMMAND_CONFIG. SW_RESET */ 1976 1977 /* 1. Program IBPPKTSETLIMIT and IBPCELLSETLIMIT */ 1978 if (!an) { 1979 /* coverity[check_return] */ 1980 bcm_esw_port_pause_get(unit, port, &tx_pause, &rx_pause); 1981 } 1982 1983 SOC_IF_ERROR_RETURN(READ_IBPPKTSETLIMITr(unit, port, &val)); 1984 if((rx_pause && tx_pause) || (!eee_en)){ 1985 if(val == 0x3FFF) { 1986 val = lc->lc_ibppktsetlimit[port-1]; 1987 SOC_IF_ERROR_RETURN 1988 (WRITE_IBPPKTSETLIMITr(unit, port, val)); 1989 val = lc->lc_ibpcelsetlimit[port-1]; 1990 SOC_IF_ERROR_RETURN 1991 (WRITE_IBPCELLSETLIMITr(unit, port, val)); 1992 1993 need_pau_eee_war = TRUE; 1994 } 1995 } else { 1996 if (val != 0x3FFF) { 1997 /* save value for restore at PAUSE mode */ 1998 lc->lc_ibppktsetlimit[port-1] = val; 1999 SOC_IF_ERROR_RETURN 2000 (READ_IBPCELLSETLIMITr(unit, port, &val)); 2001 lc->lc_ibpcelsetlimit[port-1] = val; 2002 2003 val = 0x3FFF; 2004 SOC_IF_ERROR_RETURN 2005 (WRITE_IBPPKTSETLIMITr(unit, port, val)); 2006 SOC_IF_ERROR_RETURN 2007 (WRITE_IBPCELLSETLIMITr(unit, port, val)); 2008 2009 need_pau_eee_war = TRUE; 2010 } 2011 } 2012 /* 2. Poll IBPBKPSTATUS register in MMU */ 2013 if (need_pau_eee_war) { 2014 soc_timeout_init(&to_time, 100000, 0); 2015 for (;;) { 2016 SOC_IF_ERROR_RETURN(READ_IBPBKPSTATUSr(unit, &val)); 2017 if(!(val & (0x1 << (port)))) { 2018 break; 2019 } 2020 2021 if (soc_timeout_check(&to_time)) { 2022 break; 2023 } 2024 } 2025 } 2026 2027 /* 3. COMMAND_CONFIG. SW_RESET */ 2028 if ((need_pau_eee_war) || (need_uni_sw_reset)) { 2029 _bcm_port_info_access(unit, port, &port_info); 2030 PORT_LOCK(unit); 2031 rv = MAC_CONTROL_SET(port_info->p_mac, 2032 unit, port, 2033 SOC_MAC_CONTROL_SW_RESET, TRUE); 2034 if (BCM_SUCCESS(rv)) { 2035 sal_udelay(2); 2036 rv = MAC_CONTROL_SET(port_info->p_mac, 2037 unit, port, 2038 SOC_MAC_CONTROL_SW_RESET, FALSE); 2039 } 2040 PORT_UNLOCK(unit); 2041 BCM_IF_ERROR_RETURN(rv); 2042 } 2043 } 2044 return BCM_E_NONE; 2045 } 2046 #endif /* #if defined(BCM_HAWKEYE_SUPPORT) */ 2047 2048 /* 2049 * Function: 2050 * _bcm_esw_linkscan_hw_link_port_get 2051 * Purpose: 2052 * Get port link status from HW. 2053 * Link status may be derived from the SW PHY driver as needed. 2054 * 2055 * In addition, it checks for ports that need to be added to 2056 * the accelerated port bitmap. Conditions: 2057 * - Linkscan mode is HW 2058 * - Specified in the SOC property 'fast_sw_rx_los_pbmp' bitmap 2059 * - State is DOWN and HW link indicates an UP state 2060 * Parameters: 2061 * unit - Device unit. 2062 * port - Port to update. 2063 * cur_link - Current port link status 2064 * new_link - Returns new port link status 2065 * Returns: 2066 * BCM_E_XXX 2067 * Notes: 2068 * Assumes LOCK. 2069 * Assumes port is in HW linkscan mode. 2070 */ 2071 STATIC int 2072 _bcm_esw_linkscan_hw_link_port_get(int unit, int port, 2073 int cur_link, int *new_link) 2074 { 2075 ls_cntl_t *lc = link_control[unit]; 2076 int sw_new_link = FALSE; 2077 2078 if (BCM_PBMP_MEMBER(lc->lc_pbm_sgmii_autoneg_port, port)) { 2079 BCM_IF_ERROR_RETURN(_bcm_port_link_get(unit, port, 0, new_link)); 2080 } else { 2081 /* Get HW link status */ 2082 /* If port is in accelerated mode, 2083 * then there was an ealier HW link up event. 2084 * Skip the HW link status get and set the new_link to TRUE. 2085 */ 2086 if (!BCM_PBMP_MEMBER(lc->lc_pbm_accel, port)) { 2087 BCM_IF_ERROR_RETURN(_bcm_port_link_get(unit, port, 1, new_link)); 2088 /* Capture time from last HW event in a down to up transition */ 2089 if ((cur_link == FALSE) && (*new_link == TRUE)) { 2090 last_time_hw_link_up[unit] = sal_time_usecs(); 2091 } 2092 } else { 2093 *new_link = TRUE; 2094 } 2095 2096 /* Check for down to up transition on ports with fast linkscan */ 2097 if (BCM_PBMP_MEMBER(lc->lc_pbm_fast, port) && (cur_link == FALSE)) { 2098 /* Get SW link status from PHY */ 2099 BCM_IF_ERROR_RETURN 2100 (_bcm_port_link_get(unit, port, 0, &sw_new_link)); 2101 /* 2102 * Add port to accelerated bitmap if HW indicates a link up 2103 * but SW indicates link down 2104 */ 2105 if (*new_link == TRUE) { 2106 if (sw_new_link == TRUE) { 2107 /* 2108 * Do not remove the port from the accelerated bitmap yet. 2109 * Linkscan logic requires that the current and new link 2110 * status are up before the fault status is read and 2111 * cleared. 2112 * 2113 * Remove is done below after link is already up. 2114 */ 2115 /* Not only get SW link status from PHY, but also trigger PHY to UP state */ 2116 BCM_IF_ERROR_RETURN 2117 (_bcm_port_link_get(unit, port, 0, &sw_new_link)); 2118 } else { 2119 /* Add port to accelerated bitmap */ 2120 if (!BCM_PBMP_MEMBER(lc->lc_pbm_accel, port)) { 2121 BCM_PBMP_PORT_ADD(lc->lc_pbm_accel, port); 2122 lc->lc_accel_poll_count = 0; 2123 LOG_INFO(BSL_LS_BCM_LINK, 2124 (BSL_META_U(unit, 2125 "Port %s: add to accelerated mode\n"), 2126 SOC_PORT_NAME(unit, port))); 2127 } 2128 } 2129 } 2130 *new_link = sw_new_link; 2131 } 2132 2133 /* Check if port needs to be removed from the accelerated bitmap */ 2134 if (BCM_PBMP_MEMBER(lc->lc_pbm_accel, port)) { 2135 if ((cur_link == TRUE) && (*new_link == TRUE)) { 2136 /* 2137 * Everything is fine, proceed with link up. 2138 * Remove port from accelerated bitmap. 2139 */ 2140 BCM_PBMP_PORT_REMOVE(lc->lc_pbm_accel, port); 2141 LOG_INFO(BSL_LS_BCM_LINK, 2142 (BSL_META_U(unit, 2143 "Port %s: remove from accelerated mode\n"), 2144 SOC_PORT_NAME(unit, port))); 2145 } 2146 } 2147 } 2148 2149 return BCM_E_NONE; 2150 } 2151 2152 /* 2153 * Function: 2154 * _bcm_esw_linkscan_sw_link_port_get 2155 * Purpose: 2156 * Get port link status from PHY. 2157 * 2158 * In addition, it checks for ports that need to be added to 2159 * the accelerated port bitmap. Conditions: 2160 * - Linkscan mode is SW 2161 * - Specified in the SOC property 'fast_sw_rx_los_pbmp' bitmap 2162 * - State is DOWN 2163 * Parameters: 2164 * unit - Device unit. 2165 * port - Port to update. 2166 * cur_link - Current port link status 2167 * new_link - Returns new port link status 2168 * Returns: 2169 * BCM_E_XXX 2170 * Notes: 2171 * Assumes LOCK. 2172 * Assumes port is in SW linkscan mode. 2173 */ 2174 STATIC int 2175 _bcm_esw_linkscan_sw_link_port_get(int unit, int port, int *new_link) 2176 { 2177 ls_cntl_t *lc = link_control[unit]; 2178 2179 /* Get link status from PHY */ 2180 BCM_IF_ERROR_RETURN 2181 (_bcm_port_link_get(unit, port, 0, new_link)); 2182 /* Check current link status and update accelerate port bitmap */ 2183 if (BCM_PBMP_MEMBER(lc->lc_pbm_fast, port)) { 2184 if (*new_link == FALSE) { 2185 /* Add port to accelerated bitmap */ 2186 if (!BCM_PBMP_MEMBER(lc->lc_pbm_accel, port)) { 2187 BCM_PBMP_PORT_ADD(lc->lc_pbm_accel, port); 2188 lc->lc_accel_poll_count = 0; 2189 LOG_INFO(BSL_LS_BCM_LINK, 2190 (BSL_META_U(unit, 2191 "Port %s: add to accelerated mode\n"), 2192 SOC_PORT_NAME(unit, port))); 2193 } 2194 } else { 2195 if (BCM_PBMP_MEMBER(lc->lc_pbm_accel, port)) { 2196 /* 2197 * Everything is fine, proceed with link up. 2198 * Remove port from accelerated bitmap. 2199 */ 2200 BCM_PBMP_PORT_REMOVE(lc->lc_pbm_accel, port); 2201 LOG_INFO(BSL_LS_BCM_LINK, 2202 (BSL_META_U(unit, 2203 "Port %s: remove from accelerated mode\n"), 2204 SOC_PORT_NAME(unit, port))); 2205 } 2206 } 2207 } 2208 return BCM_E_NONE; 2209 } 2210 2211 #if defined(INCLUDE_PHY_542XX) 2212 /* 2213 * Function: 2214 * _bcm_esw_linkscan_serdes_link_update 2215 * Purpose: 2216 * Update the Force SerDes link status. 2217 * 2218 * Parameters: 2219 * unit - Device unit. 2220 * port - Port to update. 2221 * link - current port link status 2222 * Returns: 2223 * BCM_E_XXX 2224 * Notes: 2225 * Assumes LOCK. 2226 * Assumes port is in SW linkscan mode. 2227 */ 2228 STATIC int 2229 _bcm_esw_linkscan_serdes_link_update(int unit, int port, int link) 2230 { 2231 int rv = BCM_E_NONE; 2232 2233 if (SOC_USE_PORTCTRL(unit) && (!IS_CPRI_PORT(unit, port))) { 2234 rv = bcmi_esw_portctrl_serdes_link_update(unit, port, link); 2235 } 2236 return rv; 2237 } 2238 #endif /* defined(INCLUDE_PHY_542XX) */ 2239 2240 /* 2241 * The introduction of fault state complicates the transitions for 2242 * the linkscan update. If the link is established, then its fault 2243 * status is valid. If the link is down, then the fault status must be 2244 * false. Since we track the "current" and "new" states of each, we 2245 * get this truth table: 2246 * 2247 * Link Fault 2248 * C N C N 2249 * - - - - 2250 * 1) 1 1 1 1 No change 2251 * 2) 1 1 1 0 Fault cleared, enable logical layer, notify link up 2252 * 3) 1 1 0 1 Fault detected, disable logical layer, notify link down 2253 * 4) 1 1 0 0 No change 2254 * 5) 1 0 1 0 Faulted link down, disable port, no notify 2255 * 6) 1 0 0 0 No fault link down, disable logical layer and port, 2256 * notify link down 2257 * 7) 0 1 0 1 Link up to fault state, enable port but not 2258 * logical layer, no notify 2259 * 8) 0 1 0 0 Link up, enable port and logical layer, notify link up 2260 * 9) 0 0 0 0 No change 2261 * 2262 * Now to the above we add LAG failover. For LAG failover, when a 2263 * front-panel port on which trunk failover is configured goes down by 2264 * either of the definitions above (3 or 6), it is not actually disabled 2265 * but instead moved to the new FAILED state. This state remains until 2266 * explicitly cleared by the application reporting that the FAILED state 2267 * has been properly handled (failed port removed from trunk groups), via 2268 * bcm_port_link_failed_clear. When bcm_port_link_failed_clear is called, 2269 * link down processing completes (forced if necessary) and the link down 2270 * status is reported. When the link goes back up, some final cleanup 2271 * of the port is performed. After this point, the port may be put back 2272 * into any LAGs by the application. 2273 */ 2274 2275 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT) 2276 extern void 2277 _bcm_stk_modport_map_linkscan_handler(int unit, bcm_port_t port, 2278 bcm_port_info_t *info); 2279 #endif /* #(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT) */ 2280 2281 2282 2283 /* 2284 * Function: 2285 * _bcm_esw_linkscan_update_port 2286 * Purpose: 2287 * Check for and process a link event on one port 2288 * Parameters: 2289 * unit - StrataSwitch unit #. 2290 * flags - flags to indicate notification 2291 * port - Port to process. 2292 * Returns: 2293 * BCM_E_XXX 2294 */ 2295 2296 STATIC int 2297 _bcm_esw_linkscan_update_port(int unit, uint32 flags, int port) 2298 { 2299 soc_persist_t *sop = SOC_PERSIST(unit); 2300 ls_cntl_t *lc = link_control[unit]; 2301 int cur_link, change, new_link = FALSE; 2302 bcm_port_info_t info; 2303 ls_handler_t *lh, *lh_next = NULL; 2304 int rv, cur_fault, new_fault = FALSE, 2305 unforced = FALSE, notify = FALSE, 2306 logical_link, asf_link, info_skip = 0; 2307 int cur_failed, new_failed = FALSE; 2308 soc_pbmp_t pbm_link_fwd; 2309 #if defined(BCM_LINK_CHANGE_BENCHMARK) 2310 sal_usecs_t time_start = 0; 2311 sal_usecs_t time_end = 0; 2312 #endif /* BCM_LINK_CHANGE_BENCHMARK */ 2313 #if defined(BCM_HAWKEYE_SUPPORT) 2314 uint32 mac_data = 0; 2315 #endif /* BCM_HAWKEYE_SUPPORT */ 2316 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 2317 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 2318 int eee_en = 0, mac_val; 2319 sal_time_t current_time = 0; 2320 _bcm_port_info_t *port_info; 2321 bcm_port_ability_t remote_advert; 2322 #endif /* HURRICANE TRIDENT HAWKEYE HURRICANE2 */ 2323 #if defined(BCM_KATANA2_SUPPORT) 2324 soc_port_t pp_port; 2325 int bypass = 0; 2326 int wc_10g_21g_sel = 0; 2327 #endif /* BCM_KATANA2_SUPPORT */ 2328 int hw_link_port = FALSE; 2329 #ifdef BCM_KATANA2_SUPPORT 2330 uint32 rval = 0; 2331 #endif 2332 char *ll_status[] = {"down", "up", "failed", "fault"}; 2333 2334 /* Here, the assert may lead to thread 'bcmLink' exit. */ 2335 /* assert(SOC_PORT_VALID(unit, port)); */ 2336 if (!SOC_PORT_VALID(unit, port)) { 2337 LOG_ERROR(BSL_LS_BCM_LINK, 2338 (BSL_META_U(unit, 2339 "unit=%d port=%d is invaild\n"), 2340 unit, port)); 2341 return BCM_E_PARAM; 2342 } 2343 /* 2344 * Current link status is calculated in the following order: 2345 * 1) If link status is in an override state, the override 2346 * state is used. 2347 * 2) If link is required to recognize a link down event, the 2348 * current scan will recognize the link down (if the link 2349 * was previously down, this will result in no action 2350 * being taken) 2351 * 3) Use real detected link status. 2352 * a) If using Hardware link scanning, use captured H/W 2353 * value since the H/W scan will clear the latched 2354 * link down event. 2355 * b) If using S/W link scanning, retrieve the current 2356 * link status from the PHY. 2357 */ 2358 2359 cur_link = SOC_PBMP_MEMBER(sop->lc_pbm_link, port); 2360 cur_fault = SOC_PBMP_MEMBER(sop->lc_pbm_remote_fault, port); 2361 cur_failed = SOC_PBMP_MEMBER(sop->lc_pbm_failed, port); 2362 2363 change = SOC_PBMP_MEMBER(sop->lc_pbm_link_change, port); 2364 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link_change, port); 2365 2366 if (change) { /* 2) */ 2367 new_link = FALSE; 2368 rv = BCM_E_NONE; 2369 } else if (SOC_PBMP_MEMBER(sop->lc_pbm_override_ports, port)) { /* 1) */ 2370 new_link = SOC_PBMP_MEMBER(sop->lc_pbm_override_link, port); 2371 rv = BCM_E_NONE; 2372 } else if (SOC_PBMP_MEMBER(lc->lc_pbm_hw, port)) { /* 3a) */ 2373 rv = _bcm_esw_linkscan_hw_link_port_get(unit, port, 2374 cur_link, &new_link); 2375 unforced = TRUE; 2376 hw_link_port = TRUE; 2377 if (new_link) { 2378 LOG_VERBOSE(BSL_LS_BCM_LINK, 2379 (BSL_META_U(unit, 2380 "Unit %d: HW link p=%d up\n"), 2381 unit, port)); 2382 } else { 2383 LOG_VERBOSE(BSL_LS_BCM_LINK, 2384 (BSL_META_U(unit, 2385 "Unit %d: HW link p=%d down\n"), 2386 unit, port)); 2387 } 2388 } else if (SOC_PBMP_MEMBER(lc->lc_pbm_sw, port)) { /* 3b) */ 2389 if (lc->lc_f[port]) { 2390 int state; 2391 2392 rv = lc->lc_f[port](unit, port, &state); 2393 if (rv == BCM_E_NONE) { 2394 new_link = state ? TRUE : FALSE; 2395 } else if (rv == BCM_E_UNAVAIL) { 2396 rv = _bcm_esw_linkscan_sw_link_port_get(unit, port, &new_link); 2397 } 2398 } else { 2399 rv = _bcm_esw_linkscan_sw_link_port_get(unit, port, &new_link); 2400 #if defined(INCLUDE_PHY_542XX) 2401 if((rv == BCM_E_NONE) && (cur_link != new_link)){ 2402 rv = _bcm_esw_linkscan_serdes_link_update(unit,port,new_link); 2403 } 2404 #endif /* defined(INCLUDE_PHY_542XX) */ 2405 } 2406 #ifdef BCM_TRIUMPH3_SUPPORT 2407 if (SOC_IS_TRIUMPH3(unit)) { 2408 if (cur_link != new_link) { 2409 if (!new_link) { 2410 _bcm_esw_ibod_syn_port_down (unit, port); 2411 } 2412 } 2413 } 2414 #endif 2415 unforced = TRUE; 2416 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 2417 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 2418 if (SOC_IS_HURRICANE (unit) || SOC_IS_TD_TT (unit) || 2419 SOC_IS_HAWKEYE (unit) || SOC_IS_KATANAX(unit) || 2420 SOC_IS_TRIUMPH3(unit) || SOC_IS_HURRICANE2(unit) || 2421 SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 2422 SOC_IS_GREYHOUND2(unit)) { 2423 /* EEE standard compliance Work Around:*/ 2424 /* When link is up, delay EEE enable in MAC by atleast 1sec from 2425 * link up time if EEE is enabled in software database and disabled 2426 * in MAC */ 2427 if(soc_feature(unit, soc_feature_eee)) { 2428 /* Get EEE status from software database */ 2429 if (bcm_esw_port_control_get(unit, port, 2430 bcmPortControlEEEEnable, 2431 &eee_en) == BCM_E_NONE) { 2432 /* If EEE is enabled in software and port link is up */ 2433 if(eee_en && new_link) { 2434 /* Get EEE status from hardware (MAC) */ 2435 current_time = sal_time(); 2436 if (SOC_USE_PORTCTRL(unit)) { 2437 if (current_time > lc->lc_up_time[port-1]) { 2438 /* Do not enable native EEE on the MAC if autoEEE is enabled */ 2439 int r; 2440 uint32 auto_eee = 1; 2441 r = bcm_esw_port_phy_control_get(unit, port, 2442 BCM_PORT_PHY_CONTROL_EEE_AUTO, 2443 &auto_eee); 2444 if (r == BCM_E_UNAVAIL || !auto_eee) { 2445 bcmi_esw_portctrl_eee_enable_set(unit, port, 1); 2446 } 2447 } 2448 } 2449 else { 2450 _bcm_port_info_access(unit, port, &port_info); 2451 if (MAC_CONTROL_GET(port_info->p_mac, unit, port, 2452 SOC_MAC_CONTROL_EEE_ENABLE, 2453 &eee_en) == BCM_E_NONE) { 2454 /* If EEE is disabled in MAC and atleast 1 second 2455 * elapsed then enable EEE in MAC */ 2456 if((current_time > lc->lc_up_time[port-1]) && 2457 !eee_en) { 2458 LOG_VERBOSE(BSL_LS_BCM_LINK, 2459 (BSL_META_U(unit, 2460 "u=%d p=%d EEE enabled in MAC\n"), 2461 unit, port)); 2462 PORT_LOCK(unit); 2463 MAC_CONTROL_SET(port_info->p_mac, unit, port, 2464 SOC_MAC_CONTROL_EEE_ENABLE, 1); 2465 PORT_UNLOCK(unit); 2466 } 2467 } 2468 } 2469 } 2470 } 2471 } 2472 } 2473 #endif /* BCM_HURRICANE_SUPPORT || BCM_HAWKEYE_SUPORT || BCM_TRIDENT_SUPPORT */ 2474 } else { 2475 return BCM_E_NONE; /* Port not being scanned */ 2476 } 2477 2478 if (BCM_FAILURE(rv)) { 2479 2480 #ifdef BCM_RCPU_SUPPORT 2481 if (SOC_IS_RCPU_ONLY(unit) && (BCM_E_TIMEOUT != rv)) { 2482 /* Ignore errors other than timeout for rcpu devices. */ 2483 return BCM_E_NONE; 2484 } 2485 #endif /* BCM_RCPU_SUPPORT */ 2486 2487 LOG_ERROR(BSL_LS_BCM_LINK, 2488 (BSL_META_U(unit, 2489 "Port %s: Failed to recover link status: %s\n"), 2490 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2491 return rv; 2492 } 2493 2494 #if defined(BCM_TRX_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) 2495 /* Check for failed state before fault since it takes priority, 2496 * and because we may force the link down on clearing the failed state. 2497 */ 2498 if (soc_feature(unit, soc_feature_port_lag_failover)) { 2499 if (cur_failed) { 2500 if (!SOC_PBMP_MEMBER(sop->lc_pbm_failed_clear, port)) { 2501 new_failed = TRUE; /* Sticky until cleared */ 2502 } else { /* Clearing failed status */ 2503 new_failed = FALSE; 2504 new_link = FALSE; /* Force link down on clear */ 2505 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_failed, port); 2506 } 2507 } else if (SOC_PBMP_MEMBER(sop->lc_pbm_failover, port)) { 2508 rv = _bcm_esw_link_lag_failover_loopback_get( 2509 unit, port, &new_failed); 2510 if (BCM_SUCCESS(rv) && new_failed) { 2511 PORT_LOCK(unit); 2512 rv = _bcm_esw_link_failover_port_disable(unit, port); 2513 PORT_UNLOCK(unit); 2514 BCM_IF_ERROR_RETURN(rv); 2515 SOC_PBMP_PORT_ADD(sop->lc_pbm_failed, port); 2516 } 2517 } /* else, new_failed = FALSE from init above */ 2518 } 2519 #endif /* BCM_TRX_SUPPORT || BCM_BRADLEY_SUPPORT */ 2520 2521 #if defined(BCM_HERCULES15_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT) 2522 if ((soc_feature(unit, soc_feature_bigmac_fault_stat) || 2523 soc_feature(unit, soc_feature_xlmac)) && 2524 unforced && (cur_link) && (new_link) && !new_failed) { 2525 /* 2526 * Check the fault status here only if: 2527 * 1) The chip supports it. 2528 * 2) The link state is coming from the PHY (unforced). 2529 * 3) The link was already up and is still. 2530 */ 2531 2532 /* Check 10G fault status for change */ 2533 rv = _bcm_esw_link_fault_get(unit, port, &new_fault); 2534 if (BCM_FAILURE(rv)) { 2535 LOG_ERROR(BSL_LS_BCM_LINK, 2536 (BSL_META_U(unit, 2537 "Unit %d, Port %s: Failed to read fault status: %s\n"), 2538 unit, SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2539 return rv; 2540 } 2541 #if defined(BCM_TRX_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) 2542 if (new_fault && soc_feature(unit, soc_feature_port_lag_failover) && 2543 SOC_PBMP_MEMBER(sop->lc_pbm_failover, port)) { 2544 /* Must force port into LAG failover mode by forcing 2545 * a PHY linkdown event. */ 2546 rv = _bcm_esw_link_failover_link_down_force(unit, port); 2547 if (BCM_FAILURE(rv)) { 2548 LOG_ERROR(BSL_LS_BCM_LINK, 2549 (BSL_META_U(unit, 2550 "Unit %d, Port %s: Failed to force link down " 2551 "for fault on LAG failover: %s\n"), 2552 unit, SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2553 return rv; 2554 } else { 2555 new_failed = TRUE; 2556 PORT_LOCK(unit); 2557 rv = _bcm_esw_link_failover_port_disable(unit, port); 2558 PORT_UNLOCK(unit); 2559 BCM_IF_ERROR_RETURN(rv); 2560 SOC_PBMP_PORT_ADD(sop->lc_pbm_failed, port); 2561 } 2562 } 2563 #endif /* BCM_TRX_SUPPORT || BCM_BRADLEY_SUPPORT */ 2564 } 2565 #endif /* HERC15, FIREBOLT */ 2566 2567 /* 2568 * Add/Remove linkdown_tx ports to forward pbmp in order to add/Remove ports 2569 * to/from EPC_LINK_BMAPm, when notified by bcm_esw_link_change() with 2570 * cur_link down, new_link down. 2571 */ 2572 if (change && (!cur_link) && (!new_link)) { 2573 SOC_PBMP_ASSIGN(pbm_link_fwd, sop->lc_pbm_link); 2574 SOC_PBMP_REMOVE(pbm_link_fwd, sop->lc_pbm_remote_fault); 2575 SOC_PBMP_OR(pbm_link_fwd, sop->lc_pbm_linkdown_tx); 2576 rv = soc_link_fwd_set(unit, pbm_link_fwd); 2577 if (BCM_FAILURE(rv)) { 2578 LOG_ERROR(BSL_LS_BCM_LINK, 2579 (BSL_META_U(unit, 2580 "Port %s: soc_link_fwd_set failed: %s\n"), 2581 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2582 return rv; 2583 } 2584 } 2585 2586 if (((cur_failed && new_failed)) || 2587 ((cur_link) && (new_link) && (cur_fault == new_fault)) || 2588 ((!cur_link) && (!new_link))) { 2589 /* No change */ 2590 return BCM_E_NONE; 2591 } 2592 2593 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 2594 /* Because of actual time of link partner port up transition, 2595 * it is possible we may receive delayed Remote Fault signal from link 2596 * partner. Assuming this situation, added internal status for each port 2597 * to ignore this delayed Remote Fault signal condition. 2598 * 2599 * When new_link is detected, set status LC_LINK_UP_STATE_START. 2600 * 2601 * In the next cycle, 2602 * if cur_link, new_link, cur_fault is true, but new_fault is false, 2603 * then move to LC_LINK_UP_STATE_DONE. 2604 * (Assuming this means link up is stable and didn't receive Remote Fault.) 2605 * 2606 * In the next cycle, 2607 * if cur_link, new_link is true, and state is LC_LINK_UP_STATE_DONE, 2608 * but detects new_fault, that is unpreferrable remote fault. 2609 * For all other cases, set state back to default LC_LINK_UP_STATE_NONE. 2610 */ 2611 if ((cur_link) && (new_link) && (!new_fault) && (cur_fault) && 2612 (lc->lc_up_proc_state[port] == LC_LINK_UP_STATE_START)) { 2613 lc->lc_up_proc_state[port] = LC_LINK_UP_STATE_DONE; 2614 } else if ((cur_link) && (new_link) && (new_fault) && (!cur_fault) && 2615 (lc->lc_up_proc_state[port] == LC_LINK_UP_STATE_DONE)) { 2616 /* port link up is stable in the previous cycle, but detected new_fault. 2617 So ignore this remote fault */ 2618 lc->lc_up_proc_state[port] = LC_LINK_UP_STATE_NONE; 2619 LOG_VERBOSE(BSL_LS_BCM_LINK, (BSL_META_U(unit, 2620 "Unit %d, Port %s: ignored new fault\n"), 2621 unit, SOC_PORT_NAME(unit, port))); 2622 return BCM_E_NONE; 2623 } else { 2624 lc->lc_up_proc_state[port] = LC_LINK_UP_STATE_NONE; 2625 } 2626 #endif 2627 2628 #if defined(BCM_LINK_CHANGE_BENCHMARK) 2629 time_start = sal_time_usecs(); 2630 #endif /* BCM_LINK_CHANGE_BENCHMARK */ 2631 2632 /* In failed state, no link processing is performed until 2633 the state is cleared */ 2634 if (!new_failed) { 2635 /* 2636 * If disabling, stop ingresses from sending any more traffic to 2637 * this port. 2638 */ 2639 if (!new_link) { 2640 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link, port); 2641 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_remote_fault, port); 2642 #if defined(BCM_KATANA2_SUPPORT) 2643 if (soc_feature(unit, soc_feature_linkphy_coe) && 2644 SOC_INFO(unit).linkphy_enabled) { 2645 if (IS_LP_PORT(unit, port)) { 2646 #if defined BCM_METROLITE_SUPPORT 2647 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 2648 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 2649 SOC_PBMP_PORT_REMOVE 2650 (sop->lc_pbm_link, pp_port); 2651 } 2652 } else 2653 #endif 2654 { 2655 for (pp_port = 0; 2656 pp_port < SOC_INFO(unit).port_num_subport[port]; 2657 pp_port++) { 2658 SOC_PBMP_PORT_REMOVE 2659 (sop->lc_pbm_link, 2660 pp_port + SOC_INFO(unit).port_subport_base[port]); 2661 } 2662 } 2663 } 2664 } 2665 if (soc_feature(unit, soc_feature_subtag_coe) && 2666 SOC_INFO(unit).subtag_enabled) { 2667 if (SOC_PBMP_MEMBER(SOC_INFO(unit).subtag_allowed_pbm, port)) { 2668 #if defined BCM_METROLITE_SUPPORT 2669 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 2670 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 2671 SOC_PBMP_PORT_REMOVE 2672 (sop->lc_pbm_link, pp_port); 2673 } 2674 } else 2675 #endif 2676 { 2677 for (pp_port = 0; 2678 pp_port < SOC_INFO(unit).port_num_subport[port]; 2679 pp_port++) { 2680 SOC_PBMP_PORT_REMOVE 2681 (sop->lc_pbm_link, 2682 pp_port + SOC_INFO(unit).port_subport_base[port]); 2683 } 2684 } 2685 } 2686 } 2687 #endif /* BCM_KATANA2_SUPPORT */ 2688 SOC_PBMP_ASSIGN(pbm_link_fwd, sop->lc_pbm_link); 2689 SOC_PBMP_REMOVE(pbm_link_fwd, sop->lc_pbm_remote_fault); 2690 /* 2691 * If new_link down, Add linkdown_tx pbmp to forward pbmp 2692 * in order to add linkdown_tx pbmp to EPC_LINK_BMAPm 2693 */ 2694 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT) 2695 if (soc_feature(unit, soc_feature_epc_linkflap_recover)) { 2696 bcm_port_info_t port_info; 2697 bcm_port_info_t_init(&port_info); 2698 port_info.linkstatus = BCM_PORT_LINK_STATUS_DOWN; 2699 _bcm_stk_modport_map_linkscan_handler(unit, port, &port_info); 2700 } 2701 #endif /* #(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT) */ 2702 2703 SOC_PBMP_OR(pbm_link_fwd, sop->lc_pbm_linkdown_tx); 2704 rv = soc_link_fwd_set(unit, pbm_link_fwd); 2705 2706 if (BCM_FAILURE(rv)) { 2707 LOG_ERROR(BSL_LS_BCM_LINK, 2708 (BSL_META_U(unit, 2709 "Port %s: soc_link_fwd_set failed: %s\n"), 2710 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2711 return rv; 2712 } 2713 #if defined(BCM_HAWKEYE_SUPPORT) 2714 if (SOC_IS_HAWKEYE(unit)) { 2715 /* coverity[result_independent_of_operands] */ 2716 SOC_IF_ERROR_RETURN 2717 (READ_CMIC_TX_PAUSE_CAPABILITYr(unit, &mac_data)); 2718 if (soc_feature(unit, soc_feature_hawkeye_a0_war)) { 2719 if (((port - 1) >= 32) || (port < 1)) { 2720 return BCM_E_INTERNAL; 2721 } 2722 mac_data &= ~(1 << (port-1)); 2723 } else { 2724 if (port >= 32) { 2725 return BCM_E_INTERNAL; 2726 } 2727 mac_data &= ~(1 << port); 2728 } 2729 /* coverity[result_independent_of_operands] */ 2730 SOC_IF_ERROR_RETURN 2731 (WRITE_CMIC_TX_PAUSE_CAPABILITYr(unit, mac_data)); 2732 2733 /* coverity[result_independent_of_operands] */ 2734 SOC_IF_ERROR_RETURN 2735 (READ_CMIC_RX_PAUSE_CAPABILITYr(unit, &mac_data)); 2736 if (soc_feature(unit, soc_feature_hawkeye_a0_war)) { 2737 if (((port - 1) >= 32) || (port < 1)) { 2738 return BCM_E_INTERNAL; 2739 } 2740 mac_data &= ~(1 << (port-1)); 2741 } else { 2742 if (port >= 32) { 2743 return BCM_E_INTERNAL; 2744 } 2745 mac_data &= ~(1 << port); 2746 } 2747 2748 /* coverity[result_independent_of_operands] */ 2749 SOC_IF_ERROR_RETURN 2750 (WRITE_CMIC_RX_PAUSE_CAPABILITYr(unit, mac_data)); 2751 } 2752 #endif /* BCM_HAWKEYE_SUPPORT */ 2753 2754 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 2755 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 2756 if (SOC_IS_HURRICANE (unit) || SOC_IS_TD_TT (unit) || 2757 SOC_IS_HAWKEYE (unit) || SOC_IS_KATANAX(unit) || 2758 SOC_IS_TRIUMPH3(unit) || SOC_IS_HURRICANE2(unit) || 2759 SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 2760 SOC_IS_GREYHOUND2(unit)) { 2761 /* EEE standard compliance Work Around:*/ 2762 if(soc_feature(unit, soc_feature_eee)) { 2763 /* Check if Native EEE is supported in MAC */ 2764 if (SOC_USE_PORTCTRL(unit)) { 2765 bcmi_esw_portctrl_eee_enable_set(unit, port, 0); 2766 } 2767 else { 2768 _bcm_port_info_access(unit, port, &port_info); 2769 if (MAC_CONTROL_GET(port_info->p_mac, unit, port, 2770 SOC_MAC_CONTROL_EEE_ENABLE, 2771 &mac_val) == BCM_E_NONE) { 2772 /* When port link goes down, disable EEE in MAC. */ 2773 PORT_LOCK(unit); 2774 MAC_CONTROL_SET(port_info->p_mac, 2775 unit, port, 2776 SOC_MAC_CONTROL_EEE_ENABLE, 0); 2777 PORT_UNLOCK(unit); 2778 } 2779 } 2780 } 2781 } 2782 #endif /* BCM_HURRICANE_SUPPORT || BCM_HAWKEYE_SUPORT || BCM_TRIDENT_SUPPORT */ 2783 } 2784 2785 /* Program MACs 2786 * (only if port is not forced, and link state changed, and 2787 * not marked as linkdown tx when link going down) 2788 */ 2789 2790 if (!SOC_PBMP_MEMBER(sop->lc_pbm_override_ports, port) && 2791 (cur_link != new_link) && 2792 (!(SOC_PBMP_MEMBER(sop->lc_pbm_linkdown_tx, port) && 2793 !new_link))) { 2794 if (!SOC_PBMP_MEMBER(sop->lc_pbm_fc, port)) { 2795 rv = bcm_esw_port_update(unit, port, new_link); 2796 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 2797 if (new_link) { 2798 lc->lc_up_proc_state[port] = LC_LINK_UP_STATE_START; 2799 } 2800 #endif 2801 if (BCM_FAILURE(rv)) { 2802 LOG_ERROR(BSL_LS_BCM_LINK, 2803 (BSL_META_U(unit, 2804 "Port %s: bcm_port_update failed: %s\n"), 2805 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2806 return rv; 2807 } 2808 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_APOLLO_SUPPORT) || \ 2809 defined(BCM_VALKYRIE2_SUPPORT) 2810 /* Enable clock recovery */ 2811 if (soc_feature(unit, soc_feature_gmii_clkout) && new_link && 2812 !SOC_IS_ENDURO(unit) && !SOC_IS_HURRICANEX(unit) && 2813 !SOC_IS_TRIUMPH3(unit) && !SOC_IS_GREYHOUND(unit) && 2814 !SOC_IS_KATANA2(unit) && !SOC_IS_GREYHOUND2(unit)) { 2815 uint32 val = 0, pvalr = 0, pval = 0; 2816 2817 SOC_IF_ERROR_RETURN 2818 (READ_EGR_L1_CLK_RECOVERY_CTRLr(unit, &val)); 2819 pvalr = soc_reg_field_get(unit, EGR_L1_CLK_RECOVERY_CTRLr, 2820 val, PRI_PORT_SELf); 2821 pval = SOC_INFO(unit).port_l2p_mapping[port]; 2822 if (pvalr && (pvalr == pval) && 2823 SOC_REG_IS_VALID(unit, CMIC_MISC_CONTROLr) && 2824 soc_reg_field_valid(unit, CMIC_MISC_CONTROLr, CLK_RECOVERY_PRI_RESETf)) { 2825 /* Toggle primary reset */ 2826 SOC_IF_ERROR_RETURN 2827 (soc_reg_field32_modify(unit, CMIC_MISC_CONTROLr, 2828 REG_PORT_ANY, 2829 CLK_RECOVERY_PRI_RESETf, 2830 0)); 2831 SOC_IF_ERROR_RETURN 2832 (soc_reg_field32_modify(unit, CMIC_MISC_CONTROLr, 2833 REG_PORT_ANY, 2834 CLK_RECOVERY_PRI_RESETf, 2835 1)); 2836 } 2837 pvalr = soc_reg_field_get(unit, EGR_L1_CLK_RECOVERY_CTRLr, 2838 val, BKUP_PORT_SELf); 2839 if (pvalr && (pvalr == pval) && 2840 SOC_REG_IS_VALID(unit, CMIC_MISC_CONTROLr) && 2841 soc_reg_field_valid(unit, CMIC_MISC_CONTROLr, CLK_RECOVERY_BKUP_RESETf)) { 2842 /* Toggle backup reset */ 2843 SOC_IF_ERROR_RETURN 2844 (soc_reg_field32_modify(unit, CMIC_MISC_CONTROLr, 2845 REG_PORT_ANY, 2846 CLK_RECOVERY_BKUP_RESETf, 2847 0)); 2848 SOC_IF_ERROR_RETURN 2849 (soc_reg_field32_modify(unit, CMIC_MISC_CONTROLr, 2850 REG_PORT_ANY, 2851 CLK_RECOVERY_BKUP_RESETf, 2852 1)); 2853 } 2854 } 2855 #endif /* TRIUMPH2, APOLLO, VALKYRIE2 */ 2856 } 2857 2858 #if defined(BCM_HERCULES15_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT) 2859 /* Physical link completed, now we can check fault */ 2860 if ((soc_feature(unit, soc_feature_bigmac_fault_stat) || 2861 soc_feature(unit, soc_feature_xlmac)) && 2862 new_link) { 2863 /* 2864 * Now our rules are: 2865 * 1) The chip supports it: feature check 2866 * 2) The link state is coming from the PHY: not override. 2867 * 3) The physical link is now up, so can check fault. 2868 */ 2869 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 2870 new_fault = FALSE; 2871 #endif 2872 rv = _bcm_esw_link_fault_get(unit, port, &new_fault); 2873 if (BCM_FAILURE(rv)) { 2874 LOG_ERROR(BSL_LS_BCM_LINK, 2875 (BSL_META_U(unit, 2876 "Port %s: Failed to read fault status: %s\n"), 2877 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2878 return rv; 2879 } 2880 } 2881 #endif /* HERC15, FIREBOLT */ 2882 } 2883 2884 /* 2885 * If enabling, allow traffic to go to this port. 2886 */ 2887 if (new_link) { 2888 2889 SOC_PBMP_PORT_ADD(sop->lc_pbm_link, port); 2890 #if defined(BCM_KATANA2_SUPPORT) 2891 if (soc_feature(unit, soc_feature_linkphy_coe) && 2892 SOC_INFO(unit).linkphy_enabled) { 2893 if (IS_LP_PORT(unit, port)) { 2894 #if defined BCM_METROLITE_SUPPORT 2895 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 2896 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 2897 SOC_PBMP_PORT_ADD 2898 (sop->lc_pbm_link, pp_port); 2899 } 2900 } else 2901 #endif 2902 { 2903 for (pp_port = 0; 2904 pp_port < SOC_INFO(unit).port_num_subport[port]; 2905 pp_port++) { 2906 SOC_PBMP_PORT_ADD 2907 (sop->lc_pbm_link, 2908 pp_port + SOC_INFO(unit).port_subport_base[port]); 2909 } 2910 } 2911 } 2912 } 2913 if (soc_feature(unit, soc_feature_subtag_coe) && 2914 SOC_INFO(unit).subtag_enabled) { 2915 if (IS_SUBTAG_PORT(unit, port)) { 2916 #if defined BCM_METROLITE_SUPPORT 2917 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 2918 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 2919 SOC_PBMP_PORT_ADD 2920 (sop->lc_pbm_link, pp_port); 2921 } 2922 } else 2923 #endif 2924 { 2925 for (pp_port = 0; 2926 pp_port < SOC_INFO(unit).port_num_subport[port]; 2927 pp_port++) { 2928 SOC_PBMP_PORT_ADD 2929 (sop->lc_pbm_link, 2930 pp_port + SOC_INFO(unit).port_subport_base[port]); 2931 } 2932 } 2933 } 2934 } 2935 #endif /* BCM_KATANA2_SUPPORT */ 2936 SOC_PBMP_ASSIGN(pbm_link_fwd, sop->lc_pbm_link); 2937 2938 if (!new_fault) { 2939 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_remote_fault, port); 2940 #if defined(BCM_TRX_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) 2941 if (SOC_PBMP_MEMBER(sop->lc_pbm_failed_clear, port)) { 2942 /* Previously failed port completing recovery */ 2943 PORT_LOCK(unit); 2944 rv = _bcm_esw_link_failover_link_up(unit, port); 2945 PORT_UNLOCK(unit); 2946 if (BCM_FAILURE(rv)) { 2947 LOG_ERROR(BSL_LS_BCM_LINK, 2948 (BSL_META_U(unit, 2949 "Port %s: failed link recovery " 2950 "unsuccessful: %s\n"), 2951 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2952 return rv; 2953 } 2954 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_failed_clear, port); 2955 } 2956 #endif /* BCM_TRX_SUPPORT || BCM_BRADLEY_SUPPORT */ 2957 } else { 2958 SOC_PBMP_PORT_ADD(sop->lc_pbm_remote_fault, port); 2959 } 2960 2961 SOC_PBMP_REMOVE(pbm_link_fwd, sop->lc_pbm_remote_fault); 2962 /* 2963 * If new_link up, Add linkdown_tx pbmp to forward pbmp 2964 * in order to add linkdown_tx pbmp to EPC_LINK_BMAPm 2965 */ 2966 SOC_PBMP_OR(pbm_link_fwd, sop->lc_pbm_linkdown_tx); 2967 rv = soc_link_fwd_set(unit, pbm_link_fwd); 2968 2969 if (BCM_FAILURE(rv)) { 2970 LOG_ERROR(BSL_LS_BCM_LINK, 2971 (BSL_META_U(unit, 2972 "Port %s: soc_link_fwd_set failed: %s\n"), 2973 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2974 return rv; 2975 } 2976 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT) 2977 /* Timing and Execution sequence sometimes might need to enforce 2978 * a port update even though only a fault state has changed. 2979 * This can happen in the case where a Disable followed by an enable 2980 * event is missed by Linkscan and where new and current links are up. 2981 * This will cause the MAC and PHY to be out of sync unless an update 2982 * is performed 2983 */ 2984 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TITAN2PLUS(unit)) 2985 || SOC_IS_TRIDENT(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2986 if ((cur_link == new_link) && (cur_fault != new_fault) 2987 && (!new_fault)) { 2988 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 2989 if (lc->lc_up_proc_state[port] == LC_LINK_UP_STATE_NONE) { 2990 #endif 2991 rv = bcm_esw_port_update(unit, port, new_link); 2992 if (BCM_FAILURE(rv)) { 2993 LOG_ERROR(BSL_LS_BCM_LINK, 2994 (BSL_META_U(unit, 2995 "Port %s: bcm_port_update failed: %s\n"), 2996 SOC_PORT_NAME(unit, port), bcm_errmsg(rv))); 2997 return rv; 2998 } 2999 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 3000 } 3001 #endif 3002 } 3003 } 3004 #endif 3005 3006 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 3007 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 3008 if (new_fault) { 3009 if (soc_feature(unit, soc_feature_xmac)) { 3010 _bcm_port_info_access(unit, port, &port_info); 3011 PORT_LOCK(unit); 3012 MAC_ENABLE_SET(port_info->p_mac, unit, port, FALSE); 3013 MAC_ENABLE_SET(port_info->p_mac, unit, port, TRUE); 3014 PORT_UNLOCK(unit); 3015 } 3016 } 3017 #endif /* BCM_HURRICANE_SUPPORT || BCM_TRIDENT_SUPPORT || BCM_HAWKEYE_SUPPORT */ 3018 } 3019 3020 #if defined(BCM_HAWKEYE_SUPPORT) 3021 if (SOC_IS_HAWKEYE(unit) && new_link) { 3022 BCM_IF_ERROR_RETURN(_hawkeye_new_link_check(unit,port)); 3023 } 3024 #endif /* BCM_HAWKEYE_SUPPORT */ 3025 3026 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) || \ 3027 defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 3028 if (SOC_IS_HURRICANE (unit) || SOC_IS_TD_TT (unit) || 3029 SOC_IS_HAWKEYE (unit) || SOC_IS_KATANAX(unit) || 3030 SOC_IS_TRIUMPH3(unit) || SOC_IS_HURRICANE2(unit) || 3031 SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 3032 SOC_IS_GREYHOUND2(unit)) { 3033 /* EEE standard compliance Work Around:*/ 3034 if(soc_feature(unit, soc_feature_eee)) { 3035 phy_ctrl_t *ext_pc; 3036 uint32 phy_val; 3037 3038 #ifdef PORTMOD_SUPPORT 3039 /* Call Port Control module */ 3040 if (SOC_USE_PORTCTRL(unit)) { 3041 rv = bcmi_esw_portctrl_eee_enable_get(unit, port, &mac_val); 3042 3043 if (BCM_SUCCESS(rv)) { 3044 phymod_phy_access_t phy_access[1+MAX_PHYN]; 3045 int nof_phys = 0; 3046 portmod_access_get_params_t params; 3047 int is_most_ext; 3048 3049 BCM_IF_ERROR_RETURN 3050 (portmod_access_get_params_t_init(unit, ¶ms)); 3051 3052 params.phyn = 0; /* Only find serdes */ 3053 BCM_IF_ERROR_RETURN 3054 (portmod_port_phy_lane_access_get( 3055 unit, port, ¶ms, (1+MAX_PHYN), phy_access, 3056 &nof_phys,&is_most_ext)); 3057 3058 /* If serdes is the outmost phy, then there is no ext phy */ 3059 if (is_most_ext && 3060 bcmi_esw_portctrl_phy_control_get( 3061 unit, port, 3062 BCM_PORT_PHY_CONTROL_EEE, 3063 &phy_val) != SOC_E_UNAVAIL) { 3064 lc->lc_up_time[port-1] = sal_time(); 3065 } else if (new_link && 3066 (bcm_esw_port_ability_remote_get 3067 (unit, port, &remote_advert) == SOC_E_NONE)) { 3068 /* Maintain link up timer. 3069 * EEE WA : delay EEE enable in MAC by 1sec once 3070 * the link is up 3071 */ 3072 LOG_VERBOSE(BSL_LS_BCM_LINK, 3073 (BSL_META_U(unit, 3074 "u=%d p=%d remote_advert.eee = %d\n"), 3075 unit, port, remote_advert.eee ? 1 : 0)); 3076 lc->lc_up_time[port-1] = (remote_advert.eee) ? 3077 sal_time() : -1; 3078 } else { 3079 lc->lc_up_time[port-1] = -1; 3080 } 3081 } else { 3082 lc->lc_up_time[port-1] = -1; 3083 } 3084 } else 3085 #endif 3086 { 3087 ext_pc = EXT_PHY_SW_STATE(unit, port); 3088 /* Check if Native EEE is supported in MAC */ 3089 _bcm_port_info_access(unit, port, &port_info); 3090 if (MAC_CONTROL_GET(port_info->p_mac, unit, port, 3091 SOC_MAC_CONTROL_EEE_ENABLE, 3092 &mac_val) == BCM_E_NONE) { 3093 PORT_LOCK(unit); 3094 if ((NULL == ext_pc) && 3095 (soc_phyctrl_control_get(unit, port, 3096 BCM_PORT_PHY_CONTROL_EEE, 3097 &phy_val) != SOC_E_UNAVAIL)) { 3098 /* 3099 * If devices which have serDes supporting Native EEE but without external 3100 * PHY attached to the port, we enable Native EEE on mac. 3101 */ 3102 lc->lc_up_time[port-1] = sal_time(); 3103 } else if (new_link && 3104 (bcm_esw_port_ability_remote_get 3105 (unit, port, &remote_advert) == SOC_E_NONE)) { 3106 /* Maintain link up timer. 3107 * EEE WA : delay EEE enable in MAC by 1sec once 3108 * the link is up 3109 */ 3110 LOG_VERBOSE(BSL_LS_BCM_LINK, 3111 (BSL_META_U(unit, 3112 "u=%d p=%d remote_advert.eee = %d\n"), 3113 unit, port, remote_advert.eee ? 1 : 0)); 3114 lc->lc_up_time[port-1] = (remote_advert.eee) ? 3115 sal_time() : -1; 3116 } else { 3117 lc->lc_up_time[port-1] = -1; 3118 } 3119 PORT_UNLOCK(unit); 3120 } 3121 } 3122 } 3123 } 3124 #endif /* BCM_HURRICANE_SUPPORT || BCM_HAWKEYE_SUPORT || BCM_TRIDENT_SUPPORT */ 3125 } 3126 3127 /* 3128 * Call registered handlers with complete link info. 3129 * Display link status message, if requested. 3130 * 3131 * In case link status changed again for bcm_port_info_get, 3132 * overwrite the linkstatus field with logical_link. This ensures 3133 * the handler is presented with a consistent alternating 3134 * sequence of link up/down. 3135 */ 3136 3137 if ((flags & _BCM_LINK_STATUS_NO_CALLBACK) == 0) { 3138 notify = (cur_failed != new_failed) || /* Change of failed state */ 3139 (cur_link && new_link) || /* => cur_fault != new_fault */ 3140 (!new_link && !cur_fault) || /* Port down w/o prior fault */ 3141 (new_link && !new_fault); /* Port up w/o fault */ 3142 } 3143 3144 logical_link = new_failed ? BCM_PORT_LINK_STATUS_FAILED : 3145 (new_fault ? BCM_PORT_LINK_STATUS_REMOTE_FAULT : 3146 (new_link ? BCM_PORT_LINK_STATUS_UP : 3147 BCM_PORT_LINK_STATUS_DOWN)); 3148 3149 LOG_VERBOSE(BSL_LS_BCM_LINK, 3150 (BSL_META_U(unit, 3151 "Unit %d, Port %s: Link: Current %s, New %s\n" 3152 "\tFault: Current %s, New %s\n" 3153 "\tFailed: Current %s, New %s\n" 3154 "\tNotify %s, Logical link %s\n"), 3155 unit, 3156 SOC_PORT_NAME(unit, port), 3157 cur_link ? "up" : "down", 3158 new_link ? "up" : "down", 3159 cur_fault ? "yes" : "no", 3160 new_fault ? "yes" : "no", 3161 cur_failed ? "yes" : "no", 3162 new_failed ? "yes" : "no", 3163 notify ? "yes" : "no", 3164 ll_status[logical_link])); 3165 3166 /* bcm_port_info_t info initialized */ 3167 bcm_port_info_t_init(&info); 3168 3169 if (notify) { 3170 if (!new_link) { 3171 BCM_IF_ERROR_RETURN 3172 (_bcm_esw_link_port_info_skip_get(unit, port, &info_skip)); 3173 } 3174 if (!info_skip) { 3175 rv = bcm_esw_port_info_get(unit, port, &info); 3176 3177 if (BCM_FAILURE(rv)) { 3178 LOG_ERROR(BSL_LS_BCM_LINK, 3179 (BSL_META_U(unit, 3180 "Port %s: bcm_port_info_get failed: %s\n"), 3181 SOC_PORT_NAME(unit, port), 3182 bcm_errmsg(rv))); 3183 return rv; 3184 } 3185 3186 if ((info.speed == 0) && (new_link == TRUE)) { 3187 LOG_WARN(BSL_LS_BCM_LINK, 3188 (BSL_META_U(unit, 3189 "Port %s: Link Up with Speed 0M!\n"), 3190 SOC_PORT_NAME(unit, port))); 3191 } 3192 3193 if (soc_feature(unit, soc_feature_asf)) { 3194 asf_link = 3195 ((logical_link != BCM_PORT_LINK_STATUS_DOWN) && 3196 (logical_link != BCM_PORT_LINK_STATUS_REMOTE_FAULT)); 3197 rv = _bcm_esw_linkscan_update_asf(unit, port, asf_link, 3198 info.speed, info.duplex); 3199 if (BCM_FAILURE(rv)) { 3200 LOG_ERROR(BSL_LS_BCM_LINK, 3201 (BSL_META_U(unit, 3202 "Port %s: linkscan ASF update failed: %s\n"), 3203 SOC_PORT_NAME(unit, port), 3204 bcm_errmsg(rv))); 3205 return rv; 3206 } 3207 } 3208 } else { 3209 info.linkstatus = BCM_PORT_LINK_STATUS_DOWN; 3210 } 3211 } 3212 3213 #if defined(BCM_LINK_CHANGE_BENCHMARK) 3214 time_end = sal_time_usecs(); 3215 #endif /* BCM_LINK_CHANGE_BENCHMARK */ 3216 3217 if (cur_failed != new_failed) { 3218 if (new_failed) { 3219 LOG_INFO(BSL_LS_BCM_LINK, 3220 (BSL_META_U(unit, 3221 "Port %s: failed\n"), 3222 SOC_PORT_NAME(unit, port))); 3223 } else { 3224 LOG_INFO(BSL_LS_BCM_LINK, 3225 (BSL_META_U(unit, 3226 "Port %s: failed state cleared\n"), 3227 SOC_PORT_NAME(unit, port))); 3228 } 3229 } 3230 3231 if (cur_link != new_link) { 3232 if (new_link) { 3233 if (hw_link_port) { 3234 LOG_INFO(BSL_LS_BCM_LINK, 3235 (BSL_META_U(unit, 3236 "Port %s: link up took %d usecs since last " 3237 "HW interrupt\n"), 3238 SOC_PORT_NAME(unit, port), 3239 SAL_USECS_SUB(sal_time_usecs(), 3240 last_time_hw_link_up[unit]))); 3241 } 3242 LOG_INFO(BSL_LS_BCM_LINK, 3243 (BSL_META_U(unit, 3244 "Port %s: link %s (%dMb %s %s)\n"), 3245 SOC_PORT_NAME(unit, port), 3246 ll_status[logical_link], 3247 info.speed, 3248 info.duplex ? "Full Duplex" : "Half Duplex", 3249 PHY_FIBER_MODE(unit, port) ? 3250 "Fiber" : "Copper")); 3251 #if defined(BCM_LINK_CHANGE_BENCHMARK) 3252 LOG_INFO(BSL_LS_BCM_LINK, 3253 (BSL_META_U(unit, 3254 "Link %s processing took %d usecs\n"), 3255 ll_status[logical_link], 3256 SAL_USECS_SUB(time_end, time_start))); 3257 #endif /* BCM_LINK_CHANGE_BENCHMARK */ 3258 #ifdef BCM_KATANA2_SUPPORT 3259 if (SOC_IS_KATANA2(unit) && (!SOC_IS_SABER2(unit))) { 3260 LOG_INFO(BSL_LS_BCM_LINK, 3261 (BSL_META_U(unit, 3262 "p=%d Applied DOWNSIZER \n"), port)); 3263 /* To recover from clock glitch(not always), Serdes init sequence 3264 requires write to reset frequency downsizer logic in MXQPORT. */ 3265 SOC_IF_ERROR_RETURN(READ_XPORT_MODE_REGr(unit, port, &rval)); 3266 bypass = soc_reg_field_get(unit, XPORT_MODE_REGr, rval, BYPASS_DOWNSIZERf); 3267 wc_10g_21g_sel = soc_reg_field_get(unit, XPORT_MODE_REGr, rval, WC_10G_21G_SELf); 3268 if ((bypass == 0) && (wc_10g_21g_sel == 0)) { 3269 soc_reg_field_set(unit, XPORT_MODE_REGr, &rval, SW_RESET_DOWNSIZERf , 1); 3270 SOC_IF_ERROR_RETURN(WRITE_XPORT_MODE_REGr(unit, port, rval)); 3271 soc_reg_field_set(unit, XPORT_MODE_REGr, &rval, SW_RESET_DOWNSIZERf , 0); 3272 SOC_IF_ERROR_RETURN(WRITE_XPORT_MODE_REGr(unit, port, rval)); 3273 } 3274 soc_katana2_mmu_port_enable_set(unit, port, 1); 3275 } 3276 #endif 3277 } else { 3278 LOG_INFO(BSL_LS_BCM_LINK, 3279 (BSL_META_U(unit, 3280 "Port %s: link down\n"), 3281 SOC_PORT_NAME(unit, port))); 3282 3283 3284 #if defined(BCM_LINK_CHANGE_BENCHMARK) 3285 LOG_INFO(BSL_LS_BCM_LINK, 3286 (BSL_META_U(unit, 3287 "Link down processing took %d usecs\n"), 3288 SAL_USECS_SUB(time_end, time_start))); 3289 #endif /* BCM_LINK_CHANGE_BENCHMARK */ 3290 } 3291 } 3292 3293 if (new_fault) { 3294 LOG_INFO(BSL_LS_BCM_LINK, 3295 (BSL_META_U(unit, 3296 "Port %s: fault detected\n"), 3297 SOC_PORT_NAME(unit, port))); 3298 } else if (cur_fault) { 3299 LOG_INFO(BSL_LS_BCM_LINK, 3300 (BSL_META_U(unit, 3301 "Port %s: fault cleared\n"), 3302 SOC_PORT_NAME(unit, port))); 3303 } 3304 3305 if (notify) { 3306 LOG_VERBOSE(BSL_LS_BCM_LINK, 3307 (BSL_META_U(unit, 3308 "Unit %d, Port %s: logical link notification - %s\n"), 3309 unit, SOC_PORT_NAME(unit, port), 3310 ll_status[logical_link])); 3311 info.linkstatus = logical_link; 3312 #if defined(INCLUDE_UC_ULINK) 3313 soc_cmic_uc_link_change_flag = 1; 3314 #endif 3315 BCM_API_XLATE_PORT_P2A(unit, &port); 3316 3317 for (lh = lc->lc_handler; lh; lh = lh_next) { 3318 /* 3319 * save the next linkscan handler first, in case current handler 3320 * unregister itself inside the handler function 3321 */ 3322 lh_next = lh->lh_next; 3323 /* 3324 * The called function must not invoke any API that may result in 3325 * a deadlock. 3326 */ 3327 lh->lh_f(unit, port, &info); 3328 } 3329 } 3330 #ifdef BCM_WARM_BOOT_SUPPORT 3331 SOC_CONTROL_LOCK(unit); 3332 SOC_CONTROL(unit)->scache_dirty = 1; 3333 SOC_CONTROL_UNLOCK(unit); 3334 #endif 3335 3336 return BCM_E_NONE; 3337 } 3338 3339 3340 3341 /* 3342 * Function: 3343 * _bcm_esw_linkscan_update 3344 * Purpose: 3345 * Check for a change in link status on each link. If a change 3346 * is detected, call bcm_port_update to program the MACs for that 3347 * link, and call the list of registered handlers. 3348 * Parameters: 3349 * unit - StrataSwitch unit #. 3350 * pbm - bit map of ports to scan. 3351 * Returns: 3352 * Nothing. 3353 */ 3354 3355 STATIC void 3356 _bcm_esw_linkscan_update(int unit, uint32 flags, pbmp_t pbm) 3357 { 3358 soc_persist_t *sop = SOC_PERSIST(unit); 3359 ls_cntl_t *lc = link_control[unit]; 3360 pbmp_t save_link_change; 3361 int rv; 3362 bcm_port_t port; 3363 3364 #if defined(BCM_SABER2_SUPPORT) 3365 if(SOC_IS_SABER2(unit)){ 3366 int oamp_enable; 3367 (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable); 3368 /* Skip OAMP port for saber2 device */ 3369 if(oamp_enable) { 3370 SOC_PBMP_PORT_REMOVE(pbm, 3371 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 3372 } 3373 } 3374 #endif 3375 3376 /* 3377 * Suspend hardware link scan here to avoid overhead of pause/resume 3378 * on MDIO accesses. Ideally this would not be required if the source 3379 * of the interrupt is the signal from the internal Serdes but 3380 * we still need to do this due to work-arounds in phy drivers 3381 * where we need to rely on SW linkscan to detect link up. 3382 */ 3383 soc_linkscan_pause(unit); /* Suspend linkscan */ 3384 3385 PBMP_ITER(pbm, port) { 3386 ls_errstate_t *err; 3387 3388 LC_LOCK(unit); 3389 err = &lc->lc_error[port]; 3390 3391 /* Port could be removed by flexport operation, so check if port 3392 * still active again before updating link */ 3393 if (!SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit),port)) { 3394 err->wait = 0; 3395 err->count = 0; 3396 LC_UNLOCK(unit); 3397 continue; 3398 } 3399 3400 if (err->wait) { /* Port waiting in error state */ 3401 if (SAL_USECS_SUB(sal_time_usecs(), err->time) >= err->delay) { 3402 err->wait = 0; /* Exit error state */ 3403 err->count = 0; 3404 3405 LOG_ERROR(BSL_LS_BCM_LINK, 3406 (BSL_META_U(unit, 3407 "Port %s: restored\n"), 3408 SOC_PORT_NAME(unit, port))); 3409 } else { 3410 LC_UNLOCK(unit); 3411 continue; 3412 } 3413 } 3414 3415 save_link_change = sop->lc_pbm_link_change; 3416 3417 rv = _bcm_esw_linkscan_update_port(unit, flags, port); 3418 3419 if (BCM_FAILURE(rv)) { 3420 sop->lc_pbm_link_change = save_link_change; 3421 3422 if (++err->count >= err->limit && err->limit > 0) { 3423 /* Enter error state */ 3424 3425 LOG_ERROR(BSL_LS_BCM_LINK, 3426 (BSL_META_U(unit, 3427 "Port %s: temporarily removed from linkscan\n"), 3428 SOC_PORT_NAME(unit, port))); 3429 3430 err->time = sal_time_usecs(); 3431 err->wait = 1; 3432 } 3433 3434 #ifdef BCM_RCPU_SUPPORT 3435 if (SOC_IS_RCPU_ONLY(unit) && (0 == lc->lc_us)) { 3436 /* 3437 * Check if it's been stopped since it may take long time 3438 * for rcpu to scan all ports. 3439 */ 3440 LC_UNLOCK(unit); 3441 return; 3442 } 3443 #endif /* BCM_RCPU_SUPPORT */ 3444 } else if (err->count > 0) { 3445 err->count--; /* Reprieve */ 3446 } 3447 LC_UNLOCK(unit); 3448 } 3449 #if defined(INCLUDE_UC_ULINK) 3450 /* link change */ 3451 if(soc_feature(unit, soc_feature_uc_ulink) && 3452 (soc_cmic_uc_link_change_flag != 0)) { 3453 3454 rv = soc_cmic_uc_pkd_link_notify(unit); 3455 if (rv == SOC_E_NONE) { 3456 soc_cmic_uc_link_change_flag = 0; 3457 } 3458 } 3459 #endif 3460 soc_linkscan_continue(unit); /* Restart H/W link scan */ 3461 } 3462 3463 3464 /* 3465 * Function: 3466 * bcm_esw_linkscan_update 3467 * Purpose: 3468 * Check for a change in link status on each link. If a change 3469 * is detected, call bcm_port_update to program the MACs for that 3470 * link, and call the list of registered handlers. 3471 * Parameters: 3472 * unit - StrataSwitch unit #. 3473 * pbm - bit map of ports to scan. 3474 * Returns: 3475 * BCM_E_XXX. 3476 */ 3477 int 3478 bcm_esw_linkscan_update(int unit, bcm_pbmp_t pbm) 3479 { 3480 LC_CHECK_INIT(unit); 3481 3482 if (BCM_PBMP_IS_NULL(pbm)) { 3483 return BCM_E_NONE; 3484 } 3485 3486 _bcm_esw_linkscan_update(unit, 0 /*flags*/, pbm); 3487 3488 #ifdef BCM_WARM_BOOT_SUPPORT 3489 SOC_CONTROL_LOCK(unit); 3490 SOC_CONTROL(unit)->scache_dirty = 1; 3491 SOC_CONTROL_UNLOCK(unit); 3492 #endif 3493 3494 return BCM_E_NONE; 3495 } 3496 3497 /* 3498 * Function: 3499 * _bcm_esw_linkscan_hw_interrupt 3500 * Purpose: 3501 * Link scan interrupt handler if using CMIC_LINK_SCAN. 3502 * Parameters: 3503 * StrataSwitch unit # 3504 * Returns: 3505 * Nothing 3506 */ 3507 3508 STATIC void 3509 _bcm_esw_linkscan_hw_interrupt(int unit) 3510 { 3511 ls_cntl_t *lc = link_control[unit]; 3512 3513 if ((NULL != lc) && (NULL != lc->lc_sema)) { 3514 lc->lc_hw_change = 1; 3515 sal_sem_give(lc->lc_sema); 3516 } 3517 LOG_VERBOSE(BSL_LS_BCM_LINK, 3518 (BSL_META_U(unit, 3519 "Linkscan interrupt unit %d\n"), unit)); 3520 } 3521 3522 /* 3523 * Function: 3524 * bcm_link_change 3525 * Purpose: 3526 * Force a transient link down event to be recognized, 3527 * regardless of the current physical up/down state of the 3528 * port. This does not affect the physical link status. 3529 * Parameters: 3530 * unit - StrataSwitch Unit #. 3531 * pbm - Bitmap of ports to operate on. 3532 * Returns: 3533 * BCM_E_XXX 3534 */ 3535 3536 int 3537 bcm_esw_link_change(int unit, pbmp_t pbm) 3538 { 3539 soc_persist_t *sop = SOC_PERSIST(unit); 3540 ls_cntl_t *lc = link_control[unit]; 3541 3542 LC_CHECK_INIT(unit); 3543 3544 if (lc->lc_warm_boot) { 3545 /* Do not change link status when recovering from Warm Boot. */ 3546 return BCM_E_NONE; 3547 } 3548 3549 SOC_PBMP_AND(pbm, PBMP_PORT_ALL(unit)); 3550 3551 #ifdef BCM_RCPU_SUPPORT 3552 if (SOC_IS_RCPU_ONLY(unit) && SOC_PORT_VALID(unit, RCPU_PORT(unit))) { 3553 /* Do not update link status for rcpu port. */ 3554 SOC_PBMP_PORT_REMOVE(pbm, RCPU_PORT(unit)); 3555 } 3556 #endif /* BCM_RCPU_SUPPORT */ 3557 3558 LC_LOCK(unit); 3559 SOC_PBMP_OR(sop->lc_pbm_link_change, pbm); 3560 LC_UNLOCK(unit); 3561 3562 /* 3563 * Wake up master thread to notice changes - required if using hardware 3564 * link scanning. 3565 */ 3566 if (lc->lc_sema != NULL) { 3567 sal_sem_give(lc->lc_sema); 3568 } 3569 3570 #ifdef BCM_WARM_BOOT_SUPPORT 3571 SOC_CONTROL_LOCK(unit); 3572 SOC_CONTROL(unit)->scache_dirty = 1; 3573 SOC_CONTROL_UNLOCK(unit); 3574 #endif 3575 3576 return(BCM_E_NONE); 3577 } 3578 3579 /* 3580 * Function: 3581 * _bcm_esw_link_get 3582 * Purpose: 3583 * Return linkscan's current link status for the given port. 3584 * Parameters: 3585 * unit - StrataSwitch Unit #. 3586 * port - StrataSwitch physical port number. 3587 * link - (OUT) Current link status. 3588 * Returns: 3589 * BCM_E_NONE - Success 3590 * BCM_E_DISABLED - Port not being scanned. 3591 * Note: 3592 * This routine does not acquire the LC_LOCK, as it only reads a 3593 * snapshot of the link bitmaps. It also cannot hold the LC_LOCK 3594 * since it is called indirectly from the linkscan thread 3595 * when requesting port info. 3596 */ 3597 3598 int 3599 _bcm_esw_link_get(int unit, bcm_port_t port, int *link) 3600 { 3601 soc_persist_t *sop = SOC_PERSIST(unit); 3602 3603 if (SOC_PBMP_MEMBER(sop->lc_pbm_override_ports, port)) { 3604 *link = SOC_PBMP_MEMBER(sop->lc_pbm_override_link, port); 3605 return (SOC_E_NONE); 3606 } 3607 3608 BCM_IF_ERROR_RETURN 3609 (bcm_esw_linkscan_enable_port_get(unit, port)); 3610 3611 if (SOC_PBMP_MEMBER(sop->lc_pbm_failed, port)) { 3612 *link = BCM_PORT_LINK_STATUS_FAILED; 3613 } else { 3614 *link = (SOC_PBMP_MEMBER(sop->lc_pbm_link, port) && 3615 !SOC_PBMP_MEMBER(sop->lc_pbm_remote_fault, port)) ? 3616 BCM_PORT_LINK_STATUS_UP : BCM_PORT_LINK_STATUS_DOWN; 3617 } 3618 3619 return(BCM_E_NONE); 3620 } 3621 3622 /* 3623 * Function: 3624 * _bcm_esw_link_force 3625 * Purpose: 3626 * Set linkscan's current link status for a port. 3627 * Parameters: 3628 * unit - StrataSwitch Unit #. 3629 * flags - flags 3630 * port - StrataSwitch physical port number. 3631 * force - If TRUE, link status is forced to new link status. 3632 * If FALSE, link status is no longer forced. 3633 * link - New link status. 3634 * Returns: 3635 * BCM_E_NONE - Success 3636 * BCM_E_INIT - Not initialized. 3637 * Notes: 3638 * When a link is forced up or down, linkscan will stop scanning 3639 * that port and _bcm_link_get will always return the forced status. 3640 * This is used for purposes such as when a link is placed in MAC 3641 * loopback. If software forces a link up, it is responsible for 3642 * configuring that port. 3643 */ 3644 3645 int 3646 _bcm_esw_link_force(int unit, uint32 flags, bcm_port_t port, 3647 int force, int link) 3648 { 3649 soc_persist_t *sop = SOC_PERSIST(unit); 3650 ls_cntl_t *lc = link_control[unit]; 3651 pbmp_t pbm; 3652 3653 LC_CHECK_INIT(unit); 3654 3655 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 3656 return BCM_E_PORT; 3657 } 3658 3659 LC_LOCK(unit); 3660 3661 if (force) { 3662 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_override_link, port); 3663 if (link) { 3664 if (lc->lc_warm_boot) { 3665 /* Don't update ports when recovering from Warm Boot. */ 3666 SOC_PBMP_PORT_ADD(sop->lc_pbm_link, port); 3667 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link_change, port); 3668 } 3669 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_link, port); 3670 } 3671 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_ports, port); 3672 } else { 3673 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_override_ports, port); 3674 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_override_link, port); 3675 3676 /* Don't set link change (link down) if port is only on 3677 hardware linkscan. This is because a hardware interrupt 3678 may never come for a port that is currently up. */ 3679 if (!(SOC_PBMP_MEMBER(lc->lc_pbm_hw, port) && 3680 !SOC_PBMP_MEMBER(lc->lc_pbm_sw, port))) { 3681 SOC_PBMP_PORT_ADD(sop->lc_pbm_link_change, port); 3682 } 3683 } 3684 3685 /* 3686 * Force immediate update to just this port - this allows loopback 3687 * forces to take effect immediately. 3688 */ 3689 SOC_PBMP_CLEAR(pbm); 3690 SOC_PBMP_PORT_ADD(pbm, port); 3691 _bcm_esw_linkscan_update(unit, flags, pbm); 3692 3693 LC_UNLOCK(unit); 3694 3695 /* 3696 * Wake up master thread to notice changes - required if using hardware 3697 * link scanning. 3698 */ 3699 if (lc->lc_sema != NULL) { 3700 sal_sem_give(lc->lc_sema); 3701 } 3702 3703 return(BCM_E_NONE); 3704 } 3705 3706 /* 3707 * Function: 3708 * _bcm_esw_link_down_tx_set 3709 * Purpose: 3710 * Mark port as linkdown TX ensuring MAC will transmit while 3711 * link is down 3712 * Parameters: 3713 * unit - StrataSwitch Unit #. 3714 * port - StrataSwitch physical port number. 3715 * enable - If TRUE, and link is down, enable MAC 3716 * If FALSE, and link is down, disable MAC 3717 * Returns: 3718 * BCM_E_NONE - Success 3719 * BCM_E_INIT - Not initialized. 3720 * Notes: 3721 */ 3722 3723 int 3724 _bcm_esw_link_down_tx_set(int unit, bcm_port_t port, int enable) 3725 { 3726 int rv = BCM_E_NONE; 3727 soc_persist_t *sop = SOC_PERSIST(unit); 3728 bcm_pbmp_t pbm; 3729 int port_enable; 3730 3731 LC_CHECK_INIT(unit); 3732 3733 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 3734 return BCM_E_PORT; 3735 } 3736 3737 BCM_IF_ERROR_RETURN( 3738 bcm_esw_port_enable_get(unit, port, &port_enable)); 3739 3740 LC_LOCK(unit); 3741 3742 if (enable) { 3743 SOC_PBMP_PORT_ADD(sop->lc_pbm_linkdown_tx, port); 3744 } else { 3745 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_linkdown_tx, port); 3746 } 3747 /* If port is enable and link is down, must enable MAC */ 3748 if (port_enable && !SOC_PBMP_MEMBER(sop->lc_pbm_link, port)) { 3749 rv = bcm_esw_port_update(unit, port, enable); 3750 } 3751 3752 LC_UNLOCK(unit); 3753 3754 if (BCM_SUCCESS(rv) && !SAL_BOOT_SIMULATION) { 3755 SOC_PBMP_CLEAR(pbm); 3756 SOC_PBMP_PORT_ADD(pbm, port); 3757 (void)bcm_esw_link_change(unit, pbm); 3758 } 3759 3760 return rv; 3761 } 3762 3763 /* 3764 * Function: 3765 * _bcm_esw_link_down_tx_get 3766 * Purpose: 3767 * Get the link down transmit function status 3768 * Parameters: 3769 * unit - StrataSwitch Unit #. 3770 * port - StrataSwitch physical port number. 3771 * *enable - return link down transmit status 3772 * Returns: 3773 * BCM_E_NONE - Success 3774 * BCM_E_PORT - Invalid port. 3775 * Notes: 3776 */ 3777 3778 int 3779 _bcm_esw_link_down_tx_get(int unit, bcm_port_t port, int *enable) 3780 { 3781 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 3782 return BCM_E_PORT; 3783 } 3784 3785 if (SOC_PBMP_MEMBER(SOC_PERSIST(unit)->lc_pbm_linkdown_tx, port)) { 3786 *enable = 1; 3787 } else { 3788 *enable = 0; 3789 } 3790 3791 return BCM_E_NONE; 3792 } 3793 3794 /* 3795 * Function: 3796 * _bcm_esw_link_failover_set 3797 * Purpose: 3798 * Set whether the given port is configured for LAG failover. 3799 * Parameters: 3800 * unit - StrataSwitch Unit #. 3801 * port - StrataSwitch physical port number. 3802 * enable - LAG failover mode. 3803 * Returns: 3804 * BCM_E_NONE - Success 3805 * BCM_E_INIT - Not initialized. 3806 * BCM_E_DISABLED - Port not being scanned. 3807 * Notes: 3808 * Called by trunk failover configuration. 3809 */ 3810 3811 int 3812 _bcm_esw_link_failover_set(int unit, bcm_port_t port, int enable) 3813 { 3814 soc_persist_t *sop = SOC_PERSIST(unit); 3815 uint32 val; 3816 3817 LC_CHECK_INIT(unit); 3818 3819 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 3820 return BCM_E_PORT; 3821 } 3822 3823 LC_LOCK(unit); 3824 3825 if (enable) { 3826 if (SOC_PBMP_MEMBER(sop->lc_pbm_failed, port) || 3827 SOC_PBMP_MEMBER(sop->lc_pbm_failed_clear, port)) { 3828 /* Not yet recovered from previous failover. 3829 * Must wait until resolved. */ 3830 LC_UNLOCK(unit); 3831 return BCM_E_PORT; 3832 } else { 3833 if (SOC_USE_PORTCTRL(unit)) { 3834 bcmi_esw_portctrl_lag_failover_status_toggle(unit, port); 3835 } else { 3836 soc_reg_t lag_failover_config_reg; 3837 3838 if (SOC_IS_SABER2(unit) && SOC_REG_PORT_VALID(unit, 3839 LAG_FAILOVER_CONFIGr, port)) { 3840 lag_failover_config_reg = LAG_FAILOVER_CONFIGr; 3841 } else if ((IS_CL_PORT(unit, port)) && (SOC_REG_IS_VALID(unit, CLPORT_LAG_FAILOVER_CONFIGr))) { 3842 lag_failover_config_reg = CLPORT_LAG_FAILOVER_CONFIGr; 3843 } else if (SOC_REG_IS_VALID(unit, XLPORT_LAG_FAILOVER_CONFIGr)) { 3844 lag_failover_config_reg = XLPORT_LAG_FAILOVER_CONFIGr; 3845 } else if (SOC_REG_IS_VALID(unit, LAG_FAILOVER_CONFIGr)) { 3846 lag_failover_config_reg = LAG_FAILOVER_CONFIGr; 3847 } else { 3848 lag_failover_config_reg = GXPORT_LAG_FAILOVER_CONFIGr; 3849 } 3850 3851 /* Toggle link bit to notify IPIPE on link up */ 3852 _BCM_LINK_IF_ERROR_RETURN 3853 (soc_reg32_get(unit, lag_failover_config_reg, port, 0, &val)); 3854 soc_reg_field_set(unit, lag_failover_config_reg, &val, 3855 LINK_STATUS_UPf, 1); 3856 _BCM_LINK_IF_ERROR_RETURN 3857 (soc_reg32_set(unit, lag_failover_config_reg, port, 0, val)); 3858 soc_reg_field_set(unit, lag_failover_config_reg, &val, 3859 LINK_STATUS_UPf, 0); 3860 _BCM_LINK_IF_ERROR_RETURN 3861 (soc_reg32_set(unit, lag_failover_config_reg, port, 0, val)); 3862 } 3863 SOC_PBMP_PORT_ADD(sop->lc_pbm_failover, port); 3864 } 3865 } else { 3866 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_failover, port); 3867 } 3868 LC_UNLOCK(unit); 3869 3870 LOG_VERBOSE(BSL_LS_BCM_LINK, 3871 (BSL_META_U(unit, 3872 "Unit %d: LAG failover: Port %d - %s\n"), 3873 unit, port, enable ? "enabled" : "disabled")); 3874 return BCM_E_NONE; 3875 } 3876 3877 /* 3878 * Function: 3879 * _bcm_esw_link_failed_clear 3880 * Purpose: 3881 * Allow a LAG failover port in failed state to complete link down 3882 * processing. 3883 * Parameters: 3884 * unit - StrataSwitch Unit #. 3885 * port - StrataSwitch physical port number. 3886 * Returns: 3887 * BCM_E_NONE - Success 3888 * BCM_E_INIT - Not initialized. 3889 * BCM_E_PORT - Not a valid port or port not in failed state. 3890 * BCM_E_DISABLED - Port not being scanned. 3891 */ 3892 3893 int 3894 _bcm_esw_link_failed_clear(int unit, bcm_port_t port) 3895 { 3896 soc_persist_t *sop = SOC_PERSIST(unit); 3897 3898 LC_CHECK_INIT(unit); 3899 3900 #if defined(BCM_TRX_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) 3901 if (!soc_feature(unit, soc_feature_port_lag_failover)) { 3902 return BCM_E_UNAVAIL; 3903 } 3904 #endif /* BCM_TRX_SUPPORT || BCM_BRADLEY_SUPPORT */ 3905 3906 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 3907 return BCM_E_PORT; 3908 } 3909 3910 LC_LOCK(unit); 3911 3912 if (!SOC_PBMP_MEMBER(sop->lc_pbm_failed, port)) { 3913 /* Not a failed port */ 3914 LC_UNLOCK(unit); 3915 return BCM_E_PORT; 3916 } else if (SOC_PBMP_MEMBER(sop->lc_pbm_failover, port)) { 3917 /* Port still in trunk, can't clear yet */ 3918 LC_UNLOCK(unit); 3919 return BCM_E_PORT; 3920 } 3921 3922 /* Signal to finish link down processing in update routine */ 3923 SOC_PBMP_PORT_ADD(sop->lc_pbm_failed_clear, port); 3924 LC_UNLOCK(unit); 3925 LOG_VERBOSE(BSL_LS_BCM_LINK, 3926 (BSL_META_U(unit, 3927 "Unit %d: LAG failover failed state clear set: Port %d\n"), 3928 unit, port)); 3929 3930 return BCM_E_NONE; 3931 } 3932 3933 /* 3934 * Function: 3935 * _bcm_esw_link_fast_set 3936 * Purpose: 3937 * Enables or disables fast linkscan for given port. 3938 * Parameters: 3939 * unit - StrataSwitch Unit #. 3940 * port - Port number. 3941 * enable - Indicates whether to enable or disable fast linkscan on port. 3942 * Returns: 3943 * BCM_E_XXX 3944 */ 3945 int 3946 _bcm_esw_link_fast_set(int unit, bcm_port_t port, int enable) 3947 { 3948 ls_cntl_t *lc = link_control[unit]; 3949 3950 LC_CHECK_INIT(unit); 3951 3952 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port)); 3953 3954 LC_LOCK(unit); 3955 3956 if (enable) { 3957 BCM_PBMP_PORT_ADD(lc->lc_pbm_fast, port); 3958 } else { 3959 BCM_PBMP_PORT_REMOVE(lc->lc_pbm_fast, port); 3960 } 3961 3962 LC_UNLOCK(unit); 3963 3964 return BCM_E_NONE; 3965 } 3966 3967 /* 3968 * Function: 3969 * _bcm_esw_link_fast_get 3970 * Purpose: 3971 * Gets fast linkscan property for given port. 3972 * Parameters: 3973 * unit - StrataSwitch Unit #. 3974 * port - Port number. 3975 * enable - (OUT) Returns fast linkscan property for port. 3976 * Returns: 3977 * BCM_E_XXX 3978 */ 3979 int 3980 _bcm_esw_link_fast_get(int unit, bcm_port_t port, int *enable) 3981 { 3982 ls_cntl_t *lc = link_control[unit]; 3983 3984 LC_CHECK_INIT(unit); 3985 3986 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &port)); 3987 3988 if (BCM_PBMP_MEMBER(lc->lc_pbm_fast, port)) { 3989 *enable = TRUE; 3990 } else { 3991 *enable = FALSE; 3992 } 3993 3994 return BCM_E_NONE; 3995 } 3996 3997 /* TRUE: need to call bcm_esw_port_update 3998 * FALSE: need not to call bcm_esw_port_update 3999 */ 4000 STATIC int 4001 _bcm_esw_port_soft_reset_is_set(int unit, soc_port_t port) 4002 { 4003 int rv = BCM_E_NONE; 4004 int soft_reset_val = 1; 4005 4006 #ifdef PORTMOD_SUPPORT 4007 if (SOC_USE_PORTCTRL(unit)) { 4008 rv = portmod_port_mac_reset_get(unit, port, &soft_reset_val); 4009 } else 4010 #endif 4011 { 4012 _bcm_port_info_t *port_info; 4013 _bcm_port_info_access(unit, port, &port_info); 4014 rv = MAC_CONTROL_GET(port_info->p_mac, unit, port, 4015 SOC_MAC_CONTROL_SW_RESET, &soft_reset_val); 4016 } 4017 4018 if (BCM_E_NONE != rv) { 4019 return TRUE; 4020 } else { 4021 return ((soft_reset_val) ? TRUE : FALSE); 4022 } 4023 } 4024 4025 STATIC void 4026 _bcm_esw_port_update_before_linkscan_exit(int unit, pbmp_t port_pbmp) 4027 { 4028 int enable = 0, soft_reset = 0; 4029 soc_port_t port; 4030 int rv = 0, hw_linkscan_mode = 0, link = 0; 4031 soc_persist_t *sop = SOC_PERSIST(unit); 4032 4033 BCM_PBMP_ITER(port_pbmp, port) { 4034 #ifdef BCM_RCPU_SUPPORT 4035 if (SOC_IS_RCPU_ONLY(unit) && IS_RCPU_PORT(unit, port)) { 4036 continue; 4037 } 4038 #endif /* BCM_RCPU_SUPPORT */ 4039 if (BCM_SUCCESS(bcm_esw_port_enable_get(unit, port, &enable))) { 4040 if (enable) { 4041 soft_reset = _bcm_esw_port_soft_reset_is_set(unit, port); 4042 4043 if (soft_reset == 0) { 4044 /* when soft_reset == 0, if sdk calls bcm_esw_port_update, 4045 * mac can't work normally */ 4046 continue; 4047 } 4048 4049 if (SOC_PBMP_MEMBER(sop->lc_pbm_override_ports, port)) { 4050 link = SOC_PBMP_MEMBER(sop->lc_pbm_override_link, port); 4051 } else { 4052 rv = _bcm_port_link_get(unit, port, hw_linkscan_mode, &link); 4053 if (soc_feature(unit, 4054 soc_feature_link_status_get_need_phy_read_twice)) { 4055 if ((BCM_SUCCESS(rv)) && !link) { 4056 rv = _bcm_port_link_get(unit, port, 4057 hw_linkscan_mode, &link); 4058 } 4059 } 4060 } 4061 4062 if (BCM_SUCCESS(rv) && link) { 4063 (void)bcm_esw_port_update(unit, port, TRUE); 4064 } else { 4065 (void)bcm_esw_port_update(unit, port, FALSE); 4066 } 4067 } else { 4068 (void)bcm_esw_port_update(unit, port, FALSE); 4069 } 4070 } 4071 } 4072 } 4073 4074 STATIC int 4075 _bcm_esw_port_update_before_linkscan_start(int unit, soc_port_t port, 4076 int hw_linkscan_mode, 4077 int *link) 4078 { 4079 int rv = 0, rx_en = 0, soft_reset = 0; 4080 4081 /* 4082 * COVERITY 4083 * The iterator above PBMP_ITER will protect the port variable 4084 * from overrun. 4085 */ 4086 /* coverity[overrun-call] */ 4087 rv = _bcm_port_link_get(unit, port, hw_linkscan_mode, link); 4088 if (soc_feature(unit, 4089 soc_feature_link_status_get_need_phy_read_twice)) { 4090 if ((BCM_SUCCESS(rv)) && !(*link)) { 4091 /* In legacy devices, PHY status register may show wrong 4092 * status on first read and we need to confirm by reading 4093 * second time if PHY status is shown as down. 4094 */ 4095 /* 4096 * COVERITY 4097 * The iterator above PBMP_ITER will protect the port 4098 * variable from overrun. 4099 */ 4100 /* coverity[overrun-call] */ 4101 rv = _bcm_port_link_get(unit, port, hw_linkscan_mode, 4102 link); 4103 } 4104 } 4105 if ((BCM_SUCCESS(rv)) && *link) { 4106 rv = bcm_esw_port_control_get(unit, port, 4107 bcmPortControlRxEnable, &rx_en); 4108 soft_reset = _bcm_esw_port_soft_reset_is_set(unit, port); 4109 /* when soft_reset == 0, if sdk calls bcm_esw_port_update, mac can't work normally */ 4110 if ((BCM_SUCCESS(rv)) && (!rx_en) && soft_reset) { 4111 #if defined(BCM_TOMAHAWK3_SUPPORT) && defined(PORTMOD_SUPPORT) 4112 if (SOC_IS_TOMAHAWK3(unit)) { 4113 int autoneg; 4114 int enabled, locked; 4115 4116 BCM_IF_ERROR_RETURN(bcm_esw_port_autoneg_get(unit, port, &autoneg)); 4117 if (autoneg == 1) { 4118 BCM_IF_ERROR_RETURN( 4119 bcmi_esw_portctrl_autoneg_status_get(unit, port, &enabled, &locked)); 4120 /* Do not allow port update if AN hasn't finished negotiating */ 4121 if (!(enabled && locked)) { 4122 return rv; 4123 } 4124 } 4125 } 4126 #endif 4127 (void)bcm_esw_port_update(unit, port, *link); 4128 } 4129 } 4130 return rv; 4131 } 4132 4133 /* 4134 * Function: 4135 * _bcm_esw_linkscan_thread 4136 * Purpose: 4137 * Scan the ports on the specified unit for link status 4138 * changes and process them as they occur. 4139 * Parameters: 4140 * unit - StrataSwitch unit #. 4141 * Returns: 4142 * Nothing 4143 */ 4144 4145 STATIC void 4146 _bcm_esw_linkscan_thread(int unit) 4147 { 4148 soc_persist_t *sop = SOC_PERSIST(unit); 4149 ls_cntl_t *lc = link_control[unit]; 4150 sal_usecs_t interval; 4151 int rv = BCM_E_NONE; 4152 int loopback; 4153 soc_port_t port; 4154 int link = 0, hw_linkscan_mode = 0; 4155 #if defined(BCM_KATANA2_SUPPORT) 4156 soc_port_t pp_port; 4157 #endif 4158 int normal_scheduled; 4159 int hw_force_scan; 4160 int hw_link_interrupt; 4161 sal_usecs_t elapsed_last_scheduled; /* Elapsed time since last 4162 normal linkscan run */ 4163 char thread_name[SAL_THREAD_NAME_MAX_LEN]; 4164 sal_thread_t thread; 4165 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 4166 pbmp_t pre_pbmp; 4167 #endif 4168 #if defined (BCM_KATANA2_SUPPORT) 4169 pbmp_t mask; 4170 #endif 4171 LOG_INFO(BSL_LS_BCM_LINK, 4172 (BSL_META_U(unit, 4173 "Linkscan starting on unit %d\n"), unit)); 4174 4175 /* Do not clear the lc_pbm_override_ports and lc_pbm_override_link. 4176 * If a port in Loopback mode forces link up before enabling linkscan, 4177 * the port status should be still forced to up after enabling linkscan. 4178 */ 4179 4180 sal_memset(lc->lc_error, 0, sizeof (lc->lc_error)); 4181 4182 #ifdef BCM_LINK_SUPPRESS_REMOTE_FAULT 4183 sal_memset(lc->lc_up_proc_state, 0, sizeof(lc->lc_up_proc_state)); 4184 #endif 4185 4186 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 4187 if (SOC_IS_TRIDENT2(unit) || SOC_IS_KATANA2(unit)) { 4188 SOC_PBMP_CLEAR(pre_pbmp); 4189 } 4190 #endif 4191 4192 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4193 lc->lc_error[port].limit = 4194 soc_property_port_get(unit, port, 4195 spn_BCM_LINKSCAN_MAXERR, 5); 4196 lc->lc_error[port].delay = 4197 soc_property_port_get(unit, port, 4198 spn_BCM_LINKSCAN_ERRDELAY, 10000000); 4199 } 4200 4201 thread = sal_thread_self(); 4202 thread_name[0] = 0; 4203 sal_thread_name(thread, thread_name, sizeof (thread_name)); 4204 /* 4205 * Assume ports are up before running linkscan. 4206 * This should avoid links to have traffic hits at warmboot. 4207 */ 4208 BCM_PBMP_ASSIGN(sop->lc_pbm_link, PBMP_ALL(unit)); 4209 4210 #if defined(BCM_KATANA2_SUPPORT) 4211 if (soc_feature(unit, soc_feature_linkphy_coe) && 4212 SOC_INFO(unit).linkphy_enabled) { 4213 SOC_PBMP_ITER(SOC_INFO(unit).linkphy_pbm, port) { 4214 #if defined BCM_METROLITE_SUPPORT 4215 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 4216 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 4217 SOC_PBMP_PORT_ADD 4218 (sop->lc_pbm_link, pp_port); 4219 } 4220 } else 4221 #endif 4222 { 4223 for (pp_port = 0; 4224 pp_port < SOC_INFO(unit).port_num_subport[port]; 4225 pp_port++) { 4226 SOC_PBMP_PORT_ADD 4227 (sop->lc_pbm_link, 4228 pp_port + SOC_INFO(unit).port_subport_base[port]); 4229 } 4230 } 4231 } 4232 SOC_PBMP_CLEAR(mask); 4233 soc_link_mask2_get(unit, &mask); 4234 rv = soc_link_mask2_set(unit, mask); 4235 if (BCM_FAILURE(rv)) { 4236 /* Just log error */ 4237 LOG_ERROR(BSL_LS_BCM_LINK, 4238 (BSL_META_U(unit, 4239 "%s: Failed to set link mask2: %s\n"), 4240 thread_name, bcm_errmsg(rv))); 4241 } 4242 } 4243 if (soc_feature(unit, soc_feature_subtag_coe) && 4244 SOC_INFO(unit).subtag_enabled) { 4245 SOC_PBMP_ITER(SOC_INFO(unit).subtag_pbm, port) { 4246 #if defined BCM_METROLITE_SUPPORT 4247 if (soc_feature(unit, soc_feature_discontinuous_pp_port)) { 4248 SOC_PBMP_ITER(SOC_PORT_PP_BITMAP(unit, port), pp_port) { 4249 SOC_PBMP_PORT_ADD 4250 (sop->lc_pbm_link, pp_port); 4251 } 4252 } else 4253 #endif 4254 { 4255 for (pp_port = 0; 4256 pp_port < SOC_INFO(unit).port_num_subport[port]; 4257 pp_port++) { 4258 SOC_PBMP_PORT_ADD 4259 (sop->lc_pbm_link, 4260 pp_port + SOC_INFO(unit).port_subport_base[port]); 4261 } 4262 } 4263 } 4264 SOC_PBMP_CLEAR(mask); 4265 soc_link_mask2_get(unit, &mask); 4266 rv = soc_link_mask2_set(unit, mask); 4267 if (BCM_FAILURE(rv)) { 4268 /* Just log error */ 4269 LOG_ERROR(BSL_LS_BCM_LINK, 4270 (BSL_META_U(unit, 4271 "%s: Failed to set link mask2: %s\n"), 4272 thread_name, bcm_errmsg(rv))); 4273 } 4274 } 4275 #endif 4276 4277 if (!lc->lc_warm_boot) { 4278 /* 4279 * Force initial scan by setting link change while pretending link 4280 * was initially up. 4281 */ 4282 /* If we set sop->lc_pbm_link_change as PBMP_PORT_ALL(unit), 4283 * MAC of all ports will be reset, and traffic will be disrupted. 4284 */ 4285 /* BCM_PBMP_ASSIGN(sop->lc_pbm_link_change, PBMP_PORT_ALL(unit)); */ 4286 4287 #ifdef BCM_RCPU_SUPPORT 4288 if (SOC_IS_RCPU_ONLY(unit) && SOC_PORT_VALID(unit, RCPU_PORT(unit))) { 4289 /* Do not update link status for rcpu port. */ 4290 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link_change, RCPU_PORT(unit)); 4291 } 4292 #endif /* BCM_RCPU_SUPPORT */ 4293 4294 4295 /* Clear initial value of forwarding ports. */ 4296 rv = soc_link_fwd_set(unit, sop->lc_pbm_link); 4297 if (BCM_FAILURE(rv)) { 4298 LOG_ERROR(BSL_LS_BCM_LINK, 4299 (BSL_META_U(unit, 4300 "AbnormalThreadExit:%s, " 4301 "Failed to clear forwarding ports: %s\n"), 4302 thread_name, bcm_errmsg(rv))); 4303 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 4304 SOC_SWITCH_EVENT_THREAD_LINKSCAN, __LINE__, rv); 4305 sal_thread_exit(0); 4306 } 4307 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4308 if (!SOC_PBMP_MEMBER(lc->lc_pbm_sw, port) && 4309 !SOC_PBMP_MEMBER(lc->lc_pbm_hw, port)) { 4310 continue; 4311 } 4312 4313 /* If port is not in Loopback link status is retrieved from 4314 * PHY link status. If port is in Loopback mode the port status 4315 * should be still forced to up after enabling linkscan. 4316 */ 4317 rv = bcm_esw_port_loopback_get(unit, port, &loopback); 4318 LOG_VERBOSE(BSL_LS_BCM_LINK, 4319 (BSL_META_U(unit, 4320 "Linkscan init loopback recovery, " 4321 "unit %d, port %d, lb=%d\n"), 4322 unit, port, loopback)); 4323 if (!BCM_FAILURE(rv) && (loopback != BCM_PORT_LOOPBACK_NONE)) { 4324 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_link, port); 4325 SOC_PBMP_PORT_ADD(sop->lc_pbm_override_ports, port); 4326 continue; 4327 } 4328 4329 rv = _bcm_esw_port_update_before_linkscan_start(unit, port, 4330 hw_linkscan_mode, 4331 &link); 4332 if ((!BCM_FAILURE(rv)) && !link) { 4333 LC_LOCK(unit); 4334 BCM_PBMP_PORT_ADD(sop->lc_pbm_link_change, port); 4335 LC_UNLOCK(unit); 4336 } 4337 } 4338 } else { 4339 /* Clear Warm Boot record */ 4340 lc->lc_warm_boot = FALSE; 4341 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4342 /* In Warm boot, if the link scan mode is HW, then link state 4343 * has to be retrieved from CMIC link status instead of 4344 * retrieving from LINK_LATCHDOWNr. 4345 */ 4346 if (SOC_PBMP_MEMBER(lc->lc_pbm_hw, port)) { 4347 hw_linkscan_mode = 1; 4348 } else { 4349 hw_linkscan_mode = 0; 4350 } 4351 (void)_bcm_esw_port_update_before_linkscan_start(unit, port, 4352 hw_linkscan_mode, 4353 &link); 4354 } 4355 } 4356 4357 /* Register for hardware linkscan interrupt. */ 4358 4359 rv = soc_linkscan_register(unit, _bcm_esw_linkscan_hw_interrupt); 4360 4361 if (BCM_FAILURE(rv)) { 4362 LOG_ERROR(BSL_LS_BCM_LINK, 4363 (BSL_META_U(unit, 4364 "AbnormalThreadExit:%s, Failed to register handler: %s\n"), 4365 thread_name, bcm_errmsg(rv))); 4366 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 4367 SOC_SWITCH_EVENT_THREAD_LINKSCAN, __LINE__, rv); 4368 sal_thread_exit(0); 4369 } 4370 4371 elapsed_last_scheduled = 0; 4372 hw_force_scan = 0; 4373 4374 lc->lc_thread = sal_thread_self(); 4375 4376 while ((interval = lc->lc_us) != 0) { 4377 pbmp_t change; 4378 pbmp_t hw_link; 4379 pbmp_t hw_update; 4380 pbmp_t fast_sw_los_down; 4381 pbmp_t pbmp_all; 4382 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 4383 soc_port_t p; 4384 pbmp_t cur_pbmp, dif_pbmp; 4385 int enable; 4386 #endif 4387 4388 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 4389 if (SOC_IS_TRIDENT2(unit) || SOC_IS_KATANA2(unit)) { 4390 LC_LOCK(unit); 4391 SOC_PBMP_ASSIGN(cur_pbmp, PBMP_ALL(unit)); 4392 /* Updating the flex pbmp for TD2. */ 4393 #ifdef BCM_TRIDENT2_SUPPORT 4394 if (SOC_IS_TRIDENT2(unit)) { 4395 PBMP_ITER(cur_pbmp, p) { 4396 rv = bcm_esw_port_subsidiary_ports_get(unit, p, &dif_pbmp); 4397 if (rv != BCM_E_NONE) { 4398 SOC_PBMP_PORT_REMOVE(cur_pbmp, p); 4399 } else { 4400 p += 3; 4401 } 4402 } 4403 } 4404 #endif 4405 /* 4406 * Updating the flexio pbmp for KT2 since lanes 4407 * splitting is done for few cases and it should 4408 * also be updated to get the correct current pbmp. 4409 */ 4410 #ifdef BCM_KATANA2_SUPPORT 4411 if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) { 4412 (void)_bcm_kt2_flexio_pbmp_update(unit, &cur_pbmp); 4413 } 4414 #endif 4415 4416 #if defined(BCM_SABER2_SUPPORT) 4417 if(SOC_IS_SABER2(unit)){ 4418 (void)bcm_sb2_sat_oamp_enable_get(unit, &enable); 4419 /* Skip OAMP port for saber2 device */ 4420 if(enable) { 4421 SOC_PBMP_PORT_REMOVE(cur_pbmp, 4422 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 4423 } 4424 } 4425 #endif 4426 if (SOC_PBMP_NOT_NULL(cur_pbmp)) { 4427 PBMP_ITER(cur_pbmp, p) { 4428 if (SOC_PBMP_MEMBER(SOC_PORT_DISABLED_BITMAP(unit, all), p) || 4429 IS_LB_PORT(unit, p) || IS_CPU_PORT(unit, p)) { 4430 SOC_PBMP_PORT_REMOVE(cur_pbmp, p); 4431 continue; 4432 } 4433 if (SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit), p)) { 4434 (void)bcm_esw_port_enable_get(unit, p, &enable); 4435 if (!enable) { 4436 SOC_PBMP_PORT_REMOVE(cur_pbmp, p); 4437 } 4438 } 4439 } 4440 } 4441 if (SOC_PBMP_NEQ(cur_pbmp, pre_pbmp)) { 4442 #ifdef BCM_TRIDENT2_SUPPORT 4443 if (SOC_IS_TRIDENT2(unit)) { 4444 SOC_PBMP_ASSIGN(dif_pbmp, pre_pbmp); 4445 } 4446 #endif 4447 #ifdef BCM_KATANA2_SUPPORT 4448 if (SOC_IS_KATANA2(unit)) { 4449 SOC_PBMP_ASSIGN(dif_pbmp, lc->lc_pbm_sw); 4450 SOC_PBMP_OR(dif_pbmp, lc->lc_pbm_hw); 4451 } 4452 #endif 4453 SOC_PBMP_ASSIGN(pre_pbmp, cur_pbmp); 4454 SOC_PBMP_XOR(dif_pbmp, cur_pbmp); 4455 if (SOC_PBMP_NOT_NULL(dif_pbmp)) { 4456 PBMP_ITER(dif_pbmp, p) { 4457 if (SOC_PBMP_MEMBER(cur_pbmp, p)) { 4458 if (SOC_PBMP_MEMBER(lc->lc_pbm_hw, p)) { 4459 (void)bcm_esw_linkscan_mode_set(unit, p, 4460 BCM_LINKSCAN_MODE_HW); 4461 } else if(SOC_PBMP_MEMBER(lc->lc_pbm_sw, p)) { 4462 (void)bcm_esw_linkscan_mode_set(unit, p, 4463 BCM_LINKSCAN_MODE_SW); 4464 } else { 4465 (void)bcm_esw_linkscan_mode_set(unit, p, 4466 BCM_LINKSCAN_MODE_NONE); 4467 } 4468 } 4469 } 4470 } 4471 } 4472 LC_UNLOCK(unit); 4473 } 4474 #endif 4475 4476 PORT_LOCK(unit); 4477 /* Flexport operation may lead to change in all bitmap */ 4478 BCM_PBMP_ASSIGN(pbmp_all, PBMP_PORT_ALL(unit)); 4479 PORT_UNLOCK(unit); 4480 4481 /* sample changed */ 4482 BCM_PBMP_ASSIGN(change, sop->lc_pbm_link_change); 4483 4484 /* If the interrupt indicates that link status changes, 4485 * process the ports indicated by HW linkscan first. 4486 */ 4487 if (lc->lc_hw_change) { 4488 /* Pause linkscan to make sure that the HW link state does 4489 * change while updating software state. 4490 */ 4491 soc_linkscan_pause(unit); 4492 lc->lc_hw_change = 0; 4493 4494 #if defined (BCM_CMICX_SUPPORT) 4495 if (soc_feature(unit, soc_feature_cmicx)) { 4496 /* Get CMICx HW link status from cached copy */ 4497 (void)soc_linkscan_hw_link_cache_get(unit, &hw_link); 4498 } else 4499 #endif /* BCM_CMICX_SUPPORT */ 4500 { 4501 (void)soc_linkscan_hw_link_get(unit, &hw_link); 4502 } 4503 BCM_PBMP_AND(hw_link, lc->lc_pbm_hw); 4504 4505 #ifdef BCM_TRUNK_FAILOVER_SUPPORT 4506 /* 4507 * If enabled on XGS3 devices, do an early callback to the 4508 * trunk code that will immediately remove link down ports 4509 * from trunks. This only works with hardware linkscanned 4510 * ports. 4511 */ 4512 #ifdef BCM_TRIDENT_SUPPORT 4513 if (soc_feature(unit, soc_feature_shared_trunk_member_table)) { 4514 extern int _bcm_trident_trunk_swfailover_trigger(int unit, 4515 bcm_pbmp_t ports_active, 4516 bcm_pbmp_t ports_status); 4517 (void)_bcm_trident_trunk_swfailover_trigger(unit, 4518 lc->lc_pbm_hw, 4519 hw_link); 4520 } else 4521 #endif /* BCM_TRIDENT_SUPPORT */ 4522 if (SOC_IS_XGS3_SWITCH(unit) || SOC_IS_XGS3_FABRIC(unit)) { 4523 extern int _bcm_xgs3_trunk_swfailover_trigger(int unit, 4524 bcm_pbmp_t ports_active, 4525 bcm_pbmp_t ports_status); 4526 (void)_bcm_xgs3_trunk_swfailover_trigger(unit, 4527 lc->lc_pbm_hw, 4528 hw_link); 4529 } 4530 #endif /* BCM_TRUNK_FAILOVER_SUPPORT */ 4531 4532 /* Make sure that only valid ports are scaned */ 4533 BCM_PBMP_ASSIGN(hw_update, hw_link); 4534 BCM_PBMP_XOR(hw_update, sop->lc_pbm_link); 4535 BCM_PBMP_AND(hw_update, lc->lc_pbm_hw); 4536 _bcm_esw_linkscan_update(unit, 0 /*flags*/, hw_update); 4537 4538 /* Make sure that only valid ports are scaned */ 4539 BCM_PBMP_AND(change, pbmp_all); 4540 _bcm_esw_linkscan_update(unit, 0 /*flags*/, change); 4541 soc_linkscan_continue(unit); 4542 4543 /* Set flag to trigger scan */ 4544 hw_force_scan = 1; 4545 } 4546 4547 /* After processing the link status changes of the ports 4548 * indicated by interrupt handler (mainly to trigger swfailover), 4549 * scan all the ports again to make sure that the link status 4550 * is stable. 4551 * For some PHYs such as 5228, hardware linkscan may say the 4552 * link is up while the PHY is actually not quite done 4553 * autonegotiating. Rescanning make sure that the PHY link is 4554 * in sync with switch HW link state. 4555 */ 4556 4557 /* 4558 * There is a new accelerated mode in the linkscan thread 4559 * that provides for a smaller linkscan interval time on 4560 * those ports that need a faster polling interval. 4561 * 4562 * The linkscan thread will run at a faster rate (faster than 4563 * the one provided by the customer), if the accelerated 4564 * port bitmap is not empty. 4565 * 4566 * The scheduling logic will still allow the normal linkscan 4567 * SW port bitmap to proceed as scheduled. 4568 */ 4569 if (elapsed_last_scheduled >= lc->lc_us) { 4570 normal_scheduled = 1; /* Time for normal schedule linkscan */ 4571 } else { 4572 normal_scheduled = 0; 4573 } 4574 4575 if (normal_scheduled || hw_force_scan) { 4576 _bcm_esw_linkscan_update(unit, 0 /*flags*/, pbmp_all); 4577 elapsed_last_scheduled = 0; /* Reset */ 4578 } else if (BCM_PBMP_NOT_NULL(lc->lc_pbm_accel)) { 4579 4580 /* Scan accelerated bitmap */ 4581 _bcm_esw_linkscan_update(unit, 0 /*flags*/, lc->lc_pbm_accel); 4582 lc->lc_accel_poll_count++; 4583 } 4584 4585 if (BCM_PBMP_NOT_NULL(change)) { 4586 /* Re-scan due to hardware force */ 4587 hw_force_scan = 1; 4588 continue; 4589 } 4590 4591 hw_force_scan = 0; 4592 4593 /* Stop accelerated mode if max accelerated poll count is reached */ 4594 if (lc->lc_accel_poll_count >= lc->lc_accel_poll_max) { 4595 BCM_PBMP_CLEAR(lc->lc_pbm_accel); 4596 LOG_INFO(BSL_LS_BCM_LINK, 4597 (BSL_META_U(unit, 4598 "Stop accelerated mode\n"))); 4599 } 4600 4601 /* If all links are HW scanned, we can usually await the 4602 * next HW interrupt. 4603 * Exceptions: 4604 * - Any port is experiencing remote fault 4605 * - SW RX LOS processing is operating on a down link port 4606 */ 4607 if (BCM_PBMP_IS_NULL(lc->lc_pbm_sw) && 4608 BCM_PBMP_IS_NULL(sop->lc_pbm_remote_fault)) { 4609 hw_link_interrupt = TRUE; 4610 4611 if (BCM_PBMP_NOT_NULL(lc->lc_pbm_fast)) { 4612 /* Are any fast ports in link down? 4613 * If so, we must continue to scan them so the PHY driver 4614 * processing continues. 4615 */ 4616 BCM_PBMP_ASSIGN(fast_sw_los_down, lc->lc_pbm_fast); 4617 BCM_PBMP_XOR(fast_sw_los_down, sop->lc_pbm_link); 4618 BCM_PBMP_AND(fast_sw_los_down, lc->lc_pbm_fast); 4619 4620 if (BCM_PBMP_NOT_NULL(fast_sw_los_down)) { 4621 hw_link_interrupt = FALSE; 4622 } 4623 } 4624 } else { 4625 hw_link_interrupt = FALSE; 4626 } 4627 4628 /* Set linkscan interval */ 4629 if (BCM_PBMP_NOT_NULL(lc->lc_pbm_accel)) { 4630 if (lc->lc_us < lc->lc_accel_us) { 4631 interval = lc->lc_us; 4632 } else { 4633 interval = lc->lc_accel_us; 4634 } 4635 } else if (hw_link_interrupt) { 4636 interval = sal_sem_FOREVER; 4637 } else { 4638 interval = lc->lc_us; 4639 } 4640 4641 if (interval != sal_sem_FOREVER) { 4642 elapsed_last_scheduled += interval; 4643 } 4644 4645 (void)sal_sem_take(lc->lc_sema, interval); 4646 } 4647 4648 (void)soc_linkscan_register(unit, NULL); 4649 4650 /* 4651 * Before exiting, re-enable all ports that were being scanned. 4652 * 4653 * For administrative reload preparation, such as _bcm_shutdown, 4654 * the reload mode is used to avoid this disturbing of ports. 4655 */ 4656 4657 if (!SOC_WARM_BOOT(unit)) { 4658 4659 _bcm_esw_port_update_before_linkscan_exit(unit, lc->lc_pbm_sw); 4660 4661 _bcm_esw_port_update_before_linkscan_exit(unit, lc->lc_pbm_hw); 4662 4663 } /* !SOC_WARM_BOOT(unit) */ 4664 4665 LOG_INFO(BSL_LS_BCM_LINK, 4666 (BSL_META_U(unit, 4667 "Linkscan exiting\n"))); 4668 4669 lc->lc_thread = NULL; 4670 sal_thread_exit(0); 4671 } 4672 4673 /************************************************************************ 4674 ********* ********* 4675 ********* Start of BCM API Exported Routines ********* 4676 */ 4677 4678 /* 4679 * Function: 4680 * bcm_linkscan_init 4681 * Purpose: 4682 * Initialize the linkscan software module. 4683 * Parameters: 4684 * unit - StrataSwitch Unit #. 4685 * Returns: 4686 * BCM_E_XXX 4687 */ 4688 4689 int 4690 bcm_esw_linkscan_init(int unit) 4691 { 4692 ls_cntl_t *lc; 4693 bcm_port_if_t intf; 4694 uint32 regval; 4695 soc_port_t port, phy_port; 4696 soc_persist_t *sop = SOC_PERSIST(unit); 4697 int val = -1; 4698 4699 if (link_control[unit] != NULL) { 4700 BCM_IF_ERROR_RETURN(bcm_esw_linkscan_detach(unit)); 4701 } 4702 4703 if ((lc = sal_alloc(sizeof (ls_cntl_t), "link_control")) == NULL) { 4704 return BCM_E_MEMORY; 4705 } 4706 4707 sal_memset(lc, 0, sizeof (ls_cntl_t)); 4708 4709 4710 lc->lc_lock = sal_mutex_create("bcm_link_LOCK"); 4711 if (lc->lc_lock == NULL) { 4712 sal_free(lc); 4713 return BCM_E_MEMORY; 4714 } 4715 4716 lc->lc_sema = sal_sem_create("bcm_link_SLEEP", 4717 sal_sem_BINARY, 0); 4718 if (lc->lc_sema == NULL) { 4719 sal_mutex_destroy(lc->lc_lock); 4720 sal_free(lc); 4721 return BCM_E_MEMORY; 4722 } 4723 4724 link_control[unit] = lc; 4725 4726 /* 4727 * Initialize link_control port bitmaps so bcm_port_update works 4728 * reasonably even if the linkscan thread is never started. 4729 */ 4730 _lc_pbm_init(unit); 4731 4732 if (!SOC_IS_RCPU_ONLY(unit)) { 4733 4734 /* 1. Select between C45 and C22 for HW linkscan 4735 * 2. Select appropriate MDIO Bus 4736 * 3. Select between MDIO scan vs. link status from internal PHY 4737 * 4. Initialize HW linkscan PHY address map. 4738 */ 4739 BCM_IF_ERROR_RETURN 4740 (soc_linkscan_hw_init(unit)); 4741 4742 /* For XGS 3 devices, select the source of the CMIC link status 4743 * interrupt to be the Internal Serdes - only for SGMII ports 4744 */ 4745 BCM_PBMP_CLEAR(lc->lc_pbm_sgmii_autoneg_port); 4746 if (soc_feature(unit, soc_feature_sgmii_autoneg)) { 4747 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4748 if (soc_property_port_get(unit, port, 4749 spn_PHY_SGMII_AUTONEG, FALSE)) { 4750 BCM_IF_ERROR_RETURN 4751 (bcm_esw_port_interface_get(unit, port, &intf)); 4752 if (intf == BCM_PORT_IF_SGMII) { 4753 BCM_PBMP_PORT_ADD(lc->lc_pbm_sgmii_autoneg_port, port); 4754 if (soc_feature(unit, soc_feature_logical_port_num)) { 4755 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 4756 } else { 4757 phy_port = port; 4758 } 4759 #ifdef BCM_CMICM_SUPPORT 4760 if (soc_feature(unit, soc_feature_cmicm)) { 4761 if (phy_port < 32) { 4762 READ_CMIC_MIIM_INT_SEL_MAP_0r(unit, ®val); 4763 regval |= (1 << phy_port); 4764 WRITE_CMIC_MIIM_INT_SEL_MAP_0r(unit, regval); 4765 } else if (phy_port < 64) { 4766 READ_CMIC_MIIM_INT_SEL_MAP_1r(unit, ®val); 4767 regval |= (1 << (phy_port-32)); 4768 WRITE_CMIC_MIIM_INT_SEL_MAP_1r(unit, regval); 4769 } else if (phy_port < 96) { 4770 READ_CMIC_MIIM_INT_SEL_MAP_2r(unit, ®val); 4771 regval |= (1 << (phy_port-64)); 4772 WRITE_CMIC_MIIM_INT_SEL_MAP_2r(unit, regval); 4773 } else if (phy_port < 128) { 4774 READ_CMIC_MIIM_INT_SEL_MAP_3r(unit, ®val); 4775 regval |= (1 << (phy_port-96)); 4776 WRITE_CMIC_MIIM_INT_SEL_MAP_3r(unit, regval); 4777 } else 4778 #ifdef BCM_CMICDV2_SUPPORT 4779 if (soc_feature(unit, soc_feature_cmicd_v2)) { 4780 if (phy_port < 160) { 4781 READ_CMIC_MIIM_INT_SEL_MAP_4r(unit, ®val); 4782 regval |= (1 << (phy_port-128)); 4783 WRITE_CMIC_MIIM_INT_SEL_MAP_4r(unit, regval); 4784 } else if (phy_port < 192) { 4785 READ_CMIC_MIIM_INT_SEL_MAP_5r(unit, ®val); 4786 regval |= (1 << (phy_port-160)); 4787 WRITE_CMIC_MIIM_INT_SEL_MAP_5r(unit, regval); 4788 } else 4789 #ifdef BCM_CMICDV3_SUPPORT 4790 if (soc_feature(unit, soc_feature_cmicd_v3)) { 4791 if (phy_port < 224) { 4792 READ_CMIC_MIIM_INT_SEL_MAP_6r(unit, ®val); 4793 regval |= (1 << (phy_port-192)); 4794 WRITE_CMIC_MIIM_INT_SEL_MAP_6r(unit, regval); 4795 } else if (phy_port < 256) { 4796 READ_CMIC_MIIM_INT_SEL_MAP_7r(unit, ®val); 4797 regval |= (1 << (phy_port-224)); 4798 WRITE_CMIC_MIIM_INT_SEL_MAP_7r(unit, regval); 4799 } else if (phy_port < 288) { 4800 READ_CMIC_MIIM_INT_SEL_MAP_8r(unit, ®val); 4801 regval |= (1 << (phy_port-256)); 4802 WRITE_CMIC_MIIM_INT_SEL_MAP_8r(unit, regval); 4803 } else if (phy_port < 320) { 4804 READ_CMIC_MIIM_INT_SEL_MAP_9r(unit, ®val); 4805 regval |= (1 << (phy_port-288)); 4806 WRITE_CMIC_MIIM_INT_SEL_MAP_9r(unit, regval); 4807 } else { 4808 return BCM_E_PORT; 4809 } 4810 } else 4811 #endif /* CMICd V3 Support */ 4812 { 4813 return BCM_E_PORT; 4814 } 4815 } else 4816 #endif /* CMICd V2 Support */ 4817 { 4818 return BCM_E_PORT; 4819 } 4820 } else 4821 #endif /* CMICm Support */ 4822 #ifdef BCM_CMICX_SUPPORT 4823 if (soc_feature(unit, soc_feature_cmicx)) { 4824 /* TBA: Add cmicx specific code */ 4825 } else 4826 #endif 4827 { 4828 if (phy_port < 32) { 4829 READ_CMIC_MIIM_INT_SEL_MAPr(unit, ®val); 4830 regval |= (1 << phy_port); 4831 WRITE_CMIC_MIIM_INT_SEL_MAPr(unit, regval); 4832 } 4833 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 4834 else if ((SOC_IS_TR_VL(unit) && 4835 !SOC_IS_ENDURO(unit) && 4836 !SOC_IS_HURRICANEX(unit) && 4837 !SOC_IS_GREYHOUND(unit) && 4838 !SOC_IS_GREYHOUND2(unit)) || 4839 soc_feature 4840 (unit, soc_feature_register_hi)) { 4841 if ((phy_port - 32) <= 31) { 4842 READ_CMIC_MIIM_INT_SEL_MAP_HIr 4843 (unit, ®val); 4844 regval |= (1 << (phy_port - 32)); 4845 WRITE_CMIC_MIIM_INT_SEL_MAP_HIr 4846 (unit, regval); 4847 } else 4848 #if defined(BCM_TRIDENT_SUPPORT) 4849 if ((phy_port - 64) <= 31) { 4850 READ_CMIC_MIIM_INT_SEL_MAP_HI_2r 4851 (unit, ®val); 4852 regval |= (1 << (phy_port - 64)); 4853 WRITE_CMIC_MIIM_INT_SEL_MAP_HI_2r 4854 (unit, regval); 4855 } else 4856 #endif 4857 { 4858 return BCM_E_PORT; 4859 } 4860 } 4861 #endif 4862 } /* Not CMICm */ 4863 } 4864 } 4865 } 4866 } 4867 } /* !SOC_IS_RCPU_ONLY */ 4868 4869 /* 4870 * Accelerated mode 4871 * Property "fast_sw_rx_los_pbmp" is old (maintained for compatibility 4872 * purpose), "rx_fast_los_link" should be used instead. 4873 * If both properties are used for the same port, the approved 4874 * "rx_fast_los_link" takes precedence. 4875 */ 4876 lc->lc_pbm_fast = soc_property_get_pbmp(unit, "fast_sw_rx_los_pbmp", 0); 4877 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4878 val = soc_property_port_get(unit, port, spn_RX_FAST_LOS_LINK, -1); 4879 if (val == 0) { 4880 BCM_PBMP_PORT_REMOVE(lc->lc_pbm_fast, port); 4881 } else if (val == 1) { 4882 BCM_PBMP_PORT_ADD(lc->lc_pbm_fast, port); 4883 } 4884 } 4885 4886 lc->lc_accel_us = soc_property_get(unit, spn_RX_FAST_LOS_USEC, 4887 ACCELERATED_INTERVAL_USEC); 4888 lc->lc_accel_poll_max = soc_property_get(unit, 4889 spn_RX_FAST_LOS_POLL_COUNT_MAX, 4890 ACCELERATED_POLL_COUNT_MAX); 4891 4892 #ifdef BCM_WARM_BOOT_SUPPORT 4893 if (SOC_WARM_BOOT(unit)) { 4894 BCM_IF_ERROR_RETURN(_bcm_esw_link_reload(unit)); 4895 } else { 4896 int alloc_size, rv; 4897 soc_scache_handle_t scache_handle; 4898 uint8 *link_scache; 4899 4900 /* Alloc size calculation */ 4901 alloc_size = BCM_LINK_PBMP_SCACHE_NUM * _LINK_PBMP_BYTE_MAX; 4902 4903 #if defined(BCM_HAWKEYE_SUPPORT) 4904 if (SOC_IS_HAWKEYE(unit) && soc_feature(unit, soc_feature_eee)) { 4905 /* For lc_ibppktsetlimit and lc_ibpcelsetlimit */ 4906 alloc_size += (SOC_MAX_NUM_PORTS * 2 * sizeof(uint32)); 4907 } 4908 #endif /* BCM_HAWKEYE_SUPPORT */ 4909 4910 /* For lc_us */ 4911 alloc_size += sizeof(int); 4912 4913 SOC_SCACHE_HANDLE_SET(scache_handle, 4914 unit, BCM_MODULE_LINKSCAN, 0); 4915 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE, 4916 alloc_size, 4917 &link_scache, 4918 BCM_WB_DEFAULT_VERSION, NULL); 4919 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 4920 return rv; 4921 } 4922 } 4923 #endif /* BCM_WARM_BOOT_SUPPORT */ 4924 4925 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 4926 /* This is needed for init time initialization */ 4927 if (soc_property_port_get(unit, port, spn_FCMAP_ENABLE, 0)) { 4928 SOC_PBMP_PORT_ADD(sop->lc_pbm_fc, port); 4929 } 4930 4931 /* Check of the external PHy is set in EBE/ETHERRAM buffer mode */ 4932 if (soc_property_port_get(unit, port, spn_PHY_OPERATIONAL_MODE, 0) == 3) { 4933 /* the External PHY is in ETHER RAM or buffered mode */ 4934 SOC_PBMP_PORT_ADD(sop->lc_pbm_eth_buffer_mode, port); 4935 } 4936 } 4937 #if defined(BCM_TRIUMPH3_SUPPORT) 4938 /* Linkscan module starts after port module. Hence register here */ 4939 if (soc_feature(unit, soc_feature_epc_linkflap_recover)) { 4940 bcm_esw_linkscan_register(unit, _bcm_port_force_forward_linkscan_handler); 4941 } 4942 #endif /*defined(BCM_TRIUMPH3_SUPPORT)*/ 4943 4944 #ifdef BCM_PREEMPTION_SUPPORT 4945 if (soc_feature(unit, soc_feature_preemption)) { 4946 BCM_IF_ERROR_RETURN( 4947 bcm_esw_linkscan_register( 4948 unit, bcmi_esw_preemption_linkscan_update)); 4949 } 4950 #endif /* BCM_PREEMPTION_SUPPORT */ 4951 4952 return (BCM_E_NONE); 4953 } 4954 4955 /* 4956 * Function: 4957 * bcm_esw_linkscan_mode_set 4958 * Purpose: 4959 * Set the current scanning mode for the specified port. 4960 * Parameters: 4961 * unit - StrataSwitch Unit #. 4962 * port - StrataSwitch Port #. 4963 * mode - New scan mode for specified port. 4964 * Returns: 4965 * BCM_E_XXX 4966 */ 4967 4968 int 4969 bcm_esw_linkscan_mode_set(int unit, bcm_port_t port, int mode) 4970 { 4971 ls_cntl_t *lc = link_control[unit]; 4972 int rv = BCM_E_NONE; 4973 pbmp_t empty_pbm; 4974 int added = 0; 4975 soc_persist_t *sop = SOC_PERSIST(unit); 4976 pbmp_t tmp_pbm; 4977 int link_up = 0; 4978 LC_CHECK_INIT(unit); 4979 4980 if (BCM_GPORT_IS_SET(port)) { 4981 BCM_IF_ERROR_RETURN( 4982 bcm_esw_port_local_get(unit, port, &port)); 4983 } 4984 if (SOC_PBMP_MEMBER(SOC_PORT_DISABLED_BITMAP(unit, all), port) 4985 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 4986 && (!(SOC_IS_TRIDENT2(unit) || SOC_IS_KATANA2(unit)) || 4987 mode != BCM_LINKSCAN_MODE_NONE) 4988 #endif 4989 ) { 4990 return BCM_E_NONE; 4991 } 4992 if(!SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit),port)) { 4993 return BCM_E_PORT; 4994 } 4995 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 4996 return BCM_E_PORT; 4997 } 4998 4999 if (mode < 0 || mode >= BCM_LINKSCAN_MODE_COUNT) { 5000 return BCM_E_PARAM; 5001 } 5002 5003 SOC_PBMP_CLEAR(empty_pbm); 5004 5005 LC_LOCK(unit); 5006 5007 /* First, remove from current configuration */ 5008 SOC_PBMP_PORT_REMOVE(lc->lc_pbm_sw, port); 5009 SOC_PBMP_PORT_REMOVE(lc->lc_pbm_hw, port); 5010 5011 /* Now add back to proper map */ 5012 switch (mode) { 5013 case BCM_LINKSCAN_MODE_NONE: 5014 if (SOC_PBMP_MEMBER(sop->lc_pbm_remote_fault, port)) { 5015 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_remote_fault, port); 5016 SOC_PBMP_PORT_REMOVE(sop->lc_pbm_link, port); 5017 } 5018 break; 5019 case BCM_LINKSCAN_MODE_SW: 5020 SOC_PBMP_PORT_ADD(lc->lc_pbm_sw, port); 5021 added = 1; 5022 break; 5023 case BCM_LINKSCAN_MODE_HW: 5024 _BCM_LINK_IF_ERROR_RETURN(_bcm_port_link_get(unit, port, 0, &link_up)); 5025 5026 /* syncup pbm with cmic_miim_link_status registesrs, 5027 to avoid misleading up/down notification */ 5028 _BCM_LINK_IF_ERROR_RETURN(soc_linkscan_hw_link_get(unit, &tmp_pbm)); 5029 if(SOC_PBMP_MEMBER(tmp_pbm, port) && !link_up && 5030 !BCM_PBMP_MEMBER(lc->lc_pbm_fast, port)) { 5031 /* if CMIC says up but phy says down, mark it up, and 5032 expect an interrupt later to trig all necessary procedure */ 5033 SOC_PBMP_PORT_ADD(sop->lc_pbm_link, port); 5034 } 5035 5036 SOC_PBMP_PORT_ADD(lc->lc_pbm_hw, port); 5037 5038 /* Need to run SW link scan as well on ports where the source 5039 * of the link status is the internal Serdes - only SGMII ports 5040 */ 5041 if (BCM_PBMP_MEMBER(lc->lc_pbm_sgmii_autoneg_port, port)) { 5042 SOC_PBMP_PORT_ADD(lc->lc_pbm_sw, port); 5043 } 5044 added = 1; 5045 lc->lc_hw_change = 1; 5046 break; 5047 /* coverity[dead_error_begin:FALSE] */ 5048 default: 5049 return BCM_E_PARAM; 5050 } 5051 5052 5053 /* Reconfigure HW linkscan in case changed */ 5054 rv = soc_linkscan_config(unit, lc->lc_pbm_hw, empty_pbm); 5055 5056 /* Prime the HW linkscan pump */ 5057 if (SOC_PBMP_NOT_NULL(lc->lc_pbm_hw)) { 5058 lc->lc_hw_change = 1; 5059 _bcm_esw_linkscan_hw_interrupt(unit); 5060 } 5061 5062 #ifdef BCM_WARM_BOOT_SUPPORT 5063 SOC_CONTROL_LOCK(unit); 5064 SOC_CONTROL(unit)->scache_dirty = 1; 5065 SOC_CONTROL_UNLOCK(unit); 5066 #endif 5067 5068 LC_UNLOCK(unit); 5069 5070 if (lc->lc_sema != NULL) { 5071 sal_sem_give(lc->lc_sema); /* register change now */ 5072 } 5073 5074 /* When no longer scanning a port, return it to the enabled state. */ 5075 if (BCM_SUCCESS(rv) && !added && !(lc->lc_warm_boot)) { 5076 int enable; 5077 5078 #ifdef BCM_RCPU_SUPPORT 5079 if (SOC_IS_RCPU_ONLY(unit) && (port == RCPU_PORT(unit))) { 5080 return BCM_E_NONE; 5081 } 5082 #endif /* BCM_RCPU_SUPPORT */ 5083 if (BCM_SUCCESS(bcm_esw_port_enable_get(unit, port, &enable))) { 5084 (void)bcm_esw_port_update(unit, port, enable); 5085 } 5086 } 5087 5088 return(rv); 5089 } 5090 5091 /* 5092 * Function: 5093 * bcm_esw_linkscan_mode_set_pbm 5094 * Purpose: 5095 * Set the current scanning mode for the specified ports. 5096 * Parameters: 5097 * unit - StrataSwitch Unit #. 5098 * pbm - Port bit map indicating port to set. 5099 * mode - New scan mode for specified ports. 5100 * Returns: 5101 * BCM_E_XXX 5102 */ 5103 5104 int 5105 bcm_esw_linkscan_mode_set_pbm(int unit, pbmp_t pbm, int mode) 5106 { 5107 bcm_port_t port; 5108 5109 LC_CHECK_INIT(unit); 5110 5111 PBMP_ITER(pbm, port) { 5112 BCM_IF_ERROR_RETURN 5113 (bcm_esw_linkscan_mode_set(unit, port, mode)); 5114 } 5115 5116 return (BCM_E_NONE); 5117 } 5118 5119 int 5120 _bcm_esw_lc_lock(int unit) 5121 { 5122 LC_LOCK(unit); 5123 return BCM_E_NONE; 5124 } 5125 5126 int 5127 _bcm_esw_lc_unlock(int unit) 5128 { 5129 LC_UNLOCK(unit); 5130 return BCM_E_NONE; 5131 } 5132 5133 int _bcm_esw_lc_check_init(int unit) 5134 { 5135 LC_CHECK_INIT(unit); 5136 return BCM_E_NONE; 5137 } 5138 /* 5139 * Function: 5140 * bcm_esw_linkscan_mode_get 5141 * Purpose: 5142 * Recover the current scanning mode for the specified port. 5143 * Parameters: 5144 * unit - StrataSwitch Unit #. 5145 * port - StrataSwitch Port #. 5146 * mode - (OUT) current scan mode for specified port. 5147 * Returns: 5148 * BCM_E_XXX 5149 */ 5150 5151 int 5152 bcm_esw_linkscan_mode_get(int unit, bcm_port_t port, int *mode) 5153 { 5154 ls_cntl_t *lc = link_control[unit]; 5155 5156 LC_CHECK_INIT(unit); 5157 if (BCM_GPORT_IS_SET(port)) { 5158 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &port)); 5159 } 5160 if (!SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 5161 return BCM_E_PORT; 5162 } 5163 if(!SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit),port)) { 5164 return BCM_E_PORT; 5165 } 5166 if (NULL == mode) { 5167 return BCM_E_PARAM; 5168 } 5169 5170 if (PBMP_MEMBER(lc->lc_pbm_hw, port)) { 5171 *mode = BCM_LINKSCAN_MODE_HW; 5172 } else if (PBMP_MEMBER(lc->lc_pbm_sw, port)) { 5173 *mode = BCM_LINKSCAN_MODE_SW; 5174 } else { 5175 *mode = BCM_LINKSCAN_MODE_NONE; 5176 } 5177 5178 return(BCM_E_NONE); 5179 } 5180 5181 /* 5182 * Function: 5183 * bcm_esw_linkscan_enable_get 5184 * Purpose: 5185 * Retrieve the current linkscan mode. 5186 * Parameters: 5187 * unit - StrataSwitch unit #. 5188 * us - (OUT) Pointer to microsecond scan time for software scanning, 5189 * 0 if not enabled. 5190 * Returns: 5191 * BCM_E_XXX 5192 */ 5193 5194 int 5195 bcm_esw_linkscan_enable_get(int unit, int *us) 5196 { 5197 LC_CHECK_INIT(unit); 5198 5199 *us = link_control[unit]->lc_us; 5200 5201 return(BCM_E_NONE); 5202 } 5203 5204 /* 5205 * Function: 5206 * bcm_esw_linkscan_enable_set 5207 * Purpose: 5208 * Enable or disable the link scan feature. 5209 * Parameters: 5210 * unit - StrataSwitch unit #. 5211 * us - Specifies the software polling interval in micro-seconds; 5212 * the value 0 disables linkscan. 5213 * Returns: 5214 * BCM_E_XXX 5215 */ 5216 5217 int 5218 bcm_esw_linkscan_enable_set(int unit, int us) 5219 { 5220 ls_cntl_t *lc = link_control[unit]; 5221 int rv = BCM_E_NONE; 5222 soc_timeout_t to; 5223 pbmp_t empty_pbm; 5224 sal_usecs_t wait_usec; 5225 5226 /* Time to wait for thread to start/end (longer for BCMSIM) */ 5227 wait_usec = (SAL_BOOT_BCMSIM || SAL_BOOT_QUICKTURN) ? 30000000 : 10000000; 5228 5229 if (!us && lc == NULL) { /* No error to disable if not inited */ 5230 return(BCM_E_NONE); 5231 } 5232 5233 LC_CHECK_INIT(unit); 5234 5235 sal_snprintf(lc->lc_taskname, 5236 sizeof (lc->lc_taskname), 5237 "bcmLINK.%d", 5238 unit); 5239 5240 SOC_PBMP_CLEAR(empty_pbm); 5241 5242 if (us) { 5243 if (us < BCM_LINKSCAN_INTERVAL_MIN) { 5244 us = BCM_LINKSCAN_INTERVAL_MIN; 5245 } 5246 5247 lc->lc_us = us; 5248 5249 if (lc->lc_thread != NULL) { 5250 /* Linkscan is already running; just update the period */ 5251 sal_sem_give(lc->lc_sema); 5252 return SOC_E_NONE; 5253 } 5254 5255 5256 if (sal_thread_create(lc->lc_taskname, 5257 SAL_THREAD_STKSZ, 5258 soc_property_get(unit, 5259 spn_LINKSCAN_THREAD_PRI, 5260 50), 5261 (void (*)(void*))_bcm_esw_linkscan_thread, 5262 INT_TO_PTR(unit)) == SAL_THREAD_ERROR) { 5263 lc->lc_us = 0; 5264 rv = BCM_E_MEMORY; 5265 } else { 5266 soc_timeout_init(&to, wait_usec, 0); 5267 5268 while (lc->lc_thread == NULL) { 5269 if (soc_timeout_check(&to)) { 5270 LOG_ERROR(BSL_LS_BCM_LINK, 5271 (BSL_META_U(unit, 5272 "%s: Thread did not start\n"), 5273 lc->lc_taskname)); 5274 lc->lc_us = 0; 5275 rv = BCM_E_INTERNAL; 5276 break; 5277 } 5278 } 5279 if (BCM_SUCCESS(rv)) { 5280 /* Make sure HW linkscanning is enabled on HW linkscan ports */ 5281 rv = soc_linkscan_config(unit, lc->lc_pbm_hw, empty_pbm); 5282 } 5283 } 5284 } else if (lc->lc_thread != NULL) { 5285 lc->lc_us = 0; 5286 5287 /* To prevent getting HW linkscan interrupt after linkscan is disabled, 5288 * HW linkscanning must be disabled. */ 5289 rv = soc_linkscan_config(unit, empty_pbm, empty_pbm); 5290 5291 sal_sem_give(lc->lc_sema); 5292 5293 soc_timeout_init(&to, wait_usec, 0); 5294 5295 while (lc->lc_thread != NULL) { 5296 if (soc_timeout_check(&to)) { 5297 LOG_ERROR(BSL_LS_BCM_LINK, 5298 (BSL_META_U(unit, 5299 "%s: Thread did not exit\n"), 5300 lc->lc_taskname)); 5301 rv = BCM_E_INTERNAL; 5302 break; 5303 } 5304 } 5305 } 5306 5307 return(rv); 5308 } 5309 5310 /* 5311 * Function: 5312 * bcm_esw_linkscan_register 5313 * Purpose: 5314 * Register a handler to be called when a link status change is noticed. 5315 * The handler function must not suspend indefinitely or invoke any API 5316 * that may result in a deadlock. 5317 * Parameters: 5318 * unit - StrataSwitch unit #. 5319 * f - pointer to function to call when link status change is seen 5320 * Returns: 5321 * BCM_E_XXX 5322 */ 5323 5324 int 5325 bcm_esw_linkscan_register(int unit, bcm_linkscan_handler_t f) 5326 { 5327 ls_cntl_t *lc = link_control[unit]; 5328 ls_handler_t *lh; 5329 int found = FALSE; 5330 5331 LC_CHECK_INIT(unit); 5332 5333 /* First, see if this handler already registered */ 5334 LC_LOCK(unit); 5335 5336 for (lh = lc->lc_handler; lh != NULL; lh = lh->lh_next) { 5337 if (lh->lh_f == f) { 5338 found = TRUE; 5339 break; 5340 } 5341 } 5342 5343 if (found) { 5344 LC_UNLOCK(unit); 5345 return BCM_E_NONE; 5346 } 5347 5348 if ((lh = sal_alloc(sizeof(*lh), "bcm_linkscan_register")) == NULL) { 5349 LC_UNLOCK(unit); 5350 return(BCM_E_MEMORY); 5351 } 5352 5353 lh->lh_next = lc->lc_handler; 5354 lh->lh_f = f; 5355 lc->lc_handler = lh; 5356 5357 LC_UNLOCK(unit); 5358 5359 return(BCM_E_NONE); 5360 } 5361 5362 /* 5363 * Function: 5364 * bcm_esw_linkscan_unregister 5365 * Purpose: 5366 * Remove a previously registered handler from the callout list. 5367 * Parameters: 5368 * unit - StrataSwitch unit #. 5369 * f - Pointer to function registered in call to 5370 * bcm_linkscan_register. 5371 * Returns: 5372 * BCM_E_NOT_FOUND Could not find matching handler 5373 * BCM_E_NONE Success 5374 */ 5375 5376 int 5377 bcm_esw_linkscan_unregister(int unit, bcm_linkscan_handler_t f) 5378 { 5379 ls_cntl_t *lc = link_control[unit]; 5380 ls_handler_t *lh, *p; 5381 5382 LC_CHECK_INIT(unit); 5383 5384 LC_LOCK(unit); 5385 5386 for (p = NULL, lh = lc->lc_handler; lh; p = lh, lh = lh->lh_next) { 5387 if (lh->lh_f == f) { 5388 if (p == NULL) { 5389 lc->lc_handler = lh->lh_next; 5390 } else { 5391 p->lh_next = lh->lh_next; 5392 } 5393 break; 5394 } 5395 } 5396 5397 LC_UNLOCK(unit); 5398 5399 if (lh != NULL) { 5400 sal_free(lh); 5401 return BCM_E_NONE; 5402 } else { 5403 return BCM_E_NOT_FOUND; 5404 } 5405 } 5406 5407 /* 5408 * Function: 5409 * bcm_esw_linkscan_port_register 5410 * Purpose: 5411 * Register a handler to be called when a link status 5412 * is to be determined by a caller provided function. 5413 * Parameters: 5414 * unit - StrataSwitch unit number. 5415 * port - StrataSwitch port number. 5416 * f - pointer to function to call for true link status 5417 * Returns: 5418 * BCM_E_XXX 5419 * Notes: 5420 * This function works with software linkscan only. 5421 */ 5422 5423 int 5424 bcm_esw_linkscan_port_register(int unit, bcm_port_t port, 5425 bcm_linkscan_port_handler_t f) 5426 { 5427 ls_cntl_t *lc = link_control[unit]; 5428 5429 LC_CHECK_INIT(unit); 5430 if (BCM_GPORT_IS_SET(port)) { 5431 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &port)); 5432 } 5433 if (!SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit),port) || 5434 !SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 5435 return BCM_E_PORT; 5436 } 5437 5438 LC_LOCK(unit); 5439 lc->lc_f[port] = f; 5440 LC_UNLOCK(unit); 5441 5442 return (BCM_E_NONE); 5443 } 5444 5445 /* 5446 * Function: 5447 * bcm_esw_linkscan_port_unregister 5448 * Purpose: 5449 * Remove a previously registered handler that is used 5450 * for setting link status. 5451 * Parameters: 5452 * unit - StrataSwitch unit number. 5453 * port - StrataSwitch port number. 5454 * f - Pointer to function registered in call to 5455 * bcm_linkscan_port_register. 5456 * Returns: 5457 * BCM_E_XXX 5458 */ 5459 5460 int 5461 bcm_esw_linkscan_port_unregister(int unit, bcm_port_t port, 5462 bcm_linkscan_port_handler_t f) 5463 { 5464 ls_cntl_t *lc = link_control[unit]; 5465 int rv; 5466 5467 LC_CHECK_INIT(unit); 5468 if (BCM_GPORT_IS_SET(port)) { 5469 BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &port)); 5470 } 5471 if (!SOC_PBMP_MEMBER(PBMP_PORT_ALL(unit),port) || 5472 !SOC_PORT_VALID(unit, port) || !IS_PORT(unit, port)) { 5473 return BCM_E_PORT; 5474 } 5475 5476 LC_LOCK(unit); 5477 if (f == lc->lc_f[port]) { 5478 lc->lc_f[port] = NULL; 5479 rv = BCM_E_NONE; 5480 } else { 5481 rv = BCM_E_NOT_FOUND; 5482 } 5483 LC_UNLOCK(unit); 5484 5485 return (rv); 5486 } 5487 5488 /* 5489 * Function: 5490 * bcm_link_wait 5491 * Purpose: 5492 * Wait for all links in the mask to be "link up". 5493 * Parameters: 5494 * unit - StrataSwitch unit #. 5495 * pbm - (IN/OUT) Port bit map to wait for, mask of those link up on 5496 * return. 5497 * us - number of microseconds to wait. 5498 * Returns: 5499 * BCM_E_NONE - all links are ready. 5500 * BCM_E_TIMEOUT - not all links ready in specified time. 5501 * BCM_E_DISABLED - linkscan not running on one or more of the ports. 5502 */ 5503 5504 int 5505 bcm_esw_link_wait(int unit, pbmp_t *pbm, int us) 5506 { 5507 soc_persist_t *sop = SOC_PERSIST(unit); 5508 ls_cntl_t *lc = link_control[unit]; 5509 soc_timeout_t to; 5510 pbmp_t sofar_pbm; 5511 soc_port_t port; 5512 5513 /* Input parameters check. */ 5514 if ((NULL == pbm) || (us < 0)) { 5515 return (BCM_E_PARAM); 5516 } 5517 5518 BCM_PBMP_ITER(*pbm, port) { 5519 BCM_IF_ERROR_RETURN 5520 (bcm_esw_linkscan_enable_port_get(unit, port)); 5521 } 5522 5523 /* 5524 * If a port was just configured, it may have gone down but 5525 * lc_pbm_link may not reflect that until the next time linkscan 5526 * runs. This is avoided by forcing an update of lc_pbm_link. 5527 */ 5528 5529 _bcm_esw_linkscan_update(unit, 0 /*flags*/, *pbm); 5530 5531 soc_timeout_init(&to, (sal_usecs_t)us, 0); 5532 5533 for (;;) { 5534 sal_usleep(lc->lc_us / 4); 5535 5536 SOC_PBMP_ASSIGN(sofar_pbm, sop->lc_pbm_link); 5537 SOC_PBMP_REMOVE(sofar_pbm, sop->lc_pbm_remote_fault); 5538 SOC_PBMP_AND(sofar_pbm, *pbm); 5539 if (SOC_PBMP_EQ(sofar_pbm, *pbm)) { 5540 break; 5541 } 5542 5543 if (soc_timeout_check(&to)) { 5544 SOC_PBMP_AND(*pbm, sop->lc_pbm_link); 5545 SOC_PBMP_REMOVE(*pbm, sop->lc_pbm_remote_fault); 5546 return (BCM_E_TIMEOUT); 5547 } 5548 } 5549 5550 #ifdef BCM_WARM_BOOT_SUPPORT 5551 SOC_CONTROL_LOCK(unit); 5552 SOC_CONTROL(unit)->scache_dirty = 1; 5553 SOC_CONTROL_UNLOCK(unit); 5554 #endif 5555 5556 return (BCM_E_NONE); 5557 } 5558 5559 /* 5560 * Function: 5561 * bcm_linkscan_detach 5562 * Purpose: 5563 * Prepare linkscan module to detach specified unit. 5564 * Parameters: 5565 * unit - StrataSwitch Unit #. 5566 * Returns: 5567 * BCM_E_NONE - detach successful. 5568 * BCM_E_XXX - detach failed. 5569 * Notes: 5570 * This is safe to call at any time, but linkscan should only be 5571 * initialized or detached from the main application thread. 5572 */ 5573 5574 int 5575 bcm_esw_linkscan_detach(int unit) 5576 { 5577 ls_cntl_t *lc = link_control[unit]; 5578 ls_handler_t *lh; 5579 pbmp_t empty_pbm; 5580 5581 if (lc == NULL) { 5582 return BCM_E_NONE; 5583 } 5584 5585 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT) 5586 if (soc_feature(unit, soc_feature_epc_linkflap_recover)) { 5587 bcm_esw_linkscan_unregister(unit, _bcm_port_force_forward_linkscan_handler); 5588 } 5589 #endif /*defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HELIX4_SUPPORT)*/ 5590 5591 #ifdef BCM_PREEMPTION_SUPPORT 5592 if (soc_feature(unit, soc_feature_preemption)) { 5593 bcm_esw_linkscan_unregister(unit, bcmi_esw_preemption_linkscan_update); 5594 } 5595 #endif /* BCM_PREEMPTION_SUPPORT */ 5596 5597 SOC_PBMP_CLEAR(empty_pbm); 5598 5599 SOC_IF_ERROR_RETURN(soc_linkscan_config(unit, empty_pbm, empty_pbm)); 5600 5601 BCM_IF_ERROR_RETURN(bcm_esw_linkscan_enable_set(unit, 0)); 5602 5603 /* Clean up list of handlers */ 5604 5605 while (lc->lc_handler != NULL) { 5606 lh = lc->lc_handler; 5607 lc->lc_handler = lh->lh_next; 5608 sal_free(lh); 5609 } 5610 5611 /* Mark and not initialized and free mutex */ 5612 5613 if (lc->lc_sema != NULL) { 5614 sal_sem_destroy(lc->lc_sema); 5615 lc->lc_sema = NULL; 5616 } 5617 5618 if (lc->lc_lock != NULL) { 5619 sal_mutex_destroy(lc->lc_lock); 5620 lc->lc_lock = NULL; 5621 } 5622 5623 link_control[unit] = NULL; 5624 5625 sal_free(lc); 5626 5627 return(BCM_E_NONE); 5628 } 5629 5630 /* 5631 * Function: 5632 * bcm_esw_linkscan_port_attach 5633 * Purpose: 5634 * Initialize linkscan info for newly added port. 5635 * Parameters: 5636 * unit - (IN) Unit number. 5637 * port - (IN) Logical port. 5638 * Returns: 5639 * BCM_E_XXX 5640 * Note: 5641 * This function only be called by flexport operation. 5642 */ 5643 int 5644 bcm_esw_linkscan_port_attach(int unit, bcm_port_t port) 5645 { 5646 ls_cntl_t *lc = link_control[unit]; 5647 int limit; /* # errors to enter error state */ 5648 int delay; /* Length of error state in seconds */ 5649 5650 if (lc == NULL || lc->lc_thread == NULL) { 5651 return BCM_E_NONE; 5652 } 5653 5654 limit = soc_property_port_get(unit, port, spn_BCM_LINKSCAN_MAXERR, 5); 5655 delay = soc_property_port_get(unit, port, 5656 spn_BCM_LINKSCAN_ERRDELAY, 10000000); 5657 5658 LC_LOCK(unit); 5659 sal_memset(&lc->lc_error[port], 0, sizeof(ls_errstate_t)); 5660 lc->lc_error[port].limit = limit; 5661 lc->lc_error[port].delay = delay; 5662 LC_UNLOCK(unit); 5663 5664 return BCM_E_NONE; 5665 } 5666 5667 #if defined(BROADCOM_DEBUG) 5668 int 5669 bcm_esw_linkscan_dump(int unit) 5670 { 5671 ls_handler_t *ent; 5672 5673 for (unit = 0; unit < BCM_MAX_NUM_UNITS; unit++) { 5674 if (link_control[unit] == NULL) { 5675 LOG_CLI((BSL_META_U(unit, 5676 "BCM linkscan not initialized for unit %d\n"), unit)); 5677 continue; 5678 } 5679 5680 LOG_CLI((BSL_META_U(unit, 5681 "BCM linkscan callbacks for unit %d\n"), unit)); 5682 for (ent = link_control[unit]->lc_handler; ent != NULL; 5683 ent = ent->lh_next) { 5684 #if !defined(__PEDANTIC__) 5685 LOG_CLI((BSL_META_U(unit, 5686 " Fn %p\n"), (void *)ent->lh_f)); 5687 #else /* !defined(__PEDANTIC__) */ 5688 LOG_CLI((BSL_META_U(unit, 5689 " Function pointer unprintable\n"))); 5690 #endif /* !defined(__PEDANTIC__) */ 5691 } 5692 } 5693 5694 return BCM_E_NONE; 5695 } 5696 #endif /* BROADCOM_DEBUG */ 5697 5698 #ifndef BCM_SW_STATE_DUMP_DISABLE 5699 /* 5700 * Function: 5701 * _bcm_link_sw_dump 5702 * Purpose: 5703 * Displays Linkscan information maintained by software. 5704 * Parameters: 5705 * unit - Device unit number 5706 * Returns: 5707 * None 5708 * Note: 5709 */ 5710 void 5711 _bcm_link_sw_dump(int unit) 5712 { 5713 ls_cntl_t *lc = link_control[unit]; 5714 soc_persist_t *sop = SOC_PERSIST(unit); 5715 char pfmt[SOC_PBMP_FMT_LEN]; 5716 int rv, enable; 5717 bcm_port_t port; 5718 bcm_pbmp_t disabled_pbmp; 5719 5720 LOG_CLI((BSL_META_U(unit, 5721 "\nSW Information Linkscan - Unit %d\n"), unit)); 5722 5723 LOG_CLI((BSL_META_U(unit, 5724 "HW linkscan ports: %s\n"), 5725 SOC_PBMP_FMT(lc->lc_pbm_hw, pfmt))); 5726 LOG_CLI((BSL_META_U(unit, 5727 "SW linkscan ports: %s\n"), 5728 SOC_PBMP_FMT(lc->lc_pbm_sw, pfmt))); 5729 LOG_CLI((BSL_META_U(unit, 5730 "SGMII autoneg ports: %s\n"), 5731 SOC_PBMP_FMT(lc->lc_pbm_sgmii_autoneg_port, pfmt))); 5732 LOG_CLI((BSL_META_U(unit, 5733 "Info skip ports: %s\n"), 5734 SOC_PBMP_FMT(lc->lc_pbm_info_skip, pfmt))); 5735 LOG_CLI((BSL_META_U(unit, 5736 "Fast linkscan ports: %s\n"), 5737 SOC_PBMP_FMT(lc->lc_pbm_fast, pfmt))); 5738 5739 LOG_CLI((BSL_META_U(unit, 5740 "Forwarding ports: %s\n"), 5741 SOC_PBMP_FMT(sop->link_fwd, pfmt))); 5742 LOG_CLI((BSL_META_U(unit, 5743 "MAC enabled ports: %s\n"), 5744 SOC_PBMP_FMT(SOC_CONTROL(unit)->link_mask2, pfmt))); 5745 LOG_CLI((BSL_META_U(unit, 5746 "Link up ports: %s\n"), 5747 SOC_PBMP_FMT(sop->lc_pbm_link, pfmt))); 5748 LOG_CLI((BSL_META_U(unit, 5749 "Impending down ports: %s\n"), 5750 SOC_PBMP_FMT(sop->lc_pbm_link_change, pfmt))); 5751 LOG_CLI((BSL_META_U(unit, 5752 "Forced ports: %s\n"), 5753 SOC_PBMP_FMT(sop->lc_pbm_override_ports, pfmt))); 5754 LOG_CLI((BSL_META_U(unit, 5755 "Link up forced link ports: %s\n"), 5756 SOC_PBMP_FMT(sop->lc_pbm_override_link, pfmt))); 5757 LOG_CLI((BSL_META_U(unit, 5758 "TX enabled without link ports: %s\n"), 5759 SOC_PBMP_FMT(sop->lc_pbm_linkdown_tx, pfmt))); 5760 LOG_CLI((BSL_META_U(unit, 5761 "Remote fault received ports: %s\n"), 5762 SOC_PBMP_FMT(sop->lc_pbm_remote_fault, pfmt))); 5763 LOG_CLI((BSL_META_U(unit, 5764 "Enabled for LAG failover ports: %s\n"), 5765 SOC_PBMP_FMT(sop->lc_pbm_failover, pfmt))); 5766 LOG_CLI((BSL_META_U(unit, 5767 "Failed LAG failover ports: %s\n"), 5768 SOC_PBMP_FMT(sop->lc_pbm_failed, pfmt))); 5769 LOG_CLI((BSL_META_U(unit, 5770 "Recovering LAG failover ports: %s\n"), 5771 SOC_PBMP_FMT(sop->lc_pbm_failed_clear, pfmt))); 5772 5773 SOC_PBMP_CLEAR(disabled_pbmp); 5774 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 5775 rv = bcm_esw_port_enable_get(unit, port, &enable); 5776 if (BCM_FAILURE(rv)) { 5777 LOG_CLI((BSL_META_U(unit, 5778 "Error checking port %d enable state: %s\n"), 5779 port, bcm_errmsg(rv))); 5780 return; 5781 } 5782 if (!enable) { 5783 SOC_PBMP_PORT_ADD(disabled_pbmp, port); 5784 } 5785 } 5786 5787 LOG_CLI((BSL_META_U(unit, 5788 "Disabled ports: %s\n"), 5789 SOC_PBMP_FMT(disabled_pbmp, pfmt))); 5790 return; 5791 } 5792 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 5793 5794 #if defined(BCM_CMICX_SUPPORT) || defined(BCM_DNXF_SUPPORT) 5795 /* 5796 * Function: 5797 * cmicx_esw_linkscan_hw_interrupt 5798 * Purpose: 5799 * Link scan interrupt handler. 5800 * Parameters: 5801 * unit - Device unit number 5802 * Returns: 5803 * Nothing 5804 * Notes: 5805 * Assumes: valid unit number. 5806 */ 5807 void 5808 cmicx_esw_linkscan_hw_interrupt(int unit) 5809 { 5810 ls_cntl_t *lc = link_control[unit]; 5811 5812 if ((NULL != lc) && (NULL != lc->lc_sema)) { 5813 lc->lc_hw_change = 1; 5814 sal_sem_give(lc->lc_sema); 5815 } 5816 LOG_VERBOSE(BSL_LS_BCM_LINK, 5817 (BSL_META_U(unit, 5818 "Linkscan interrupt unit %d\n"), unit)); 5819 } 5820 #endif 5821