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

mac.c (111530B)


      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  * StrataSwitch Media Access Controller API
      8  */
      9 
     10 #include <shared/bsl.h>
     11 
     12 #include <sal/core/libc.h>
     13 #include <shared/alloc.h>
     14 #include <sal/core/spl.h>
     15 
     16 #include <soc/drv.h>
     17 #include <soc/error.h>
     18 #include <soc/cmic.h>
     19 #include <soc/portmode.h>
     20 #include <soc/ll.h>
     21 #include <soc/phyctrl.h>
     22 #include <soc/macutil.h>
     23 
     24 #include <soc/mem.h>
     25 
     26 #if defined(BCM_ESW_SUPPORT)
     27 
     28 #define JUMBO_MAXSZ  0x3fe8
     29 
     30 /*
     31  * Forward Declarations
     32  *
     33  *      mac_fe_xxx      Routines that work on FE ports and
     34  *                      GE ports that support 10/100 mode.
     35  *      mac_ge_xxx      Routines that work on GE ports and
     36  *                      GE ports that support 10/100 mode.
     37  */
     38 
     39 STATIC int      mac_fe_init(int unit, soc_port_t port);
     40 STATIC int      mac_fe_enable_set(int unit, soc_port_t port, int enable);
     41 STATIC int      mac_fe_enable_get(int unit, soc_port_t port, int *enable);
     42 
     43 STATIC int      mac_fe_duplex_set(int unit, soc_port_t port, int duplex);
     44 STATIC int      mac_fe_duplex_get(int unit, soc_port_t port, int *duplex);
     45 STATIC int      mac_fe_speed_set(int unit, soc_port_t port, int speed);
     46 STATIC int      mac_fe_speed_get(int unit, soc_port_t port, int *speed);
     47 
     48 STATIC int      mac_fe_pause_set(int unit, soc_port_t port,
     49                                  int pause_tx, int pause_rx);
     50 STATIC int      mac_fe_pause_get(int unit, soc_port_t port,
     51                                  int *pause_tx, int *pause_rx);
     52 
     53 STATIC int      mac_ge_init(int unit, soc_port_t port);
     54 STATIC int      mac_ge_enable_set(int unit, soc_port_t port, int enable);
     55 STATIC int      mac_ge_enable_get(int unit, soc_port_t port, int *enable);
     56 
     57 STATIC int      mac_ge_duplex_set(int unit, soc_port_t port, int duplex);
     58 STATIC int      mac_ge_duplex_get(int unit, soc_port_t port, int *duplex);
     59 STATIC int      mac_ge_speed_set(int unit, soc_port_t port, int speed);
     60 STATIC int      mac_ge_speed_get(int unit, soc_port_t port, int *speed);
     61 STATIC int      mac_ge_frame_max_set(int unit, soc_port_t port, int size);
     62 
     63 STATIC int      mac_ge_pause_set(int unit, soc_port_t port,
     64                                  int pause_tx, int pause_rx);
     65 STATIC int      mac_ge_pause_get(int unit, soc_port_t port,
     66                                  int *pause_tx, int *pause_rx);
     67 STATIC int      mac_ge_pause_addr_set(int unit, soc_port_t port,
     68                                       sal_mac_addr_t);
     69 STATIC int      mac_ge_pause_addr_get(int unit, soc_port_t port,
     70                                       sal_mac_addr_t);
     71 STATIC int      mac_ge_loopback_set(int unit, soc_port_t port, int);
     72 STATIC int      mac_ge_loopback_get(int unit, soc_port_t port, int *);
     73 STATIC int      mac_ge_interface_set(int unit, soc_port_t port,
     74                                      soc_port_if_t pif);
     75 
     76 /*
     77  * Helper macros for PAUSE_CONTROL setting.  The PAUSE_CONTROL value
     78  * determines how often XOFFs must be sent.  We use 75% of the maximum
     79  * value to give some time for the pause to be transmitted and parsed
     80  * on the far side.  These are all usually counted in units of 512 bit
     81  * times independent of port speed, so PAUSE_VAL(512) can be used to
     82  * set the PAUSE_CONTROL register at initialization time.
     83  */
     84 #define	PAUSE_MAX	0x10000		/* units of 512 bit times */
     85 #define	PAUSE_VAL(_bt)	(PAUSE_MAX * (512/_bt) * 3 / 4)
     86 
     87 /*
     88  * Function:
     89  *      soc_mac_probe
     90  * Purpose:
     91  *      Probe the specified unit/port for MAC type and return
     92  *      a mac_driver_t pointer used to drive the MAC.
     93  * Parameters:
     94  *      unit - StrataSwitch/XGS Unit #.
     95  *      port - StrataSwitch/XGS Port # on unit.
     96  *      macd_ptr - (OUT) Pointer to MAC driver.
     97  * Returns:
     98  *      SOC_E_XXX
     99  */
    100 
    101 int
    102 soc_mac_probe(int unit, soc_port_t port, mac_driver_t **macdp)
    103 {
    104 #if defined(BCM_SABER2_SUPPORT)
    105     if (SOC_IS_SABER2(unit)) {
    106         *macdp = &soc_mac_xl;
    107          return SOC_E_NONE;
    108     }
    109 #endif
    110 
    111 #ifdef BCM_CLMAC_SUPPORT
    112     if (soc_feature(unit, soc_feature_cport_clmac)) {
    113         if ((IS_CXX_PORT(unit, port) || IS_C_PORT(unit, port)) &&
    114             SOC_INFO(unit).port_speed_max[port] >= 100000) {
    115             *macdp = &soc_mac_cl;
    116         } else if ((SOC_IS_APACHE(unit) || SOC_IS_MONTEREY(unit)) &&
    117                    (IS_CL_PORT(unit, port) || IS_CLG2_PORT(unit, port))) {
    118             *macdp = &soc_mac_cl;
    119         } else 
    120         {
    121             *macdp = &soc_mac_xl;
    122         }
    123         return SOC_E_NONE;
    124     }
    125 #endif /* BCM_CLMAC_SUPPORT */
    126 
    127 #ifdef BCM_GREYHOUND2_SUPPORT
    128     if (SOC_IS_GREYHOUND2(unit) && IS_CL_PORT(unit, port)) {
    129         *macdp = &soc_mac_cl;
    130         return SOC_E_NONE;
    131     }
    132 #endif /* BCM_GREYHOUND2_SUPPORT */
    133 
    134     if (IS_FE_PORT(unit, port)) {
    135 #ifdef BCM_UNIMAC_SUPPORT
    136         if (soc_feature(unit, soc_feature_unimac)) {
    137             *macdp = &soc_mac_uni;
    138         } else 
    139 #endif
    140         {
    141             *macdp = &soc_mac_fe;
    142         }
    143 #if defined(BCM_XMAC_SUPPORT) && defined(BCM_ESW_SUPPORT)
    144     } else if (IS_MXQ_PORT(unit, port)) {
    145         *macdp = &soc_mac_x;
    146 #endif
    147 #ifdef BCM_GXPORT_SUPPORT
    148 #if defined(BCM_HUMV_SUPPORT) || defined(BCM_BRADLEY_SUPPORT) || \
    149     defined(BCM_GOLDWING_SUPPORT)
    150     } else if (IS_GX_PORT(unit, port) &&
    151                (SOC_IS_HUMV(unit) || SOC_IS_BRADLEY(unit) ||
    152                 SOC_IS_GOLDWING(unit))) {
    153         *macdp = &soc_mac_gx;
    154 #endif /* BCM_HUMV_SUPPORT || BCM_BRADLEY_SUPPORT || BCM_GOLDWING_SUPPORT */
    155 #endif /* BCM_GXPORT_SUPPORT */
    156     } else if (IS_GE_PORT(unit, port) && !SOC_IS_TD2_TT2(unit)) {
    157 #ifdef BCM_HURRICANE2_SUPPORT
    158 	if ((SOC_IS_HURRICANE2(unit)|| SOC_IS_GREYHOUND(unit) || 
    159         SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) && 
    160 			IS_XL_PORT(unit,port)) {
    161 		*macdp = &soc_mac_xl;
    162 	} else
    163 #endif
    164 #ifdef BCM_UNIMAC_SUPPORT
    165         if (soc_feature(unit, soc_feature_unimac)) {
    166             *macdp = &soc_mac_uni;
    167         } else
    168 #endif
    169         {
    170             if (SOC_IS_TRIUMPH3(unit)) { /* For all GE's */
    171                 *macdp = &soc_mac_x;
    172             } else {
    173                 *macdp = &soc_mac_ge;
    174             }
    175         }
    176     } else if (soc_feature(unit, soc_feature_unified_port)) {
    177 #if defined(BCM_CMAC_SUPPORT)
    178         if (IS_CL_PORT(unit, port) || IS_C_PORT(unit, port)) {
    179 #if defined(BCM_CLMAC_SUPPORT)
    180             if (soc_feature(unit, soc_feature_clmac)) {
    181                 *macdp = &soc_mac_cl;
    182                 return SOC_E_NONE;
    183             } else
    184 #endif /* BCM_CLMAC_SUPPORT */
    185             if (IS_CE_PORT(unit, port) ||
    186                 SOC_INFO(unit).port_speed_max[port] >= 100000) {
    187                 *macdp = &soc_mac_c;
    188                 return SOC_E_NONE;
    189             } else {
    190                 *macdp = &soc_mac_x;
    191                 return SOC_E_NONE;
    192             }
    193         }
    194 #endif /* BCM_CMAC_SUPPORT */
    195 #if defined(BCM_XLMAC_SUPPORT)
    196         if (soc_feature(unit, soc_feature_xlmac)) {
    197             *macdp = &soc_mac_xl;
    198         }
    199 #endif /* BCM_XLPORT_SUPPORT */
    200 #if defined(BCM_XMAC_SUPPORT)
    201         if (soc_feature(unit, soc_feature_xmac)) {
    202             *macdp = &soc_mac_x;
    203         }
    204 #endif /* BCM_XMAC_SUPPORT */
    205         return SOC_E_NONE;
    206 #if (defined(BCM_BIGMAC_SUPPORT) || defined(BCM_XMAC_SUPPORT)) && defined(BCM_UNIMAC_SUPPORT)
    207     } else if (IS_GX_PORT(unit, port) ||
    208                (IS_XG_PORT(unit, port) &&
    209                 soc_feature(unit, soc_feature_flexible_xgport))) {
    210 #ifdef BCM_ESW_SUPPORT
    211         if (IS_IL_PORT(unit, port)) {
    212             *macdp = &soc_mac_il;
    213         } else
    214 #endif /* BCM_ESW_SUPPORT */
    215         {
    216             *macdp = &soc_mac_combo;
    217         }
    218 #endif /* (BCM_BIGMAC_SUPPORT || BCM_XMAC_SUPPORT) && BCM_UNIMAC_SUPPORT */
    219     } else if (((IS_XE_PORT(unit, port)) || (IS_HG_PORT(unit, port))) && !SOC_IS_TRIUMPH3(unit)) {
    220 #ifdef BCM_BIGMAC_SUPPORT
    221         {
    222             *macdp = &soc_mac_big;
    223         }
    224 #endif /* BCM_BIGMAC_SUPPORT */
    225     } else {
    226         return SOC_E_PARAM;
    227     }
    228     return SOC_E_NONE;
    229 }
    230 
    231 /*
    232  * Function:
    233  *      soc_mac_speed_get
    234  * Purpose:
    235  *      Get the speed of a given mac
    236  * Parameters:
    237  *      unit   - Strata Switch unit #
    238  *      port   - Strata Switch port #
    239  *      speed - (OUT) Speed in Mb/sec
    240  * Notes:
    241  *      Do not add a soc_mac_speed_set function.  Use the
    242  *      higher level MAC driver (eg in bcm/port.c) for this.
    243  * Returns:
    244  *      SOC_E_XXX
    245  */
    246 
    247 int
    248 soc_mac_speed_get(int unit, soc_port_t port, int *speed)
    249 {
    250     uint32           fereg;
    251     soc_mac_mode_t   mode;
    252     int              turbo = 0;
    253 
    254     if (speed == NULL) {
    255         return SOC_E_PARAM;
    256     }
    257 
    258     if (IS_FE_PORT(unit, port)) {
    259         SOC_IF_ERROR_RETURN(READ_FE_SUPPr(unit, port, &fereg));
    260         if (soc_reg_field_get(unit, FE_SUPPr, fereg, SPEEDf)) {
    261             *speed = 100;
    262         } else {
    263             *speed = 10;
    264         }
    265     } else {
    266         SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
    267         switch (mode) {
    268         case SOC_MAC_MODE_10:
    269         case SOC_MAC_MODE_10_100:       /* Get the speed from the mac */
    270             SOC_IF_ERROR_RETURN(FE_READ(FE_SUPPr, GTH_FE_SUPPr,
    271                                         unit, port, &fereg));
    272             if (soc_reg_field_get(unit, FE_SUPPr, fereg, SPEEDf)) {
    273                 *speed = 100;
    274             } else {
    275                 *speed = 10;
    276             }
    277             break;
    278         case SOC_MAC_MODE_1000_T:
    279 #if defined(BCM_RAPTOR1_SUPPORT)
    280             if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port))  {
    281                 soc_pbmp_t pbmp_s0;
    282                 uint32     gport_config;
    283 
    284                 SOC_IF_ERROR_RETURN(
    285                     READ_GPORT_CONFIGr(unit, port, &gport_config));
    286                 SOC_PBMP_WORD_SET(pbmp_s0, 0, 0x00000002);
    287                 if (SOC_PBMP_MEMBER(pbmp_s0, port)) {
    288                     turbo = soc_reg_field_get(unit, GPORT_CONFIGr, 
    289                                               gport_config, PLL_MODE_DEF_S0f); 
    290                 } else {
    291                     turbo = soc_reg_field_get(unit, GPORT_CONFIGr, 
    292                                               gport_config, PLL_MODE_DEF_S1f); 
    293                 }
    294             }
    295 #endif
    296             /* coverity[dead_error_line] */
    297             *speed = turbo ? 2500 : 1000;
    298             break;
    299         case SOC_MAC_MODE_10000:
    300             *speed = 10000;
    301 #if defined(BCM_HELIX15_SUPPORT) || defined(BCM_FELIX15_SUPPORT) || \
    302     defined(BCM_FIREBOLT2_SUPPORT)
    303             if (soc_feature(unit, soc_feature_lmd)) {
    304                 if (IS_LMD_ENABLED_PORT(unit, port)) {
    305                     *speed >>= 2;   /* Div by 4 */
    306                 }
    307             }
    308 #endif /* BCM_HELIX15_SUPPORT || BCM_FELIX15_SUPPORT ||
    309           BCM_FIREBOLT2_SUPPORT */
    310             break;
    311         default:
    312             return(SOC_E_INTERNAL);
    313         }
    314     }
    315     return(SOC_E_NONE);
    316 }
    317 
    318 /*
    319  * Function:
    320  *      _port_sp_sel_get/set
    321  * Purpose:
    322  *      Get/set speed select for a port based on chip type and port
    323  * Parameters:
    324  *      unit, port
    325  * Returns:
    326  *      Returns < 0 on error.  Otherwise, speed select value for port.
    327  * Notes:
    328  *      These should only be called for gig ports supporting fe mode.
    329  */
    330 
    331 STATIC int
    332 _port_sp_sel_get(int unit, int port)
    333 {
    334 #ifdef  BCM_XGS3_SWITCH_SUPPORT
    335     if (soc_feature(unit, soc_feature_trimac)) {
    336         /* FB/ER puts speed into GE_PORT_CONFIGr */
    337         uint32 val;
    338 
    339         SOC_IF_ERROR_RETURN(READ_GE_PORT_CONFIGr(unit, port, &val));
    340         return soc_reg_field_get(unit, GE_PORT_CONFIGr, val, SPEED_SELECTf);
    341     }
    342 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    343 
    344     return SOC_E_INTERNAL;
    345 }
    346 
    347 STATIC int
    348 _port_sp_sel_set(int unit, int port, uint32 sp_sel)
    349 {
    350 #ifdef  BCM_XGS3_SWITCH_SUPPORT
    351     if (soc_feature(unit, soc_feature_trimac)) {
    352         /* FB/ER puts speed into GE_PORT_CONFIGr */
    353         uint32 val;
    354 
    355         SOC_IF_ERROR_RETURN(READ_GE_PORT_CONFIGr(unit, port, &val));
    356         soc_reg_field_set(unit, GE_PORT_CONFIGr, &val, SPEED_SELECTf, sp_sel);
    357         SOC_IF_ERROR_RETURN(WRITE_GE_PORT_CONFIGr(unit, port, val));
    358     }
    359 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    360 
    361     return sp_sel;
    362 }
    363 
    364 
    365 /*
    366  * Function:
    367  *      soc_mac_mode_get
    368  * Purpose:
    369  *      Certain gig ports have two MACs.  This function indicates which
    370  *      mode a gig port is in.
    371  * Parameters:
    372  *      unit - StrataSwitch unit #.
    373  *      port - Port number on unit.
    374  *      mode - (OUT) current operating mode.
    375  * Returns:
    376  *      SOC_E_XXX
    377  * Notes:
    378  *      This routine is used outside of this module.
    379  */
    380 
    381 int
    382 soc_mac_mode_get(int unit, soc_port_t port, soc_mac_mode_t *mode)
    383 {
    384     int speed_sel;
    385     uint32 rval;
    386     int bits;
    387 
    388     if(IS_GE_PORT(unit, port) && soc_feature(unit, soc_feature_unimac)) {
    389         *mode = SOC_MAC_MODE_1000_T; /* Default */
    390     } else if (IS_GE_PORT(unit, port) ||
    391         (IS_FE_PORT(unit, port) && soc_feature(unit, soc_feature_trimac))) {
    392         *mode = SOC_MAC_MODE_1000_T; /* Default */
    393 
    394         if (soc_feature(unit, soc_feature_fe_gig_macs)) {
    395             if ((speed_sel = _port_sp_sel_get(unit, port)) < 0) {
    396                 return SOC_E_INTERNAL;
    397             }
    398             if (soc_feature(unit, soc_feature_trimac)) {
    399                 if (speed_sel == 1) {
    400                     *mode = SOC_MAC_MODE_10_100;
    401                 } else if (speed_sel == 2) {
    402                     *mode = SOC_MAC_MODE_10;
    403                 }
    404             } else if (speed_sel != 0) {
    405                 *mode = SOC_MAC_MODE_10_100;
    406             }
    407         }
    408     } else if (IS_FE_PORT(unit, port)) {
    409         *mode = SOC_MAC_MODE_10_100;
    410     } else if (IS_HG_PORT(unit, port) || IS_XE_PORT(unit, port)) {
    411         if (IS_XQ_PORT(unit, port)) {
    412             if (SOC_REG_IS_VALID(unit, XQPORT_MODE_REGr)) {
    413                 SOC_IF_ERROR_RETURN(READ_XQPORT_MODE_REGr(unit, port, &rval));
    414                 bits = soc_reg_field_get(unit, XQPORT_MODE_REGr, rval,
    415                                  XQPORT_MODE_BITSf);
    416                 if (bits == 2) { /* xport-mode */
    417                     *mode = SOC_MAC_MODE_10000;
    418                 } else if (bits == 1) { /* gport-mode */
    419                     *mode = SOC_MAC_MODE_1000_T;
    420                     return SOC_E_NONE;
    421                 }
    422             }
    423         }
    424         *mode = SOC_MAC_MODE_10000;
    425     } else {
    426         return SOC_E_INTERNAL;
    427     }
    428 
    429     return SOC_E_NONE;
    430 }
    431 
    432 /*
    433  * Function:
    434  *      soc_drain_cells
    435  * Purpose:
    436  *      Wait until MMU cell count reaches zero for a specified port.
    437  * Parameters:
    438  *      unit - StrataSwitch unit #.
    439  *      port - Port number being examined.
    440  * Returns:
    441  *      SOC_E_XXX
    442  * Notes:
    443  *      Keeps polling as long as LCCCOUNT/GCCCOUNT is decrementing.
    444  *      If LCCCOUNT/GCCCOUNT stops decrementing without reaching zero,
    445  *      after a timeout period a warning message is printed
    446  *      and it gives up.
    447  *
    448  *      Before calling this routine, make sure no packets are switching
    449  *      to the port or it might never finish draining.
    450  */
    451 
    452 int
    453 soc_drain_cells(int unit, soc_port_t port)
    454 {
    455     soc_timeout_t       to;
    456     int                 rv, timeout_usec, loopback = -1;
    457     uint32              cur_cells, new_cells;
    458     soc_mac_mode_t      mode;
    459     uint32              egr_meter_config;
    460 #ifdef BCM_XGS3_SWITCH_SUPPORT
    461     uint32  pkt_drop_ctrl, pkt_drop_set;
    462     int                 pause_tx = 0, pause_rx = 0;
    463 #endif
    464 
    465     if (SOC_IS_RELOADING(unit)) {
    466         return SOC_E_NONE;
    467     }
    468 
    469     timeout_usec = soc_property_get(unit, spn_LCCDRAIN_TIMEOUT_USEC, 250000);
    470     soc_timeout_init(&to, timeout_usec, 0); 
    471 
    472 #ifdef BCM_XGS3_SWITCH_SUPPORT
    473     if (SOC_IS_XGS3_SWITCH(unit)) {
    474         SOC_IF_ERROR_RETURN
    475             (mac_ge_pause_get(unit, port, &pause_tx, &pause_rx));
    476         SOC_IF_ERROR_RETURN
    477             (mac_ge_pause_set(unit, port, 0, 0));
    478         SOC_IF_ERROR_RETURN
    479             (READ_GE_EGR_PKT_DROP_CTLr(unit, port, &pkt_drop_ctrl));
    480         pkt_drop_set = 0;
    481         soc_reg_field_set(unit, GE_EGR_PKT_DROP_CTLr, &pkt_drop_set, FLUSHf, 1);
    482         SOC_IF_ERROR_RETURN
    483             (WRITE_GE_EGR_PKT_DROP_CTLr(unit, port, pkt_drop_set));
    484         if (IS_GE_PORT(unit, port) && !IS_GMII_PORT(unit, port) &&
    485             soc_feature(unit, soc_feature_dodeca_serdes) &&
    486             !PHY_SGMII_AUTONEG_MODE(unit, port)) {
    487             SOC_IF_ERROR_RETURN
    488                 (soc_phyctrl_notify(unit, port, 
    489                                     phyEventStop, PHY_STOP_DRAIN));
    490         }
    491     }
    492 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    493 
    494     /* Disable egress metering. */
    495     if (SOC_REG_IS_VALID(unit, EGRMETERINGCONFIGr)) {
    496         SOC_EGRESS_METERING_LOCK(unit);
    497         rv = READ_EGRMETERINGCONFIGr(unit, port, &egr_meter_config);
    498         if (rv < 0) {
    499             SOC_EGRESS_METERING_UNLOCK(unit);
    500             return (rv);
    501         }
    502         rv = WRITE_EGRMETERINGCONFIGr(unit, port, 0);
    503         if (rv < 0) {
    504             SOC_EGRESS_METERING_UNLOCK(unit);
    505             return (rv);
    506         }
    507     }
    508 
    509     if (soc_mac_mode_get(unit, port, &mode) < 0) {
    510         mode = SOC_MAC_MODE_10_100;
    511     }
    512 
    513     cur_cells = 0xffffffff;
    514 
    515     for (;;) {
    516         if ((rv = soc_egress_cell_count(unit, port, &new_cells)) < 0) {
    517             break;
    518         }
    519 
    520         if (new_cells == 0) {
    521             rv = SOC_E_NONE;
    522             break;
    523         }
    524 
    525         /* gig mac in pause state needs loopback mode to clear xoff */
    526         if (new_cells == cur_cells && loopback < 0 &&
    527             mode == SOC_MAC_MODE_1000_T) {
    528             if (mac_ge_loopback_get(unit, port, &loopback) < 0) {
    529                 loopback = -1;
    530             } else {
    531                 mac_ge_loopback_set(unit, port, 1);
    532             }
    533         }
    534 
    535         if (new_cells < cur_cells) {                    /* Progress made */
    536             soc_timeout_init(&to, timeout_usec, 0);     /* Restart timeout */
    537             cur_cells = new_cells;
    538         }
    539 
    540         if (soc_timeout_check(&to)) {
    541             if ((rv = soc_egress_cell_count(unit, port, &new_cells)) < 0) {
    542                 break;
    543             }
    544 
    545             LOG_ERROR(BSL_LS_SOC_GE,
    546                       (BSL_META_U(unit,
    547                                   "MacDrainTimeOut:port %d,%s, "
    548                                   "timeout draining packets (%d cells remain)\n"),
    549                        unit, SOC_PORT_NAME(unit, port), new_cells));
    550             rv = SOC_E_INTERNAL;
    551             break;
    552         }
    553     }
    554 
    555     /* Reenable egres metering. */
    556     if (SOC_REG_IS_VALID(unit, EGRMETERINGCONFIGr)) {
    557         rv = WRITE_EGRMETERINGCONFIGr(unit, port, egr_meter_config);
    558         SOC_EGRESS_METERING_UNLOCK(unit);
    559         if (rv < 0) {
    560             return (rv);
    561         }
    562     }
    563 
    564     if (loopback >= 0) {
    565         SOC_IF_ERROR_RETURN
    566             (mac_ge_loopback_set(unit, port, loopback));
    567     }
    568 
    569 #ifdef BCM_XGS3_SWITCH_SUPPORT
    570     if (SOC_IS_XGS3_SWITCH(unit)) {
    571         if (IS_GE_PORT(unit, port) && !IS_GMII_PORT(unit, port) &&
    572             soc_feature(unit, soc_feature_dodeca_serdes) &&
    573             !PHY_SGMII_AUTONEG_MODE(unit, port)) {
    574             SOC_IF_ERROR_RETURN
    575                 (soc_phyctrl_notify(unit, port, 
    576                                     phyEventResume, PHY_STOP_DRAIN));
    577         }
    578         SOC_IF_ERROR_RETURN
    579             (WRITE_GE_EGR_PKT_DROP_CTLr(unit, port, pkt_drop_ctrl));
    580         SOC_IF_ERROR_RETURN
    581             (mac_ge_pause_set(unit, port, pause_tx, pause_rx));
    582     }
    583 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    584 
    585     return rv;
    586 }
    587 
    588 /*
    589  * Function:
    590  *      soc_mac_mode_set
    591  * Purpose:
    592  *      Force GE MAC into 10/100 or 1000 mode.
    593  * Parameters:
    594  *      unit - StrataSwitch unit #.
    595  *      port - Port number on unit.
    596  *      mode - one of SOC_MAC_MODE_*
    597  * Returns:
    598  *      SOC_E_CONFIG - Speed not available on port
    599  *      SOC_E_XXX
    600  * Notes:
    601  *      Can be used on any port; verifies parameters.
    602  */
    603 
    604 int
    605 soc_mac_mode_set(int unit, soc_port_t port, soc_mac_mode_t new_mode)
    606 {
    607     soc_mac_mode_t      old_mode;
    608     int                 old_mac_enable;
    609     int                 save_duplex;
    610     sal_mac_addr_t      save_pause_mac;         /* Pause MAC address */
    611     int                 save_pause_tx;          /* Pause Tx enable status */
    612     int                 save_pause_rx;          /* Pause Rx enable status */
    613     int                 save_lb;                /* Mac LB enable status */
    614 
    615     LOG_INFO(BSL_LS_SOC_PHY,
    616              (BSL_META_U(unit,
    617                          "soc_mac_mode_set: reconfiguring port=%d mode=%d\n"),
    618               port, new_mode));
    619 
    620     switch (new_mode) {                 /* Check mode for validity */
    621     case SOC_MAC_MODE_10:
    622         if (!soc_feature(unit, soc_feature_trimac)) {
    623             return SOC_E_CONFIG;
    624         }
    625         break;
    626     case SOC_MAC_MODE_10_100:
    627         if (IS_FE_PORT(unit, port) && !soc_feature(unit, soc_feature_trimac)) {
    628             return SOC_E_NONE;
    629         } else if (IS_GE_PORT(unit, port)) {
    630             if (!soc_feature(unit, soc_feature_fe_gig_macs)) {
    631                 return SOC_E_CONFIG;
    632             }
    633         }
    634         break;
    635     case SOC_MAC_MODE_1000_T:
    636         if (!IS_GE_PORT(unit, port)) {
    637             return SOC_E_CONFIG;
    638         }
    639         break;
    640     case SOC_MAC_MODE_10000:
    641         if (!IS_HG_PORT(unit, port) && !IS_XE_PORT(unit, port)) {
    642             return SOC_E_CONFIG;
    643         } else {
    644             return SOC_E_NONE;
    645         }
    646         break;
    647     default:
    648         return SOC_E_INTERNAL;
    649     }
    650 
    651     /*
    652      * At this point, we know the request is valid, and that we *MAY* need
    653      * to take action. Cases such as setting mac on 10/100 port only OR
    654      * 10G on HG port are already handled.
    655      */
    656 
    657     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &old_mode));
    658 
    659     if (new_mode == old_mode) {         /* Already in requested mode */
    660         return SOC_E_NONE;
    661     }
    662 
    663     /*
    664      * Save some state from the current MAC that must be restored in the
    665      * new MAC after the mode is switched.
    666      */
    667 
    668     SOC_IF_ERROR_RETURN
    669         (mac_ge_duplex_get(unit, port, &save_duplex));
    670 
    671     SOC_IF_ERROR_RETURN
    672         (mac_ge_pause_get(unit, port, &save_pause_tx, &save_pause_rx));
    673 
    674     SOC_IF_ERROR_RETURN
    675         (mac_ge_pause_addr_get(unit, port, save_pause_mac));
    676 
    677     SOC_IF_ERROR_RETURN
    678         (mac_ge_loopback_get(unit, port, &save_lb));
    679 
    680     /*
    681      * The currently selected MAC is quiesced before switching it out.
    682      * It must not be talking to the MMU when the switch occurs.  For
    683      * receive, RX is disabled.  For transmit, Egress is disabled.
    684      */
    685 
    686     SOC_IF_ERROR_RETURN
    687         (mac_ge_enable_get(unit, port, &old_mac_enable));
    688     SOC_IF_ERROR_RETURN
    689         (mac_ge_enable_set(unit, port, FALSE));
    690 
    691     switch (new_mode) {
    692     case SOC_MAC_MODE_10:
    693     case SOC_MAC_MODE_10_100:
    694         LOG_INFO(BSL_LS_SOC_PHY,
    695                  (BSL_META_U(unit,
    696                              "soc_mac_mode_set: port=%d, 10/100 mode\n"),
    697                   port));
    698         if (new_mode == SOC_MAC_MODE_10) {
    699             _port_sp_sel_set(unit, port, 2);
    700         } else {
    701             _port_sp_sel_set(unit, port, 1);
    702         }
    703         break;
    704     case SOC_MAC_MODE_1000_T:
    705         LOG_INFO(BSL_LS_SOC_PHY,
    706                  (BSL_META_U(unit,
    707                              "soc_mac_mode_set: port=%d, Gig mode\n"),
    708                   port));
    709         _port_sp_sel_set(unit, port, 0);
    710         break;
    711         /*
    712          * COVERITY
    713          *
    714          * Defensive default
    715          */
    716         /* coverity[dead_error_begin] */
    717     default:
    718         return SOC_E_INTERNAL;
    719     }
    720 
    721     /*
    722      * Restore the saved state in the new MAC.
    723      */
    724 
    725     SOC_IF_ERROR_RETURN
    726         (mac_ge_duplex_set(unit, port, save_duplex));
    727 
    728     SOC_IF_ERROR_RETURN
    729         (mac_ge_pause_set(unit, port, save_pause_tx, save_pause_rx));
    730 
    731     SOC_IF_ERROR_RETURN
    732         (mac_ge_pause_addr_set(unit, port, save_pause_mac));
    733 
    734     SOC_IF_ERROR_RETURN
    735         (mac_ge_loopback_set(unit, port, save_lb));
    736 
    737     /*
    738      * Enable the egress and MAC, if previously enabled.
    739      */
    740 
    741     if (old_mac_enable) {
    742         if (new_mode == SOC_MAC_MODE_1000_T) {
    743             SOC_IF_ERROR_RETURN(mac_ge_enable_set(unit, port, TRUE));
    744         } else {
    745             SOC_IF_ERROR_RETURN(mac_fe_enable_set(unit, port, TRUE));
    746         }
    747     }
    748 
    749     return SOC_E_NONE;
    750 }
    751 
    752 /*
    753  * Function:
    754  *      mac_fe_enable_set
    755  * Purpose:
    756  *      Enable or disable MAC
    757  * Parameters:
    758  *      unit - StrataSwitch unit #.
    759  *      port - Port number on unit.
    760  *      enable - TRUE to enable, FALSE to disable
    761  * Returns:
    762  *      SOC_E_XXX
    763  * Notes:
    764  *      The EGR_ENABLE and GEGR_ENABLE registers disable the egress,
    765  *      chopping any packet that is in progress and leaving part of it
    766  *      in the MMU.
    767  *
    768  *      On FE ports, we can avoid using EGR_ENABLE by putting the egress
    769  *      single step debug mode.  This will stop traffic to the egress
    770  *      between packets.
    771  *
    772  *      On GE ports, egress single step is not implemented.  Before
    773  *      setting GEGR_ENABLE to 0, we necessary to clear the port from
    774  *      EPC LINK to stop traffic from flowing to it, then wait for all
    775  *      packets to drain from the MMU to the egress.
    776  *
    777  *      The draining approach is not used for FE because the draining
    778  *      takes too long.  It is likely for a link to come back up before
    779  *      the draining is complete.
    780  */
    781 
    782 STATIC int
    783 mac_fe_enable_set(int unit, soc_port_t port, int enable)
    784 {
    785     uint32              regval;
    786     pbmp_t              mask;
    787 
    788 #ifdef BCM_RAPTOR1_SUPPORT
    789     /* Need to reset the FE MAC for Raptor before enabling RX */
    790     if (SOC_IS_RAPTOR(unit) && enable) {    
    791         SOC_IF_ERROR_RETURN
    792             (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 1));
    793         SOC_IF_ERROR_RETURN
    794             (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 0));
    795     }
    796 #endif
    797     /*
    798      * Turn on/off receive enable.
    799      *
    800      * We do not bother then TXEN because on some chips this signal does
    801      * not take effect (get latched) until traffic stops flowing.
    802      */
    803 
    804     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &regval));
    805     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_ENf, regval, enable ? 1 : 0);
    806     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC1r, GTH_FE_MAC1r, unit, port, regval));
    807     
    808     sal_usleep(50000); /* sleep 50ms */
    809 
    810     /*
    811      * Use EPC_LINK to control other ports sending to this port.  This
    812      * blocking is independent and in addition to what Linkscan does.
    813      *
    814      * Single-step mode is used to stop traffic from going from the
    815      * egress to the MAC.
    816      */
    817 
    818     if (!enable) {
    819         soc_link_mask2_get(unit, &mask);
    820         SOC_PBMP_PORT_REMOVE(mask, port);
    821         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
    822 
    823         SOC_IF_ERROR_RETURN(soc_drain_cells(unit, port));
    824 
    825 #if defined(BCM_FIREBOLT2_SUPPORT) 
    826         if (SOC_IS_FIREBOLT2(unit)) {
    827             int fd, speed;
    828 
    829             SOC_IF_ERROR_RETURN(mac_fe_duplex_get(unit, port, &fd));
    830             SOC_IF_ERROR_RETURN(mac_fe_speed_get(unit, port, &speed));
    831             
    832             /* Only for 100 FX via the SerDes */
    833             if ((speed == 100) && fd && PHY_FIBER_MODE(unit, port) &&
    834                 !PHY_EXTERNAL_MODE(unit, port)) {
    835                 /* Reset the MAC so that the error link state which may
    836                  * affect receive false carrier counter is cleared when
    837                  * the link is up again. */
    838                 SOC_IF_ERROR_RETURN
    839                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 1));
    840                 SOC_IF_ERROR_RETURN
    841                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 0));
    842             }
    843         }
    844 #endif /* BCM_FIREBOLT2_SUPPORT */
    845     } else {
    846         soc_link_mask2_get(unit, &mask);
    847         SOC_PBMP_PORT_ADD(mask, port);
    848         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
    849     }
    850 
    851     /*
    852      * The SERDES PHY is kept in reset whenever the MAC is
    853      * disabled.  When the link comes up, the SERDES PHY must come out
    854      * of reset last, *after* the speed and duplex are programmed.  If
    855      * the SERDES PHY is reset after the external PHY has link, a false
    856      * carrier is generated which can cause certain remote hardware to
    857      * drop link.  SEE ALSO: mac_ge_enable_set.
    858      */
    859 
    860 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
    861     if (soc_feature(unit, soc_feature_dodeca_serdes)) {
    862         if (enable) {
    863             SOC_IF_ERROR_RETURN
    864                 (soc_phyctrl_notify(unit, port, 
    865                                     phyEventResume, PHY_STOP_MAC_DIS));
    866         } else {
    867             SOC_IF_ERROR_RETURN
    868                 (soc_phyctrl_notify(unit, port, 
    869                                     phyEventStop, PHY_STOP_MAC_DIS));
    870         }
    871     }
    872 #endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT */
    873 
    874     return SOC_E_NONE;
    875 }
    876 
    877 /*
    878  * Function:
    879  *      mac_fe_enable_get
    880  * Purpose:
    881  *      Get MAC enable state
    882  * Parameters:
    883  *      unit - StrataSwitch unit #.
    884  *      port - Port number on unit.
    885  *      enable - (OUT) TRUE if enabled, FALSE if disabled
    886  * Returns:
    887  *      SOC_E_XXX
    888  */
    889 
    890 STATIC int
    891 mac_fe_enable_get(int unit, soc_port_t port, int *enable)
    892 {
    893     uint32      regval;
    894 
    895     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &regval));
    896 
    897     *enable = FE_GET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_ENf, regval);
    898 
    899     return SOC_E_NONE;
    900 }
    901 
    902 /*
    903  * Function:
    904  *      mac_fe_ifg_to_ipg
    905  * Description:
    906  *      Converts the inter-frame gap specified in bit-times into a value
    907  *      suitable to be programmed into the IPG register
    908  * Parameters:
    909  *      unit   - Device number
    910  *      port   - Port number
    911  *      speed  - the speed for which the IFG is being set
    912  *      duplex - the duplex for which the IFG is being set
    913  *      ifg    - Inter-frame gap in bit-times
    914  *      ipg    - (OUT) the value to be written into IPG
    915  * Return Value:
    916  *      BCM_E_XXX
    917  * Notes:
    918  *      The function makes sure the calculated IPG value will not cause
    919  *      hardware to fail. If the requested ifg value cannot be supported in
    920  *      hardware, the function will choose a value that approximates the
    921  *      requested value as best as possible.
    922  *
    923  *      Specifically:
    924  *         -- Current chips only support ifg which is divisible by 8. If
    925  *            the specified ifg is not divisible by 8, it will be rounded
    926  *            to the next multiplier of 8 (65 will result in 72).
    927  *         -- ifg < 64 are not supported
    928  *
    929  *      This function support both FE and GTH_FE MACs
    930  */
    931 STATIC int
    932 mac_fe_ifg_to_ipg(int unit, soc_port_t port, int speed, int duplex,
    933                   int ifg, int *ipg)
    934 {
    935     /*
    936      * The inter-frame gap should be a multiple of 8 bit-times.
    937      */
    938      ifg = (ifg + 7) & ~7;
    939 
    940      /*
    941       * The smallest supported ifg is 64 bit-times
    942       */
    943      ifg = (ifg < 64) ? 64 : ifg;
    944 
    945      /*
    946       * Now we need to convert the value according to various chips'
    947       * peculiarities
    948       */
    949      if (duplex) {
    950          *ipg = ifg / 4 - 3;
    951      } else {
    952         switch (SOC_CHIP_GROUP(unit)) {
    953         case SOC_CHIP_BCM56504:
    954         case SOC_CHIP_BCM56102:
    955         case SOC_CHIP_BCM56304:
    956         case SOC_CHIP_BCM56800:
    957         case SOC_CHIP_BCM56218:
    958         case SOC_CHIP_BCM56112:
    959         case SOC_CHIP_BCM56314:
    960         case SOC_CHIP_BCM56514:
    961         case SOC_CHIP_BCM56624:
    962         case SOC_CHIP_BCM56820:
    963         case SOC_CHIP_BCM56680:
    964         case SOC_CHIP_BCM56634:
    965         case SOC_CHIP_BCM56524:
    966         case SOC_CHIP_BCM56685:
    967         case SOC_CHIP_BCM88732:
    968             switch (speed) {
    969             case 10:
    970                 if (soc_feature(unit, soc_feature_ext_gth_hd_ipg)) {
    971                     *ipg = ifg / 4 - 4;
    972                 } else {
    973                     *ipg = ifg / 4 - 12;
    974                 }
    975                 break;
    976             case 100:
    977                 if (soc_feature(unit, soc_feature_ext_gth_hd_ipg)) {
    978                     *ipg = ifg / 4 - 5;
    979                 } else {
    980                     *ipg = ifg / 4 - 13;
    981                 }
    982                 break;
    983             default:
    984                 return SOC_E_INTERNAL;
    985             }
    986             break;
    987         default:
    988             *ipg = ifg / 4 - 6;
    989             break;
    990         }
    991     }
    992 
    993      /*
    994       * Notice, that since we force the minimal ifg to be 64, then there
    995       * no way ipg will be less than 0 or something like that.
    996       */
    997 
    998      return SOC_E_NONE;
    999 }
   1000 
   1001 /*
   1002  * Function:
   1003  *      mac_fe_ipg_to_ifg
   1004  * Description:
   1005  *      Converts the IPG register value into the inter-frame gap expressed in
   1006  *      bit-times
   1007  * Parameters:
   1008  *      unit   - Device number
   1009  *      port   - Port number
   1010  *      speed  - the speed for which the IFG is being set
   1011  *      duplex - the duplex for which the IFG is being set
   1012  *      ipg    - the value in the IPG register
   1013  *      ifg    - Inter-frame gap in bit-times
   1014  * Return Value:
   1015  *      BCM_E_XXX
   1016  * Notes:
   1017  *      This function works for both FE and GTH_FE MACs
   1018  */
   1019 STATIC int
   1020 mac_fe_ipg_to_ifg(int unit, soc_port_t port, int speed, int duplex,
   1021                   int ipg, int *ifg)
   1022 {
   1023      /*
   1024       * Now we need to convert the value according to various chips'
   1025       * peculiarities
   1026       */
   1027      if (duplex) {
   1028          *ifg = (ipg + 3) * 4;
   1029      } else {
   1030         switch (SOC_CHIP_GROUP(unit)) {
   1031         case SOC_CHIP_BCM56504:
   1032         case SOC_CHIP_BCM56102:
   1033         case SOC_CHIP_BCM56304:
   1034         case SOC_CHIP_BCM56800:
   1035         case SOC_CHIP_BCM56218:
   1036         case SOC_CHIP_BCM56112:
   1037         case SOC_CHIP_BCM56314:
   1038         case SOC_CHIP_BCM56514:
   1039         case SOC_CHIP_BCM56624:
   1040         case SOC_CHIP_BCM56820:
   1041         case SOC_CHIP_BCM56680:
   1042         case SOC_CHIP_BCM56634:
   1043         case SOC_CHIP_BCM56524:
   1044         case SOC_CHIP_BCM56685:
   1045         case SOC_CHIP_BCM88732:
   1046             if (soc_feature(unit, soc_feature_ext_gth_hd_ipg)) {
   1047                 if (speed == 10) {
   1048                     *ifg = (ipg + 4) * 4;
   1049                 } else {
   1050                     *ifg = (ipg + 5) * 4;
   1051                 }
   1052             } else {
   1053                 if (speed == 10) {
   1054                     *ifg = (ipg + 12) * 4;
   1055                 } else {
   1056                     *ifg = (ipg + 13) * 4;
   1057                 }
   1058             }
   1059             break;
   1060         default:
   1061             *ifg = (ipg + 6) * 4;
   1062             break;
   1063         }
   1064     }
   1065 
   1066      return SOC_E_NONE;
   1067 }
   1068 
   1069 /*
   1070  * Function:
   1071  *      mac_fe_ipg_update
   1072  * Purpose:
   1073  *      Set the IPG appropriate for current speed/duplex
   1074  * Parameters:
   1075  *      unit - StrataSwitch unit #.
   1076  *      port - Port number on unit.
   1077  * Notes:
   1078  *      The current speed/duplex are read from the hardware registers.
   1079  */
   1080 
   1081 STATIC int
   1082 mac_fe_ipg_update(int unit, int port)
   1083 {
   1084     int                 fd, speed, ifg, ipg = 0;
   1085     soc_ipg_t           *si = &SOC_PERSIST(unit)->ipg[port];
   1086     uint32              ipg32;
   1087 
   1088     SOC_IF_ERROR_RETURN(mac_fe_duplex_get(unit, port, &fd));
   1089     SOC_IF_ERROR_RETURN(mac_fe_speed_get(unit, port, &speed));
   1090 
   1091     /*
   1092      * Get the ifg value in bit-times
   1093      */
   1094     if (fd) {
   1095         switch (speed) {
   1096         case 10:
   1097             ifg = si->fd_10;
   1098             break;
   1099         case 100:
   1100             ifg = si->fd_100;
   1101             break;
   1102         default:
   1103             return SOC_E_INTERNAL;
   1104         }
   1105         if (SOC_IS_XGS3_SWITCH(unit)) {
   1106             SOC_IF_ERROR_RETURN(mac_fe_ifg_to_ipg(unit, port, speed, fd, ifg, &ipg));
   1107         }
   1108     } else {
   1109         switch (speed) {
   1110         case 10:
   1111             ifg = si->hd_10;
   1112             break;
   1113         case 100:
   1114             ifg = si->hd_100;
   1115             break;
   1116         default:
   1117             return SOC_E_INTERNAL;
   1118         }
   1119         /* Deal with XGS 3 switches */
   1120         if (SOC_IS_XGS3_SWITCH(unit)) {
   1121             switch (SOC_CHIP_GROUP(unit)) {
   1122             case SOC_CHIP_BCM56102:
   1123             case SOC_CHIP_BCM56112:
   1124                 ipg = 0x11;
   1125                 break;
   1126             case SOC_CHIP_BCM56601:
   1127             case SOC_CHIP_BCM56602:
   1128             case SOC_CHIP_BCM56504:
   1129             case SOC_CHIP_BCM56304:
   1130             case SOC_CHIP_BCM56800:
   1131             case SOC_CHIP_BCM56218:
   1132             case SOC_CHIP_BCM56314:
   1133             case SOC_CHIP_BCM56514:
   1134                 ipg = 0x12;
   1135                 break;
   1136             default:
   1137                 return SOC_E_INTERNAL;
   1138             }
   1139         }
   1140     }
   1141 
   1142     /*
   1143      * Convert the ifg value from bit-times into IPG register-specific value
   1144      * Do only for older switches - XGS3 dealt with separately
   1145      */
   1146     if (!SOC_IS_XGS3_SWITCH(unit)) {
   1147         SOC_IF_ERROR_RETURN(mac_fe_ifg_to_ipg(unit, port, speed, fd, ifg, &ipg));
   1148     }
   1149 
   1150     /*
   1151      * Program the appropriate register
   1152      */
   1153     ipg32 = ipg;
   1154     SOC_IF_ERROR_RETURN(FE_WRITE(FE_IPGTr, GTH_FE_IPGTr, unit, port, ipg32));
   1155 
   1156     return SOC_E_NONE;
   1157 }
   1158 
   1159 /*
   1160  * Function:
   1161  *      mac_fe_init
   1162  * Purpose:
   1163  *      Initialize FE MAC into a known good state.
   1164  * Parameters:
   1165  *      unit - StrataSwitch unit #.
   1166  *      port - Port number on unit.
   1167  * Returns:
   1168  *      SOC_E_XXX
   1169  * Notes:
   1170  *      The initialization speed/duplex is arbitrary and must be
   1171  *      updated by linkscan before enabling the MAC.
   1172  */
   1173 
   1174 STATIC int
   1175 mac_fe_init(int unit, soc_port_t port)
   1176 {
   1177     uint32      reg32;
   1178 
   1179 #if defined(BCM_FELIX_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   1180         if (IS_FE_PORT(unit, port) && soc_feature(unit, soc_feature_trimac)) {
   1181             SOC_IF_ERROR_RETURN(soc_mac_mode_set(unit, port,
   1182                                                  SOC_MAC_MODE_10_100));
   1183 #ifdef BCM_RAPTOR1_SUPPORT
   1184             /*
   1185              * Do a MAC soft reset
   1186              */
   1187             if (SOC_IS_RAPTOR(unit)) {
   1188                 SOC_IF_ERROR_RETURN
   1189                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 1));
   1190                 SOC_IF_ERROR_RETURN
   1191                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 0));
   1192             }
   1193 #endif
   1194         }
   1195 #endif /* BCM_FELIX_SUPPORT || BCM_RAPTOR_SUPPORT */
   1196     /*
   1197      * Perform length check on Ethernet frames and do not allow huge frames
   1198      */
   1199     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC2r, GTH_FE_MAC2r, unit, port, &reg32));
   1200     /* FULL_DUP=0 for workaround */
   1201     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, FULL_DUPf, reg32, 0);
   1202     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, EXC_DEFf, reg32, 1);
   1203     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, LG_CHKf, reg32, 0);
   1204     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, HUGE_FRf, reg32, 0);
   1205     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, DEL_CRCf, reg32, 0);
   1206     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, CRC_ENf, reg32, 0);
   1207     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, PAD_ENf, reg32, 0);
   1208     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, VLAN_PADf, reg32, 0);
   1209     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, AUTO_PADf, reg32, 0);
   1210     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, PURE_PADf, reg32, 0);
   1211     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, LONG_PREf, reg32, 0);
   1212     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, NO_BOFFf, reg32, 0);
   1213     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r, BP_NO_BOFFf, reg32, 0);
   1214     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC2r, GTH_FE_MAC2r, unit, port, reg32));
   1215 
   1216     SOC_IF_ERROR_RETURN(FE_READ(FE_CLRTr, GTH_FE_CLRTr, unit, port, &reg32));
   1217     FE_SET(unit, port, FE_CLRTr, GTH_FE_CLRTr, COL_WINf, reg32, 0x37);
   1218     FE_SET(unit, port, FE_CLRTr, GTH_FE_CLRTr, RETRYf, reg32, 0xf);
   1219     SOC_IF_ERROR_RETURN(FE_WRITE(FE_CLRTr, GTH_FE_CLRTr, unit, port, reg32));
   1220 
   1221     if (soc_feature(unit, soc_feature_fe_maxframe)) {
   1222         reg32 = 1518 + 1;
   1223         SOC_IF_ERROR_RETURN(WRITE_FE_MAXFr(unit, port,  reg32));
   1224     }
   1225 
   1226     SOC_IF_ERROR_RETURN(FE_READ(FE_IPGRr, GTH_FE_IPGRr, unit, port, &reg32));
   1227     FE_SET(unit, port, FE_IPGRr, GTH_FE_IPGRr, IPGR2f, reg32, 0x12);
   1228     FE_SET(unit, port, FE_IPGRr, GTH_FE_IPGRr, IPGR1f, reg32, 0xc);
   1229     SOC_IF_ERROR_RETURN(FE_WRITE(FE_IPGRr, GTH_FE_IPGRr, unit, port, reg32));
   1230 
   1231     SOC_IF_ERROR_RETURN(FE_READ(FE_SUPPr, GTH_FE_SUPPr, unit, port, &reg32));
   1232     FE_SET(unit, port, FE_SUPPr, GTH_FE_SUPPr, SPEEDf, reg32, 1);
   1233     FE_SET(unit, port, FE_SUPPr, GTH_FE_SUPPr, BIT_MODEf, reg32, 0);
   1234 
   1235     SOC_IF_ERROR_RETURN(FE_WRITE(FE_SUPPr, GTH_FE_SUPPr, unit, port, reg32));
   1236     SOC_IF_ERROR_RETURN(FE_READ(FE_TESTr, GTH_FE_TESTr, unit, port, &reg32));
   1237     FE_SET(unit, port, FE_TESTr, GTH_FE_TESTr, SHORT_QNTAf, reg32, 0);
   1238     FE_SET(unit, port, FE_TESTr, GTH_FE_TESTr, TEST_PAUSEf, reg32, 0);
   1239     FE_SET(unit, port, FE_TESTr, GTH_FE_TESTr, TEST_BACKf, reg32, 0);
   1240     SOC_IF_ERROR_RETURN(FE_WRITE(FE_TESTr, GTH_FE_TESTr, unit, port, reg32));
   1241 
   1242     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &reg32));
   1243     if (!SOC_IS_XGS_SWITCH(unit)) {
   1244         FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, SOFT_RSTf, reg32, 0);
   1245     }
   1246 
   1247     /* Enable pause on FE ports */
   1248     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, TX_PAUf, reg32, 1);
   1249     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_PAUf, reg32, 1);
   1250 
   1251     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, LBACKf, reg32, 0);
   1252     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_ENf, reg32, 0);
   1253     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC1r, GTH_FE_MAC1r, unit, port, reg32));
   1254 
   1255     /* Clear station address */
   1256     reg32 = 0;
   1257     SOC_IF_ERROR_RETURN(FE_WRITE(ESA0r, GTH_ESA0r, unit, port, reg32));
   1258     SOC_IF_ERROR_RETURN(FE_WRITE(ESA1r, GTH_ESA1r, unit, port, reg32));
   1259     SOC_IF_ERROR_RETURN(FE_WRITE(ESA2r, GTH_ESA2r, unit, port, reg32));
   1260 
   1261     /* Set IPG to match initial operating mode */
   1262     SOC_IF_ERROR_RETURN(mac_fe_ipg_update(unit, port));
   1263 
   1264     if (!IS_GE_PORT(unit, port)) {
   1265         uint32 port_bit;
   1266 
   1267         port_bit = (1 << (port % 8));
   1268 
   1269 #if defined(BCM_FELIX_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   1270         if (IS_FE_PORT(unit, port) && soc_feature(unit, soc_feature_trimac)) {
   1271             SOC_IF_ERROR_RETURN(READ_EGR_ENABLEr(unit, port, &reg32));
   1272             soc_reg_field_set(unit, EGR_ENABLEr, &reg32, PRT_ENABLEf, 1);
   1273             SOC_IF_ERROR_RETURN(WRITE_EGR_ENABLEr(unit, port, reg32));
   1274         } else
   1275 #endif /* BCM_FELIX_SUPPORT || BCM_RAPTOR_SUPPORT */
   1276         {
   1277             /* Set egress enable */
   1278             SOC_IF_ERROR_RETURN(READ_EGR_ENABLEr(unit, port, &reg32));
   1279             reg32 |= port_bit;
   1280             SOC_IF_ERROR_RETURN(WRITE_EGR_ENABLEr(unit, port, reg32));
   1281         }
   1282     }
   1283 
   1284     return (SOC_E_NONE);
   1285 }
   1286 
   1287 /*
   1288  * Function:
   1289  *      mac_fe_duplex_set
   1290  * Purpose:
   1291  *      Set FE MAC in the specified duplex mode.
   1292  * Parameters:
   1293  *      unit - StrataSwitch unit #.
   1294  *      port - StrataSwitch port # on unit.
   1295  *      duplex - Boolean: true --> full duplex, false --> half duplex.
   1296  * Returns:
   1297  *      SOC_E_XXX
   1298  * Notes:
   1299  *      Programs an IFG time appropriate to speed and duplex.
   1300  *      Also handles GTH ports (gig ports in 10/100 MAC mode).
   1301  */
   1302 
   1303 STATIC int
   1304 mac_fe_duplex_set(int unit, soc_port_t port, int duplex)
   1305 {
   1306     uint32      fe_mac2;
   1307     int         old_mac_en;
   1308 
   1309     SOC_IF_ERROR_RETURN(mac_fe_enable_get(unit, port, &old_mac_en));
   1310     if (old_mac_en) {
   1311         SOC_IF_ERROR_RETURN(mac_fe_enable_set(unit, port, FALSE));
   1312     }
   1313 
   1314     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC2r, GTH_FE_MAC2r, unit, port, &fe_mac2));
   1315     FE_SET(unit, port, FE_MAC2r, GTH_FE_MAC2r,
   1316            FULL_DUPf, fe_mac2, duplex ? 1 : 0);
   1317     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC2r, GTH_FE_MAC2r, unit, port, fe_mac2));
   1318 
   1319     /* Set IPG to match new duplex */
   1320     SOC_IF_ERROR_RETURN(mac_fe_ipg_update(unit, port));
   1321 
   1322     if (old_mac_en) {
   1323         SOC_IF_ERROR_RETURN(mac_fe_enable_set(unit, port, TRUE));
   1324     }
   1325 
   1326 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   1327     /*
   1328      * Notify internal PHY driver of duplex change in case it is being
   1329      * used as pass-through to an external PHY.
   1330      */
   1331     if (soc_feature(unit, soc_feature_dodeca_serdes)) {
   1332         if (IS_GE_PORT(unit, port)) {
   1333             SOC_IF_ERROR_RETURN
   1334                 (soc_phyctrl_notify(unit, port, phyEventDuplex, duplex));
   1335         }
   1336     }
   1337 #endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT */
   1338 
   1339     return (SOC_E_NONE);
   1340 }
   1341 
   1342 /*
   1343  * Function:
   1344  *      mac_fe_duplex_get
   1345  * Purpose:
   1346  *      Get FE MAC duplex mode.
   1347  * Parameters:
   1348  *      unit - StrataSwitch unit #.
   1349  *      duplex - (OUT) Boolean: true --> full duplex, false --> half duplex.
   1350  * Returns:
   1351  *      SOC_E_XXX
   1352  */
   1353 
   1354 STATIC int
   1355 mac_fe_duplex_get(int unit, soc_port_t port, int *duplex)
   1356 {
   1357     uint32      fe_mac2;
   1358 
   1359     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC2r, GTH_FE_MAC2r, unit, port, &fe_mac2));
   1360 
   1361     *duplex = FE_GET(unit, port, FE_MAC2r, GTH_FE_MAC2r,
   1362                      FULL_DUPf, fe_mac2) ? 1 : 0;
   1363 
   1364     return (SOC_E_NONE);
   1365 }
   1366 
   1367 /*
   1368  * Function:
   1369  *      mac_fe_speed_set
   1370  * Purpose:
   1371  *      Set FE MAC in the specified speed.
   1372  * Parameters:
   1373  *      unit - StrataSwitch unit #.
   1374  *      port - StrataSwitch port # on unit.
   1375  *      speed - 10,100 for speed.
   1376  * Returns:
   1377  *      SOC_E_XXX
   1378  * Notes:
   1379  *      On chips with a PHYMOD field:
   1380  *              If PHYMOD=0, the speed is hardwired to 100Mb/s.
   1381  *              If PHYMOD=1, the speed is obtained directly from the PHY.
   1382  *      In either case, FE_SUPP.SPEED is completely ignored.
   1383  *      Programs an IFG time appropriate to speed and duplex.
   1384  */
   1385 
   1386 STATIC int
   1387 mac_fe_speed_set(int unit, soc_port_t port, int speed)
   1388 {
   1389     uint32      fe_supp;
   1390 
   1391     SOC_IF_ERROR_RETURN(FE_READ(FE_SUPPr, GTH_FE_SUPPr, unit, port, &fe_supp));
   1392 
   1393     switch (speed) {
   1394     case 0:
   1395         /* Leave speed unchanged; supports NULL PHY */
   1396         break;
   1397     case 10:
   1398         if (IS_FE_PORT(unit, port) && soc_feature(unit, soc_feature_trimac)) {
   1399             SOC_IF_ERROR_RETURN(soc_mac_mode_set(unit, port,
   1400                                                  SOC_MAC_MODE_10));
   1401         }
   1402         FE_SET(unit, port, FE_SUPPr, GTH_FE_SUPPr, SPEEDf, fe_supp, 0);
   1403         break;
   1404     case 100:
   1405         if (IS_FE_PORT(unit, port) && soc_feature(unit, soc_feature_trimac)) {
   1406             SOC_IF_ERROR_RETURN(soc_mac_mode_set(unit, port,
   1407                                                  SOC_MAC_MODE_10_100));
   1408         }
   1409         FE_SET(unit, port, FE_SUPPr, GTH_FE_SUPPr, SPEEDf, fe_supp, 1);
   1410         break;
   1411     default:
   1412         return (SOC_E_CONFIG);
   1413     }
   1414 
   1415     SOC_IF_ERROR_RETURN(FE_WRITE(FE_SUPPr, GTH_FE_SUPPr, unit, port, fe_supp));
   1416 
   1417     /* Set IPG to match new speed */
   1418     SOC_IF_ERROR_RETURN(mac_fe_ipg_update(unit, port));
   1419 
   1420 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   1421     /*
   1422      * Notify internal PHY driver of speed change in case it is being
   1423      * used as pass-through to an external PHY.
   1424      */
   1425     if (soc_feature(unit, soc_feature_dodeca_serdes)) {
   1426         if (IS_GE_PORT(unit, port)) {
   1427             SOC_IF_ERROR_RETURN
   1428                 (soc_phyctrl_notify(unit, port, phyEventSpeed, speed));
   1429         }
   1430     }
   1431 #endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT */
   1432 
   1433     return (SOC_E_NONE);
   1434 }
   1435 
   1436 /*
   1437  * Function:
   1438  *      mac_fe_speed_get
   1439  * Purpose:
   1440  *      Get FE MAC speed
   1441  * Parameters:
   1442  *      unit - StrataSwitch unit #.
   1443  *      port - StrataSwitch port # on unit.
   1444  *      speed - (OUT) speed in Mb (10/100)
   1445  * Returns:
   1446  *      SOC_E_XXX
   1447  * Notes:
   1448  *      On chips with a PHYMOD field:
   1449  *              If PHYMOD=0, the speed is hardwired to 100Mb/s.
   1450  *              If PHYMOD=1, the speed is obtained directly from the PHY.
   1451  *      In either case, FE_SUPP.SPEED is completely ignored.
   1452  */
   1453 
   1454 STATIC int
   1455 mac_fe_speed_get(int unit, soc_port_t port, int *speed)
   1456 {
   1457     uint32      fe_supp;
   1458 
   1459     SOC_IF_ERROR_RETURN(FE_READ(FE_SUPPr, GTH_FE_SUPPr, unit, port, &fe_supp));
   1460 
   1461     if (FE_GET(unit, port, FE_SUPPr, GTH_FE_SUPPr, SPEEDf, fe_supp) == 1) {
   1462         *speed = 100;
   1463     } else {
   1464         *speed = 10;
   1465     }
   1466 
   1467     return (SOC_E_NONE);
   1468 }
   1469 
   1470 /*
   1471  * Function:
   1472  *      mac_fe_pause_set
   1473  * Purpose:
   1474  *      Configure MAC to transmit/receive pause frames.
   1475  * Parameters:
   1476  *      unit - StrataSwitch unit #.
   1477  *      port - StrataSwitch port # on unit.
   1478  *      pause_tx - Boolean: transmit pause, or -1 (don't change)
   1479  *      pause_rx - Boolean: receive pause, or -1 (don't change)
   1480  * Returns:
   1481  *      SOC_E_XXX
   1482  */
   1483 
   1484 STATIC  int
   1485 mac_fe_pause_set(int unit, soc_port_t port, int pause_tx, int pause_rx)
   1486 {
   1487     uint32      fe_mac1;
   1488 
   1489     if (pause_tx < 0 && pause_rx < 0) {
   1490         return SOC_E_NONE;
   1491     }
   1492 
   1493     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &fe_mac1));
   1494     if (pause_rx >= 0) {
   1495         FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1496                RX_PAUf, fe_mac1, pause_rx ? 1 : 0);
   1497     }
   1498     if (pause_tx >= 0) {
   1499         FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1500                TX_PAUf, fe_mac1, pause_tx ? 1 : 0);
   1501     }
   1502     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC1r, GTH_FE_MAC1r, unit, port, fe_mac1));
   1503 
   1504     return SOC_E_NONE;
   1505 }
   1506 
   1507 /*
   1508  * Function:
   1509  *      mac_fe_pause_addr_set
   1510  * Purpose:
   1511  *      Configure FE MAC PAUSE frame source address.
   1512  * Parameters:
   1513  *      unit - StrataSwitch unit #.
   1514  *      port - StrataSwitch port # on unit.
   1515  *      pause_mac - MAC address used for pause transmission.
   1516  * Returns:
   1517  *      SOC_E_XXX
   1518  */
   1519 
   1520 STATIC  int
   1521 mac_fe_pause_addr_set(int unit, soc_port_t port, sal_mac_addr_t pause_mac)
   1522 {
   1523     uint32      esa0, esa1, esa2;
   1524 
   1525     esa0 = 0;
   1526     esa1 = 0;
   1527     esa2 = 0;
   1528 
   1529     FE_SET(unit, port, ESA0r, GTH_ESA0r, STAD0f, esa0,
   1530            (pause_mac[4] << 8) | pause_mac[5]);
   1531     FE_SET(unit, port, ESA1r, GTH_ESA1r, STAD0f, esa1,
   1532            (pause_mac[2] << 8) | pause_mac[3]);
   1533     FE_SET(unit, port, ESA2r, GTH_ESA2r, STAD0f, esa2,
   1534            (pause_mac[0] << 8) | pause_mac[1]);
   1535 
   1536     SOC_IF_ERROR_RETURN(FE_WRITE(ESA0r, GTH_ESA0r, unit, port, esa0));
   1537     SOC_IF_ERROR_RETURN(FE_WRITE(ESA1r, GTH_ESA1r, unit, port, esa1));
   1538     SOC_IF_ERROR_RETURN(FE_WRITE(ESA2r, GTH_ESA2r, unit, port, esa2));
   1539 
   1540     return (SOC_E_NONE);
   1541 }
   1542 
   1543 /*
   1544  * Function:
   1545  *      mac_fe_pause_get
   1546  * Purpose:
   1547  *      Return the ability of FE MAC
   1548  * Parameters:
   1549  *      unit - StrataSwitch unit #.
   1550  *      port - StrataSwitch port # on unit.
   1551  *      pause_tx - Boolean: transmit pause
   1552  *      pause_rx - Boolean: receive pause
   1553  *      pause_mac - MAC address used for pause transmission.
   1554  * Returns:
   1555  *      SOC_E_XXX
   1556  */
   1557 
   1558 STATIC  int
   1559 mac_fe_pause_get(int unit, soc_port_t port, int *pause_tx, int *pause_rx)
   1560 {
   1561     uint32      fe_mac1;
   1562 
   1563     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &fe_mac1));
   1564 
   1565     *pause_rx = FE_GET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1566                        RX_PAUf, fe_mac1) ? 1 : 0;
   1567     *pause_tx = FE_GET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1568                        TX_PAUf, fe_mac1) ? 1 : 0;
   1569 
   1570     return (SOC_E_NONE);
   1571 }
   1572 
   1573 /*
   1574  * Function:
   1575  *      mac_fe_pause_addr_set
   1576  * Purpose:
   1577  *      Configure PAUSE frame source address.
   1578  * Parameters:
   1579  *      unit - StrataSwitch unit #.
   1580  *      port - StrataSwitch port # on unit.
   1581  *      pause_mac - (OUT) MAC address used for pause transmission.
   1582  * Returns:
   1583  *      SOC_E_XXX
   1584  */
   1585 
   1586 STATIC  int
   1587 mac_fe_pause_addr_get(int unit, soc_port_t port, sal_mac_addr_t pause_mac)
   1588 {
   1589     uint32      esa0, esa1, esa2;
   1590     uint32      b0_15, b16_31, b32_47;
   1591 
   1592     SOC_IF_ERROR_RETURN(FE_READ(ESA0r, GTH_ESA0r, unit, port, &esa0));
   1593     SOC_IF_ERROR_RETURN(FE_READ(ESA1r, GTH_ESA1r, unit, port, &esa1));
   1594     SOC_IF_ERROR_RETURN(FE_READ(ESA2r, GTH_ESA2r, unit, port, &esa2));
   1595 
   1596     b0_15  = FE_GET(unit, port, ESA0r, GTH_ESA0r, STAD0f, esa0);
   1597     b16_31 = FE_GET(unit, port, ESA1r, GTH_ESA1r, STAD0f, esa1);
   1598     b32_47 = FE_GET(unit, port, ESA2r, GTH_ESA2r, STAD0f, esa2);
   1599 
   1600     pause_mac[0] = (uint8)(b32_47 >> 8);
   1601     pause_mac[1] = (uint8)(b32_47 >> 0);
   1602     pause_mac[2] = (uint8)(b16_31 >> 8);
   1603     pause_mac[3] = (uint8)(b16_31 >> 0);
   1604     pause_mac[4] = (uint8)(b0_15  >> 8);
   1605     pause_mac[5] = (uint8)(b0_15  >> 0);
   1606 
   1607     return (SOC_E_NONE);
   1608 }
   1609 
   1610 /*
   1611  * Function:
   1612  *      mac_fe_loopback_set
   1613  * Purpose:
   1614  *      Set a MAC into/out-of loopback mode
   1615  * Parameters:
   1616  *      unit - StrataSwitch unit #.
   1617  *      port - StrataSwitch unit # on unit.
   1618  *      loopback - Boolean: true -> loopback mode, false -> normal operation
   1619  * Returns:
   1620  *      SOC_E_XXX
   1621  */
   1622 
   1623 STATIC int
   1624 mac_fe_loopback_set(int unit, soc_port_t port, int loopback)
   1625 {
   1626     uint32      fe_mac1;
   1627 
   1628     SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &fe_mac1));
   1629     FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1630            LBACKf, fe_mac1, loopback ? 1 : 0);
   1631     SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC1r, GTH_FE_MAC1r, unit, port, fe_mac1));
   1632 
   1633     return (SOC_E_NONE);
   1634 }
   1635 
   1636 /*
   1637  * Function:
   1638  *      mac_fe_loopback_get
   1639  * Purpose:
   1640  *      Get current FE MAC loopback mode setting.
   1641  * Parameters:
   1642  *      unit - StrataSwitch unit #.
   1643  *      port - StrataSwitch port # on unit.
   1644  *      loopback - (OUT) Boolean: true = loopback, false = normal
   1645  * Returns:
   1646  *      SOC_E_XXX
   1647  */
   1648 
   1649 STATIC int
   1650 mac_fe_loopback_get(int unit, soc_port_t port, int *loopback)
   1651 {
   1652     int         rv;
   1653     uint32      fe_mac1;
   1654 
   1655     if ((rv = FE_READ(FE_MAC1r, GTH_FE_MAC1r,
   1656                       unit, port, &fe_mac1)) == SOC_E_NONE) {
   1657         *loopback = FE_GET(unit, port, FE_MAC1r, GTH_FE_MAC1r,
   1658                            LBACKf, fe_mac1);
   1659     }
   1660 
   1661     return(rv);
   1662 }
   1663 
   1664 /*
   1665  * Function:
   1666  *      mac_fe_interface_set
   1667  * Purpose:
   1668  *      Set a FE MAC interface type
   1669  * Parameters:
   1670  *      unit - StrataSwitch unit #.
   1671  *      port - StrataSwitch port # on unit.
   1672  *      pif - one of SOC_PORT_IF_*
   1673  * Returns:
   1674  *      SOC_E_NONE
   1675  *      SOC_E_UNAVAIL - requested mode not supported.
   1676  * Notes:
   1677  *      Only MII supported on FE ports.
   1678  */
   1679 
   1680 STATIC int
   1681 mac_fe_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1682 {
   1683     COMPILER_REFERENCE(unit);
   1684     COMPILER_REFERENCE(port);
   1685 
   1686     switch (pif) {
   1687     case SOC_PORT_IF_MII:
   1688         return SOC_E_NONE;
   1689     default:
   1690         return SOC_E_UNAVAIL;
   1691     }
   1692 }
   1693 
   1694 /*
   1695  * Function:
   1696  *      mac_fe_interface_get
   1697  * Purpose:
   1698  *      Retrieve FE MAC interface type
   1699  * Parameters:
   1700  *      unit - StrataSwitch unit #.
   1701  *      port - StrataSwitch port # on unit.
   1702  *      pif - (OUT) one of SOC_PORT_IF_*
   1703  * Returns:
   1704  *      SOC_E_NONE
   1705  */
   1706 
   1707 STATIC int
   1708 mac_fe_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1709 {
   1710     COMPILER_REFERENCE(unit);
   1711     COMPILER_REFERENCE(port);
   1712 
   1713     *pif = SOC_PORT_IF_MII;
   1714 
   1715     return (SOC_E_NONE);
   1716 }
   1717 
   1718 /*
   1719  * Function:
   1720  *      mac_fe_ability_get
   1721  * Purpose:
   1722  *      Return the abilities of FE MAC
   1723  * Parameters:
   1724  *      unit - StrataSwitch unit #.
   1725  *      port - StrataSwitch port # on unit.
   1726  *      mode - (OUT) Supported operating modes as a mask of abilities.
   1727  * Returns:
   1728  *      SOC_E_XXX
   1729  */
   1730 
   1731 STATIC  int
   1732 mac_fe_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1733 {
   1734     COMPILER_REFERENCE(unit);
   1735 
   1736     if (IS_FE_PORT(unit, port)) {
   1737         /* Asymmetric pause not available (SOC_PM_PAUSE_ASYMM) */
   1738         *mode = (SOC_PM_10MB | SOC_PM_100MB | SOC_PM_PAUSE |
   1739                  SOC_PM_MII | SOC_PM_LB_MAC);
   1740         return (SOC_E_NONE);
   1741     } else {
   1742         *mode = 0;
   1743         return (SOC_E_UNAVAIL);
   1744     }
   1745 }
   1746 
   1747 /*
   1748  * Function:
   1749  *      mac_fe_frame_max_set
   1750  * Description:
   1751  *      Set the maximum receive frame size for the GE port
   1752  * Parameters:
   1753  *      unit - Device number
   1754  *      port - Port number
   1755  *      size - Maximum frame size in bytes
   1756  * Return Value:
   1757  *      BCM_E_XXX
   1758  * Notes:
   1759  *      1) Depending on chip or port type the actual maximum receive frame
   1760  *         size might be slightly higher.
   1761  */
   1762 
   1763 STATIC int
   1764 mac_fe_frame_max_set(int unit, soc_port_t port, int size)
   1765 {
   1766     uint32 val32;
   1767 
   1768     if (soc_feature(unit, soc_feature_fe_maxframe)) {
   1769         size += 1; /* XGS3 FE MAC MAX_FR is one greater than MAX len */
   1770     }
   1771 
   1772     val32 = size;
   1773 
   1774     return FE_WRITE(FE_MAXFr, GTH_FE_MAXFr, unit, port, val32);
   1775 }
   1776 
   1777 /*
   1778  * Function:
   1779  *      mac_fe_frame_max_get
   1780  * Description:
   1781  *      Set the maximum receive frame size for the GE port
   1782  * Parameters:
   1783  *      unit - Device number
   1784  *      port - Port number
   1785  *      size - Maximum frame size in bytes
   1786  * Return Value:
   1787  *      BCM_E_XXX
   1788  * Notes:
   1789  *      1) Depending on chip or port type the actual maximum receive frame
   1790  *         size might be slightly higher.
   1791  */
   1792 STATIC int
   1793 mac_fe_frame_max_get(int unit, soc_port_t port, int *size)
   1794 {
   1795     uint32         val32;
   1796 
   1797     SOC_IF_ERROR_RETURN(FE_READ(FE_MAXFr, GTH_FE_MAXFr, unit, port, &val32));
   1798     *size = val32;
   1799 
   1800     if (soc_feature(unit, soc_feature_fe_maxframe)) {
   1801         *size -= 1; /* XGS3 FE MAC MAX_FR is one greater than MAX len */
   1802     }
   1803 
   1804     return SOC_E_NONE;
   1805 }
   1806 
   1807 /*
   1808  * Function:
   1809  *      mac_fe_ifg_set
   1810  * Description:
   1811  *      Sets the new ifg (Inter-frame gap) value
   1812  * Parameters:
   1813  *      unit   - Device number
   1814  *      port   - Port number
   1815  *      speed  - the speed for which the IFG is being set
   1816  *      duplex - the duplex for which the IFG is being set
   1817  *      ifg    - Inter-frame gap in bit-times
   1818  * Return Value:
   1819  *      BCM_E_XXX
   1820  * Notes:
   1821  *      The function makes sure the IFG value makes sense and updates the
   1822  *      IPG register in case the speed/duplex match the current settings
   1823  */
   1824 STATIC int
   1825 mac_fe_ifg_set(int unit, soc_port_t port, int speed, soc_port_duplex_t duplex,
   1826                int ifg)
   1827 {
   1828     int         cur_speed;
   1829     int         cur_duplex;
   1830     int         ipg;
   1831     int         real_ifg;
   1832     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   1833     int         rv;
   1834 
   1835     SOC_IF_ERROR_RETURN(mac_fe_ifg_to_ipg(unit, port, speed, duplex,
   1836                                           ifg, &ipg));
   1837     SOC_IF_ERROR_RETURN(mac_fe_ipg_to_ifg(unit, port, speed, duplex,
   1838                                           ipg, &real_ifg));
   1839 
   1840     if (duplex) {
   1841         switch (speed) {
   1842         case 10:
   1843             si->fd_10 = real_ifg;
   1844             break;
   1845         case 100:
   1846             si->fd_100 = real_ifg;
   1847             break;
   1848         default:
   1849             return SOC_E_PARAM;
   1850             break;
   1851         }
   1852     } else {
   1853         switch (speed) {
   1854         case 10:
   1855             si->hd_10 = real_ifg;
   1856     /*    coverity[equality_cond]    */
   1857             break;
   1858         case 100:
   1859             si->hd_100 = real_ifg;
   1860             break;
   1861         default:
   1862             return SOC_E_PARAM;
   1863             break;
   1864         }
   1865     }
   1866 
   1867     SOC_IF_ERROR_RETURN(mac_fe_duplex_get(unit, port, &cur_duplex));
   1868     SOC_IF_ERROR_RETURN(mac_fe_speed_get(unit, port, &cur_speed));
   1869 
   1870     if (cur_speed == speed && ((soc_port_duplex_t)cur_duplex == duplex)) {
   1871         switch (speed) {
   1872         case 10:
   1873         case 100:
   1874             rv = mac_fe_ipg_update(unit, port);
   1875             break;
   1876         /* coverity[dead_error_begin] */
   1877         default:
   1878             rv =  SOC_E_PARAM;
   1879         }
   1880     } else {
   1881         rv = SOC_E_NONE;
   1882     }
   1883 
   1884     return (rv);
   1885 }
   1886 
   1887 /*
   1888  * Function:
   1889  *      mac_fe_ifg_get
   1890  * Description:
   1891  *      Gets the ifg (Inter-frame gap) value for a specific speed/duplex
   1892  *      combination
   1893  * Parameters:
   1894  *      unit   - Device number
   1895  *      port   - Port number
   1896  *      speed  - the speed for which the IFG is being set
   1897  *      duplex - the duplex for which the IFG is being set
   1898  *      ifg    - Inter-frame gap in bit-times
   1899  * Return Value:
   1900  *      BCM_E_XXX
   1901  * Notes:
   1902  *      The function returns the REAL ifg value that will be (or is currently)
   1903  *      used by the chip, which might be different from the value initially
   1904  *      set by the ifg_set() call. The reason for that is that only certain
   1905  *      values are allowed.
   1906  */
   1907 STATIC int
   1908 mac_fe_ifg_get(int unit, soc_port_t port, int speed, soc_port_duplex_t  duplex,
   1909                int *ifg)
   1910 {
   1911     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   1912 
   1913     if (duplex) {
   1914         switch (speed) {
   1915         case 10:
   1916             *ifg = si->fd_10;
   1917             break;
   1918         case 100:
   1919             *ifg = si->fd_100;
   1920             break;
   1921         default:
   1922             return SOC_E_PARAM;
   1923             break;
   1924         }
   1925     } else {
   1926         switch (speed) {
   1927         case 10:
   1928             *ifg = si->hd_10;
   1929             break;
   1930         case 100:
   1931             *ifg = si->hd_100;
   1932             break;
   1933         default:
   1934             return SOC_E_PARAM;
   1935             break;
   1936         }
   1937     }
   1938 
   1939     return SOC_E_NONE;
   1940 }
   1941 
   1942 /*
   1943  * Function:
   1944  *      mac_fe_encap_set
   1945  * Purpose:
   1946  *      Set the port encapsulation mode.
   1947  * Parameters:
   1948  *      unit - XGS unit #.
   1949  *      port - XGS port # on unit.
   1950  *      mode - encapsulation mode
   1951  * Returns:
   1952  *      SOC_E_XXX
   1953  */
   1954 STATIC int
   1955 mac_fe_encap_set(int unit, soc_port_t port, int mode)
   1956 {
   1957     if (mode == SOC_ENCAP_IEEE) {
   1958         return SOC_E_NONE;
   1959     }
   1960     return SOC_E_PARAM;
   1961 }
   1962 
   1963 /*
   1964  * Function:
   1965  *      mac_fe_encap_get
   1966  * Purpose:
   1967  *      Get the port encapsulation mode.
   1968  * Parameters:
   1969  *      unit - XGS unit #.
   1970  *      port - XGS port # on unit.
   1971  *      mode - (INT) encapsulation mode
   1972  * Returns:
   1973  *      SOC_E_XXX
   1974  */
   1975 STATIC int
   1976 mac_fe_encap_get(int unit, soc_port_t port, int *mode)
   1977 {
   1978     *mode = SOC_ENCAP_IEEE;
   1979 
   1980     return SOC_E_NONE;
   1981 }
   1982 
   1983 /*
   1984  * Function:
   1985  *      mac_fe_ability_local_get
   1986  * Purpose:
   1987  *      Return the abilities of FE MAC
   1988  * Parameters:
   1989  *      unit - StrataSwitch unit #.
   1990  *      port - StrataSwitch port # on unit.
   1991  *      mode - (OUT) Supported operating modes as a mask of abilities.
   1992  * Returns:
   1993  *      SOC_E_XXX
   1994  */
   1995 
   1996 STATIC  int
   1997 mac_fe_ability_local_get(int unit, soc_port_t port,
   1998                         soc_port_ability_t *ability)
   1999 {
   2000     if (NULL == ability) {
   2001         return (SOC_E_PARAM);
   2002     }
   2003 
   2004     if (IS_FE_PORT(unit, port)) {
   2005         ability->speed_half_duplex  = SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB; 
   2006         ability->speed_full_duplex  = SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB;
   2007         ability->pause     = SOC_PA_PAUSE;
   2008         ability->interface = SOC_PA_INTF_MII;
   2009         ability->medium    = SOC_PA_ABILITY_NONE;
   2010         ability->loopback  = SOC_PA_LB_MAC;
   2011         ability->flags     = SOC_PA_ABILITY_NONE;
   2012         ability->encap     = SOC_PA_ENCAP_IEEE;
   2013         return (SOC_E_NONE);
   2014     } else {
   2015         return (SOC_E_UNAVAIL);
   2016     }
   2017 }
   2018 
   2019 /* Exported FE MAC driver structure */
   2020 mac_driver_t soc_mac_fe = {
   2021     "10Mb/100Mb MAC Driver",        /* drv_name */
   2022     mac_fe_init,                    /* md_init  */
   2023     mac_fe_enable_set,              /* md_enable_set */
   2024     mac_fe_enable_get,              /* md_enable_get */
   2025     mac_fe_duplex_set,              /* md_duplex_set */
   2026     mac_fe_duplex_get,              /* md_duplex_get */
   2027     mac_fe_speed_set,               /* md_speed_set */
   2028     mac_fe_speed_get,               /* md_speed_get */
   2029     mac_fe_pause_set,               /* md_pause_set */
   2030     mac_fe_pause_get,               /* md_pause_get */
   2031     mac_fe_pause_addr_set,          /* md_pause_addr_set */
   2032     mac_fe_pause_addr_get,          /* md_pause_addr_get */
   2033     mac_fe_loopback_set,            /* md_lb_set */
   2034     mac_fe_loopback_get,            /* md_lb_get */
   2035     mac_fe_interface_set,           /* md_interface_set */
   2036     mac_fe_interface_get,           /* md_interface_get */
   2037     mac_fe_ability_get,             /* md_ability_get */
   2038     mac_fe_frame_max_set,           /* md_frame_max_set */
   2039     mac_fe_frame_max_get,           /* md_frame_max_get */
   2040     mac_fe_ifg_set,                 /* md_ifg_set */
   2041     mac_fe_ifg_get,                 /* md_ifg_get */
   2042     mac_fe_encap_set,               /* md_encap_set */
   2043     mac_fe_encap_get,               /* md_encap_get */
   2044     NULL,                           /* md_control_set */
   2045     NULL,                           /* md_control_get */
   2046     mac_fe_ability_local_get,       /* md_ability_local_get */
   2047     NULL,                           /* md_timesync_tx_info_get */
   2048 };
   2049 
   2050 /*
   2051  * Function:
   2052  *      mac_ge_enable_set
   2053  * Purpose:
   2054  *      Enable or disable MAC
   2055  * Parameters:
   2056  *      unit - StrataSwitch unit #.
   2057  *      port - Port number on unit.
   2058  *      enable - TRUE to enable, FALSE to disable
   2059  * Returns:
   2060  *      SOC_E_XXX
   2061  */
   2062 
   2063 STATIC int
   2064 mac_ge_enable_set(int unit, soc_port_t port, int enable)
   2065 {
   2066     uint32              gmacc1, ogmacc1;
   2067     soc_mac_mode_t      mode;
   2068     pbmp_t              mask;
   2069 
   2070     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2071 
   2072     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2073         return (mac_fe_enable_set(unit, port, enable));
   2074     }
   2075 
   2076     /*
   2077      * Turn on/off receive enable.
   2078      *
   2079      * We do not bother then TXEN because on some chips this signal does
   2080      * not take effect (get latched) until traffic stops flowing.
   2081      */
   2082 
   2083     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2084     ogmacc1 = gmacc1;
   2085     if (enable) {
   2086         soc_reg_field_set(unit, GMACC1r, &gmacc1, TXEN0f, 1);
   2087         soc_reg_field_set(unit, GMACC1r, &gmacc1, RXEN0f, 1);
   2088     } else {            /* Turn off Receive Enable */
   2089         soc_reg_field_set(unit, GMACC1r, &gmacc1, RXEN0f, 0);
   2090     }
   2091     if (gmacc1 != ogmacc1) {
   2092         SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   2093     }
   2094 
   2095     /*
   2096      * Use EPC_LINK to control other ports sending to this port.  This
   2097      * blocking is independent and in addition to what Linkscan does.
   2098      *
   2099      * Single-step mode is used to stop traffic from going from the
   2100      * egress to the MAC.
   2101      */
   2102 
   2103     if (!enable) {
   2104         soc_link_mask2_get(unit, &mask);
   2105         SOC_PBMP_PORT_REMOVE(mask, port);
   2106         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
   2107 
   2108         SOC_IF_ERROR_RETURN(soc_drain_cells(unit, port));
   2109 
   2110     } else {
   2111         soc_link_mask2_get(unit, &mask);
   2112         SOC_PBMP_PORT_ADD(mask, port);
   2113         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
   2114    }
   2115 
   2116     /*
   2117      * The SERDES PHY is kept in reset whenever the MAC is
   2118      * disabled.  When the link comes up, the SERDES PHY must come out
   2119      * of reset last, *after* the speed and duplex are programmed.  If
   2120      * the SERDES PHY is reset after the external PHY has link, a false
   2121      * carrier is generated which can cause certain remote hardware to
   2122      * drop link.  SEE ALSO: mac_fe_enable_set.
   2123      */
   2124 
   2125 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   2126     if (soc_feature(unit, soc_feature_dodeca_serdes)) {
   2127         if (IS_GE_PORT(unit, port)) {
   2128             if (enable) {
   2129                 SOC_IF_ERROR_RETURN
   2130                     (soc_phyctrl_notify(unit, port,
   2131                                         phyEventResume, PHY_STOP_MAC_DIS));
   2132             } else {
   2133                 SOC_IF_ERROR_RETURN
   2134                     (soc_phyctrl_notify(unit, port,
   2135                                         phyEventStop, PHY_STOP_MAC_DIS));
   2136             }
   2137         }
   2138     }
   2139 #endif /* BCM_FIREBOLT_SUPPORT || BCM_RAPTOR_SUPPORT */
   2140 
   2141     return SOC_E_NONE;
   2142 }
   2143 
   2144 /*
   2145  * Function:
   2146  *      mac_ge_enable_get
   2147  * Purpose:
   2148  *      Get MAC enable state
   2149  * Parameters:
   2150  *      unit - StrataSwitch unit #.
   2151  *      port - Port number on unit.
   2152  *      enable - (OUT) TRUE if enabled, FALSE if disabled
   2153  * Returns:
   2154  *      SOC_E_XXX
   2155  */
   2156 
   2157 STATIC int
   2158 mac_ge_enable_get(int unit, soc_port_t port, int *enable)
   2159 {
   2160     soc_mac_mode_t      mode;
   2161 
   2162     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2163 
   2164     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2165         return (mac_fe_enable_get(unit, port, enable));
   2166     } else {
   2167         uint32          gmacc1;
   2168 
   2169         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2170 
   2171         *enable = soc_reg_field_get(unit, GMACC1r, gmacc1, RXEN0f);
   2172     }
   2173 
   2174     return SOC_E_NONE;
   2175 }
   2176 
   2177 /*
   2178  * Function:
   2179  *      mac_ge_ifg_to_ipg
   2180  * Description:
   2181  *      Converts the inter-frame gap specified in bit-times into a value
   2182  *      suitable to be programmed into the IPG register
   2183  * Parameters:
   2184  *      unit   - Device number
   2185  *      port   - Port number
   2186  *      speed  - the speed for which the IFG is being set
   2187  *      duplex - the duplex for which the IFG is being set
   2188  *      ifg    - Inter-frame gap in bit-times
   2189  *      ipg    - (OUT) the value to be written into IPG
   2190  * Return Value:
   2191  *      BCM_E_XXX
   2192  * Notes:
   2193  *      The function makes sure the calculated IPG value will not cause
   2194  *      hardware to fail. If the requested ifg value cannot be supported in
   2195  *      hardware, the function will choose a value that approximates the
   2196  *      requested value as best as possible.
   2197  *
   2198  *      Specifically:
   2199  *         -- Current chips only support ifg which is divisible by 8. If
   2200  *            the specified ifg is not divisible by 8, it will be rounded
   2201  *            to the next multiplier of 8 (65 will result in 72).
   2202  *         -- ifg < 64 are not supported
   2203  *
   2204  *      This function supports only GE portion of GE MAC (FE portion is
   2205  *      supported by mac_fe_ipg_* functions
   2206  */
   2207 STATIC int
   2208 mac_ge_ifg_to_ipg(int unit, soc_port_t port, int speed, int duplex,
   2209                   int ifg, int *ipg)
   2210 {
   2211     /*
   2212      * The inter-frame gap should be a multiple of 8 bit-times.
   2213      */
   2214      ifg = (ifg + 7) & ~7;
   2215 
   2216      /*
   2217       * The smallest supported ifg is 64 bit-times
   2218       */
   2219      ifg = (ifg < 64) ? 64 : ifg;
   2220 
   2221      /*
   2222       * Now we need to convert the value according to various chips'
   2223       * peculiarities (there are none as of now)
   2224       */
   2225      *ipg = ifg / 8;
   2226 
   2227      return SOC_E_NONE;
   2228 }
   2229 
   2230 /*
   2231  * Function:
   2232  *      mac_ge_ipg_to_ifg
   2233  * Description:
   2234  *      Converts the IPG register value into the inter-frame gap expressed in
   2235  *      bit-times
   2236  * Parameters:
   2237  *      unit   - Device number
   2238  *      port   - Port number
   2239  *      speed  - the speed for which the IFG is being set
   2240  *      duplex - the duplex for which the IFG is being set
   2241  *      ipg    - the value in the IPG register
   2242  *      ifg    - Inter-frame gap in bit-times
   2243  * Return Value:
   2244  *      BCM_E_XXX
   2245  * Notes:
   2246  *      This function supports only GE portion of GE MAC (FE portion is
   2247  *      supported by mac_fe_ipg_* functions
   2248  */
   2249 STATIC int
   2250 mac_ge_ipg_to_ifg(int unit, soc_port_t port, int speed, int duplex,
   2251                   int ipg, int *ifg)
   2252 {
   2253     /*
   2254      * Now we need to convert the value according to various chips'
   2255      * peculiarities (there are none as of now)
   2256      */
   2257     *ifg = ipg * 8;
   2258 
   2259     return SOC_E_NONE;
   2260 }
   2261 
   2262 /*
   2263  * Function:
   2264  *      mac_ge_ipg_update
   2265  * Purpose:
   2266  *      Set the IPG appropriate for current duplex
   2267  * Parameters:
   2268  *      unit - StrataSwitch unit #.
   2269  *      port - Port number on unit.
   2270  * Notes:
   2271  *      The current duplex is read from the hardware registers.
   2272  */
   2273 
   2274 STATIC int
   2275 mac_ge_ipg_update(int unit, int port)
   2276 {
   2277     uint32              gmacc2, ogmacc2;
   2278     int                 fd, speed, ipg, ifg;
   2279     soc_ipg_t           *si = &SOC_PERSIST(unit)->ipg[port];
   2280 
   2281     SOC_IF_ERROR_RETURN(mac_ge_duplex_get(unit, port, &fd));
   2282     SOC_IF_ERROR_RETURN(mac_ge_speed_get(unit, port, &speed));
   2283 
   2284     if (fd) {
   2285         switch (speed) {
   2286         case 10:
   2287         case 100:
   2288             return (mac_fe_ipg_update(unit, port));
   2289             break;
   2290         case 1000:
   2291             ifg = si->fd_1000;
   2292             break;
   2293         case 2500:
   2294             ifg = si->fd_2500;
   2295             break;
   2296         default:
   2297             return SOC_E_INTERNAL;
   2298             break;
   2299         }
   2300     } else {
   2301         switch (speed) {
   2302         case 10:
   2303         case 100:
   2304             return (mac_fe_ipg_update(unit, port));
   2305             break;
   2306         case 1000:
   2307             ifg = si->hd_1000;
   2308             break;
   2309         case 2500:
   2310             ifg = si->hd_2500;
   2311             break;
   2312         default:
   2313             return SOC_E_INTERNAL;
   2314             break;
   2315         }
   2316     }
   2317 
   2318     /*
   2319      * Convert the ifg value from bit-times into IPG register-specific value
   2320      */
   2321     SOC_IF_ERROR_RETURN(mac_ge_ifg_to_ipg(unit, port, speed, fd, ifg, &ipg));
   2322 
   2323     /*
   2324      * Program the appropriate register (if necessary)
   2325      */
   2326     SOC_IF_ERROR_RETURN(READ_GMACC2r(unit, port, &gmacc2));
   2327     ogmacc2 = gmacc2;
   2328     soc_reg_field_set(unit, GMACC2r, &gmacc2, IPGTf, ipg);
   2329     if (gmacc2 != ogmacc2) {
   2330         SOC_IF_ERROR_RETURN(WRITE_GMACC2r(unit, port, gmacc2));
   2331     }
   2332 
   2333    return SOC_E_NONE;
   2334 }
   2335 
   2336 /*
   2337  * Function:
   2338  *      mac_ge_init
   2339  * Purpose:
   2340  *      Initialize the gigabit MAC into a known good state.
   2341  * Parameters:
   2342  *      unit - StrataSwitch unit #.
   2343  *      port - StrataSwitch port # on unit.
   2344  * Returns:
   2345  *      SOC_E_XXX
   2346  * Notes:
   2347  *      Both the FE and GE MACs are initialized.
   2348  *      The initialization speed/duplex is arbitrary and must be
   2349  *      updated by linkscan before enabling the MAC.
   2350  */
   2351 
   2352 STATIC  int
   2353 mac_ge_init(int unit, soc_port_t port)
   2354 {
   2355     uint32              gmacc0, gmacc1, gmacc2, val32;
   2356     uint32              ogmacc0, ogmacc1, ogmacc2;
   2357     uint32 pctrl;
   2358 
   2359     /*
   2360      * Initialize 10/100MB/s MAC if present
   2361      */
   2362     if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   2363         SOC_IF_ERROR_RETURN(soc_mac_mode_set(unit, port,
   2364                                              SOC_MAC_MODE_10_100));
   2365         SOC_IF_ERROR_RETURN(mac_fe_init(unit, port));
   2366     }
   2367 
   2368     /*
   2369      * Initialize 1000Mb/s MAC
   2370      */
   2371     SOC_IF_ERROR_RETURN(soc_mac_mode_set(unit, port, SOC_MAC_MODE_1000_T));
   2372 
   2373     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   2374     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2375     SOC_IF_ERROR_RETURN(READ_GMACC2r(unit, port, &gmacc2));
   2376     ogmacc0 = gmacc0;
   2377     ogmacc1 = gmacc1;
   2378     ogmacc2 = gmacc2;
   2379     soc_reg_field_set(unit, GMACC0r, &gmacc0, SRSTf, 0);
   2380     soc_reg_field_set(unit, GMACC0r, &gmacc0, L10Bf, 0);
   2381     soc_reg_field_set(unit, GMACC0r, &gmacc0, L32Bf, 0);
   2382     soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 0);
   2383 
   2384     soc_reg_field_set(unit, GMACC1r, &gmacc1, FULLDf, 1);  /* arbitrary */
   2385     if (IS_ST_PORT(unit, port)) {
   2386         /* Flow control should not be enabled in stacking mode. */
   2387         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf, 0);  /* Flow ctl */
   2388         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf, 0);  /* Flow ctl */
   2389     } else {
   2390         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf, 1);  /* Flow ctl */
   2391         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf, 1);  /* Flow ctl */
   2392     }
   2393     soc_reg_field_set(unit, GMACC1r, &gmacc1, LONGPf, 1);
   2394     soc_reg_field_set(unit, GMACC1r, &gmacc1, MIFGf, 2);
   2395     soc_reg_field_set(unit, GMACC1r, &gmacc1, GLVRf, 1);
   2396     soc_reg_field_set(unit, GMACC1r, &gmacc1, TXEN0f, 0);
   2397     soc_reg_field_set(unit, GMACC1r, &gmacc1, RXEN0f, 0);
   2398     soc_reg_field_set(unit, GMACC1r, &gmacc1, JUMBOf, 1);  /* HUGEN=0 */
   2399 
   2400     pctrl = 0;
   2401     soc_reg_field_set(unit, PAUSE_CONTROLr, &pctrl, ENABLEf, 1);
   2402     soc_reg_field_set(unit, PAUSE_CONTROLr, &pctrl, VALUEf,
   2403                           PAUSE_VAL(512));
   2404 
   2405     SOC_IF_ERROR_RETURN(WRITE_PAUSE_CONTROLr(unit, port, pctrl));
   2406 
   2407     val32 = 0;
   2408     SOC_IF_ERROR_RETURN(WRITE_TEST2r(unit, port, val32));
   2409 
   2410     if (gmacc2 != ogmacc2) {
   2411         SOC_IF_ERROR_RETURN(WRITE_GMACC2r(unit, port, gmacc2));
   2412     }
   2413     if (gmacc1 != ogmacc1) {
   2414         SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   2415     }
   2416     if (gmacc0 != ogmacc0) {
   2417         SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   2418     }
   2419 
   2420 #if defined(BCM_RAPTOR_SUPPORT) 
   2421     if (IS_S_PORT(unit, port)) {
   2422         soc_pbmp_t pbmp_s0;
   2423 #if defined(BCM_RAPTOR1_SUPPORT)
   2424         int        support_2_5g = 0;
   2425 #endif
   2426 
   2427         /* Select between 2.5 and 1G mode */
   2428         if (!PHY_EXTERNAL_MODE(unit, port)) {
   2429             mac_ge_frame_max_set(unit, port, JUMBO_MAXSZ);
   2430 #if defined(BCM_RAPTOR1_SUPPORT)
   2431             support_2_5g = 1;
   2432 #endif
   2433         } else {
   2434             mac_ge_frame_max_set(unit, port, 1518);
   2435         }
   2436 
   2437         SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &val32));
   2438         soc_reg_field_set(unit, GPORT_CONFIGr, &val32, CLR_CNTf, 1);
   2439         soc_reg_field_set(unit, GPORT_CONFIGr, &val32, GPORT_ENf, 1);
   2440         SOC_PBMP_WORD_SET(pbmp_s0, 0, 0x00000002);
   2441         if (SOC_PBMP_MEMBER(pbmp_s0, port)) {
   2442             /* The "SOP check enables" are not gated with "HiGig2 enables"
   2443              * and "bond_disable_stacking". 
   2444              * Thus software need to enable/disable the SOP drop check 
   2445              * in HiGig2 mode as desired.
   2446              */
   2447             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2448                               DROP_ON_WRONG_SOP_EN_S0f, 0);
   2449 #if defined(BCM_RAPTOR1_SUPPORT)
   2450             /* Select 2.5 Gbps or 1 Gbps mode. */
   2451             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2452                               PLL_MODE_DEF_S0f, support_2_5g);
   2453 #endif
   2454             /* Enable HiGig 2 */
   2455             /* Assuming that always use stacking port in HiGig mode */
   2456             /* Actually, stacking port can also be used in ethernet mode */
   2457             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2458                               HGIG2_EN_S0f, IS_ST_PORT(unit, port) ? 1 : 0);
   2459 #if defined(BCM_RAPTOR1_SUPPORT)
   2460             /* Select LCPLL as reference clock */
   2461             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2462                               SEL_LCPLL_S0f, 1);
   2463 #endif
   2464         } else {
   2465             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2466                               DROP_ON_WRONG_SOP_EN_S1f, 0);
   2467 #if defined(BCM_RAPTOR1_SUPPORT)
   2468             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2469                               PLL_MODE_DEF_S1f, support_2_5g);
   2470 #endif
   2471             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2472                               HGIG2_EN_S1f, IS_ST_PORT(unit, port) ? 1 : 0);
   2473 #if defined(BCM_RAPTOR1_SUPPORT)
   2474             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2475                               SEL_LCPLL_S1f, 1);
   2476 #endif
   2477         }
   2478         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, val32));
   2479 
   2480         /* Reset the clear-count bit after 64 clocks */
   2481         SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &val32));
   2482         soc_reg_field_set(unit, GPORT_CONFIGr, &val32, CLR_CNTf, 0);
   2483         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, val32));
   2484     }
   2485 #endif /* BCM_RAPTOR_SUPPORT */
   2486 
   2487     /* Clear station address */
   2488     val32 = 0;
   2489     SOC_IF_ERROR_RETURN(WRITE_GSA0r(unit, port, val32));
   2490     SOC_IF_ERROR_RETURN(WRITE_GSA1r(unit, port, val32));
   2491 
   2492     /* Set IPG to match initial operating mode */
   2493     SOC_IF_ERROR_RETURN(mac_ge_ipg_update(unit, port));
   2494 
   2495     /* Set receive IPGs */
   2496     switch (SOC_CHIP_GROUP(unit)) {
   2497     case SOC_CHIP_BCM56504:
   2498     case SOC_CHIP_BCM56102:
   2499     case SOC_CHIP_BCM56304:
   2500     case SOC_CHIP_BCM56800:
   2501     case SOC_CHIP_BCM56218:
   2502     case SOC_CHIP_BCM56112:
   2503     case SOC_CHIP_BCM56314:
   2504     case SOC_CHIP_BCM56514:
   2505     case SOC_CHIP_BCM56624:
   2506     case SOC_CHIP_BCM56820:
   2507     case SOC_CHIP_BCM56680:
   2508     case SOC_CHIP_BCM56634:
   2509     case SOC_CHIP_BCM56524:
   2510     case SOC_CHIP_BCM56685:
   2511     case SOC_CHIP_BCM88732:
   2512         val32 = 0;
   2513         soc_reg_field_set(unit, FE_IPGRr, &val32, IPGR1f, 0x6);
   2514         soc_reg_field_set(unit, FE_IPGRr, &val32, IPGR2f, 0xf);
   2515         SOC_IF_ERROR_RETURN(WRITE_FE_IPGRr(unit, port, val32));
   2516         break;
   2517     default:
   2518         break;
   2519     }
   2520 
   2521     /* Set egress enable */
   2522 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   2523     if (SOC_IS_FBX(unit) || SOC_IS_RAPTOR(unit)) {
   2524         SOC_IF_ERROR_RETURN(READ_EGR_ENABLEr(unit, port, &val32));
   2525         soc_reg_field_set(unit, EGR_ENABLEr, &val32, PRT_ENABLEf, 1);
   2526         SOC_IF_ERROR_RETURN(WRITE_EGR_ENABLEr(unit, port, val32));
   2527     }
   2528 #endif /* BCM_FIREBOLT_SUPPORT */
   2529 
   2530     /*
   2531      * Firebolt ports are initialized in bcm_port_init() so as to
   2532      * block control frames (PORT_TABm.PASS_CONTROL_FRAMESf = 0).
   2533      */
   2534 
   2535 #if defined(BCM_RAPTOR1_SUPPORT)
   2536     if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   2537         /* Must initialize the ComboSerDes after MAC is initialized. */
   2538         SOC_IF_ERROR_RETURN
   2539             (soc_phyctrl_init(unit, port));
   2540     }
   2541 #endif /* BCM_RAPTOR1_SUPPORT */
   2542 
   2543     return SOC_E_NONE;
   2544 }
   2545 
   2546 /*
   2547  * Function:
   2548  *      mac_ge_interface_set
   2549  * Purpose:
   2550  *      Set GE MAC interface type
   2551  * Parameters:
   2552  *      unit - StrataSwitch unit #.
   2553  *      port - Port number on unit.
   2554  *      pif - one of SOC_PORT_IF_*
   2555  * Returns:
   2556  *      SOC_E_XXX
   2557  */
   2558 
   2559 STATIC int
   2560 mac_ge_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   2561 {
   2562     uint32              gmacc0, gpcsc;
   2563     uint32              ogmacc0, ogpcsc;
   2564 
   2565     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   2566     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
   2567     ogmacc0 = gmacc0;
   2568     ogpcsc = gpcsc;
   2569 
   2570     switch (pif) {
   2571     case SOC_PORT_IF_MII:
   2572     case SOC_PORT_IF_GMII:
   2573     case SOC_PORT_IF_SGMII:
   2574         soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 1); /* GMII */
   2575         soc_reg_field_set(unit, GPCSCr, &gpcsc, RCSELf, 1);  /* 125 MHz */
   2576         break;
   2577     case SOC_PORT_IF_TBI:
   2578         soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 0); /* TBI */
   2579         soc_reg_field_set(unit, GPCSCr, &gpcsc, RCSELf, 0);  /* 62.5 MHz */
   2580         break;
   2581     default:
   2582         return SOC_E_UNAVAIL;
   2583     }
   2584 
   2585     if (gpcsc != ogpcsc) {
   2586         SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
   2587     }
   2588     if (gmacc0 != ogmacc0) {
   2589         SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   2590     }
   2591     return SOC_E_NONE;
   2592 }
   2593 
   2594 /*
   2595  * Function:
   2596  *      mac_ge_interface_get
   2597  * Purpose:
   2598  *      Retrieve GE MAC interface type
   2599  * Parameters:
   2600  *      unit - StrataSwitch unit #.
   2601  *      port - StrataSwitch port # on unit.
   2602  *      pif - (OUT) one of SOC_PORT_IF_*
   2603  * Returns:
   2604  *      SOC_E_XXX
   2605  */
   2606 
   2607 STATIC int
   2608 mac_ge_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   2609 {
   2610     uint32      gmacc0;
   2611 
   2612     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   2613 
   2614     *pif = (soc_reg_field_get(unit, GMACC0r, gmacc0, TMDSf) ?
   2615             SOC_PORT_IF_GMII :
   2616             SOC_PORT_IF_TBI);
   2617 
   2618     return SOC_E_NONE;
   2619 }
   2620 
   2621 /*
   2622  * Function:
   2623  *      mac_ge_duplex_set
   2624  * Purpose:
   2625  *      Set GE MAC in the specified duplex mode.
   2626  * Parameters:
   2627  *      unit - StrataSwitch unit #.
   2628  *      port - StrataSwitch port # on unit.
   2629  *      duplex - Boolean: true --> full duplex, false --> half duplex.
   2630  * Returns:
   2631  *      SOC_E_XXX
   2632  * Notes:
   2633  *      Programs an IFG time appropriate to speed and duplex.
   2634  */
   2635 
   2636 STATIC int
   2637 mac_ge_duplex_set(int unit, soc_port_t port, int duplex)
   2638 {
   2639     soc_mac_mode_t      mode;
   2640 
   2641     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2642 
   2643     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2644         return (mac_fe_duplex_set(unit, port, duplex));
   2645     } else {
   2646         uint32 gmacc1, ogmacc1;
   2647         if (IS_S_PORT(unit, port)) {
   2648             /* Full-Duplex is tied to 1 on Raptor combo SerDes */
   2649             duplex = 1;
   2650         }
   2651         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2652         ogmacc1 = gmacc1;
   2653         soc_reg_field_set(unit, GMACC1r, &gmacc1, 
   2654                               FULLDf, duplex ? 1 : 0);
   2655         if (gmacc1 != ogmacc1) {
   2656             SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   2657 
   2658             /* Set IPG to match new duplex */
   2659             SOC_IF_ERROR_RETURN(mac_ge_ipg_update(unit, port));
   2660         }
   2661 
   2662     }
   2663 
   2664 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_RAPTOR_SUPPORT)
   2665     /*
   2666      * Notify internal PHY driver of duplex change in case it is being
   2667      * used as pass-through to an external PHY.
   2668      */
   2669     if (soc_feature(unit, soc_feature_dodeca_serdes)) {
   2670         if (IS_GE_PORT(unit, port)) {
   2671             SOC_IF_ERROR_RETURN
   2672                 (soc_phyctrl_notify(unit, port, phyEventDuplex, duplex));
   2673         }
   2674     }
   2675 #endif /* BCM_FIREBOLT_SUPPORT */
   2676 
   2677     return SOC_E_NONE;
   2678 }
   2679 
   2680 /*
   2681  * Function:
   2682  *      mac_ge_duplex_get
   2683  * Purpose:
   2684  *      Get GE MAC duplex mode.
   2685  * Parameters:
   2686  *      unit - StrataSwitch unit #.
   2687  *      port - StrataSwitch port # on unit.
   2688  *      duplex - (OUT) Boolean: true --> full duplex, false --> half duplex.
   2689  * Returns:
   2690  *      SOC_E_XXX
   2691  */
   2692 
   2693 STATIC int
   2694 mac_ge_duplex_get(int unit, soc_port_t port, int *duplex)
   2695 {
   2696     soc_mac_mode_t      mode;
   2697 
   2698     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2699 
   2700     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2701         return mac_fe_duplex_get(unit, port, duplex);
   2702     } else {
   2703         uint32          gmacc1;
   2704 
   2705         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2706 
   2707         *duplex = soc_reg_field_get(unit, GMACC1r, gmacc1, FULLDf);
   2708 
   2709         return SOC_E_NONE;
   2710     }
   2711 }
   2712 
   2713 #if defined(BCM_RAPTOR1_SUPPORT)
   2714 STATIC int
   2715 mac_se_speed_set(int unit, soc_port_t port, int speed)
   2716 {
   2717     int        cur_speed;
   2718     uint32     val32;
   2719     uint32     val64;
   2720     soc_pbmp_t pbmp_s0;
   2721 
   2722     SOC_IF_ERROR_RETURN(mac_ge_speed_get(unit, port, &cur_speed));
   2723     if (cur_speed == speed) {
   2724         return SOC_E_NONE;
   2725     }
   2726 
   2727     /* Make sure all packets in flight have reached destination */
   2728 
   2729     /* Keep Trimac in soft reset */
   2730     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &val64));
   2731     soc_reg_field_set(unit, GMACC0r, &val64, SRSTf, 1);
   2732     SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, val64));
   2733 
   2734     /* Change the config bits to desired mode */
   2735     SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &val32));
   2736     SOC_PBMP_WORD_SET(pbmp_s0, 0, 0x00000002);
   2737     if (SOC_PBMP_MEMBER(pbmp_s0, port)) {
   2738         /* Select 2.5 Gbps or 1 Gbps mode. */
   2739         soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2740                               PLL_MODE_DEF_S0f, (speed == 2500) ? 1 : 0);
   2741     } else {
   2742             soc_reg_field_set(unit, GPORT_CONFIGr, &val32,
   2743                               PLL_MODE_DEF_S1f, (speed == 2500) ? 1 : 0);
   2744     }
   2745     SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, val32));
   2746 
   2747     /* Bring Trimac out of reset */
   2748     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &val64));
   2749     soc_reg_field_set(unit, GMACC0r, &val64, SRSTf, 0);
   2750     SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, val64));
   2751 
   2752     return SOC_E_NONE;
   2753 }
   2754 #endif /* BCM_RAPTOR1_SUPPORT */
   2755 
   2756 /*
   2757  * Function:
   2758  *      mac_ge_speed_set
   2759  * Purpose:
   2760  *      Set GE MAC in the specified speed.
   2761  * Parameters:
   2762  *      unit - StrataSwitch unit #.
   2763  *      port - Port number on unit.
   2764  *      speed - 10,100,1000 for speed.
   2765  * Returns:
   2766  *      SOC_E_XXX
   2767  * Notes:
   2768  *      Programs an IFG time appropriate to speed and duplex.
   2769  */
   2770 
   2771 STATIC int
   2772 mac_ge_speed_set(int unit, soc_port_t port, int speed)
   2773 {
   2774     int cur_speed;
   2775 
   2776     if (!IS_GE_PORT(unit, port)) {
   2777         return SOC_E_CONFIG;
   2778     }
   2779 
   2780     SOC_IF_ERROR_RETURN(mac_ge_speed_get(unit, port, &cur_speed));
   2781 
   2782 #if defined(BCM_RAPTOR1_SUPPORT)
   2783     if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   2784         if (!PHY_EXTERNAL_MODE(unit, port)) {
   2785             SOC_IF_ERROR_RETURN
   2786                 (mac_se_speed_set(unit, port, speed));
   2787         }
   2788     }  
   2789 #endif  /* BCM_RAPTOR1_SUPPORT */
   2790 
   2791     switch (speed) {
   2792     case 0:
   2793         break;                          /* Support NULL PHY */
   2794 
   2795     case 10:
   2796     case 100:
   2797         if (soc_feature(unit, soc_feature_trimac)) {
   2798             SOC_IF_ERROR_RETURN
   2799                 (soc_mac_mode_set(unit, port,
   2800                                   (speed == 10) ?
   2801                                   SOC_MAC_MODE_10:
   2802                                   SOC_MAC_MODE_10_100));
   2803         } else {
   2804             SOC_IF_ERROR_RETURN
   2805                 (soc_mac_mode_set(unit, port, SOC_MAC_MODE_10_100));
   2806         }
   2807         SOC_IF_ERROR_RETURN
   2808             (mac_fe_speed_set(unit, port, speed));
   2809 
   2810         break;
   2811 
   2812     case 1000:
   2813         SOC_IF_ERROR_RETURN
   2814             (soc_mac_mode_set(unit, port, SOC_MAC_MODE_1000_T));
   2815 
   2816 #if defined(BCM_FIREBOLT_SUPPORT)
   2817         /*
   2818          * Notify internal PHY driver of speed change in case it is being
   2819          * used as pass-through to an external PHY.
   2820          */
   2821 
   2822         if (soc_feature(unit, soc_feature_dodeca_serdes)) {
   2823             /*
   2824              * Notify internal PHY driver of speed change in case it is being
   2825              * used as pass-through to an external PHY.
   2826              */
   2827             if (IS_GE_PORT(unit, port)) {
   2828                 SOC_IF_ERROR_RETURN(soc_phyctrl_notify(unit, port,
   2829                                                    phyEventSpeed, speed));
   2830             }
   2831         }
   2832 #endif /* BCM_FIREBOLT_SUPPORT */
   2833 
   2834         break;
   2835 
   2836     case 2500:
   2837         SOC_IF_ERROR_RETURN
   2838             (soc_mac_mode_set(unit, port, SOC_MAC_MODE_1000_T));
   2839         break;
   2840 
   2841     default:
   2842         return (SOC_E_CONFIG);
   2843     }
   2844 
   2845     /* Set IPG to match new speed */
   2846     SOC_IF_ERROR_RETURN(mac_ge_ipg_update(unit, port));
   2847 
   2848     /* MAC speed switch results in a tx clock glitch to the serdes in 100fx mode.
   2849      * reset serdes txfifo clears this condition. However this reset triggers
   2850      * a link transition. Do not apply this reset if speed is already in 100M
   2851      */
   2852     if ((speed == 100) && (cur_speed != 100)) {
   2853         (void)soc_phyctrl_notify(unit, port, phyEventTxFifoReset, 100);
   2854     }
   2855 
   2856     return (SOC_E_NONE);
   2857 }
   2858 
   2859 /*
   2860  * Function:
   2861  *      mac_ge_speed_get
   2862  * Purpose:
   2863  *      Get GE MAC speed
   2864  * Parameters:
   2865  *      unit - StrataSwitch unit #.
   2866  *      port - Port number on unit.
   2867  *      speed - (OUT) speed in Mb (10/100/1000)
   2868  * Returns:
   2869  *      SOC_E_NONE
   2870  */
   2871 
   2872 STATIC int
   2873 mac_ge_speed_get(int unit, soc_port_t port, int *speed)
   2874 {
   2875     soc_mac_mode_t      mode;
   2876     int                 turbo = 0;
   2877     int                 rv = SOC_E_NONE;
   2878 
   2879     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2880 
   2881     switch(mode) {
   2882     case SOC_MAC_MODE_10:
   2883     case SOC_MAC_MODE_10_100:
   2884         rv = mac_fe_speed_get(unit, port, speed);
   2885         break;
   2886     case SOC_MAC_MODE_1000_T:
   2887 #if defined(BCM_RAPTOR1_SUPPORT)
   2888         if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   2889             uint32        gport_config;
   2890             soc_pbmp_t    pbmp_s0;
   2891 
   2892             SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &gport_config));
   2893 
   2894             SOC_PBMP_WORD_SET(pbmp_s0, 0, 0x00000002);
   2895             if (SOC_PBMP_MEMBER(pbmp_s0, port)) {
   2896                  turbo = soc_reg_field_get(unit, GPORT_CONFIGr, 
   2897                                            gport_config, PLL_MODE_DEF_S0f);
   2898             } else {
   2899                  turbo = soc_reg_field_get(unit, GPORT_CONFIGr,
   2900                                            gport_config, PLL_MODE_DEF_S1f);
   2901             }
   2902         }
   2903 #endif
   2904         /* coverity[dead_error_line] */
   2905         *speed = turbo ? 2500 : 1000;
   2906         break;
   2907     default:
   2908         rv = SOC_E_INTERNAL;
   2909     }
   2910     return(rv);
   2911 }
   2912 
   2913 /*
   2914  * Function:
   2915  *      mac_ge_pause_set
   2916  * Purpose:
   2917  *      Configure GE MAC to transmit/receive pause frames.
   2918  * Parameters:
   2919  *      unit - StrataSwitch unit #.
   2920  *      port - StrataSwitch port # on unit.
   2921  *      pause_tx - Boolean: transmit pause, or -1 (don't change)
   2922  *      pause_rx - Boolean: receive pause, or -1 (don't change)
   2923  * Returns:
   2924  *      SOC_E_XXX
   2925  */
   2926 
   2927 STATIC  int
   2928 mac_ge_pause_set(int unit, soc_port_t port, int pause_tx, int pause_rx)
   2929 {
   2930     soc_mac_mode_t      mode;
   2931 
   2932     if (pause_tx < 0 && pause_rx < 0) {
   2933         return SOC_E_NONE;
   2934     }
   2935 #if defined(BCM_RAPTOR1_SUPPORT)
   2936     if (SOC_IS_RAPTOR(unit) && IS_ST_PORT(unit, port)) {
   2937         /* Flow control cannot be enabled in HiGL mode */
   2938         pause_tx = 0;
   2939         pause_rx = 0;
   2940     }
   2941 #endif
   2942     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2943 
   2944     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2945         return (mac_fe_pause_set(unit, port, pause_tx, pause_rx));
   2946     } else {
   2947         uint32          gmacc1, ogmacc1;
   2948 
   2949         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   2950         ogmacc1 = gmacc1;
   2951         if (pause_tx >= 0) {
   2952             soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf,
   2953                                   pause_tx ? 1 : 0);
   2954         }
   2955         if (pause_rx >= 0) {
   2956             soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf,
   2957                                   pause_rx ? 1 : 0);
   2958         }
   2959         if (gmacc1 != ogmacc1) {
   2960             SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   2961         }
   2962 
   2963         return SOC_E_NONE;
   2964     }
   2965 }
   2966 
   2967 /*
   2968  * Function:
   2969  *      mac_ge_pause_addr_set
   2970  * Purpose:
   2971  *      Set GE MAC source address for transmitted PAUSE frame
   2972  * Parameters:
   2973  *      unit - StrataSwitch unit #.
   2974  *      port - StrataSwitch port # on unit.
   2975  *      pause_mac - MAC address used for pause transmission.
   2976  * Returns:
   2977  *      SOC_E_XXX
   2978  */
   2979 
   2980 STATIC  int
   2981 mac_ge_pause_addr_set(int unit, soc_port_t port, sal_mac_addr_t pause_mac)
   2982 {
   2983     soc_mac_mode_t      mode;
   2984 
   2985     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   2986 
   2987     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   2988         return (mac_fe_pause_addr_set(unit, port, pause_mac));
   2989     } else {                    /* mac in gig mode */
   2990         uint32  gsa0, gsa1;
   2991 
   2992         gsa0 = 0;
   2993         gsa1 = 0;
   2994 
   2995         soc_reg_field_set(unit, GSA0r, &gsa0, STAD1f,
   2996                           pause_mac[0] << 24 |
   2997                           pause_mac[1] << 16 |
   2998                           pause_mac[2] << 8 |
   2999                           pause_mac[3] << 0);
   3000 
   3001         soc_reg_field_set(unit, GSA1r, &gsa1, STAD2f,
   3002                           pause_mac[4] << 8 |
   3003                           pause_mac[5]);
   3004 
   3005         SOC_IF_ERROR_RETURN(WRITE_GSA0r(unit, port, gsa0));
   3006         SOC_IF_ERROR_RETURN(WRITE_GSA1r(unit, port, gsa1));
   3007     }
   3008 
   3009     return (SOC_E_NONE);
   3010 }
   3011 
   3012 /*
   3013  * Function:
   3014  *      mac_ge_pause_get
   3015  * Purpose:
   3016  *      Return current GE MAC transmit/receive pause frame configuration.
   3017  * Parameters:
   3018  *      unit - StrataSwitch unit #.
   3019  *      port - StrataSwitch port # on unit.
   3020  *      pause_tx - (OUT) TRUE is TX pause enabled.
   3021  *      pause_rx - (OUT) TRUE if obey RX pause enabled.
   3022  * Returns:
   3023  *      SOC_E_XXX
   3024  */
   3025 
   3026 STATIC  int
   3027 mac_ge_pause_get(int unit, soc_port_t port, int *pause_tx, int *pause_rx)
   3028 {
   3029     soc_mac_mode_t      mode;
   3030 
   3031     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3032 
   3033     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3034         return (mac_fe_pause_get(unit, port, pause_tx, pause_rx));
   3035     } else {                    /* mac in gig mode */
   3036         uint32          gmacc1;
   3037 
   3038         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   3039 
   3040         *pause_tx = soc_reg_field_get(unit, GMACC1r, gmacc1, FCTXf) ?
   3041             TRUE : FALSE;
   3042         *pause_rx = soc_reg_field_get(unit, GMACC1r, gmacc1, FCRXf) ?
   3043             TRUE : FALSE;
   3044 
   3045         return (SOC_E_NONE);
   3046     }
   3047 }
   3048 
   3049 /*
   3050  * Function:
   3051  *      mac_ge_pause_addr_get
   3052  * Purpose:
   3053  *      Return current GE MAC source address for transmitted PAUSE frames
   3054  * Parameters:
   3055  *      unit - StrataSwitch unit #.
   3056  *      port - StrataSwitch port # on unit.
   3057  *      pause_mac - (OUT) MAC address used for pause transmission.
   3058  * Returns:
   3059  *      SOC_E_XXX
   3060  */
   3061 
   3062 STATIC  int
   3063 mac_ge_pause_addr_get(int unit, soc_port_t port, sal_mac_addr_t pause_mac)
   3064 {
   3065     soc_mac_mode_t      mode;
   3066 
   3067     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3068 
   3069     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3070         return (mac_fe_pause_addr_get(unit, port, pause_mac));
   3071     } else {                    /* mac in gig mode */
   3072         uint32 gsa0, gsa1;
   3073         uint32 stad1, stad2;
   3074 
   3075         SOC_IF_ERROR_RETURN(READ_GSA0r(unit, port, &gsa0));
   3076         SOC_IF_ERROR_RETURN(READ_GSA1r(unit, port, &gsa1));
   3077 
   3078         stad1 = soc_reg_field_get(unit, GSA0r, gsa0, STAD1f);
   3079         stad2 = soc_reg_field_get(unit, GSA1r, gsa1, STAD2f);
   3080 
   3081         pause_mac[0] = (uint8)(stad1 >> 24);
   3082         pause_mac[1] = (uint8)(stad1 >> 16);
   3083         pause_mac[2] = (uint8)(stad1 >> 8);
   3084         pause_mac[3] = (uint8)(stad1 >> 0);
   3085         pause_mac[4] = (uint8)(stad2 >> 8);
   3086         pause_mac[5] = (uint8)(stad2 >> 0);
   3087 
   3088         return (SOC_E_NONE);
   3089     }
   3090 }
   3091 
   3092 /*
   3093  * Function:
   3094  *      mac_ge_loopback_set
   3095  * Purpose:
   3096  *      Set GE MAC into/out-of loopback mode
   3097  * Parameters:
   3098  *      unit - StrataSwitch unit #.
   3099  *      port - Port number on unit.
   3100  *      loopback - Boolean: true -> loopback mode, false -> normal operation
   3101  * Returns:
   3102  *      SOC_E_XXX
   3103  */
   3104 
   3105 STATIC int
   3106 mac_ge_loopback_set(int unit, soc_port_t port, int loopback)
   3107 {
   3108     soc_mac_mode_t      mode;
   3109 
   3110     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3111 
   3112     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3113         return mac_fe_loopback_set(unit, port, loopback);
   3114     } else {
   3115         uint32 gmacc0, ogmacc0;
   3116 
   3117         /* L10B also works, but not on Raptor so we'll use L32B */
   3118         SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   3119         ogmacc0 = gmacc0;
   3120         soc_reg_field_set(unit, GMACC0r, &gmacc0, L32Bf, loopback ? 1 : 0);
   3121         if (gmacc0 != ogmacc0) {
   3122             SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   3123         }
   3124 
   3125         return (SOC_E_NONE);
   3126     }
   3127 }
   3128 
   3129 /*
   3130  * Function:
   3131  *      mac_ge_loopback_get
   3132  * Purpose:
   3133  *      Get current GE MAC loopback mode setting.
   3134  * Parameters:
   3135  *      unit - StrataSwitch unit #.
   3136  *      port - StrataSwitch port # on unit
   3137  *      loopback - (OUT) Boolean: true = loopback, false = normal
   3138  * Returns:
   3139  *      SOC_E_XXX
   3140  */
   3141 
   3142 STATIC int
   3143 mac_ge_loopback_get(int unit, soc_port_t port, int *loopback)
   3144 {
   3145     soc_mac_mode_t      mode;
   3146 
   3147     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3148 
   3149     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3150         return mac_fe_loopback_get(unit, port, loopback);
   3151     } else {                    /* mac in gig mode */
   3152         uint32 gmacc0;
   3153 
   3154         SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   3155 
   3156         *loopback = soc_reg_field_get(unit, GMACC0r, gmacc0, L32Bf);
   3157 
   3158         return (SOC_E_NONE);
   3159     }
   3160 }
   3161 
   3162 /*
   3163  * Function:
   3164  *      mac_ge_ability_get
   3165  * Purpose:
   3166  *      Return the GE MAC abilities
   3167  * Parameters:
   3168  *      unit - StrataSwitch Unit #.
   3169  *      port - StrataSwitch Port # on unit.
   3170  *      mode - (OUT) Mask of MAC abilities returned.
   3171  * Returns:
   3172  *      SOC_E_NONE
   3173  */
   3174 
   3175 STATIC  int
   3176 mac_ge_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   3177 {
   3178     COMPILER_REFERENCE(unit);
   3179     COMPILER_REFERENCE(port);
   3180 
   3181     *mode = (SOC_PM_1000MB_FD | SOC_PM_MII | SOC_PM_GMII | SOC_PM_TBI |
   3182              SOC_PM_LB_MAC | SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM);
   3183 
   3184     if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3185         *mode |= SOC_PM_100MB | SOC_PM_10MB;
   3186     }
   3187 
   3188 #if defined(BCM_RAPTOR1_SUPPORT)
   3189     if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   3190         *mode |= SOC_PM_2500MB_FD;
   3191     }
   3192 #endif /* BCM_RAPTOR_SUPPORT */
   3193 
   3194     return (SOC_E_NONE);
   3195 }
   3196 
   3197 /*
   3198  * Function:
   3199  *      mac_ge_frame_max_set
   3200  * Description:
   3201  *      Set the maximum receive frame size for the GE port
   3202  * Parameters:
   3203  *      unit - Device number
   3204  *      port - Port number
   3205  *      size - Maximum frame size in bytes
   3206  * Return Value:
   3207  *      BCM_E_XXX
   3208  * Notes:
   3209  *      The maximum frame size on GE port is set the same for both GE and
   3210  *      10/100 mode
   3211  */
   3212 
   3213 STATIC int
   3214 mac_ge_frame_max_set(int unit, soc_port_t port, int size)
   3215 {
   3216     uint32 val32;
   3217 
   3218     /* 10/100 mode first */
   3219     if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3220         SOC_IF_ERROR_RETURN(mac_fe_frame_max_set(unit, port, size));
   3221     }
   3222 
   3223     /* now 1000 mode */
   3224 
   3225     if (IS_ST_PORT(unit, port)) {
   3226         size += 16; /* Account for 16 bytes of Higig2 header */
   3227     }
   3228 
   3229     val32 = size;
   3230     return WRITE_MAXFRr(unit, port, val32);
   3231 }
   3232 
   3233 /*
   3234  * Function:
   3235  *      mac_ge_frame_max_get
   3236  * Description:
   3237  *      Set the maximum receive frame size for the GE port
   3238  * Parameters:
   3239  *      unit - Device number
   3240  *      port - Port number
   3241  *      size - Maximum frame size in bytes
   3242  * Return Value:
   3243  *      BCM_E_XXX
   3244  * Notes:
   3245  *      Depending on chip or port type the actual maximum receive frame size
   3246  *      might be slightly higher.
   3247  *
   3248  *      For GE ports that use 2 separate MACs (one for GE and another one for
   3249  *      10/100 modes) the function returns the maximum rx frame size set for
   3250  *      the current mode.
   3251  */
   3252 STATIC int
   3253 mac_ge_frame_max_get(int unit, soc_port_t port, int *size)
   3254 {
   3255     uint32         val32;
   3256     soc_mac_mode_t mode;
   3257 
   3258     SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3259 
   3260     if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3261         return mac_fe_frame_max_get(unit, port, size);
   3262     } else {
   3263         SOC_IF_ERROR_RETURN(READ_MAXFRr(unit, port, &val32));
   3264         *size = val32;
   3265 
   3266         if (IS_ST_PORT(unit, port)) {
   3267             *size -= 16; /* Account for 16 bytes of Higig2 header */
   3268         }
   3269         return SOC_E_NONE;
   3270     }
   3271 }
   3272 
   3273 /*
   3274  * Function:
   3275  *      mac_ge_ifg_set
   3276  * Description:
   3277  *      Sets the new ifg (Inter-frame gap) value
   3278  * Parameters:
   3279  *      unit   - Device number
   3280  *      port   - Port number
   3281  *      speed  - the speed for which the IFG is being set
   3282  *      duplex - the duplex for which the IFG is being set
   3283  *      ifg    - Inter-frame gap in bit-times
   3284  * Return Value:
   3285  *      BCM_E_XXX
   3286  * Notes:
   3287  *      The function makes sure the IFG value makes sense and updates the
   3288  *      IPG register in case the speed/duplex match the current settings
   3289  */
   3290 STATIC int
   3291 mac_ge_ifg_set(int unit, soc_port_t port, int speed, soc_port_duplex_t  duplex,
   3292                int ifg)
   3293 {
   3294     int         cur_speed;
   3295     int         cur_duplex;
   3296     int         ipg;
   3297     int         real_ifg;
   3298     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   3299     int         rv;
   3300 
   3301     SOC_IF_ERROR_RETURN(mac_ge_ifg_to_ipg(unit, port, speed, duplex,
   3302                                           ifg, &ipg));
   3303     SOC_IF_ERROR_RETURN(mac_ge_ipg_to_ifg(unit, port, speed, duplex,
   3304                                           ipg, &real_ifg));
   3305 
   3306     if (duplex) {
   3307         switch (speed) {
   3308         case 10:
   3309             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3310                 si->fd_10 = real_ifg;
   3311             }  else {
   3312                 return SOC_E_PARAM;
   3313             }
   3314             break;
   3315         case 100:
   3316             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3317                 si->fd_100 = real_ifg;
   3318             }  else {
   3319                 return SOC_E_PARAM;
   3320             }
   3321             break;
   3322         case 1000:
   3323     /** coverity[equality_cond]    **/
   3324             si->fd_1000 = real_ifg;
   3325     /** coverity[equality_cond]    **/
   3326             break;
   3327         case 2500:
   3328 #ifdef BCM_RAPTOR1_SUPPORT
   3329             if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   3330                 si->fd_2500 = real_ifg;
   3331             } else
   3332 #endif
   3333             {
   3334                 return SOC_E_PARAM;
   3335             }
   3336             break;
   3337 
   3338         default:
   3339             return SOC_E_PARAM;
   3340             break;
   3341         }
   3342     } else {
   3343         switch (speed) {
   3344         case 10:
   3345             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3346                 si->hd_10 = real_ifg;
   3347             }  else {
   3348                 return SOC_E_PARAM;
   3349             }
   3350             break;
   3351         case 100:
   3352             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3353                 si->hd_100 = real_ifg;
   3354             }  else {
   3355                 return SOC_E_PARAM;
   3356             }
   3357             break;
   3358         case 1000:
   3359             si->hd_1000 = real_ifg;
   3360             break;
   3361 
   3362         default:
   3363             return SOC_E_PARAM;
   3364             break;
   3365         }
   3366     }
   3367 
   3368     SOC_IF_ERROR_RETURN(mac_ge_duplex_get(unit, port, &cur_duplex));
   3369     SOC_IF_ERROR_RETURN(mac_ge_speed_get(unit, port, &cur_speed));
   3370 
   3371     if (cur_speed == speed && ((soc_port_duplex_t)cur_duplex == duplex)) {
   3372         switch (speed) {
   3373         case 10:
   3374         case 100:
   3375             rv = mac_fe_ipg_update(unit, port);
   3376             break;
   3377         case 1000:
   3378         case 2500:
   3379             rv = mac_ge_ipg_update(unit, port);
   3380             break;
   3381         /* coverity[dead_error_begin] */
   3382         default:
   3383             rv =  SOC_E_PARAM;
   3384         }
   3385     } else {
   3386         rv = SOC_E_NONE;
   3387     }
   3388 
   3389     return (rv);
   3390 }
   3391 
   3392 /*
   3393  * Function:
   3394  *      mac_ge_ifg_get
   3395  * Description:
   3396  *      Gets the ifg (Inter-frame gap) value for a specific speed/duplex
   3397  *      combination
   3398  * Parameters:
   3399  *      unit   - Device number
   3400  *      port   - Port number
   3401  *      speed  - the speed for which the IFG is being set
   3402  *      duplex - the duplex for which the IFG is being set
   3403  *      ifg    - Inter-frame gap in bit-times
   3404  * Return Value:
   3405  *      BCM_E_XXX
   3406  * Notes:
   3407  *      The function returns the REAL ifg value that will be (or is currently)
   3408  *      used by the chip, which might be different from the value initially
   3409  *      set by the ifg_set() call. The reason for that is that only certain
   3410  *      values are allowed.
   3411  */
   3412 STATIC int
   3413 mac_ge_ifg_get(int unit, soc_port_t port, int speed, soc_port_duplex_t  duplex,
   3414                int *ifg)
   3415 {
   3416     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   3417 
   3418     if (duplex) {
   3419         switch (speed) {
   3420         case 10:
   3421             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3422                 *ifg = si->fd_10;
   3423             }  else {
   3424                 return SOC_E_PARAM;
   3425             }
   3426             break;
   3427         case 100:
   3428             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3429                 *ifg = si->fd_100;
   3430             }  else {
   3431                 return SOC_E_PARAM;
   3432             }
   3433             break;
   3434         case 1000:
   3435             *ifg = si->fd_1000;
   3436             break;
   3437         case 2500:
   3438 #ifdef BCM_RAPTOR1_SUPPORT
   3439             if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   3440                 *ifg = si->fd_2500;
   3441             } else
   3442 #endif
   3443             {
   3444                 return SOC_E_PARAM;
   3445             }
   3446             break;
   3447 
   3448         default:
   3449             return SOC_E_PARAM;
   3450             break;
   3451         }
   3452     } else {
   3453         switch (speed) {
   3454         case 10:
   3455             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3456                 *ifg = si->hd_10;
   3457             }  else {
   3458                 return SOC_E_PARAM;
   3459             }
   3460             break;
   3461         case 100:
   3462             if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3463                 *ifg = si->hd_100;
   3464             }  else {
   3465                 return SOC_E_PARAM;
   3466             }
   3467             break;
   3468         case 1000:
   3469             *ifg = si->hd_1000;
   3470             break;
   3471 
   3472         default:
   3473             return SOC_E_PARAM;
   3474             break;
   3475         }
   3476     }
   3477 
   3478     return SOC_E_NONE;
   3479 }
   3480 
   3481 /*
   3482  * Function:
   3483  *      mac_ge_encap_set
   3484  * Purpose:
   3485  *      Set the port encapsulation mode.
   3486  * Parameters:
   3487  *      unit - XGS unit #.
   3488  *      port - XGS port # on unit.
   3489  *      mode - encapsulation mode
   3490  * Returns:
   3491  *      SOC_E_XXX
   3492  */
   3493 STATIC int
   3494 mac_ge_encap_set(int unit, soc_port_t port, int mode)
   3495 {
   3496     if (mode == SOC_ENCAP_IEEE) {
   3497         return SOC_E_NONE;
   3498     }
   3499     return SOC_E_PARAM;
   3500 }
   3501 
   3502 /*
   3503  * Function:
   3504  *      mac_ge_encap_get
   3505  * Purpose:
   3506  *      Get the port encapsulation mode.
   3507  * Parameters:
   3508  *      unit - XGS unit #.
   3509  *      port - XGS port # on unit.
   3510  *      mode - (INT) encapsulation mode
   3511  * Returns:
   3512  *      SOC_E_XXX
   3513  */
   3514 STATIC int
   3515 mac_ge_encap_get(int unit, soc_port_t port, int *mode)
   3516 {
   3517     *mode = SOC_ENCAP_IEEE;
   3518 
   3519     return SOC_E_NONE;
   3520 }
   3521 
   3522 /*
   3523  * Function:
   3524  *      mac_ge_control_set
   3525  * Purpose:
   3526  *      To configure GE MAC control properties.
   3527  * Parameters:
   3528  *      unit - XGS unit #.
   3529  *      port - XGS port # on unit.
   3530  *      type - MAC control property to set.
   3531  *      int  - New setting for MAC control.
   3532  * Returns:
   3533  *      SOC_E_XXX
   3534  */
   3535 STATIC int
   3536 mac_ge_control_set(int unit, soc_port_t port, soc_mac_control_t type,
   3537                    int value)
   3538 {
   3539     soc_mac_mode_t mode;
   3540     uint32 regval, copy;
   3541 
   3542     LOG_VERBOSE(BSL_LS_SOC_GE,
   3543                 (BSL_META_U(unit,
   3544                             "mac_ge_control_set: unit %d port %s type=%d value=%d\n"),
   3545                  unit, SOC_PORT_NAME(unit, port),
   3546                  type, value));
   3547 
   3548     switch (type) {
   3549     case SOC_MAC_CONTROL_RX_SET:
   3550         SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3551         if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3552 #ifdef BCM_RAPTOR1_SUPPORT
   3553             /* Need to reset the FE MAC for Raptor before enabling RX */
   3554             if (SOC_IS_RAPTOR(unit) && value) {    
   3555                 SOC_IF_ERROR_RETURN
   3556                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 1));
   3557                 SOC_IF_ERROR_RETURN
   3558                     (soc_reg_field32_modify(unit, GMACC0r, port, SRSTf, 0));
   3559             }
   3560 #endif
   3561             SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &regval));
   3562             FE_SET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_ENf, regval, value ? 1 : 0);
   3563             SOC_IF_ERROR_RETURN(FE_WRITE(FE_MAC1r, GTH_FE_MAC1r, unit, port, regval));
   3564             break;
   3565         }
   3566     
   3567         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &regval));
   3568         copy = regval;
   3569         if (value) {
   3570             soc_reg_field_set(unit, GMACC1r, &regval, RXEN0f, 1);
   3571         } else {
   3572             soc_reg_field_set(unit, GMACC1r, &regval, RXEN0f, 0);
   3573         }
   3574         if (regval != copy) {
   3575             SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, regval));
   3576         }
   3577         break;
   3578      
   3579     default:
   3580         return SOC_E_UNAVAIL;
   3581     }
   3582 
   3583     return SOC_E_NONE;
   3584 }
   3585 
   3586 /*
   3587  * Function:
   3588  *      mac_ge_control_get
   3589  * Purpose:
   3590  *      To get current GE MAC control setting.
   3591  * Parameters:
   3592  *      unit - XGS unit #.
   3593  *      port - XGS port # on unit.
   3594  *      type - MAC control property to set.
   3595  *      int  - New setting for MAC control.
   3596  * Returns:
   3597  *      SOC_E_XXX
   3598  */
   3599 STATIC int
   3600 mac_ge_control_get(int unit, soc_port_t port, soc_mac_control_t type,
   3601                    int *value)
   3602 {
   3603     soc_mac_mode_t mode;
   3604     uint32 regval;
   3605 
   3606     if (value == NULL) {
   3607         return SOC_E_PARAM;
   3608     }
   3609 
   3610     switch (type) {
   3611     case SOC_MAC_CONTROL_RX_SET:
   3612         SOC_IF_ERROR_RETURN(soc_mac_mode_get(unit, port, &mode));
   3613         if ((mode == SOC_MAC_MODE_10_100) || (mode == SOC_MAC_MODE_10)) {
   3614             SOC_IF_ERROR_RETURN(FE_READ(FE_MAC1r, GTH_FE_MAC1r, unit, port, &regval));
   3615             *value = FE_GET(unit, port, FE_MAC1r, GTH_FE_MAC1r, RX_ENf, regval);
   3616             break;
   3617         }
   3618         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &regval));
   3619         *value = soc_reg_field_get(unit, GMACC1r, regval, RXEN0f);
   3620         break;
   3621     default:
   3622         return SOC_E_UNAVAIL;
   3623     }
   3624 
   3625     LOG_VERBOSE(BSL_LS_SOC_GE,
   3626                 (BSL_META_U(unit,
   3627                             "mac_ge_control_get: unit %d port %s type=%d value=%d\n"),
   3628                  unit, SOC_PORT_NAME(unit, port),
   3629                  type, *value));
   3630     return SOC_E_NONE;
   3631 }            
   3632 
   3633 /*
   3634  * Function:
   3635  *      mac_ge_ability_local_get
   3636  * Purpose:
   3637  *      Return the GE MAC abilities
   3638  * Parameters:
   3639  *      unit - StrataSwitch Unit #.
   3640  *      port - StrataSwitch Port # on unit.
   3641  *      mode - (OUT) Mask of MAC abilities returned.
   3642  * Returns:
   3643  *      SOC_E_NONE
   3644  */
   3645 
   3646 STATIC  int
   3647 mac_ge_ability_local_get(int unit, soc_port_t port,
   3648                         soc_port_ability_t *ability)
   3649 {
   3650     if (NULL == ability) {
   3651         return SOC_E_PARAM;
   3652     }
   3653 
   3654     ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   3655     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB; 
   3656     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   3657     ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_TBI; 
   3658     ability->medium    = SOC_PA_ABILITY_NONE;
   3659     ability->loopback  = SOC_PA_LB_MAC;
   3660     ability->flags     = SOC_PA_ABILITY_NONE;
   3661     ability->encap     = SOC_PA_ENCAP_IEEE;
   3662 
   3663     if (soc_feature(unit, soc_feature_fe_gig_macs)) {
   3664         ability->speed_half_duplex |= SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB;
   3665         ability->speed_full_duplex |= SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB; 
   3666     }
   3667 
   3668 #if defined(BCM_RAPTOR1_SUPPORT)
   3669     if (SOC_IS_RAPTOR(unit) && IS_S_PORT(unit, port)) {
   3670         ability->speed_full_duplex |= SOC_PA_SPEED_2500MB; 
   3671     }
   3672 #endif /* BCM_RAPTOR_SUPPORT */
   3673 
   3674     return (SOC_E_NONE);
   3675 }
   3676 
   3677 /* Exported GE MAC driver structure */
   3678 mac_driver_t soc_mac_ge = {
   3679     "1000Mb MAC Driver",            /* drv_name */
   3680     mac_ge_init,                    /* md_init  */
   3681     mac_ge_enable_set,              /* md_enable_set */
   3682     mac_ge_enable_get,              /* md_enable_get */
   3683     mac_ge_duplex_set,              /* md_duplex_set */
   3684     mac_ge_duplex_get,              /* md_duplex_get */
   3685     mac_ge_speed_set,               /* md_speed_set */
   3686     mac_ge_speed_get,               /* md_speed_get */
   3687     mac_ge_pause_set,               /* md_pause_set */
   3688     mac_ge_pause_get,               /* md_pause_get */
   3689     mac_ge_pause_addr_set,          /* md_pause_addr_set */
   3690     mac_ge_pause_addr_get,          /* md_pause_addr_get */
   3691     mac_ge_loopback_set,            /* md_lb_set */
   3692     mac_ge_loopback_get,            /* md_lb_get */
   3693     mac_ge_interface_set,           /* md_interface_set */
   3694     mac_ge_interface_get,           /* md_interface_get */
   3695     mac_ge_ability_get,             /* md_ability_get */
   3696     mac_ge_frame_max_set,           /* md_frame_max_set */
   3697     mac_ge_frame_max_get,           /* md_frame_max_get */
   3698     mac_ge_ifg_set,                 /* md_ifg_set */
   3699     mac_ge_ifg_get,                 /* md_ifg_get */
   3700     mac_ge_encap_set,               /* md_encap_set */
   3701     mac_ge_encap_get,               /* md_encap_get */
   3702     mac_ge_control_set,             /* md_control_set */
   3703     mac_ge_control_get,             /* md_control_get */
   3704     mac_ge_ability_local_get,       /* md_ability_local_get */
   3705     NULL                            /* md_timesync_tx_info_get */
   3706 };
   3707 
   3708 #endif /* defined(BCM_ESW_SUPPORT) */
   3709