openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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, &params));
   3051 
   3052                         params.phyn = 0; /* Only find serdes */
   3053                         BCM_IF_ERROR_RETURN
   3054                             (portmod_port_phy_lane_access_get(
   3055                                  unit, port, &params, (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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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, &regval);
   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