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

gxmac.c (94216B)


      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  * XGS 1/2.5/10/12G Media Access Controller Driver (gxmac)
      8  *
      9  * This module is used for:
     10  *
     11  *   - All ports on XGS3 HUMV/Bradley/Goldwing family
     12  */
     13 
     14 #include <shared/bsl.h>
     15 
     16 #include <sal/core/libc.h>
     17 #include <shared/alloc.h>
     18 #include <sal/core/spl.h>
     19 #include <sal/core/boot.h>
     20 #include <soc/drv.h>
     21 #include <soc/error.h>
     22 #include <soc/cmic.h>
     23 #include <soc/portmode.h>
     24 #include <soc/ll.h>
     25 #include <soc/counter.h>
     26 #include <soc/phy.h>
     27 #include <soc/phyctrl.h>
     28 
     29 #ifdef BCM_GXPORT_SUPPORT
     30 
     31 
     32 #ifndef GXPORT_ISLOATE_IF_LOOPBACK
     33 #define GXPORT_ISLOATE_IF_LOOPBACK 0
     34 #endif
     35 
     36 /*
     37  * GXMAC Register field definitions.
     38  */
     39 
     40 /* Transmit CRC Modes (Receive has bit field definitions in register) */
     41 #define GXMAC_CRC_APPEND          0x00   /* Append CRC (Default) */
     42 #define GXMAC_CRC_KEEP            0x01   /* CRC Assumed correct */
     43 #define GXMAC_CRC_REGEN           0x02   /* Replace CRC with a new one */
     44 #define GXMAC_CRC_RSVP            0x03   /* Reserved (does Replace) */
     45 
     46 
     47 #define JUMBO_MAXSZ              0x3fe8 /* Max legal value (per regsfile) */
     48 
     49 /*
     50  * Forward Declarations
     51  *
     52  *      gxmac_xxx        Routines that work on XGS ports in 10Gig mode.
     53  */
     54 STATIC int   gxmac_ipg_update(int unit, soc_port_t port);
     55 STATIC int   gxmac_init(int unit, soc_port_t port);
     56 STATIC int   gxmac_enable_set(int unit, soc_port_t port, int enable);
     57 STATIC int   gxmac_enable_get(int unit, soc_port_t port, int *enable);
     58 STATIC int   gxmac_duplex_set(int unit, soc_port_t port, int duplex);
     59 STATIC int   gxmac_duplex_get(int unit, soc_port_t port, int *duplex);
     60 STATIC int   gxmac_pause_set(int unit, soc_port_t, int, int);
     61 STATIC int   gxmac_pause_get(int unit, soc_port_t, int*, int*);
     62 STATIC int   gxmac_pause_addr_set(int unit, soc_port_t port, sal_mac_addr_t);
     63 STATIC int   gxmac_pause_addr_get(int unit, soc_port_t port, sal_mac_addr_t);
     64 STATIC int   gxmac_interface_set(int unit, soc_port_t port,
     65                                 soc_port_if_t pif);
     66 STATIC int   gxmac_interface_get(int unit, soc_port_t port,
     67                                 soc_port_if_t *pif);
     68 STATIC int   gxmac_speed_set(int unit, soc_port_t port, int speed);
     69 STATIC int   gxmac_speed_get(int unit, soc_port_t port, int *speed);
     70 STATIC int   gxmac_loopback_get(int unit, soc_port_t port, int *loopback);
     71 STATIC int   gxmac_loopback_set(int unit, soc_port_t port, int loopback);
     72 STATIC int   gxmac_frame_max_set(int unit, soc_port_t port, int size);
     73 STATIC int   gxmac_frame_max_get(int unit, soc_port_t port, int *size);
     74 STATIC int   gxmac_control_set(int unit, soc_port_t port,
     75               soc_mac_control_t type, int value);
     76 STATIC int   gxmac_control_get(int unit, soc_port_t port,
     77               soc_mac_control_t type, int *value);
     78 STATIC int   gxmac_frame_spacing_stretch_set(int unit,
     79               soc_port_t port, int value);
     80 STATIC int   soc_unicore_pll_lock_wait(int unit, soc_port_t port);
     81 STATIC int   soc_unicore_speed_set(int unit, soc_port_t port, int speed);
     82 
     83 #ifdef BROADCOM_DEBUG
     84 static char *gxmac_encap_mode[] = SOC_ENCAP_MODE_NAMES_INITIALIZER;
     85 static char *gxmac_port_if_names[] = SOC_PORT_IF_NAMES_INITIALIZER;
     86 #endif /* BROADCOM_DEBUG */
     87 
     88 /*
     89  * Returns the CMIC_XGXS_MDIO_CONFIG_N register corresponding to the port.
     90  */
     91 STATIC int
     92 _port2cmic_xgxs_mdio_config(int unit, soc_port_t port)
     93 {
     94     if (SOC_IS_HB_GW(unit)) {
     95         switch(port) {
     96             case  0: return CMIC_XGXS_MDIO_CONFIG_0r;
     97             case  1: return CMIC_XGXS_MDIO_CONFIG_1r;
     98             case  2: return CMIC_XGXS_MDIO_CONFIG_2r;
     99             case  3: return CMIC_XGXS_MDIO_CONFIG_3r;
    100             case  4: return CMIC_XGXS_MDIO_CONFIG_4r;
    101             case  5: return CMIC_XGXS_MDIO_CONFIG_5r;
    102             case  6: return CMIC_XGXS_MDIO_CONFIG_6r;
    103             case  7: return CMIC_XGXS_MDIO_CONFIG_7r;
    104             case  8: return CMIC_XGXS_MDIO_CONFIG_8r;
    105             case  9: return CMIC_XGXS_MDIO_CONFIG_9r;
    106             case 10: return CMIC_XGXS_MDIO_CONFIG_10r;
    107             case 11: return CMIC_XGXS_MDIO_CONFIG_11r;
    108             case 12: return CMIC_XGXS_MDIO_CONFIG_12r;
    109             case 13: return CMIC_XGXS_MDIO_CONFIG_13r;
    110             case 14: return CMIC_XGXS_MDIO_CONFIG_14r;
    111             case 15: return CMIC_XGXS_MDIO_CONFIG_15r;
    112             case 16: return CMIC_XGXS_MDIO_CONFIG_16r;
    113             case 17: return CMIC_XGXS_MDIO_CONFIG_17r;
    114             case 18: return CMIC_XGXS_MDIO_CONFIG_18r;
    115             case 19: return CMIC_XGXS_MDIO_CONFIG_19r;
    116             default: return INVALIDr;
    117         }
    118     }
    119 
    120     return INVALIDr;
    121 }
    122 
    123 /*
    124  * Function:
    125  *     soc_unicore_reset (10(X)-Gig/Xaui/Serdes (XGXS) reset)
    126  * Purpose:
    127  *     Reset and initialize the BigMAC and Unicore.
    128  * Parameters:
    129  *     unit - XGS unit #.
    130  *     port - Port number on unit.
    131  * Returns:
    132  *     SOC_E_XXX
    133  */
    134 int
    135 soc_unicore_reset(int unit, soc_port_t port)
    136 {
    137     uint8               phy_addr;
    138     uint64              xgxs_ctrl;
    139     uint32              reg_val, lcpll;
    140     uint16              mreg_val, hg_speeds;
    141     soc_reg_t           reg;
    142     int                 preemph;
    143     int                 idriver, pdriver;
    144     int                 rxequal, offsctl;
    145     int                 reset_sleep_usec;
    146 #ifdef BCM_HB_GW_SUPPORT
    147     uint32              gport_config;
    148 #endif
    149 
    150     LOG_VERBOSE(BSL_LS_SOC_10G,
    151                 (BSL_META_U(unit,
    152                 "gxmac: unit %d port %s: unicore reset\n"),
    153                  unit, SOC_PORT_NAME(unit, port)));
    154 
    155     /* 
    156      * CX4 compliance related
    157      */
    158     reg = _port2cmic_xgxs_mdio_config(unit, port);
    159     if (reg == INVALIDr) {
    160         return SOC_E_INTERNAL;
    161     }
    162     reg_val = soc_pci_read(unit, soc_reg_addr(unit, reg, REG_PORT_ANY, 0));
    163     soc_reg_field_set(unit, reg, &reg_val, MD_DEVADf, 0x0);
    164     soc_reg_field_set(unit, reg, &reg_val, IEEE_DEVICES_IN_PKGf,
    165                       (IS_HG_PORT(unit, port)) ? 0x03 : 0x15);
    166     soc_pci_write(unit, soc_reg_addr(unit, reg, REG_PORT_ANY, 0), reg_val);
    167 
    168     /*
    169      * Unicore reference clock selection between LCPLL and clock pads.
    170      */
    171     lcpll = soc_property_port_get(unit, port, spn_XGXS_LCPLL,
    172                                   (SAL_BOOT_QUICKTURN) ? 0 : 1);
    173     SOC_IF_ERROR_RETURN(READ_MAC_XGXS_CTRLr(unit, port, &xgxs_ctrl));
    174     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr,
    175                           &xgxs_ctrl, LCREFENf, lcpll);
    176     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    177 
    178     /*
    179      * Allow properties to change important variables.
    180      */
    181     rxequal = soc_property_port_get(unit, port, spn_XGXS_EQUALIZER,
    182                                     /* coverity[identical_branches : FALSE] */
    183                                     IS_HG_PORT(unit,port) ? 0x5 : 0x5);
    184     offsctl = soc_property_port_get(unit, port, spn_XGXS_OFFSET, 
    185                                     /* coverity[identical_branches : FALSE] */
    186                                     IS_HG_PORT(unit,port) ? 0x2 : 0x2);
    187     /* NB: preemphasis, driver, pre-driver currents are bit-reversed in HW */
    188     preemph = soc_property_port_get(unit, port, spn_XGXS_PREEMPHASIS, 
    189                                     /* coverity[identical_branches : FALSE] */
    190                                     IS_HG_PORT(unit,port) ? 0x4 : 0x4);
    191     preemph = _shr_bit_rev8(preemph) >> 4;
    192 
    193     idriver = soc_property_port_get(unit, port, spn_XGXS_DRIVER_CURRENT, 
    194                                     IS_HG_PORT(unit,port) ? 0x9 : 0xf);
    195     idriver = _shr_bit_rev8(idriver) >> 4;
    196 
    197     pdriver = soc_property_port_get(unit, port, spn_XGXS_PRE_DRIVER_CURRENT, 
    198                                     IS_HG_PORT(unit,port) ? 0x9 : 0xf);
    199     pdriver = _shr_bit_rev8(pdriver) >> 4;
    200 
    201     phy_addr = PORT_TO_PHY_ADDR_INT(unit, port);
    202     reset_sleep_usec = 100;
    203     if (SAL_BOOT_QUICKTURN) {
    204         /* Kick the QT phy model */
    205         uint16 rv, kv;
    206 
    207         rv = 0x0800; /* Reset */ 
    208         if (IS_HG_PORT(unit,port)) {
    209             kv = 0x0000; /* Configure for HG mode */ 
    210         } else {
    211             kv = 0x0002; /* Configure for XE mode */ 
    212         }
    213         SOC_IF_ERROR_RETURN(soc_miim_write(unit, port + 0x41 , 0x00, rv));
    214         SOC_IF_ERROR_RETURN(soc_miim_write(unit, port + 0x41 , 0x00, kv));
    215         reset_sleep_usec = 500000;
    216     } else {
    217         if (!SOC_WARM_BOOT(unit) && !SOC_IS_RELOADING(unit)) {
    218             SOC_IF_ERROR_RETURN(soc_miim_write(unit, port + 1, 0x00, 0x0000));
    219         }
    220     }
    221 
    222     /* 
    223      * Force BigMAC and TriMAC into reset before initialization
    224      */
    225     SOC_IF_ERROR_RETURN(READ_MAC_XGXS_CTRLr(unit, port, &xgxs_ctrl));
    226     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, IDDQf, 1);
    227     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, PWRDWNf, 1);
    228     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, HW_RSTLf, 0);
    229     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, RSTB_MDIOREGSf, 0);
    230     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, RSTB_PLLf, 0);
    231     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, BIGMACRSTLf, 0);
    232     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, TXFIFO_RSTLf, 0);
    233     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    234 
    235 #ifdef BCM_HB_GW_SUPPORT
    236     if (soc_reg_field_valid(unit, GPORT_CONFIGr, TRIMAC_RESETf)) {
    237         SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &gport_config));
    238         soc_reg_field_set(unit, GPORT_CONFIGr, &gport_config,
    239                           TRIMAC_RESETf, 1);
    240         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, gport_config));
    241     }
    242 #endif
    243     sal_usleep(reset_sleep_usec);
    244 
    245     /*
    246      * XGXS MAC initialization steps.
    247      *
    248      * A minimum delay is required between various initialization steps.
    249      * There is no maximum delay.  The values given are very conservative
    250      * including the timeout for PLL lock.
    251      */
    252 
    253     /* Powerup Unicore interface (digital and analog clocks) */
    254     SOC_IF_ERROR_RETURN(READ_MAC_XGXS_CTRLr(unit, port, &xgxs_ctrl));
    255     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, IDDQf, 0);
    256     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, PWRDWNf, 0);
    257     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    258     sal_usleep(reset_sleep_usec);
    259 
    260     /* Bring Unicore out of reset */
    261     SOC_IF_ERROR_RETURN(READ_MAC_XGXS_CTRLr(unit, port, &xgxs_ctrl));
    262     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, HW_RSTLf, 1);
    263     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    264 
    265     /* Bring MDIO registers out of reset */
    266     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, RSTB_MDIOREGSf, 1);
    267     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    268 
    269     /* Activate all clocks */
    270     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, RSTB_PLLf, 1);
    271     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    272 
    273     /* Bring TriMac out of reset */
    274 #ifdef BCM_HB_GW_SUPPORT
    275     if (soc_reg_field_valid(unit, GPORT_CONFIGr, TRIMAC_RESETf)) {
    276         SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &gport_config));
    277         soc_reg_field_set(unit, GPORT_CONFIGr, &gport_config,
    278                           TRIMAC_RESETf, 0);
    279         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, gport_config));
    280     }
    281 #endif
    282 
    283     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RELOADING(unit)) {
    284         /*
    285          * Isolate external power-down input pins
    286          */
    287         if (soc_feature(unit, soc_feature_xgxs_power)) {
    288             SOC_IF_ERROR_RETURN     /* Select block 0x1 */
    289                 (soc_miim_write(unit, phy_addr, 0x1f, 0x0010));
    290             SOC_IF_ERROR_RETURN
    291                 (soc_miim_read(unit, phy_addr, 0x1a, &mreg_val));
    292             mreg_val |= (1 << 10);
    293             SOC_IF_ERROR_RETURN     /* Power on Core */
    294                 (soc_miim_write(unit, phy_addr, 0x1a, mreg_val));
    295         }
    296     
    297         /*
    298          * Basic XGXS configuration
    299          */
    300         SOC_IF_ERROR_RETURN	        /* Select block 0x5 */
    301             (soc_miim_write(unit, phy_addr, 0x1f, 0x0050));
    302         SOC_IF_ERROR_RETURN	        /* Disable PLL state machine */
    303             (soc_miim_write(unit, phy_addr, 0x11, 0x5006));
    304         SOC_IF_ERROR_RETURN	        /* PLL VCO step time */
    305             (soc_miim_write(unit, phy_addr, 0x12, 0x04ff));
    306         SOC_IF_ERROR_RETURN	        /* Turn off slowdn_xor */
    307             (soc_miim_write(unit, phy_addr, 0x15, 0x0000));
    308         SOC_IF_ERROR_RETURN	        /* Select block 0xf */
    309             (soc_miim_write(unit, phy_addr, 0x1f, 0x00f0));
    310         SOC_IF_ERROR_RETURN	        /* CDR bandwidth */
    311             (soc_miim_write(unit, phy_addr, 0x16, 0x8300));
    312     
    313         SOC_IF_ERROR_RETURN		/* Select block 0x0 */
    314             (soc_miim_write(unit, phy_addr, 0x1f, 0x0000));
    315         SOC_IF_ERROR_RETURN
    316             (soc_miim_read(unit, phy_addr, 0x10, &mreg_val));
    317         mreg_val = (mreg_val & 0xf0ff) | (0xc << 8);
    318         SOC_IF_ERROR_RETURN         /* Select ComboCore mode */
    319             (soc_miim_write(unit, phy_addr, 0x10, mreg_val));
    320         if (IS_HG_PORT(unit,port)) {
    321             SOC_IF_ERROR_RETURN     /* Enable DTE mdio reg mapping */
    322                 (soc_miim_write(unit, phy_addr, 0x1e, 0x0001));
    323             SOC_IF_ERROR_RETURN     /* Select block 0x32 */
    324                 (soc_miim_write(unit, phy_addr, 0x1f, 0x0320));
    325             /* For Draco and Hercules, use pre-CX4 signalling */
    326             hg_speeds = 0x0008;
    327             if (soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE)) {
    328                 /* Also advertise 10G CX4 signalling by default */
    329                 hg_speeds |= 0x0010;
    330             }
    331             if (SOC_INFO(unit).port_speed_max[port] >= 13000) {
    332                 /* Also advertise 12G and 13G */
    333                 hg_speeds |= 0x00a0;
    334             }
    335             SOC_IF_ERROR_RETURN     
    336                 (soc_miim_write(unit, phy_addr, 0x19, hg_speeds));
    337         } else {
    338             SOC_IF_ERROR_RETURN     /* Enable PMA/PMD mdio reg mapping */
    339                 (soc_miim_write(unit, phy_addr, 0x1e, 0x0201));
    340             SOC_IF_ERROR_RETURN     /* Select block 0x32 */
    341                 (soc_miim_write(unit, phy_addr, 0x1f, 0x0320));
    342             if (IS_GE_PORT(unit,port)) {
    343                 SOC_IF_ERROR_RETURN     /* Only advertise 2.5G CX4 */
    344                     (soc_miim_write(unit, phy_addr, 0x19, 0x0001));
    345             } else {
    346                 /* Advertise only 10G CX4 for XE port */
    347                 SOC_IF_ERROR_RETURN     /* Advertise 10G CX4 only */
    348                     (soc_miim_write(unit, phy_addr, 0x19, 0x0010));
    349            }
    350         }
    351     
    352         /*
    353          * Configure 10G parallel detect
    354          */
    355         SOC_IF_ERROR_RETURN     /* Select block 0x34 */
    356             (soc_miim_write(unit, phy_addr, 0x1f, 0x0340));
    357         SOC_IF_ERROR_RETURN     /* Adjust parallel detect link timer to 60ms */
    358             (soc_miim_write(unit, phy_addr, 0x13, 0x16E2));
    359         SOC_IF_ERROR_RETURN     /* Read parDet10GControl register */
    360             (soc_miim_read(unit, phy_addr, 0x11, &mreg_val));
    361         mreg_val &= ~(1 << 0);
    362         if (soc_property_port_get(unit, port, spn_XGXS_PDETECT_10G, 1)) {
    363             mreg_val |= (1 << 0);   /* Enable 10G parallel detect */
    364         }
    365         SOC_IF_ERROR_RETURN     /* Update parDet10GControl register */
    366             (soc_miim_write(unit, phy_addr, 0x11, mreg_val));
    367         if (!(IS_HG_PORT(unit, port) && 
    368             SOC_INFO(unit).port_speed_max[port] > 10000)) {
    369             /*
    370              * Disable 12 Gbps parallel detect on all ports with max
    371              * speed 10Gbps and lower.
    372              */ 
    373             SOC_IF_ERROR_RETURN     /* Read parDet10GControl register */
    374                 (soc_miim_read(unit, phy_addr, 0x11, &mreg_val));
    375             mreg_val |= (1 << 5);   /* Disable parallel detect for 12 Gbps */
    376             mreg_val |= (1 << 6);   /* Disable parallel detect 12 Gbps TXD */
    377             SOC_IF_ERROR_RETURN     /* Update parDet10GControl register */
    378                 (soc_miim_write(unit, phy_addr, 0x11, mreg_val));
    379         }
    380         SOC_IF_ERROR_RETURN     /* Update parDet10GLostLink register */
    381             (soc_miim_write(unit, phy_addr, 0x14, 0x4c4a));
    382     
    383         /*
    384          * Configure TX pre-emphasis, driver and pre-driver currents
    385          */
    386         SOC_IF_ERROR_RETURN         /* Select block 0xa */
    387             (soc_miim_write(unit, phy_addr, 0x1f, 0x00a0));
    388         SOC_IF_ERROR_RETURN         /* TX pre-emphasis */
    389             (soc_miim_write(unit, phy_addr, 0x17, ((preemph & 0xf) << 12) |
    390                                                   ((idriver & 0xf) << 8) |
    391                                                   ((pdriver & 0xf) << 4)));
    392     
    393         /*
    394          * Configure PLL
    395          */
    396         SOC_IF_ERROR_RETURN	        /* Select block 0x5 */
    397             (soc_miim_write(unit, phy_addr, 0x1f, 0x0050));
    398         SOC_IF_ERROR_RETURN	        /* Enable PLL state machine */
    399             (soc_miim_write(unit, phy_addr, 0x11, 0xf01e));
    400     
    401         /*
    402          * Transform CX4 pin out on the board to HG pinout
    403          */
    404         if (soc_property_port_get(unit, port, spn_CX4_TO_HIGIG, FALSE)) {
    405             SOC_IF_ERROR_RETURN     /* Select block 0x10 */
    406                 (soc_miim_write(unit, phy_addr, 0x1f, 0x0100));
    407             SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    408                 (soc_miim_write(unit, phy_addr, 0x11, 0x80e4));
    409     
    410             SOC_IF_ERROR_RETURN     /* Select block 0x0a */
    411                 (soc_miim_write(unit, phy_addr, 0x1f, 0x00a0));
    412             SOC_IF_ERROR_RETURN     /* Flip TX Lane polarity */
    413                 (soc_miim_write(unit, phy_addr, 0x11, 0x1020));
    414         } else {
    415             /* If CX4 to HG conversion is enabled, do not allow individual lane 
    416              * swapping.
    417              */
    418             uint16 lane_map, i;
    419             uint16 lane, hw_map, chk_map;
    420           
    421             /* Update RX lane map */
    422             lane_map = soc_property_port_get(unit, port, 
    423                                             spn_XGXS_RX_LANE_MAP, 0x0123) & 0xffff; 
    424     
    425             if (lane_map != 0x0123) {
    426                 hw_map  = 0;
    427                 chk_map = 0;
    428                 for (i = 0; i < 4; i++) {
    429                     lane     = (lane_map >> (i * 4)) & 0xf;
    430                     hw_map  |= lane << (i * 2);
    431                     chk_map |= 1 << lane;
    432                 }
    433                 if (chk_map == 0xf) {
    434                     SOC_IF_ERROR_RETURN     /* Select block 0x10 */
    435                         (soc_miim_write(unit, phy_addr, 0x1f, 0x0100));
    436                     SOC_IF_ERROR_RETURN     /* Enable RX Lane swap */
    437                        (soc_miim_modify(unit, phy_addr, 0x10, 
    438                                         0x8000 | hw_map, 0x80ff));
    439                 } else {
    440                     LOG_ERROR(BSL_LS_SOC_COMMON,
    441                               (BSL_META_U(unit,
    442                                           "unit %d port %s: Invalid RX lane map 0x%04x.\n"),
    443                                unit, SOC_PORT_NAME(unit, port), lane_map));
    444                 }
    445             }
    446     
    447             /* Update TX lane map */
    448             lane_map = soc_property_port_get(unit, port, 
    449                                             spn_XGXS_TX_LANE_MAP, 0x0123) & 0xffff;
    450             
    451             if (lane_map != 0x0123) {
    452                 hw_map  = 0;
    453                 chk_map = 0;
    454                 for (i = 0; i < 4; i++) {
    455                     lane     = (lane_map >> (i * 4)) & 0xf;
    456                     hw_map  |= lane << (i * 2);
    457                     chk_map |= 1 << lane;
    458                 }
    459                 if (chk_map == 0xf) {
    460                     SOC_IF_ERROR_RETURN     /* Select block 0x10 */
    461                         (soc_miim_write(unit, phy_addr, 0x1f, 0x0100));
    462                     SOC_IF_ERROR_RETURN     /* Enable TX Lane swap */
    463                        (soc_miim_modify(unit, phy_addr, 0x11, 
    464                                         0x8000 | hw_map, 0x80ff));
    465                 } else {
    466                     LOG_ERROR(BSL_LS_SOC_COMMON,
    467                               (BSL_META_U(unit,
    468                                           "unit %d port %s: Invalid TX lane map 0x%04x.\n"),
    469                                unit, SOC_PORT_NAME(unit, port), lane_map));
    470                 }
    471             }
    472         }
    473     
    474         /*
    475          * Configure RX equalizer boost
    476          */
    477         SOC_IF_ERROR_RETURN         /* Select block 0xb */
    478             (soc_miim_write(unit, phy_addr, 0x1f, 0x00b0));
    479         SOC_IF_ERROR_RETURN         /* RX equalizer and offset controls */
    480             (soc_miim_write(unit, phy_addr, 0x1c, ((offsctl & 0x7) << 3) |
    481                                                   (rxequal & 0x7)));
    482     
    483         SOC_IF_ERROR_RETURN         /* Select block 0x0 */
    484             (soc_miim_write(unit, phy_addr, 0x1f, 0x0000));
    485     
    486         if (SAL_BOOT_QUICKTURN) {
    487             LOG_VERBOSE(BSL_LS_SOC_10G,
    488                         (BSL_META_U(unit,
    489                         "SIMULATION: xmac: unit %d port %s: "
    490                          "skipped waiting for pll lock\n"),
    491                          unit, SOC_PORT_NAME(unit, port)));
    492         } else {
    493             /* Wait for Tx PLL lock */
    494             SOC_IF_ERROR_RETURN
    495                 (soc_unicore_pll_lock_wait(unit, port));
    496         }
    497     
    498         /*
    499          * Configure signal auto-detection between SGMII and fiber.
    500          */
    501         SOC_IF_ERROR_RETURN         /* Select block DIGITAL (0x30) */
    502             (soc_miim_write(unit, phy_addr, 0x1f, 0x0300));
    503         SOC_IF_ERROR_RETURN
    504             (soc_miim_read(unit, phy_addr, 0x10, &mreg_val));
    505         mreg_val &= ~((1 << 4) | (1 << 0)); 
    506         if (soc_property_port_get(unit, port, spn_SERDES_AUTOMEDIUM, TRUE)) {
    507             mreg_val |= (1 << 4); 
    508         }
    509         if (soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, TRUE)) {
    510             mreg_val |= (1 << 0); 
    511         }
    512         SOC_IF_ERROR_RETURN
    513             (soc_miim_write(unit, phy_addr, 0x10, mreg_val)); 
    514      
    515         /* Set the block select to 0 after reset */ 
    516         SOC_IF_ERROR_RETURN
    517             (soc_miim_write(unit, phy_addr, 0x1f, 0));
    518     } /* end if (!SOC_WARM_BOOT(unit) && !SOC_IS_RELOADING(unit)) */
    519  
    520     /* Bring BigMac out of reset */
    521     SOC_IF_ERROR_RETURN(READ_MAC_XGXS_CTRLr(unit, port, &xgxs_ctrl));
    522     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, BIGMACRSTLf, 1);
    523     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    524 
    525     /* Enable Tx FIFO */
    526     soc_reg64_field32_set(unit, MAC_XGXS_CTRLr, &xgxs_ctrl, TXFIFO_RSTLf, 1);
    527     SOC_IF_ERROR_RETURN(WRITE_MAC_XGXS_CTRLr(unit, port, xgxs_ctrl));
    528 
    529     /* Set default speed */
    530     if (IS_HG_PORT(unit, port) || IS_XE_PORT(unit, port)) {
    531         SOC_IF_ERROR_RETURN(soc_unicore_speed_set(unit, port, 10000));
    532     }
    533 
    534     return SOC_E_NONE;
    535 }
    536 
    537 /*
    538  * Function:
    539  *     soc_unicore_pll_lock_wait
    540  * Purpose:
    541  *     Wait for Unicore Tx PLL lock.
    542  * Parameters:
    543  *     unit - XGS unit #.
    544  *     port - Port number on unit.
    545  * Returns:
    546  *     SOC_E_XXX
    547  */
    548 int
    549 soc_unicore_pll_lock_wait(int unit, int port)
    550 {
    551     uint64 xgxs_stat;
    552     int pll_lock_usec;
    553     int locked;
    554     soc_timeout_t to;
    555 
    556     /* 
    557      * Wait up to 500 msec for TX PLL lock.
    558      */
    559     pll_lock_usec = 500000;
    560     soc_timeout_init(&to, pll_lock_usec, 0);
    561 
    562     locked = 0;
    563     while (!soc_timeout_check(&to)) {
    564         SOC_IF_ERROR_RETURN(READ_MAC_XGXS_STATr(unit, port, &xgxs_stat));
    565         locked = soc_reg64_field32_get(unit, MAC_XGXS_STATr, xgxs_stat,
    566                                        TXPLL_LOCKf);
    567         if (locked) {
    568             break;
    569         }
    570     }
    571 
    572     if (!locked) {
    573         uint16  x_pll_stat;
    574         uint16  block_select;
    575  
    576         uint8 phy_addr = PORT_TO_PHY_ADDR_INT(unit, port);
    577 
    578         SOC_IF_ERROR_RETURN   /* Save original block select to restore later */ 
    579             (soc_miim_read(unit, phy_addr, 0x1f, &block_select));
    580         SOC_IF_ERROR_RETURN		/* Select block 0x5 */
    581             (soc_miim_write(unit, phy_addr, 0x1f, 0x0050));
    582         SOC_IF_ERROR_RETURN		/* Read PLL status */
    583             (soc_miim_read(unit, phy_addr, 0x10, &x_pll_stat));
    584         SOC_IF_ERROR_RETURN		/* Restore original block select */
    585             (soc_miim_write(unit, phy_addr, 0x1f, block_select));
    586 
    587         LOG_ERROR(BSL_LS_SOC_COMMON,
    588                   (BSL_META_U(unit,
    589                               "unit %d port %s: Unicore PLL did not lock "
    590                               "PLL_STAT %04x\n"),
    591                    unit, SOC_PORT_NAME(unit, port), x_pll_stat));
    592 
    593         return SOC_E_TIMEOUT;
    594     }
    595 
    596     LOG_VERBOSE(BSL_LS_SOC_10G,
    597                 (BSL_META_U(unit,
    598                 "unit %d port %s: Unicore PLL locked in %d usec\n"),
    599                  unit, SOC_PORT_NAME(unit, port),
    600                  soc_timeout_elapsed(&to)));
    601 
    602     return SOC_E_NONE;
    603 }
    604 
    605 #ifdef GXPORT_ISLOATE_IF_LOOPBACK
    606 /*
    607  * Function:
    608  *     soc_unicore_lane_power_set
    609  * Purpose:
    610  *     Power XAUI lanes /up/down
    611  * Parameters:
    612  *     unit - XGS unit #.
    613  *     port - Port number on unit.
    614  *     power_mask - mask of lanes to power up
    615  * Returns:
    616  *     SOC_E_XXX
    617  */
    618 int
    619 soc_unicore_lane_power_set(int unit, soc_port_t port, uint32 power_mask)
    620 {
    621     uint8 phy_addr = PORT_TO_PHY_ADDR_INT(unit, port);
    622     uint16 lane_ctrl, o_lane_ctrl;
    623 
    624     SOC_IF_ERROR_RETURN     /* Select block 0x10 */
    625         (soc_miim_write(unit, phy_addr, 0x1f, 0x0010));
    626 
    627     SOC_IF_ERROR_RETURN
    628         (soc_miim_read(unit, phy_addr, 0x18, &lane_ctrl));
    629 
    630     o_lane_ctrl = lane_ctrl;
    631     lane_ctrl &= ~0x8ff;
    632     /* Note that register bit value 1 means power down */
    633     power_mask = (power_mask & 0xf) ^ 0xf;
    634     /* Set power for both Rx and Tx lanes */
    635     lane_ctrl |= (power_mask << 4) | power_mask;
    636     if (power_mask) {
    637         /* Force power down */
    638         lane_ctrl |= 0x800;
    639     }
    640 
    641     if (o_lane_ctrl != lane_ctrl) {
    642         SOC_IF_ERROR_RETURN
    643             (soc_miim_write(unit, phy_addr, 0x18, lane_ctrl));
    644     }
    645 
    646     SOC_IF_ERROR_RETURN     /* Select block 0 */
    647         (soc_miim_write(unit, phy_addr, 0x1f, 0));
    648 
    649     return SOC_E_NONE;
    650 }
    651 #endif
    652 
    653 /*
    654  * Function:
    655  *     soc_unicore_speed_set
    656  * Purpose:
    657  *     Get current Unicore speed.
    658  * Parameters:
    659  *     unit - XGS unit #.
    660  *     port - Port number on unit.
    661  *     speed - new XGXS speed.
    662  * Returns:
    663  *     SOC_E_XXX
    664  * Notes:
    665  *      The Start Sequencer bit in the xgxsControl register should
    666  *      be deasserted before calling this function to guarantee a
    667  *      glitch-free clock change.
    668  */
    669 int
    670 soc_unicore_speed_set(int unit, soc_port_t port, int speed)
    671 {
    672     int    speed_val;
    673     uint8  phy_addr = PORT_TO_PHY_ADDR_INT(unit, port);
    674     uint16 mii_ctrl, misc1, misc_ctrl;
    675     uint16 block_select;
    676 
    677     if (IS_HG_PORT(unit, port)) {
    678         if ((speed != 0) && (speed < 10000)) {
    679             return SOC_E_PARAM;
    680         }
    681         if (SOC_INFO(unit).port_speed_max[port] > 0 &&
    682             speed > SOC_INFO(unit).port_speed_max[port]) {
    683             return SOC_E_PARAM;
    684         }
    685     } else if (IS_XE_PORT(unit, port)) {
    686         if ((speed != 0) && ((speed < 1000) || (speed > 10000))) {
    687             return SOC_E_PARAM;
    688         }
    689     } else {
    690         if ((speed < 0) || (speed > 2500)) {
    691             return SOC_E_PARAM;
    692         }
    693     }
    694 
    695     switch (speed) {
    696     case 13000:
    697         speed_val = 7;
    698         break;
    699     case 12500:
    700         speed_val = 6;
    701         break;
    702     case 12000:
    703         speed_val = 5;
    704         break;
    705     case 10000:
    706         speed_val = 4; /* 10G CX4 */
    707         if (IS_HG_PORT(unit, port) && 
    708             soc_property_port_get(unit, port, spn_10G_IS_CX4, TRUE) == FALSE) {
    709             speed_val = 3; /* 10G HiG */
    710         }
    711         break;
    712     case 2500:
    713         speed_val = 0;
    714         break;
    715     case 1000:
    716     case 100:
    717     case 10:
    718         speed_val = -1;
    719         break;
    720     case 0:
    721         return SOC_E_NONE;
    722     case 16000:
    723     case 15000:
    724     case 6000:
    725     case 5000:
    726     default:
    727         return SOC_E_PARAM;
    728     }
    729 
    730     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RELOADING(unit)) {
    731         /* Save original block select mapping */
    732         SOC_IF_ERROR_RETURN
    733             (soc_miim_read(unit, phy_addr, 0x1f, &block_select)); 
    734      
    735         /* Select block DIGITAL (0x30) */
    736         SOC_IF_ERROR_RETURN
    737             (soc_miim_write(unit, phy_addr, 0x1f, 0x0300));
    738     
    739         /* Set speed in Misc1 register */
    740         SOC_IF_ERROR_RETURN
    741             (soc_miim_read(unit, phy_addr, 0x18, &misc1));
    742         misc1 &= ~0x001f;
    743         if (speed_val >= 0) {
    744             misc1 |= 0x0010 | speed_val;
    745         }
    746         SOC_IF_ERROR_RETURN
    747             (soc_miim_write(unit, phy_addr, 0x18, misc1));
    748     
    749         /* Select block BLOCK0 */
    750         SOC_IF_ERROR_RETURN
    751             (soc_miim_write(unit, phy_addr, 0x1f, 0x0000));
    752     
    753         /* Map XAUI or SerDes IEEE registers */
    754         SOC_IF_ERROR_RETURN
    755             (soc_miim_read(unit, phy_addr, 0x1e, &misc_ctrl));
    756         /* Disable dynamic IEEE address space mapping and 
    757          * map Serdes IEEE address space.
    758          */
    759         misc_ctrl &= ~0x0003;
    760         if (speed > 2500) {
    761             misc_ctrl |= 0x0001; /* Select XAUI registers */
    762         }
    763     
    764         /* Write final IEEE register mapping */
    765         SOC_IF_ERROR_RETURN
    766             (soc_miim_write(unit, phy_addr, 0x1e, misc_ctrl));
    767     
    768         /* 
    769          * Speeds of 2.5 Gbps and below must be set in IEEE registers.
    770          */
    771         if (speed <= 2500) {
    772             SOC_IF_ERROR_RETURN
    773                 (soc_miim_read(unit, phy_addr, MII_CTRL_REG, &mii_ctrl));
    774             mii_ctrl &= ~(MII_CTRL_SS_MASK | MII_CTRL_FS_2500);
    775             if (speed == 2500) {
    776                 /* Force 2.5 Gbps */
    777                 mii_ctrl |= MII_CTRL_FS_2500;
    778             } else if (speed == 1000) {
    779                 mii_ctrl |= MII_CTRL_SS_1000;
    780             } else if (speed == 100) {
    781                 mii_ctrl |= MII_CTRL_SS_100;
    782             } else {
    783                 mii_ctrl |= MII_CTRL_SS_10;
    784             }
    785             SOC_IF_ERROR_RETURN
    786                 (soc_miim_write(unit, phy_addr, MII_CTRL_REG, mii_ctrl));
    787         }
    788     
    789         /* Restore Original Block select mapping */
    790         SOC_IF_ERROR_RETURN
    791             (soc_miim_write(unit, phy_addr, 0x1f, block_select));
    792     }
    793  
    794     if (speed < 10000) {
    795         SOC_IF_ERROR_RETURN
    796             (gxmac_interface_set(unit, port, SOC_PORT_IF_GMII));
    797     } else {
    798         SOC_IF_ERROR_RETURN
    799             (gxmac_interface_set(unit, port, SOC_PORT_IF_XGMII));
    800     }
    801     return SOC_E_NONE;
    802 }
    803 
    804 /*
    805  * Function:
    806  *     soc_unicore_speed_get
    807  * Purpose:
    808  *     Get current Unicore speed.
    809  * Parameters:
    810  *     unit - XGS unit #.
    811  *     port - Port number on unit.
    812  *     speed - (OUT) current XGXS speed (forced or negotiated).
    813  *     an_done - (OUT) if true, auto-negotiation is complete. This value
    814  *	     	 is undefined unless auto-negotiation is enabled.
    815  * Returns:
    816  *     SOC_E_XXX
    817  */
    818 int
    819 soc_unicore_speed_get(int unit, soc_port_t port, int *speed, int *an_done)
    820 {
    821     uint64 xgxs_stat;
    822     uint32 i;
    823 
    824     static struct {
    825         soc_field_t field;
    826         int speed;
    827     } _sp_sel[] = {
    828         { SPEED_13000f,     13000 },
    829         { SPEED_12500f,     12500 },
    830         { SPEED_12000f,     12000 },
    831         { SPEED_10000_CX4f, 10000 },
    832         { SPEED_10000f,     10000 },
    833         { SPEED_6000f,      6000  },
    834         { SPEED_5000f,      5000  },
    835         { SPEED_2500f,      2500  },
    836         { SPEED_1000f,      1000  },
    837         { SPEED_100f,       100   },
    838         { SPEED_10f,        10    }
    839     };
    840 
    841     /* Provide reasonable default value */
    842     *speed = IS_GE_PORT(unit, port) ? 1000 : 10000;
    843 
    844     SOC_IF_ERROR_RETURN
    845         (READ_MAC_XGXS_STATr(unit, port, &xgxs_stat));
    846 
    847     for (i = 0; i < COUNTOF(_sp_sel); i++) {
    848         if (soc_reg64_field32_get(unit, MAC_XGXS_STATr, xgxs_stat, 
    849                                   _sp_sel[i].field)) {
    850             *speed = _sp_sel[i].speed;
    851             break;
    852         }
    853     }
    854 
    855     if (IS_HG_PORT(unit, port) && *speed < 10000) {
    856         *speed = 0;
    857     }
    858 
    859     /* Ignore if null pointer */
    860     if (an_done) {
    861         *an_done = soc_reg64_field32_get(unit, MAC_XGXS_STATr, xgxs_stat, 
    862                                          AUTONEG_COMPLETEf);
    863     }
    864 
    865     return SOC_E_NONE;
    866 }
    867 
    868 /*
    869  * Function:
    870  *     soc_unicore_mac_mode_set
    871  * Purpose:
    872  *     Set current Unicore MAC mode.
    873  * Parameters:
    874  *     unit - XGS unit #.
    875  *     port - Port number on unit.
    876  *     mode - new XGXS MAC mode (TriMAC or BigMAC).
    877  *     enable - if zero, disable both MACs
    878  * Returns:
    879  *     SOC_E_NONE
    880  * Note:
    881  *     Don't need to restore old MAC states to new MAC when switching
    882  *  mode. All MACs are already in the same state.
    883  */
    884 int
    885 soc_unicore_mac_mode_set(int unit, soc_port_t port, 
    886                          soc_mac_mode_t mode, int enable)
    887 {
    888     int gmac_en, bmac_en, femac_en, gport_en, xport_en;
    889     uint32 xport, gport;
    890     uint64 ctrl, octrl;
    891     uint32 gmacc1, ogmacc1;
    892     uint32 fe_mac1, ofe_mac1;
    893 
    894     xport_en = (mode == SOC_MAC_MODE_10000) ? 1 : 0;
    895 
    896     /*
    897      * Note that for correct LED operation, either the XPORT or the
    898      * GPORT must be enabled, even when both MACs are disabled.
    899      */
    900     gport_en = !xport_en;
    901 
    902     femac_en = gmac_en = bmac_en = 0;
    903     if (enable) {
    904         switch (mode) {
    905         case SOC_MAC_MODE_10000:
    906             bmac_en = 1;
    907             break;
    908         case SOC_MAC_MODE_1000_T:
    909             gmac_en   = 1;
    910             break;  
    911         case SOC_MAC_MODE_10_100: /* fall through */
    912         case SOC_MAC_MODE_10:
    913             femac_en  = 1;
    914             break;
    915         default:
    916             return SOC_E_INTERNAL;
    917         }
    918     }
    919 
    920     SOC_IF_ERROR_RETURN(READ_GPORT_CONFIGr(unit, port, &gport));
    921     SOC_IF_ERROR_RETURN(READ_XPORT_CONFIGr(unit, port, &xport));
    922 
    923     /*
    924      * When switching between MAC modes, both GPORT and XPORT should be
    925      * disabled before enabling the appropriate PORT. However, we should
    926      * only disable the ports if necessary. In particular, when disabling
    927      * a port the xPORT_EN should remain set to avoid incoming packets
    928      * getting chopped in the middle. Only by disabling the MAC Rx we
    929      * can ensure that packets are stopped at a packet boundary.
    930      */
    931     if (xport_en) {
    932         if (soc_reg_field_valid(unit, GPORT_CONFIGr, GPORT_ENf)) {
    933             soc_reg_field_set(unit, GPORT_CONFIGr, &gport, GPORT_ENf, 0);
    934         }
    935         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, gport));
    936     } else {
    937         soc_reg_field_set(unit, XPORT_CONFIGr, &xport, XPORT_ENf, 0);
    938         SOC_IF_ERROR_RETURN(WRITE_XPORT_CONFIGr(unit, port, xport));
    939     }
    940 
    941     /* Enable/disable TriMAC */
    942     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
    943     ogmacc1 = gmacc1;
    944     soc_reg_field_set(unit, GMACC1r, &gmacc1, TXEN0f, 1);
    945     soc_reg_field_set(unit, GMACC1r, &gmacc1, RXEN0f, gmac_en);
    946     if (gmacc1 != ogmacc1) {
    947         SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
    948     }
    949 
    950     SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &fe_mac1));
    951     ofe_mac1 = fe_mac1;
    952     soc_reg_field_set(unit, FE_MAC1r, &fe_mac1, RX_ENf, femac_en);
    953     if (fe_mac1 != ofe_mac1) {
    954         SOC_IF_ERROR_RETURN(WRITE_FE_MAC1r(unit, port, fe_mac1));
    955     }
    956 
    957     if (gport_en) {
    958         if (soc_reg_field_valid(unit, GPORT_CONFIGr, GPORT_ENf)) {
    959             soc_reg_field_set(unit, GPORT_CONFIGr, &gport, GPORT_ENf, 1);
    960         }
    961         SOC_IF_ERROR_RETURN(WRITE_GPORT_CONFIGr(unit, port, gport));
    962     }
    963 
    964     /* Enable/disable BigMAC */
    965     SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &ctrl));
    966     octrl = ctrl;
    967     soc_reg64_field32_set(unit, MAC_CTRLr, &ctrl, TXENf, 1);
    968     soc_reg64_field32_set(unit, MAC_CTRLr, &ctrl, RXENf, bmac_en);
    969     if (COMPILER_64_NE(ctrl, octrl)) {
    970         SOC_IF_ERROR_RETURN(WRITE_MAC_CTRLr(unit, port, ctrl));
    971     }
    972     if (xport_en) {
    973         soc_reg_field_set(unit, XPORT_CONFIGr, &xport, XPORT_ENf, 1);
    974         SOC_IF_ERROR_RETURN(WRITE_XPORT_CONFIGr(unit, port, xport));
    975     }
    976 
    977     return SOC_E_NONE;
    978 }
    979 
    980 /*
    981  * Function:
    982  *     soc_unicore_mac_mode_get
    983  * Purpose:
    984  *     Get current Unicore MAC mode.
    985  * Parameters:
    986  *     unit - XGS unit #.
    987  *     port - Port number on unit.
    988  *     mode - (OUT) current XGXS MAC mode (TriMAC or BigMAC).
    989  * Returns:
    990  *     SOC_E_NONE
    991  */
    992 int
    993 soc_unicore_mac_mode_get(int unit, soc_port_t port, soc_mac_mode_t *mode)
    994 {
    995     int cur_speed;
    996     SOC_IF_ERROR_RETURN
    997             (soc_unicore_speed_get(unit, port, &cur_speed, NULL));
    998     switch (cur_speed) {
    999         case 16000: /* fall through */
   1000         case 15000: /* fall through */
   1001         case 13000: /* fall through */
   1002         case 12500: /* fall through */
   1003         case 12000: /* fall through */
   1004         case 10000: 
   1005         *mode = SOC_MAC_MODE_10000;
   1006             break;
   1007         case 2500: /* fall through */
   1008         case 1000:
   1009         *mode = SOC_MAC_MODE_1000_T;
   1010             break;
   1011         case 100:
   1012             *mode = SOC_MAC_MODE_10_100;
   1013             break;
   1014         case 10:
   1015             *mode = SOC_MAC_MODE_10;
   1016             break;
   1017         default:
   1018             return SOC_E_INTERNAL;
   1019     }
   1020     return SOC_E_NONE;
   1021 }
   1022 
   1023 /*
   1024  * Function:
   1025  *      gxmac_ifg_to_ipg
   1026  * Description:
   1027  *      Converts the inter-frame gap specified in bit-times into a value 
   1028  *      suitable to be programmed into the IPG register
   1029  * Parameters:
   1030  *      unit   - Device number
   1031  *      port   - Port number
   1032  *      speed  - the speed for which the IFG is being set
   1033  *      duplex - the duplex for which the IFG is being set
   1034  *      ifg    - Inter-frame gap in bit-times
   1035  *      ipg    - (OUT) the value to be written into IPG
   1036  * Return Value:
   1037  *      BCM_E_XXX
   1038  * Notes:
   1039  *      The function makes sure the calculated IPG value will not cause
   1040  *      hardware to fail. If the requested ifg value cannot be supported in
   1041  *      hardware, the function will choose a value that approximates the 
   1042  *      requested value as best as possible. 
   1043  *
   1044  *      Specifically:
   1045  *         -- Current chips only support ifg which is divisible by 8. If 
   1046  *            the specified ifg is not divisible by 8, it will be rounded 
   1047  *            to the next multiplier of 8 (65 will result in 72).
   1048  *         -- ifg < 64 are not supported
   1049  */
   1050 STATIC int
   1051 gxmac_ifg_to_ipg(int unit, soc_port_t port, int speed, int duplex,
   1052                 int ifg, int *ipg)
   1053 {
   1054     /* The inter-frame gap should be a multiple of 8 bit-times */
   1055      ifg = (ifg + 7) & ~7;
   1056 
   1057      /* The smallest supported ifg is 64 bit-times */
   1058      ifg = (ifg < 64) ? 64 : ifg;
   1059      
   1060     if (duplex) {
   1061         if (speed == 10 || speed == 100) {
   1062             *ipg = ifg / 4 - 3;
   1063         } else {
   1064             *ipg = ifg / 8;
   1065         }
   1066     } else {
   1067         switch (speed) {
   1068         case 10:
   1069             *ipg = ifg / 4 - 12;
   1070             break;
   1071         case 100:
   1072             *ipg = ifg / 4 - 13;
   1073             break;
   1074         default:
   1075             return SOC_E_INTERNAL;
   1076         }
   1077     }
   1078 
   1079     if (IS_HG_PORT(unit, port) && *ipg >= 4) {
   1080         *ipg -= 4;
   1081     }
   1082 
   1083     return SOC_E_NONE;
   1084 }
   1085 
   1086 /*
   1087  * Function:
   1088  *      gxmac_ipg_to_ifg
   1089  * Description:
   1090  *      Converts the IPG register value into the inter-frame gap expressed in
   1091  *      bit-times
   1092  * Parameters:
   1093  *      unit   - Device number
   1094  *      port   - Port number
   1095  *      speed  - the speed for which the IFG is being set
   1096  *      duplex - the duplex for which the IFG is being set
   1097  *      ipg    - the value in the IPG register
   1098  *      ifg    - Inter-frame gap in bit-times
   1099  * Return Value:
   1100  *      BCM_E_XXX
   1101  */
   1102 STATIC int
   1103 gxmac_ipg_to_ifg(int unit, soc_port_t port, int speed, int duplex,
   1104                 int ipg, int *ifg)
   1105 {
   1106      /*
   1107       * Now we need to convert the value accoring to various chips' 
   1108       * peculiarities (there are none as of now)
   1109       */
   1110      if (IS_HG_PORT(unit, port)) {
   1111          ipg += 4;
   1112      }
   1113 
   1114      if (duplex) {
   1115          if (speed == 10 || speed == 100) { 
   1116              *ifg = (ipg + 3) * 4;
   1117          } else {
   1118              *ifg = ipg * 8;
   1119          }
   1120      } else {
   1121          switch (speed) {
   1122          case 10:
   1123              *ifg = (ipg + 12) * 4;
   1124              break;
   1125          case 100:
   1126              *ifg = (ipg + 13) * 4;
   1127              break;
   1128          default:
   1129              return SOC_E_INTERNAL;
   1130          }
   1131      }
   1132 
   1133      return SOC_E_NONE;
   1134 }
   1135 
   1136 /*
   1137  * Function:
   1138  *      gxmac_ipg_update
   1139  * Purpose:
   1140  *      Set the IPG appropriate for current speed/duplex
   1141  * Parameters:
   1142  *      unit - StrataSwitch unit #.
   1143  *      port - Port number on unit.
   1144  * Notes:
   1145  *      The current speed/duplex are read from the hardware registers.
   1146  */
   1147 STATIC int
   1148 gxmac_ipg_update(int unit, int port)
   1149 {
   1150     int                 fd, speed, ifg, ipg;
   1151     soc_ipg_t           *si = &SOC_PERSIST(unit)->ipg[port];
   1152     uint64              tx_ctrl, otx_ctrl;
   1153     uint32              gmacc2, ogmacc2, fe_ipg;
   1154 
   1155     SOC_IF_ERROR_RETURN(gxmac_duplex_get(unit, port, &fd));
   1156     SOC_IF_ERROR_RETURN(gxmac_speed_get(unit, port, &speed));
   1157 
   1158     /* Get the ifg value in bit-times */
   1159     if (fd) {
   1160         switch (speed) {
   1161         case 0:
   1162             ifg = IS_GE_PORT(unit, port) ? si->fd_1000 : si->fd_10000;
   1163             break;
   1164         case 10:
   1165             ifg = si->fd_10;
   1166             break;
   1167         case 100:
   1168             ifg = si->fd_100;
   1169             break;
   1170         case 1000:
   1171             ifg = si->fd_1000;
   1172             break;
   1173         case 2500:
   1174             ifg = si->fd_2500;
   1175             break;
   1176         case 10000: /* fall through */
   1177         case 12000: /* fall through */
   1178         case 12500: /* fall through */
   1179         case 13000: /* fall through */
   1180         case 15000: /* fall through */
   1181         case 16000: /* fall through */
   1182             ifg = si->fd_10000;
   1183             break;
   1184         default:
   1185             return SOC_E_INTERNAL;
   1186         }
   1187     } else {
   1188         switch (speed) {
   1189         case 10:
   1190             ifg = si->hd_10;
   1191             break;
   1192         case 100:
   1193             ifg = si->hd_100;
   1194             break;
   1195         default:
   1196             return SOC_E_INTERNAL;
   1197         }
   1198     }
   1199 
   1200     /* Convert the ifg value from bit-times into IPG register-specific value */
   1201     SOC_IF_ERROR_RETURN(gxmac_ifg_to_ipg(unit, port, speed, fd, ifg, &ipg));
   1202 
   1203 
   1204     /* Program the appropriate register */
   1205     switch (speed) {
   1206     case 10:
   1207     case 100:
   1208         fe_ipg = 0;
   1209         soc_reg_field_set(unit, FE_IPGTr, &fe_ipg, IPGTf, ipg);
   1210         SOC_IF_ERROR_RETURN(WRITE_FE_IPGTr(unit, port, fe_ipg));
   1211         break;        
   1212     case 2500:
   1213     case 1000:
   1214         SOC_IF_ERROR_RETURN(READ_GMACC2r(unit, port, &gmacc2));
   1215         ogmacc2 = gmacc2;
   1216         soc_reg_field_set(unit, GMACC2r, &gmacc2, IPGTf, ipg);
   1217         if (gmacc2 != ogmacc2) {
   1218             SOC_IF_ERROR_RETURN(WRITE_GMACC2r(unit, port, gmacc2));
   1219         }
   1220         break;
   1221     default:
   1222         SOC_IF_ERROR_RETURN(READ_MAC_TXCTRLr(unit, port, &tx_ctrl));
   1223         otx_ctrl = tx_ctrl;
   1224 
   1225         
   1226         if (soc_property_port_get(unit, port, spn_PHY_WAN_MODE, FALSE)) {
   1227             /* Back to back 64 bytes packet must have IPG = 19 to 
   1228              * prevent data rate higher than acceptable WAN mode line rate.
   1229              */ 
   1230             if (ipg < 19) {
   1231                 ipg = 19;
   1232             }
   1233 
   1234             /* Insert an Idle after every 13 bytes of data to keep
   1235              * the data rate lower than 9.294Gbps.
   1236              */
   1237             soc_reg64_field32_set(unit, MAC_TXCTRLr, &otx_ctrl, THROTDENOMf,
   1238                                   13);              
   1239 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   1240             if (SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
   1241                 soc_reg64_field32_set(unit, MAC_TXCTRLr, &otx_ctrl, THROTNUMERf, 1);
   1242             }
   1243             else
   1244 #endif
   1245             {
   1246                 soc_reg64_field32_set(unit, MAC_TXCTRLr, &otx_ctrl, THROTNUMf, 1);
   1247             }
   1248         }
   1249 
   1250         soc_reg64_field32_set(unit, MAC_TXCTRLr, &otx_ctrl, AVGIPGf, 
   1251                               ipg & 0x1f);
   1252         if (COMPILER_64_NE(tx_ctrl, otx_ctrl)) {
   1253             SOC_IF_ERROR_RETURN(WRITE_MAC_TXCTRLr(unit, port, otx_ctrl));
   1254         }
   1255         break;
   1256     }
   1257 
   1258     return SOC_E_NONE;
   1259 }
   1260 
   1261 STATIC int
   1262 _gxmac_trimac_init(int unit, soc_port_t port)
   1263 {
   1264     uint32              gmacc0, gmacc1, gmacc2, val32, pctrl;
   1265 
   1266     /*
   1267      * Perform length check on Ethernet frames and do not allow huge frames
   1268      */
   1269     SOC_IF_ERROR_RETURN(READ_FE_MAC2r(unit, port, &val32));
   1270     soc_reg_field_set(unit, FE_MAC2r, &val32, FULL_DUPf, 1);
   1271     soc_reg_field_set(unit, FE_MAC2r, &val32, EXC_DEFf, 1);
   1272     soc_reg_field_set(unit, FE_MAC2r, &val32, LG_CHKf, 0);
   1273     soc_reg_field_set(unit, FE_MAC2r, &val32, HUGE_FRf, 0);
   1274     soc_reg_field_set(unit, FE_MAC2r, &val32, DEL_CRCf, 0);
   1275     soc_reg_field_set(unit, FE_MAC2r, &val32, CRC_ENf, 0);
   1276     soc_reg_field_set(unit, FE_MAC2r, &val32, PAD_ENf, 0);
   1277     soc_reg_field_set(unit, FE_MAC2r, &val32, VLAN_PADf, 0);
   1278     soc_reg_field_set(unit, FE_MAC2r, &val32, AUTO_PADf, 0);
   1279     soc_reg_field_set(unit, FE_MAC2r, &val32, PURE_PADf, 0);
   1280     soc_reg_field_set(unit, FE_MAC2r, &val32, LONG_PREf, 0);
   1281     soc_reg_field_set(unit, FE_MAC2r, &val32, NO_BOFFf, 0);
   1282     soc_reg_field_set(unit, FE_MAC2r, &val32, BP_NO_BOFFf, 0);
   1283     SOC_IF_ERROR_RETURN(WRITE_FE_MAC2r(unit, port, val32));
   1284 
   1285     SOC_IF_ERROR_RETURN(READ_FE_CLRTr(unit, port, &val32));
   1286     soc_reg_field_set(unit, FE_CLRTr, &val32, COL_WINf, 0x37);
   1287     soc_reg_field_set(unit, FE_CLRTr, &val32, RETRYf, 0xf);
   1288     SOC_IF_ERROR_RETURN(WRITE_FE_CLRTr(unit, port, val32));
   1289 
   1290     /* Set receive IPG for FE MAC */
   1291     val32 = 0;
   1292     soc_reg_field_set(unit, FE_IPGRr, &val32, IPGR1f, 0x6);
   1293     soc_reg_field_set(unit, FE_IPGRr, &val32, IPGR2f, 0xf);
   1294     SOC_IF_ERROR_RETURN(WRITE_FE_IPGRr(unit, port, val32));
   1295 
   1296     /* Update transmit IPG for FE MAC */ 
   1297     val32 = 0;
   1298     soc_reg_field_set(unit, FE_IPGTr, &val32, IPGTf, 0xb);
   1299     SOC_IF_ERROR_RETURN(WRITE_FE_IPGTr(unit, port, val32));
   1300 
   1301     SOC_IF_ERROR_RETURN(READ_FE_SUPPr(unit, port, &val32));
   1302     soc_reg_field_set(unit, FE_SUPPr, &val32, SPEEDf, 1);
   1303     soc_reg_field_set(unit, FE_SUPPr, &val32, BIT_MODEf, 0);
   1304     SOC_IF_ERROR_RETURN(WRITE_FE_SUPPr(unit, port, val32));
   1305 
   1306     SOC_IF_ERROR_RETURN(READ_FE_TESTr(unit, port, &val32));
   1307     soc_reg_field_set(unit, FE_TESTr, &val32, SHORT_QNTAf, 0);
   1308     soc_reg_field_set(unit, FE_TESTr, &val32, TEST_PAUSEf, 0);
   1309     soc_reg_field_set(unit, FE_TESTr, &val32, TEST_BACKf, 0);
   1310     SOC_IF_ERROR_RETURN(WRITE_FE_TESTr(unit, port, val32));
   1311 
   1312     SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &val32));
   1313     soc_reg_field_set(unit, FE_MAC1r, &val32, LBACKf, 0);
   1314     soc_reg_field_set(unit, FE_MAC1r, &val32, RX_ENf, 0);
   1315     SOC_IF_ERROR_RETURN(WRITE_FE_MAC1r(unit, port, val32));
   1316 
   1317     /* Clear station address */
   1318     val32 = 0;
   1319     SOC_IF_ERROR_RETURN(WRITE_ESA0r(unit, port, val32));
   1320     SOC_IF_ERROR_RETURN(WRITE_ESA1r(unit, port, val32));
   1321     SOC_IF_ERROR_RETURN(WRITE_ESA2r(unit, port, val32));
   1322 
   1323     /* NOTE : Allow dribble packets? */
   1324 
   1325     /* Initialize 1000 Mbps MAC */
   1326     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   1327     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   1328     SOC_IF_ERROR_RETURN(READ_GMACC2r(unit, port, &gmacc2));
   1329 
   1330     soc_reg_field_set(unit, GMACC0r, &gmacc0, SRSTf, 0);
   1331     soc_reg_field_set(unit, GMACC0r, &gmacc0, L10Bf, 0);
   1332     soc_reg_field_set(unit, GMACC0r, &gmacc0, L32Bf, 0);
   1333     soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 0);
   1334 
   1335     soc_reg_field_set(unit, GMACC1r, &gmacc1, FULLDf, 1);  /* arbitrary */
   1336     if (IS_ST_PORT(unit, port)) {
   1337         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf, 0);  /* Flow ctl */
   1338         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf, 0);  /* Flow ctl */
   1339     } else { 	 
   1340         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf, 1);  /* Flow ctl */ 	 
   1341         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf, 1);  /* Flow ctl */ 	 
   1342     }
   1343     soc_reg_field_set(unit, GMACC1r, &gmacc1, LONGPf, 1);
   1344     soc_reg_field_set(unit, GMACC1r, &gmacc1, MIFGf, 2);
   1345     soc_reg_field_set(unit, GMACC1r, &gmacc1, GLVRf, 1);
   1346     soc_reg_field_set(unit, GMACC1r, &gmacc1, TXEN0f, 1);
   1347     soc_reg_field_set(unit, GMACC1r, &gmacc1, RXEN0f, 0);
   1348     soc_reg_field_set(unit, GMACC1r, &gmacc1, JUMBOf, 1);  /* HUGEN=0 */
   1349     
   1350     soc_reg_field_set(unit, GMACC2r, &gmacc2, IPGTf, 0xc);
   1351 
   1352     SOC_IF_ERROR_RETURN(WRITE_GMACC2r(unit, port, gmacc2));
   1353     SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   1354     SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   1355     
   1356     pctrl = 0;
   1357     soc_reg_field_set(unit, PAUSE_CONTROLr, &pctrl, ENABLEf, 1);
   1358     /* Max out the pause duration; "resume" pause frame will end pause */
   1359     soc_reg_field_set(unit, PAUSE_CONTROLr, &pctrl, VALUEf,
   1360                       (1 << soc_reg_field_length(unit,
   1361                                                  PAUSE_CONTROLr,
   1362                                                  VALUEf)) - 1);
   1363     SOC_IF_ERROR_RETURN(WRITE_PAUSE_CONTROLr(unit, port, pctrl));
   1364 
   1365     val32 = 0;
   1366     SOC_IF_ERROR_RETURN(WRITE_TEST2r(unit, port, val32));
   1367 
   1368 
   1369     /* Clear station address */
   1370     val32 = 0;
   1371     SOC_IF_ERROR_RETURN(WRITE_GSA0r(unit, port, val32));
   1372     SOC_IF_ERROR_RETURN(WRITE_GSA1r(unit, port, val32));
   1373 
   1374     /* Set egress enable */
   1375     SOC_IF_ERROR_RETURN(READ_EGR_ENABLEr(unit, port, &val32));
   1376     soc_reg_field_set(unit, EGR_ENABLEr, &val32, PRT_ENABLEf, 1);
   1377     SOC_IF_ERROR_RETURN(WRITE_EGR_ENABLEr(unit, port, val32));
   1378 
   1379     /* Update IPG for GE MAC */
   1380     SOC_IF_ERROR_RETURN(gxmac_ipg_update(unit, port));
   1381 
   1382     return SOC_E_NONE;
   1383 }
   1384 
   1385 /*
   1386  * Function:
   1387  *      gxmac_init
   1388  * Purpose:
   1389  *      Initialize GMAC / Unicore MAC into a known good state.
   1390  * Parameters:
   1391  *      unit - XGS unit #.
   1392  *      port - Port number on unit.
   1393  * Returns:
   1394  *      SOC_E_XXX
   1395  * Notes:
   1396  */
   1397 STATIC int
   1398 gxmac_init(int unit, soc_port_t port)
   1399 {
   1400     uint64              rx_ctrl, tx_ctrl, mac_ctrl;
   1401     int                 encap;
   1402 
   1403     LOG_VERBOSE(BSL_LS_SOC_10G,
   1404                 (BSL_META_U(unit,
   1405                 "gxmac_init: unit %d port %s\n"),
   1406                  unit, SOC_PORT_NAME(unit, port)));
   1407 
   1408     SOC_IF_ERROR_RETURN(_gxmac_trimac_init(unit, port));
   1409 
   1410     /*
   1411      * Initialize BigMAC
   1412      */
   1413 
   1414     /* Disable Tx/Rx, assume that MAC is stable (or out of reset) */
   1415     SOC_IF_ERROR_RETURN(READ_MAC_RXCTRLr(unit, port, &rx_ctrl));
   1416     SOC_IF_ERROR_RETURN(READ_MAC_TXCTRLr(unit, port, &tx_ctrl));
   1417     SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &mac_ctrl));
   1418 
   1419     soc_reg64_field32_set(unit, MAC_CTRLr, &mac_ctrl, RXENf, 0);
   1420     soc_reg64_field32_set(unit, MAC_CTRLr, &mac_ctrl, TXENf, 0);
   1421     soc_reg64_field32_set(unit, MAC_CTRLr, &mac_ctrl, RMTLOOPf, 0);
   1422     soc_reg64_field32_set(unit, MAC_CTRLr, &mac_ctrl, LCLLOOPf, 0);
   1423     soc_reg64_field32_set(unit, MAC_TXCTRLr, &tx_ctrl, PAUSEENf, 0);
   1424     soc_reg64_field32_set(unit, MAC_RXCTRLr, &rx_ctrl, RXPAUSENf, 0);
   1425 
   1426     SOC_IF_ERROR_RETURN(WRITE_MAC_CTRLr(unit, port, mac_ctrl));
   1427     SOC_IF_ERROR_RETURN(WRITE_MAC_TXCTRLr(unit, port, tx_ctrl));
   1428     SOC_IF_ERROR_RETURN(WRITE_MAC_RXCTRLr(unit, port, rx_ctrl));
   1429 
   1430     /* Re-read MAC_TXCTRL, since it gets affected by ipg_update() */
   1431     SOC_IF_ERROR_RETURN(READ_MAC_TXCTRLr(unit, port, &tx_ctrl));
   1432 
   1433     /* Set jumbo max size for 10G and Higig by default */
   1434     if (IS_XE_PORT(unit, port) || IS_HG_PORT(unit, port)) {
   1435         SOC_IF_ERROR_RETURN(gxmac_frame_max_set(unit, port, JUMBO_MAXSZ));
   1436     }
   1437 
   1438     /* Program MAC settings */
   1439 
   1440     /* Setup header mode */
   1441     encap = (IS_HG_PORT(unit, port)) ? SOC_ENCAP_HIGIG : SOC_ENCAP_IEEE;
   1442     soc_reg64_field32_set(unit, MAC_TXCTRLr, &tx_ctrl, HDRMODEf, encap);
   1443     soc_reg64_field32_set(unit, MAC_RXCTRLr, &rx_ctrl, HDRMODEf, encap);
   1444 
   1445     /*
   1446      * Power-up defaults are CRC_APPEND for TX and STRIPCRC for RX.
   1447      * Change to CRC_KEEP for Hercules, CRC_REGEN for other XGS,
   1448      * and turn off STRIPCRC to be compatible with other BCM56xx.
   1449      */
   1450     soc_reg64_field32_set(unit, MAC_RXCTRLr, &rx_ctrl, STRIPCRCf, 0);
   1451     soc_reg64_field32_set(unit, MAC_TXCTRLr, &tx_ctrl, CRC_MODEf, 
   1452                           GXMAC_CRC_REGEN);
   1453     SOC_IF_ERROR_RETURN(WRITE_MAC_TXCTRLr(unit, port, tx_ctrl));
   1454     SOC_IF_ERROR_RETURN(WRITE_MAC_RXCTRLr(unit, port, rx_ctrl));
   1455 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   1456     if (SOC_IS_XGS3_SWITCH(unit)) {
   1457          int wan_mode = soc_property_port_get(unit, port, spn_PHY_WAN_MODE, FALSE);
   1458          if (wan_mode) {
   1459             /* Max speed for WAN mode is 9.294Gbps.
   1460               * This setting gives 10Gbps * (13/14) or 9.286 Gbps */
   1461             SOC_IF_ERROR_RETURN
   1462                        (gxmac_control_set(unit, port,
   1463                            SOC_MAC_CONTROL_FRAME_SPACING_STRETCH, 13));
   1464          }
   1465     }
   1466 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1467     /* Update IPG separately */
   1468     SOC_IF_ERROR_RETURN(gxmac_ipg_update(unit, port));
   1469 
   1470     /*
   1471      * Note that we leave Rx and Tx in the disabled state.
   1472      * Rx and Tx are enabled for the appropriate MAC (BigMAC/TriMAc)
   1473      * in gxmac_enable_set.
   1474      */
   1475 
   1476     return SOC_E_NONE;
   1477 }
   1478 
   1479 /*
   1480  * Function:
   1481  *      gxmac_enable_set
   1482  * Purpose:
   1483  *      Enable or disable MAC
   1484  * Parameters:
   1485  *      unit - XGS unit #.
   1486  *      port - Port number on unit.
   1487  *      enable - TRUE to enable, FALSE to disable
   1488  * Returns:
   1489  *      SOC_E_XXX
   1490  */
   1491 STATIC int
   1492 gxmac_enable_set(int unit, soc_port_t port, int enable)
   1493 {
   1494     uint32 val, val2, drain_cells;
   1495     pbmp_t mask;
   1496     int cur_speed;
   1497     soc_mac_mode_t mode;
   1498     int drain_usec, loopback = -1;
   1499     soc_timeout_t to;
   1500     int rv = SOC_E_NONE;
   1501 
   1502     /* Ensure we match the register field size */
   1503     if (enable) {
   1504         enable = 1;
   1505     }
   1506 
   1507     /* Select appropriate MAC */
   1508     SOC_IF_ERROR_RETURN(soc_unicore_speed_get(unit, port, &cur_speed, NULL));
   1509     if (cur_speed > 2500 || IS_HG_PORT(unit, port)) {
   1510         mode = SOC_MAC_MODE_10000;
   1511     } else if (cur_speed >= 1000) {
   1512         mode = SOC_MAC_MODE_1000_T;
   1513     } else if (cur_speed >= 100) {
   1514         mode = SOC_MAC_MODE_10_100;
   1515     } else {
   1516         mode = SOC_MAC_MODE_10;
   1517     }
   1518 
   1519     /*
   1520      * Use EPC_LINK to control other ports sending to this port.  This
   1521      * blocking is independent and in addition to what Linkscan does.
   1522      */
   1523     soc_link_mask2_get(unit, &mask);
   1524     if (enable) {
   1525         SOC_PBMP_PORT_ADD(mask, port);
   1526         /* Postpone write until MAC is enabled */
   1527     } else {
   1528         SOC_PBMP_PORT_REMOVE(mask, port);
   1529         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
   1530     }
   1531 
   1532     if (!(SOC_IS_RELOADING(unit)))
   1533     {
   1534         /* 
   1535         * Drain all buffers and FIFOs if we are disabled
   1536         */
   1537         if (!enable) {
   1538             /* Start flushing BigMAc and TriMAC */
   1539             SOC_IF_ERROR_RETURN(WRITE_XP_EGR_PKT_DROP_CTLr(unit, port, 1));
   1540             SOC_IF_ERROR_RETURN(WRITE_GE_EGR_PKT_DROP_CTLr(unit, port, 1));
   1541 
   1542             /* Do not drain forever in case of problems */
   1543             drain_usec = soc_property_get(unit, spn_LCCDRAIN_TIMEOUT_USEC, 250000);
   1544             soc_timeout_init(&to, drain_usec, 0);
   1545 
   1546             /* Drain MMU and GXPORT in one go */
   1547             drain_cells = 0xffffffff;
   1548             do {
   1549                 if (SOC_REG_IS_VALID(unit, OP_PORT_TOTAL_COUNTr)) {
   1550                     SOC_IF_ERROR_RETURN(READ_OP_PORT_TOTAL_COUNTr(unit, port, &val));
   1551                 } else {
   1552                     SOC_IF_ERROR_RETURN(READ_OP_PORT_TOTAL_COUNT_CELLr(unit, port, &val));
   1553                 }
   1554                 SOC_IF_ERROR_RETURN(READ_XP_XBODE_CELL_CNTr(unit, port, &val2));
   1555                 val += val2;
   1556                 SOC_IF_ERROR_RETURN(READ_GE_GBODE_CELL_CNTr(unit, port, &val2));
   1557                 val += val2;
   1558                 /* Gig MAC in pause state needs loopback mode to clear xoff */
   1559                 if (drain_cells == val && loopback < 0 &&
   1560                     mode == SOC_MAC_MODE_1000_T) {
   1561                         if (gxmac_loopback_get(unit, port, &loopback) < 0) {
   1562                             loopback = -1;
   1563                         } else {
   1564                             gxmac_loopback_set(unit, port, 1);
   1565                         }
   1566                 }
   1567                 /* Check for progress */
   1568                 if (val < drain_cells) {
   1569                     soc_timeout_init(&to, drain_usec, 0);
   1570                 }
   1571                 drain_cells = val;
   1572             }
   1573             while (drain_cells && !soc_timeout_check(&to));
   1574 
   1575             /* Stop flushing */
   1576             SOC_IF_ERROR_RETURN(WRITE_XP_EGR_PKT_DROP_CTLr(unit, port, 0));
   1577             SOC_IF_ERROR_RETURN(WRITE_GE_EGR_PKT_DROP_CTLr(unit, port, 0));
   1578 
   1579             /* Restore loopback setting if changed */
   1580             if (loopback >= 0) {
   1581                 SOC_IF_ERROR_RETURN
   1582                     (gxmac_loopback_set(unit, port, loopback));
   1583             }
   1584 
   1585             /* Check for drain error */
   1586             if (drain_cells) {
   1587                 LOG_ERROR(BSL_LS_SOC_COMMON,
   1588                           (BSL_META_U(unit,
   1589                                       "ERROR: port %d:%s: "
   1590                                       "timeout draining packets (%d cells remain)\n"),
   1591                            unit, SOC_PORT_NAME(unit, port), drain_cells));
   1592                 /* Indicate error, but continue to MAC disable below */
   1593                 rv = SOC_E_INTERNAL;
   1594             }
   1595         }
   1596     }
   1597 
   1598     /* Set new MAC mode (or disable MACs) */
   1599     SOC_IF_ERROR_RETURN(soc_unicore_mac_mode_set(unit, port, mode, enable));
   1600 
   1601     if (enable) {
   1602         /* Set EPC_LINK */
   1603         SOC_IF_ERROR_RETURN(soc_link_mask2_set(unit, mask));
   1604     }
   1605 
   1606     return rv;
   1607 }
   1608 
   1609 /*
   1610  * Function:
   1611  *      gxmac_enable_get
   1612  * Purpose:
   1613  *      Get MAC enable state
   1614  * Parameters:
   1615  *      unit - XGS unit #.
   1616  *      port - Port number on unit.
   1617  *      enable - (OUT) TRUE if enabled, FALSE if disabled
   1618  * Returns:
   1619  *      SOC_E_XXX
   1620  */
   1621 STATIC int
   1622 gxmac_enable_get(int unit, soc_port_t port, int *enable)
   1623 {
   1624     uint32 fe_mac1, gmacc1;
   1625     uint64 ctrl;
   1626 
   1627     /* Instead of checking the current mode we read from all MACs */
   1628 
   1629     /* TriMAC */
   1630     SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &fe_mac1));
   1631     *enable = soc_reg_field_get(unit, FE_MAC1r, fe_mac1, RX_ENf);
   1632 
   1633     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   1634     *enable |= soc_reg_field_get(unit, GMACC1r, gmacc1, RXEN0f);
   1635 
   1636     /* BigMAC */
   1637     SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &ctrl));
   1638     *enable |= soc_reg64_field32_get(unit, MAC_CTRLr, ctrl, RXENf);
   1639 
   1640     LOG_VERBOSE(BSL_LS_SOC_10G,
   1641                 (BSL_META_U(unit,
   1642                 "gxmac_enable_get:u=%d port=%d enable=%c\n"),
   1643                  unit, port, *enable ? 'T' : 'F'));
   1644 
   1645     return SOC_E_NONE;
   1646 }
   1647 
   1648 /*
   1649  * Function:
   1650  *      gxmac_duplex_set
   1651  * Purpose:
   1652  *      Set  GXMAC in the specified duplex mode.
   1653  * Parameters:
   1654  *      unit - XGS unit #.
   1655  *      port - XGS port # on unit.
   1656  *      duplex - Boolean: true --> full duplex, false --> half duplex.
   1657  * Returns:
   1658  *      SOC_E_XXX
   1659  * Notes:
   1660  */
   1661 STATIC int
   1662 gxmac_duplex_set(int unit, soc_port_t port, int duplex)
   1663 {
   1664     /* Always full duplex */
   1665     COMPILER_REFERENCE(unit);
   1666     COMPILER_REFERENCE(port);
   1667     COMPILER_REFERENCE(duplex);
   1668 
   1669     LOG_VERBOSE(BSL_LS_SOC_10G,
   1670                 (BSL_META_U(unit,
   1671                 "gxmac_duplex_set: unit %d port %s %s duplex\n"),
   1672                  unit, SOC_PORT_NAME(unit, port),
   1673                  duplex ? "FULL" : "HALF"));
   1674 
   1675     if (IS_GE_PORT(unit, port)) {
   1676         int cur_speed;
   1677 
   1678         SOC_IF_ERROR_RETURN
   1679             (soc_unicore_speed_get(unit, port, &cur_speed, NULL));
   1680 
   1681         /* Do not support half duplex for 1Gbps speed */
   1682         if (cur_speed <= 100) { 
   1683             uint32 fe_mac2, ofe_mac2;
   1684             duplex = duplex ? 1 : 0;
   1685 
   1686             SOC_IF_ERROR_RETURN(READ_FE_MAC2r(unit, port, &fe_mac2));
   1687             ofe_mac2 = fe_mac2;
   1688             soc_reg_field_set(unit, FE_MAC2r, &fe_mac2, FULL_DUPf, duplex);
   1689             if (fe_mac2 != ofe_mac2) {
   1690                 /* Set duplex for FE MAC */ 
   1691                 SOC_IF_ERROR_RETURN(WRITE_FE_MAC2r(unit, port, fe_mac2));
   1692 
   1693                 /* Set IPG to match new duplex */
   1694                 SOC_IF_ERROR_RETURN(gxmac_ipg_update(unit, port));
   1695           
   1696             }
   1697         }
   1698     }
   1699     return SOC_E_NONE;
   1700 }
   1701 
   1702 /*
   1703  * Function:
   1704  *      gxmac_duplex_get
   1705  * Purpose:
   1706  *      Get GXMAC duplex mode.
   1707  * Parameters:
   1708  *      unit - XGS unit #.
   1709  *      duplex - (OUT) Boolean: true --> full duplex, false --> half duplex.
   1710  * Returns:
   1711  *      SOC_E_XXX
   1712  */
   1713 STATIC int
   1714 gxmac_duplex_get(int unit, soc_port_t port, int *duplex)
   1715 {
   1716     COMPILER_REFERENCE(unit);
   1717     COMPILER_REFERENCE(port);
   1718 
   1719     *duplex = TRUE; /* HG and XE ports are always full duplex */
   1720 
   1721     if (IS_GE_PORT(unit, port)){
   1722         int cur_speed;
   1723 
   1724         SOC_IF_ERROR_RETURN
   1725             (soc_unicore_speed_get(unit, port, &cur_speed, NULL));
   1726         if (cur_speed <= 100) {
   1727             uint32 fe_mac2;
   1728 
   1729             SOC_IF_ERROR_RETURN(READ_FE_MAC2r(unit, port, &fe_mac2));
   1730             *duplex = soc_reg_field_get(unit, FE_MAC2r, fe_mac2, FULL_DUPf);
   1731         }
   1732     } 
   1733     LOG_VERBOSE(BSL_LS_SOC_10G,
   1734                 (BSL_META_U(unit,
   1735                 "gxmac_duplex_get: unit %d port %s %s duplex\n"),
   1736                  unit, SOC_PORT_NAME(unit, port),
   1737                  *duplex ? "FULL" : "HALF"));
   1738 
   1739     return SOC_E_NONE;
   1740 }
   1741 
   1742 /*
   1743  * Function:
   1744  *      gxmac_pause_set
   1745  * Purpose:
   1746  *      Configure GXMAC to transmit/receive pause frames.
   1747  * Parameters:
   1748  *      unit - XGS unit #.
   1749  *      port - XGS port # on unit.
   1750  *      pause_tx - Boolean: transmit pause or -1 (don't change)
   1751  *      pause_rx - Boolean: receive pause or -1 (don't change)
   1752  * Returns:
   1753  *      SOC_E_XXX
   1754  */
   1755 STATIC int
   1756 gxmac_pause_set(int unit, soc_port_t port, int pause_tx, int pause_rx)
   1757 {
   1758     uint64 ctrl, octrl;
   1759     uint32 gmacc1, ogmacc1;
   1760     uint32 fe_mac1, ofe_mac1;
   1761 
   1762     pause_tx = pause_tx ? 1 : 0;
   1763     pause_rx = pause_rx ? 1 : 0;
   1764 
   1765     /* TriMAC */
   1766     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   1767     ogmacc1 = gmacc1;
   1768     SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &fe_mac1));
   1769     ofe_mac1 = fe_mac1;
   1770 
   1771     if (pause_tx >= 0) {
   1772         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCTXf, pause_tx);
   1773         soc_reg_field_set(unit, FE_MAC1r, &fe_mac1,
   1774                           TX_PAUf, pause_tx);
   1775     }
   1776     if (pause_rx >= 0) {
   1777         soc_reg_field_set(unit, GMACC1r, &gmacc1, FCRXf, pause_rx);
   1778         soc_reg_field_set(unit, FE_MAC1r, &fe_mac1,
   1779                           RX_PAUf, pause_rx);
   1780     }
   1781 
   1782     if (gmacc1 != ogmacc1) {
   1783         SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, gmacc1));
   1784     }
   1785     if (fe_mac1 != ofe_mac1) {
   1786         SOC_IF_ERROR_RETURN(WRITE_FE_MAC1r(unit, port, fe_mac1));
   1787     }
   1788 
   1789     /* BigMAC */
   1790     if (pause_tx >= 0) {
   1791         SOC_IF_ERROR_RETURN(READ_MAC_TXCTRLr(unit, port, &ctrl));
   1792         octrl = ctrl;
   1793         soc_reg64_field32_set(unit, MAC_TXCTRLr, &ctrl, PAUSEENf,
   1794                               pause_tx ? 1 : 0);
   1795         if (COMPILER_64_NE(ctrl, octrl)) {
   1796             SOC_IF_ERROR_RETURN(WRITE_MAC_TXCTRLr(unit, port, ctrl));
   1797         }
   1798     }
   1799     if (pause_rx >= 0) {
   1800         SOC_IF_ERROR_RETURN(READ_MAC_RXCTRLr(unit, port, &ctrl));
   1801         octrl = ctrl;
   1802         soc_reg64_field32_set(unit, MAC_RXCTRLr, &ctrl, RXPAUSENf,
   1803                               pause_rx ? 1 : 0);
   1804         if (COMPILER_64_NE(ctrl, octrl)) {
   1805             SOC_IF_ERROR_RETURN(WRITE_MAC_RXCTRLr(unit, port, ctrl));
   1806         }
   1807     }
   1808 
   1809     LOG_VERBOSE(BSL_LS_SOC_10G,
   1810                 (BSL_META_U(unit,
   1811                 "gxmac_pause_set: unit %d port %s RX=%s TX=%s\n"),
   1812                  unit, SOC_PORT_NAME(unit, port),
   1813                  pause_rx ? "on" : "off",
   1814                  pause_tx ? "on" : "off"));
   1815 
   1816     return SOC_E_NONE;
   1817 }
   1818 
   1819 /*
   1820  * Function:
   1821  *      gxmac_pause_get
   1822  * Purpose:
   1823  *      Return the pause ability of GXMAC
   1824  * Parameters:
   1825  *      unit - XGS unit #.
   1826  *      port - XGS port # on unit.
   1827  *      pause_tx - Boolean: transmit pause
   1828  *      pause_rx - Boolean: receive pause
   1829  *      pause_mac - MAC address used for pause transmission.
   1830  * Returns:
   1831  *      SOC_E_XXX
   1832  */
   1833 STATIC int
   1834 gxmac_pause_get(int unit, soc_port_t port, int *pause_tx, int *pause_rx)
   1835 {
   1836     uint32 gmacc1;
   1837 
   1838     /* Read TriMAC status only */
   1839     SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &gmacc1));
   1840     *pause_tx = soc_reg_field_get(unit, GMACC1r, gmacc1, FCTXf);
   1841     *pause_rx = soc_reg_field_get(unit, GMACC1r, gmacc1, FCRXf);
   1842 
   1843     LOG_VERBOSE(BSL_LS_SOC_10G,
   1844                 (BSL_META_U(unit,
   1845                 "gxmac_pause_get: unit %d port %s RX=%s TX=%s\n"),
   1846                  unit, SOC_PORT_NAME(unit, port),
   1847                  *pause_rx ? "on" : "off",
   1848                  *pause_tx ? "on" : "off"));
   1849 
   1850     return SOC_E_NONE;
   1851 }
   1852 
   1853 /*
   1854  * Function:
   1855  *      gxmac_speed_set
   1856  * Purpose:
   1857  *      Set BigMAC in the specified speed.
   1858  * Parameters:
   1859  *      unit - XGS unit #.
   1860  *      port - XGS port # on unit.
   1861  *      speed - 1000, 2500, ... 13000.
   1862  * Returns:
   1863  *      SOC_E_NONE
   1864  */
   1865 STATIC int
   1866 gxmac_speed_set(int unit, soc_port_t port, int speed)
   1867 {
   1868     soc_mac_mode_t mode;
   1869     int enable;
   1870     uint32 speed_sel, fe_supp;
   1871 
   1872     /* Also set the Unicore speed here for MAC loopback support */
   1873     SOC_IF_ERROR_RETURN(soc_unicore_speed_set(unit, port, speed));
   1874 
   1875     /* Disable MACs before doing anything else */
   1876     SOC_IF_ERROR_RETURN(gxmac_enable_get(unit, port, &enable));
   1877     SOC_IF_ERROR_RETURN(gxmac_enable_set(unit, port, 0));
   1878 
   1879     speed_sel = 0;
   1880     fe_supp   = 0;
   1881     if (speed > 2500) {
   1882         mode      = SOC_MAC_MODE_10000;
   1883     } else if (speed >=1000) {
   1884         speed_sel = 0;
   1885         mode      = SOC_MAC_MODE_1000_T;
   1886     } else if (speed >=100) {
   1887         fe_supp   = 1;
   1888         speed_sel = 1;
   1889         mode      = SOC_MAC_MODE_10_100;
   1890     } else {
   1891         fe_supp   = 0;
   1892         speed_sel = 2;
   1893         mode      = SOC_MAC_MODE_10;
   1894     }
   1895 
   1896     if (speed <= 1000) { 
   1897         SOC_IF_ERROR_RETURN
   1898             (soc_reg_field32_modify(unit, GE_PORT_CONFIGr, port, 
   1899                                     SPEED_SELECTf, speed_sel));
   1900 
   1901         if (speed <= 100) {
   1902             SOC_IF_ERROR_RETURN
   1903                 (soc_reg_field32_modify(unit, FE_SUPPr, port, SPEEDf, fe_supp));
   1904         }
   1905     }
   1906 
   1907     /* Select appropriate MAC */
   1908     SOC_IF_ERROR_RETURN(soc_unicore_mac_mode_set(unit, port, mode, enable));
   1909 
   1910     /* Update IPG for new speed */
   1911     SOC_IF_ERROR_RETURN(gxmac_ipg_update(unit, port));
   1912 
   1913     /* Re-enable MAC */
   1914     SOC_IF_ERROR_RETURN(gxmac_enable_set(unit, port, enable));
   1915 
   1916     LOG_VERBOSE(BSL_LS_SOC_10G,
   1917                 (BSL_META_U(unit,
   1918                 "gxmac_speed_set: unit %d port %s speed %dMb\n"),
   1919                  unit, SOC_PORT_NAME(unit, port), speed));
   1920 
   1921     return SOC_E_NONE;
   1922 }
   1923 
   1924 /*
   1925  * Function:
   1926  *      gxmac_speed_get
   1927  * Purpose:
   1928  *      Get GXMAC speed
   1929  * Parameters:
   1930  *      unit - XGS unit #.
   1931  *      port - XGS port # on unit.
   1932  *      speed - (OUT) speed in Mbps
   1933  * Returns:
   1934  *      SOC_E_XXX
   1935  */
   1936 STATIC int
   1937 gxmac_speed_get(int unit, soc_port_t port, int *speed)
   1938 {
   1939     int rv;
   1940 
   1941     rv = soc_unicore_speed_get(unit, port, speed, NULL);
   1942 
   1943     LOG_VERBOSE(BSL_LS_SOC_10G,
   1944                 (BSL_META_U(unit,
   1945                 "gxmac_speed_get: unit %d port %s speed %dMb\n"),
   1946                  unit, SOC_PORT_NAME(unit, port), *speed));
   1947     return rv;
   1948 }
   1949 
   1950 /*
   1951  * Function:
   1952  *      gxmac_loopback_set
   1953  * Purpose:
   1954  *      Set a GXMAC into/out-of loopback mode
   1955  * Parameters:
   1956  *      unit - XGS unit #.
   1957  *      port - XGS unit # on unit.
   1958  *      loopback - Boolean: true -> loopback mode, false -> normal operation
   1959  * Note:
   1960  *      On bigmac, when setting loopback, we enable the TX/RX function also.
   1961  *      Note that to test the PHY, we use the remote loopback facility.
   1962  * Returns:
   1963  *      SOC_E_XXX
   1964  */
   1965 STATIC int
   1966 gxmac_loopback_set(int unit, soc_port_t port, int lb)
   1967 {
   1968     uint64 ctrl, octrl;
   1969     uint32 gmacc0, ogmacc0;
   1970     uint32 fe_mac1, ofe_mac1;
   1971 
   1972     LOG_VERBOSE(BSL_LS_SOC_10G,
   1973                 (BSL_META_U(unit,
   1974                 "gxmac_loopback_set: unit %d port %s %s loopback\n"),
   1975                  unit, SOC_PORT_NAME(unit, port),
   1976                  lb ? "local" : "no"));
   1977 
   1978     lb = lb ? 1 : 0;
   1979 
   1980     /* TriMAC */
   1981     SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &fe_mac1));
   1982     ofe_mac1 = fe_mac1;
   1983     soc_reg_field_set(unit, FE_MAC1r, &fe_mac1, LBACKf, lb); 
   1984     if (fe_mac1 != ofe_mac1) {
   1985         SOC_IF_ERROR_RETURN(WRITE_FE_MAC1r(unit, port, fe_mac1));
   1986     }
   1987 
   1988     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   1989     ogmacc0 = gmacc0;
   1990     soc_reg_field_set(unit, GMACC0r, &gmacc0, L32Bf, lb);
   1991     if (gmacc0 != ogmacc0) {
   1992         SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   1993     }
   1994 
   1995     /* BigMAC */
   1996     SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &ctrl));
   1997     octrl = ctrl;
   1998     soc_reg64_field32_set(unit, MAC_CTRLr, &ctrl, LCLLOOPf, lb);
   1999     if (COMPILER_64_NE(ctrl, octrl)) {
   2000         SOC_IF_ERROR_RETURN(WRITE_MAC_CTRLr(unit, port, ctrl));
   2001     }
   2002 
   2003 #ifdef GXPORT_ISLOATE_IF_LOOPBACK
   2004     /* Power lanes up/down */
   2005     soc_unicore_lane_power_set(unit, port, lb ? 0 : 0xf);
   2006 #endif
   2007 
   2008     return SOC_E_NONE;
   2009 }
   2010 
   2011 /*
   2012  * Function:
   2013  *      gxmac_loopback_get
   2014  * Purpose:
   2015  *      Get current GXMAC loopback mode setting.
   2016  * Parameters:
   2017  *      unit - XGS unit #.
   2018  *      port - XGS port # on unit.
   2019  *      loopback - (OUT) Boolean: true = loopback, false = normal
   2020  * Returns:
   2021  *      SOC_E_XXX
   2022  */
   2023 STATIC int
   2024 gxmac_loopback_get(int unit, soc_port_t port, int *lb)
   2025 {
   2026     uint64 ctrl;
   2027     int local, remote;
   2028 
   2029     /* Read BigMAC status only */
   2030     SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &ctrl));
   2031     remote = soc_reg64_field32_get(unit, MAC_CTRLr, ctrl, RMTLOOPf);
   2032     local = soc_reg64_field32_get(unit, MAC_CTRLr, ctrl, LCLLOOPf);
   2033     *lb = local | remote;
   2034 
   2035     LOG_VERBOSE(BSL_LS_SOC_10G,
   2036                 (BSL_META_U(unit,
   2037                 "gxmac_loopback_get: unit %d port %s %s loopback\n"),
   2038                  unit, SOC_PORT_NAME(unit, port),
   2039                  *lb ? (remote ? "remote" : "local") : "no"));
   2040 
   2041     return SOC_E_NONE;
   2042 }
   2043 
   2044 /*
   2045  * Function:
   2046  *      gxmac_pause_addr_set
   2047  * Purpose:
   2048  *      Configure PAUSE frame source address.
   2049  * Parameters:
   2050  *      unit - XGS unit #.
   2051  *      port - XGS port # on unit.
   2052  *      pause_mac - (OUT) MAC address used for pause transmission.
   2053  * Returns:
   2054  *      SOC_E_XXX
   2055  */
   2056 STATIC int
   2057 gxmac_pause_addr_set(int unit, soc_port_t port, sal_mac_addr_t mac)
   2058 {
   2059     uint32 w0, w1, w2;
   2060     uint32 gsa0, gsa1;
   2061     uint32 esa0, esa1, esa2;
   2062     uint64 macsa;
   2063 
   2064     w0 = mac[0] << 8 | mac[1];
   2065     w1 = mac[2] << 8 | mac[3];
   2066     w2 = mac[4] << 8 | mac[5];
   2067 
   2068     /* TriMAC */
   2069     esa0 = 0;
   2070     esa1 = 0;
   2071     esa2 = 0;
   2072 
   2073     soc_reg_field_set(unit, ESA0r, &esa0, STAD0f, (mac[4] << 8) | mac[5]);
   2074     soc_reg_field_set(unit, ESA1r, &esa1, STAD0f, (mac[2] << 8) | mac[3]);
   2075     soc_reg_field_set(unit, ESA2r, &esa2, STAD0f, (mac[0] << 8) | mac[1]);
   2076 
   2077     SOC_IF_ERROR_RETURN(FE_WRITE(ESA0r, GTH_ESA0r, unit, port, esa0));
   2078     SOC_IF_ERROR_RETURN(FE_WRITE(ESA1r, GTH_ESA1r, unit, port, esa1));
   2079     SOC_IF_ERROR_RETURN(FE_WRITE(ESA2r, GTH_ESA2r, unit, port, esa2));
   2080 
   2081     gsa0 = 0;
   2082     gsa1 = 0;
   2083     soc_reg_field_set(unit, GSA0r, &gsa0, STAD1f, (w0 << 16) | w1);
   2084     soc_reg_field_set(unit, GSA1r, &gsa1, STAD2f, w2);
   2085 
   2086     SOC_IF_ERROR_RETURN(WRITE_GSA0r(unit, port, gsa0));
   2087     SOC_IF_ERROR_RETURN(WRITE_GSA1r(unit, port, gsa1));
   2088 
   2089     /* BigMAC */
   2090     COMPILER_64_SET(macsa, w0, (w1 << 16) | w2);
   2091 
   2092     SOC_IF_ERROR_RETURN(WRITE_MAC_TXMACSAr(unit, port, macsa));
   2093     SOC_IF_ERROR_RETURN(WRITE_MAC_RXMACSAr(unit, port, macsa));
   2094 
   2095     LOG_VERBOSE(BSL_LS_SOC_10G,
   2096                 (BSL_META_U(unit,
   2097                 "gxmac_pause_addr_set: unit %d port %s MAC=<"
   2098                  "%02x:%02x:%02x:%02x:%02x:%02x>\n"),
   2099                  unit, SOC_PORT_NAME(unit, port),
   2100                  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
   2101     return SOC_E_NONE;
   2102 }
   2103 
   2104 /*
   2105  * Function:
   2106  *      gxmac_pause_addr_get
   2107  * Purpose:
   2108  *      Retrieve PAUSE frame source address.
   2109  * Parameters:
   2110  *      unit - XGS unit #.
   2111  *      port - XGS port # on unit.
   2112  *      pause_mac - (OUT) MAC address used for pause transmission.
   2113  * Returns:
   2114  *      SOC_E_XXX
   2115  * Notes;
   2116  *       We always write the same thing to TX & RX SA
   2117  *       so, we just return the contects on RXMACSA.
   2118  */
   2119 STATIC int
   2120 gxmac_pause_addr_get(int unit, soc_port_t port, sal_mac_addr_t mac)
   2121 {
   2122     uint64 macsa;
   2123     uint32 msw, lsw;
   2124 
   2125     /* Read BigMAC only */
   2126     SOC_IF_ERROR_RETURN(READ_MAC_RXMACSAr(unit, port, &macsa));
   2127 
   2128     COMPILER_64_TO_32_HI(msw, macsa);
   2129     COMPILER_64_TO_32_LO(lsw, macsa);
   2130 
   2131     mac[0] = (uint8)(msw >> 8);
   2132     mac[1] = (uint8)(msw >> 0);
   2133     mac[2] = (uint8)(lsw >> 24);
   2134     mac[3] = (uint8)(lsw >> 16);
   2135     mac[4] = (uint8)(lsw >> 8);
   2136     mac[5] = (uint8)(lsw >> 0);
   2137 
   2138     LOG_VERBOSE(BSL_LS_SOC_10G,
   2139                 (BSL_META_U(unit,
   2140                 "gxmac_pause_addr_get: unit %d port %s MAC=<"
   2141                  "%02x:%02x:%02x:%02x:%02x:%02x>\n"),
   2142                  unit, SOC_PORT_NAME(unit, port),
   2143                  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
   2144 
   2145     return SOC_E_NONE;
   2146 }
   2147 
   2148 /*
   2149  * Function:
   2150  *      gxmac_interface_set
   2151  * Purpose:
   2152  *      Set a GXMAC interface type
   2153  * Parameters:
   2154  *      unit - XGS unit #.
   2155  *      port - XGS port # on unit.
   2156  *      pif - one of SOC_PORT_IF_*
   2157  * Returns:
   2158  *      SOC_E_NONE
   2159  *      SOC_E_UNAVAIL - requested mode not supported.
   2160  * Notes:
   2161  */
   2162 STATIC int
   2163 gxmac_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   2164 {
   2165     uint32 gmacc0, gpcsc;
   2166     uint32 ogmacc0, ogpcsc;
   2167 
   2168 #ifdef BROADCOM_DEBUG
   2169     LOG_VERBOSE(BSL_LS_SOC_10G,
   2170                 (BSL_META_U(unit,
   2171                 "gxmac_interface_set: unit %d port %s %s interface\n"),
   2172                  unit, SOC_PORT_NAME(unit, port), gxmac_port_if_names[pif]));
   2173 #endif
   2174 
   2175     if (pif == SOC_PORT_IF_XGMII) {
   2176         return SOC_E_NONE;
   2177     }
   2178 
   2179     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   2180     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
   2181     ogmacc0 = gmacc0;
   2182     ogpcsc = gpcsc;
   2183 
   2184     switch (pif) {
   2185     case SOC_PORT_IF_MII:
   2186     case SOC_PORT_IF_GMII:
   2187     case SOC_PORT_IF_SGMII:
   2188         soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 1); /* GMII */
   2189         soc_reg_field_set(unit, GPCSCr, &gpcsc, RCSELf, 1);  /* 125 MHz */
   2190         break;
   2191     case SOC_PORT_IF_TBI:
   2192         soc_reg_field_set(unit, GMACC0r, &gmacc0, TMDSf, 0); /* TBI */
   2193         soc_reg_field_set(unit, GPCSCr, &gpcsc, RCSELf, 0);  /* 62.5 MHz */
   2194         break;
   2195     default:
   2196         return SOC_E_UNAVAIL;
   2197     }
   2198 
   2199     if (gpcsc != ogpcsc) {
   2200         SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
   2201     }
   2202     if (gmacc0 != ogmacc0) {
   2203         SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
   2204     }
   2205 
   2206     return SOC_E_NONE;
   2207 }
   2208 
   2209 
   2210 /*
   2211  * Function:
   2212  *      gxmac_interface_get
   2213  * Purpose:
   2214  *      Retrieve GXMAC interface type
   2215  * Parameters:
   2216  *      unit - XGS unit #.
   2217  *      port - XGS port # on unit.
   2218  *      pif - (OUT) one of SOC_PORT_IF_*
   2219  * Returns:
   2220  *      SOC_E_NONE
   2221  */
   2222 STATIC int
   2223 gxmac_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   2224 {
   2225     uint32 gmacc0;
   2226     soc_mac_mode_t mode;
   2227 
   2228     SOC_IF_ERROR_RETURN(soc_unicore_mac_mode_get(unit, port, &mode));
   2229 
   2230     if (mode == SOC_MAC_MODE_1000_T) {
   2231         SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0));
   2232 
   2233         *pif = (soc_reg_field_get(unit, GMACC0r, gmacc0, TMDSf) ?
   2234                 SOC_PORT_IF_GMII :
   2235                 SOC_PORT_IF_TBI);
   2236     } else {
   2237         *pif = SOC_PORT_IF_MII;
   2238     }
   2239 
   2240     
   2241 #ifdef BROADCOM_DEBUG
   2242     LOG_VERBOSE(BSL_LS_SOC_10G,
   2243                 (BSL_META_U(unit,
   2244                 "gxmac_interface_get: unit %d port %s %s interface\n"),
   2245                  unit, SOC_PORT_NAME(unit, port), gxmac_port_if_names[*pif]));
   2246 #endif
   2247 
   2248     return SOC_E_NONE;
   2249 }
   2250 
   2251 
   2252 /*
   2253  * Function:
   2254  *      gxmac_frame_max_set
   2255  * Description:
   2256  *      Set the maximum receive frame size for the port
   2257  * Parameters:
   2258  *      unit - Device number
   2259  *      port - Port number
   2260  *      size - Maximum frame size in bytes
   2261  * Return Value:
   2262  *      BCM_E_XXX
   2263  */
   2264 STATIC int
   2265 gxmac_frame_max_set(int unit, soc_port_t port, int size)
   2266 {
   2267     uint64 val64;
   2268     uint32 val32;
   2269 
   2270     if (!IS_ST_PORT(unit, port)) {
   2271         /* Account for vlan tagged packets */
   2272         COMPILER_64_SET(val64, 0, size + 4);
   2273     } else {
   2274         COMPILER_64_SET(val64, 0, size);
   2275     }
   2276 
   2277     /* BigMAC */
   2278     SOC_IF_ERROR_RETURN(WRITE_MAC_TXMAXSZr(unit, port, val64));
   2279     SOC_IF_ERROR_RETURN(WRITE_MAC_RXMAXSZr(unit, port, val64));
   2280 
   2281     /* To be neutral to the above change */
   2282     val32 = size;
   2283 
   2284     /* TriMAC */
   2285     SOC_IF_ERROR_RETURN(WRITE_MAXFRr(unit, port, val32));
   2286 
   2287     size += 1; /* XGS3 FE MAC_FR is one greater than MAX len */
   2288     val32 = size;
   2289     return (WRITE_FE_MAXFr(unit, port, val32));
   2290 }
   2291 
   2292 /*
   2293  * Function:
   2294  *      gxmac_frame_max_get
   2295  * Description:
   2296  *      Set the maximum receive frame size for the port
   2297  * Parameters:
   2298  *      unit - Device number
   2299  *      port - Port number
   2300  *      size - Maximum frame size in bytes
   2301  * Return Value:
   2302  *      BCM_E_XXX
   2303  */
   2304 STATIC int
   2305 gxmac_frame_max_get(int unit, soc_port_t port, int *size)
   2306 {
   2307     int    rv;
   2308     uint64 val64;
   2309 
   2310     /* Note: MAC_RXMAXSZ returns 0 if the port is in GPORT mode. */ 
   2311     rv = READ_MAC_TXMAXSZr(unit, port, &val64);
   2312 
   2313     if (rv == SOC_E_NONE) {
   2314         COMPILER_64_TO_32_LO(*size, val64);
   2315         if (!IS_ST_PORT(unit, port)) {
   2316             /* For VLAN tagged packets */
   2317             *size -= 4;
   2318         }
   2319     }
   2320 
   2321     return rv;
   2322 }
   2323 
   2324 /*
   2325  * Function:
   2326  *      gxmac_ifg_set
   2327  * Description:
   2328  *      Sets the new ifg (Inter-frame gap) value
   2329  * Parameters:
   2330  *      unit   - Device number
   2331  *      port   - Port number
   2332  *      speed  - the speed for which the IFG is being set
   2333  *      duplex - the duplex for which the IFG is being set
   2334  *      size - Maximum frame size in bytes
   2335  * Return Value:
   2336  *      BCM_E_XXX
   2337  * Notes:
   2338  *      The function makes sure the IFG value makes sense and updates the
   2339  *      IPG register in case the speed/duplex match the current settings
   2340  */
   2341 STATIC int
   2342 gxmac_ifg_set(int unit, soc_port_t port, int speed, soc_port_duplex_t duplex, 
   2343                int ifg)
   2344 {
   2345     int         cur_duplex;
   2346     int         cur_speed;
   2347     int         ipg;
   2348     int         real_ifg;
   2349     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   2350     int         rv;
   2351 
   2352     SOC_IF_ERROR_RETURN(gxmac_ifg_to_ipg(unit, port, speed, duplex, 
   2353                                         ifg, &ipg));
   2354     SOC_IF_ERROR_RETURN(gxmac_ipg_to_ifg(unit, port, speed, duplex, 
   2355                                         ipg, &real_ifg));
   2356 
   2357     if (duplex) {
   2358         switch (speed) {
   2359         case 10:
   2360             si->fd_10 = real_ifg;
   2361             break;
   2362         case 100:
   2363             si->fd_100 = real_ifg;
   2364             break;
   2365         case 1000:
   2366             si->fd_1000 = real_ifg;
   2367             break;
   2368         case 2500:
   2369             si->fd_2500 = real_ifg;
   2370             break;
   2371         case 10000:
   2372         case 12000:
   2373         case 12500:
   2374         case 13000:
   2375             si->fd_10000 = real_ifg;
   2376             break;
   2377         case 5000:
   2378         case 6000:
   2379         case 15000:
   2380         case 16000:
   2381         default:
   2382             return SOC_E_PARAM;
   2383         }
   2384     } else {
   2385         switch (speed) {
   2386         case 10:
   2387             si->hd_10 = real_ifg;
   2388             break;
   2389         case 100:
   2390             si->hd_100 = real_ifg;
   2391             break;
   2392         default: 
   2393         return SOC_E_PARAM;
   2394         }
   2395     }
   2396 
   2397     SOC_IF_ERROR_RETURN(gxmac_duplex_get(unit, port, &cur_duplex));
   2398     SOC_IF_ERROR_RETURN(gxmac_speed_get(unit, port, &cur_speed));
   2399 
   2400     if (cur_speed == speed && ((soc_port_duplex_t)cur_duplex == duplex)) {
   2401         rv = gxmac_ipg_update(unit, port);
   2402     } else {
   2403         rv = SOC_E_NONE;
   2404     }
   2405     
   2406     return (rv);
   2407 }
   2408 
   2409 /*
   2410  * Function:
   2411  *      gxmac_ifg_get
   2412  * Description:
   2413  *      Sets the new ifg (Inter-frame gap) value
   2414  * Parameters:
   2415  *      unit   - Device number
   2416  *      port   - Port number
   2417  *      speed  - the speed for which the IFG is being set
   2418  *      duplex - the duplex for which the IFG is being set
   2419  *      size - Maximum frame size in bytes
   2420  * Return Value:
   2421  *      BCM_E_XXX
   2422  * Notes:
   2423  *      The function makes sure the IFG value makes sense and updates the
   2424  *      IPG register in case the speed/duplex match the current settings
   2425  */
   2426 STATIC int
   2427 gxmac_ifg_get(int unit, soc_port_t port, int speed, soc_port_duplex_t duplex, 
   2428              int *ifg)
   2429 {
   2430     soc_ipg_t  *si = &SOC_PERSIST(unit)->ipg[port];
   2431 
   2432     if (duplex) {
   2433         switch (speed) {
   2434         case 10:
   2435             *ifg = si->fd_10;
   2436             break;
   2437         case 100:
   2438             *ifg = si->fd_100;
   2439             break;
   2440         case 1000:
   2441             *ifg = si->fd_1000;
   2442             break;
   2443         case 2500:
   2444             *ifg = si->fd_2500;
   2445             break;
   2446         case 10000:
   2447         case 12000:
   2448         case 12500:
   2449         case 13000:
   2450             *ifg = si->fd_10000;
   2451             break;
   2452         case 5000:
   2453         case 6000:
   2454         case 15000:
   2455         case 16000:
   2456         default:
   2457             return SOC_E_PARAM;
   2458         }
   2459     } else {
   2460         switch (speed) {
   2461         case 10:
   2462             *ifg = si->hd_10;
   2463             break;
   2464         case 100:
   2465             *ifg = si->hd_100;
   2466             break;
   2467         default: 
   2468         return SOC_E_PARAM;
   2469     }
   2470     }
   2471 
   2472     return SOC_E_NONE;
   2473 }
   2474 
   2475 /*
   2476  * Function:
   2477  *      soc_gxmac_port_mode_update
   2478  * Purpose:
   2479  *      Set the GXMAC port encapsulation mode.
   2480  * Parameters:
   2481  *      unit - XGS unit #.
   2482  *      port - XGS port # on unit.
   2483  *      to_hg_port - (TRUE/FALSE) 
   2484  * Returns:
   2485  *      SOC_E_XXX
   2486  */
   2487 STATIC int
   2488 soc_gxmac_port_mode_update(int unit, soc_port_t port, int to_hg_port)
   2489 {
   2490     uint32              rval;
   2491     uint64              val64;
   2492     soc_pbmp_t          ctr_pbmp;
   2493     int                 rv = SOC_E_NONE;
   2494 
   2495     /* Pause linkscan */
   2496     soc_linkscan_pause(unit);
   2497     
   2498     /* Pause counter collection */
   2499     COUNTER_LOCK(unit);
   2500     
   2501     soc_xport_type_update(unit, port, to_hg_port);
   2502 
   2503     /* Now that we've patched, reinit the port */
   2504     rv = soc_unicore_reset(unit, port);
   2505 
   2506     if (rv >= 0) {
   2507         rv = gxmac_init(unit, port);
   2508     }
   2509 
   2510     if (rv >= 0) {
   2511         rv = gxmac_enable_set( unit, port, 0);
   2512     }
   2513 
   2514     if (rv >= 0) {
   2515         SOC_PBMP_CLEAR(ctr_pbmp);
   2516         SOC_PBMP_PORT_SET(ctr_pbmp, port);
   2517         COMPILER_64_SET(val64, 0, 0);
   2518         rv = soc_counter_set_by_port(unit, ctr_pbmp, val64);
   2519     }
   2520 
   2521     COUNTER_UNLOCK(unit);
   2522     soc_linkscan_continue(unit); 
   2523 
   2524     SOC_IF_ERROR_RETURN(READ_XPORT_CONFIGr(unit, port, &rval));
   2525     if (to_hg_port) {
   2526         soc_reg_field_set(unit, XPORT_CONFIGr, &rval, HIGIG_MODEf, 1);
   2527     } else {
   2528         soc_reg_field_set(unit, XPORT_CONFIGr, &rval, HIGIG_MODEf, 0);
   2529     }
   2530     SOC_IF_ERROR_RETURN(WRITE_XPORT_CONFIGr(unit, port, rval));
   2531 
   2532     return rv;
   2533 }
   2534 
   2535 /*
   2536  * Function:
   2537  *      gxmac_encap_set
   2538  * Purpose:
   2539  *      Set the GXMAC port encapsulation mode.
   2540  * Parameters:
   2541  *      unit - XGS unit #.
   2542  *      port - XGS port # on unit.
   2543  *      mode - (IN) encap bits (defined above)
   2544  * Returns:
   2545  *      SOC_E_XXX
   2546  */
   2547 STATIC int
   2548 gxmac_encap_set(int unit, soc_port_t port, int mode)
   2549 {
   2550     uint64 rx_ctrl, tx_ctrl, orx, otx;
   2551     int encap = 0; /* IEEE */
   2552     int higig2 = 0;
   2553     int enable;
   2554 
   2555     switch (mode) {
   2556     case SOC_ENCAP_IEEE:
   2557         break;
   2558     case SOC_ENCAP_HIGIG2:
   2559         higig2 = 1;
   2560         /* Fall through */
   2561     case SOC_ENCAP_HIGIG:
   2562         encap = 1;
   2563         break;
   2564     default:
   2565         return SOC_E_PARAM;
   2566     }
   2567 
   2568 #ifdef BROADCOM_DEBUG
   2569     LOG_VERBOSE(BSL_LS_SOC_10G,
   2570                 (BSL_META_U(unit,
   2571                 "gxmac_encap_set: unit %d port %s %s encapsulation\n"),
   2572                  unit, SOC_PORT_NAME(unit, port), gxmac_encap_mode[mode]));
   2573 #endif
   2574 
   2575     SOC_IF_ERROR_RETURN(gxmac_enable_get(unit, port, &enable));
   2576 
   2577     if (enable) {
   2578         /* Turn off TX/RX enable */
   2579         SOC_IF_ERROR_RETURN(gxmac_enable_set(unit, port, 0));
   2580     }
   2581 
   2582     if ((mode != SOC_ENCAP_IEEE) && IS_E_PORT(unit, port)) {
   2583         /* XE -> HG */
   2584         SOC_IF_ERROR_RETURN(soc_gxmac_port_mode_update(unit, port, TRUE));
   2585     } else if ((mode == SOC_ENCAP_IEEE) && IS_ST_PORT(unit, port)) {
   2586         /* HG -> XE */
   2587         SOC_IF_ERROR_RETURN(soc_gxmac_port_mode_update(unit, port, FALSE));
   2588     }
   2589 
   2590     /* Read modify write the encapsulation mode */
   2591     SOC_IF_ERROR_RETURN(READ_MAC_RXCTRLr(unit, port, &rx_ctrl));
   2592     SOC_IF_ERROR_RETURN(READ_MAC_TXCTRLr(unit, port, &tx_ctrl));
   2593     orx = rx_ctrl;
   2594     otx = tx_ctrl;
   2595     soc_reg64_field32_set(unit, MAC_TXCTRLr, &tx_ctrl, HDRMODEf, encap);
   2596     soc_reg64_field32_set(unit, MAC_TXCTRLr, &tx_ctrl, HIGIG2MODEf, higig2);
   2597     soc_reg64_field32_set(unit, MAC_RXCTRLr, &rx_ctrl, HDRMODEf, encap);
   2598     soc_reg64_field32_set(unit, MAC_RXCTRLr, &rx_ctrl, HIGIG2MODEf, higig2);
   2599     if (COMPILER_64_NE(tx_ctrl, otx)) {
   2600         SOC_IF_ERROR_RETURN(WRITE_MAC_TXCTRLr(unit, port, tx_ctrl));
   2601     }
   2602     if (COMPILER_64_NE(rx_ctrl, orx)) {
   2603         SOC_IF_ERROR_RETURN(WRITE_MAC_RXCTRLr(unit, port, rx_ctrl));
   2604     }
   2605 
   2606     if (enable) {
   2607     /* Re-enable transmitter and receiver */
   2608     SOC_IF_ERROR_RETURN(gxmac_enable_set(unit, port, 1));
   2609     }
   2610 
   2611     return SOC_E_NONE;
   2612 }
   2613 
   2614 /*
   2615  * Function:
   2616  *      gxmac_encap_get
   2617  * Purpose:
   2618  *      Get the GXMAC port encapsulation mode.
   2619  * Parameters:
   2620  *      unit - XGS unit #.
   2621  *      port - XGS port # on unit.
   2622  *      mode - (INT) encap bits (defined above)
   2623  * Returns:
   2624  *      SOC_E_XXX
   2625  */
   2626 STATIC int
   2627 gxmac_encap_get(int unit, soc_port_t port, int *mode)
   2628 {
   2629     uint64              rx_ctrl;
   2630 
   2631     /*
   2632      * TX/RX mode should always be programmed to the same
   2633      * value (or all sorts of weird things will happen).
   2634      * So, for purpose of S/W state, we only need to read
   2635      * one or the other and return the state.
   2636      *
   2637      * WARNING: The following assumes BCM_PORT_ENCAP_xxx values equal
   2638      * the hardware register field values.
   2639      */
   2640 
   2641     SOC_IF_ERROR_RETURN(READ_MAC_RXCTRLr(unit, port, &rx_ctrl));
   2642     *mode = soc_reg64_field32_get(unit, MAC_RXCTRLr, rx_ctrl, HDRMODEf);
   2643 
   2644     if (*mode == SOC_ENCAP_HIGIG && 
   2645         soc_reg64_field32_get(unit, MAC_RXCTRLr, rx_ctrl, HIGIG2MODEf)) {
   2646         *mode = SOC_ENCAP_HIGIG2;
   2647     }
   2648 
   2649 #ifdef BROADCOM_DEBUG
   2650     LOG_VERBOSE(BSL_LS_SOC_10G,
   2651                 (BSL_META_U(unit,
   2652                 "gxmac_encap_get: unit %d port %s %s encapsulation\n"),
   2653                  unit, SOC_PORT_NAME(unit, port), gxmac_encap_mode[*mode]));
   2654 #endif
   2655 
   2656     return SOC_E_NONE;
   2657 }
   2658 
   2659 /*
   2660  * Function:
   2661  *      gxmac_ability_local_get
   2662  * Purpose:
   2663  *      Return the abilities of GXMAC
   2664  * Parameters:
   2665  *      unit - XGS unit #.
   2666  *      port - XGS port # on unit.
   2667  *      mode - (OUT) Supported operating modes as a mask of abilities.
   2668  * Returns:
   2669  *      SOC_E_XXX
   2670  */
   2671 STATIC  int
   2672 gxmac_ability_local_get(int unit, soc_port_t port,
   2673                        soc_port_ability_t *ability)
   2674 {
   2675     if (NULL == ability) {
   2676        return (SOC_E_PARAM);
   2677     }
   2678 
   2679     ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
   2680     ability->speed_full_duplex  = SOC_PA_ABILITY_NONE;
   2681     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   2682     ability->interface = SOC_PA_INTF_MII | SOC_PA_INTF_GMII | 
   2683                          SOC_PA_INTF_XGMII;
   2684     ability->medium    = SOC_PA_ABILITY_NONE;
   2685     ability->loopback  = SOC_PA_LB_MAC;
   2686     ability->flags     = SOC_PA_ABILITY_NONE;
   2687     ability->encap = SOC_PA_ENCAP_IEEE | SOC_PA_ENCAP_HIGIG |
   2688         SOC_PA_ENCAP_HIGIG2;
   2689 
   2690     if (IS_HG_PORT(unit, port)) {
   2691         switch (SOC_INFO(unit).port_speed_max[port]) {
   2692         case 13000:
   2693             ability->speed_full_duplex |= SOC_PA_SPEED_13GB;
   2694             /* fall through */
   2695         case 12000:
   2696             ability->speed_full_duplex |= SOC_PA_SPEED_12GB;
   2697             /* fall through */
   2698         default:
   2699             ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 
   2700             break;
   2701         } 
   2702 
   2703     } else if (IS_XE_PORT(unit, port)) {
   2704         ability->speed_full_duplex = SOC_PA_SPEED_1000MB | SOC_PA_SPEED_2500MB |
   2705                             SOC_PA_SPEED_10GB;
   2706     } else {
   2707         ability->speed_half_duplex = SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB;
   2708         ability->speed_full_duplex = SOC_PA_SPEED_10MB | SOC_PA_SPEED_100MB | 
   2709                             SOC_PA_SPEED_1000MB | SOC_PA_SPEED_2500MB;
   2710     }
   2711 
   2712     return (SOC_E_NONE);
   2713 }
   2714 
   2715 /*
   2716 * Function:
   2717 *      gxmac_frame_spacing_stretch_set
   2718 * Purpose:
   2719 *      Set frame spacing stretch parameters.
   2720 * Parameters:
   2721 *      unit - XGS unit #.
   2722 *      port - XGS port # on unit.
   2723 * Returns:
   2724 *      SOC_E_XXX
   2725 */
   2726 
   2727 STATIC int
   2728 gxmac_frame_spacing_stretch_set(int unit, soc_port_t port, int value)
   2729 {
   2730 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   2731  if (SOC_IS_XGS3_SWITCH(unit)) {
   2732      int    field_width, max_value;
   2733      uint64 reg_val;
   2734      field_width = soc_reg_field_length(unit, MAC_TXCTRLr, THROTDENOMf);
   2735      max_value = (1 << field_width) - 1;
   2736      if ((value > max_value) || (value < 0)) {
   2737          return SOC_E_PARAM;
   2738      }
   2739 
   2740      SOC_IF_ERROR_RETURN
   2741          (READ_MAC_TXCTRLr(unit, port, &reg_val));
   2742      soc_reg64_field32_set(unit, MAC_TXCTRLr, &reg_val,
   2743                            THROTDENOMf, value);
   2744 
   2745 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
   2746      if (SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
   2747          soc_reg64_field32_set(unit, MAC_TXCTRLr, &reg_val,
   2748                            THROTNUMERf, value ? 1 : 0);
   2749      } else 
   2750 #endif
   2751 	 {
   2752          soc_reg64_field32_set(unit, MAC_TXCTRLr, &reg_val,
   2753                            THROTNUMf, value ? 1 : 0);
   2754      }
   2755      SOC_IF_ERROR_RETURN
   2756          (WRITE_MAC_TXCTRLr(unit, port, reg_val));
   2757 
   2758      return SOC_E_NONE;
   2759  }
   2760 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   2761 
   2762  return SOC_E_UNAVAIL;
   2763 }
   2764 
   2765 /*
   2766  * Function:
   2767  *      gxmac_control_set
   2768  * Purpose:
   2769  *      To configure MAC control properties.
   2770  * Parameters:
   2771  *      unit - XGS unit #.
   2772  *      port - XGS port # on unit.
   2773  *      type - MAC control property to set.
   2774  *      int  - New setting for MAC control.
   2775  * Returns:
   2776  *      SOC_E_XXX
   2777  */
   2778 
   2779 STATIC int
   2780 gxmac_control_set(int unit, soc_port_t port,
   2781                   soc_mac_control_t type, int value)
   2782 {
   2783     int rv;
   2784     uint32 reg32, copy32;
   2785     uint64 reg64, copy64;
   2786 
   2787     LOG_VERBOSE(BSL_LS_SOC_10G,
   2788                 (BSL_META_U(unit,
   2789                 "gxmac_control_set: unit %d port %s: %d = %d\n"),
   2790                  unit, SOC_PORT_NAME(unit, port),
   2791                  type, value));
   2792 
   2793     if ((type < 0) || (type >= SOC_MAC_CONTROL_COUNT)) {
   2794         return SOC_E_PARAM;
   2795     }
   2796 
   2797     rv = SOC_E_UNAVAIL;
   2798     switch(type) {
   2799     case SOC_MAC_CONTROL_RX_SET:
   2800         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &reg32));
   2801         copy32 = reg32;
   2802         soc_reg_field_set(unit, GMACC1r, &reg32, RXEN0f, value ? 1 : 0);
   2803         if (reg32 != copy32) {
   2804             SOC_IF_ERROR_RETURN(WRITE_GMACC1r(unit, port, reg32));
   2805         }
   2806         SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &reg32));
   2807         copy32 = reg32;
   2808         soc_reg_field_set(unit, FE_MAC1r, &reg32, RX_ENf, value ? 1 : 0);
   2809         if (reg32 != copy32) {
   2810             SOC_IF_ERROR_RETURN(WRITE_FE_MAC1r(unit, port, reg32));
   2811         }
   2812         SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &reg64));
   2813         copy64 = reg64;
   2814         soc_reg64_field32_set(unit, MAC_CTRLr, &reg64, RXENf, value ? 1 : 0);
   2815         if (COMPILER_64_NE(reg64, copy64)) {
   2816             SOC_IF_ERROR_RETURN(WRITE_MAC_CTRLr(unit, port, reg64));
   2817         }
   2818         break;
   2819     case SOC_MAC_CONTROL_FRAME_SPACING_STRETCH:
   2820         rv = gxmac_frame_spacing_stretch_set(unit, port, value);
   2821         break;
   2822     default:
   2823         rv = SOC_E_UNAVAIL;
   2824         break;
   2825     }
   2826 
   2827     return rv;
   2828 }
   2829 
   2830 /*
   2831  * Function:
   2832  *      gxmac_control_get
   2833  * Purpose:
   2834  *      To get current MAC control setting.
   2835  * Parameters:
   2836  *      unit - XGS unit #.
   2837  *      port - XGS port # on unit.
   2838  *      type - MAC control property to set.
   2839  *      int  - New setting for MAC control.
   2840  * Returns:
   2841  *      SOC_E_XXX
   2842  */
   2843 
   2844 STATIC int
   2845 gxmac_control_get(int unit, soc_port_t port,
   2846                   soc_mac_control_t type, int *value)
   2847 {
   2848     uint32 val;
   2849     int rv;
   2850     uint32 reg32;
   2851     uint64 reg64;
   2852 
   2853     if (NULL == value) {
   2854         return SOC_E_PARAM;
   2855     }
   2856 
   2857     if ((type < 0) || (type >= SOC_MAC_CONTROL_COUNT)) {
   2858         return SOC_E_PARAM;
   2859     }
   2860 
   2861     rv = SOC_E_UNAVAIL;
   2862     switch(type) {
   2863     case SOC_MAC_CONTROL_RX_SET:
   2864         SOC_IF_ERROR_RETURN(READ_GMACC1r(unit, port, &reg32));
   2865         val = soc_reg_field_get(unit, GMACC1r, reg32, RXEN0f);
   2866         SOC_IF_ERROR_RETURN(READ_FE_MAC1r(unit, port, &reg32));
   2867         val |= soc_reg_field_get(unit, FE_MAC1r, reg32, RX_ENf);
   2868         SOC_IF_ERROR_RETURN(READ_MAC_CTRLr(unit, port, &reg64));
   2869         val |= soc_reg64_field32_get(unit, MAC_CTRLr, reg64, RXENf);
   2870         *value = val ? 1 : 0;
   2871         break;
   2872     case SOC_MAC_CONTROL_FRAME_SPACING_STRETCH:
   2873         if (SOC_REG_IS_VALID(unit, MAC_TXCTRLr)) {
   2874             SOC_IF_ERROR_RETURN
   2875                 (READ_MAC_TXCTRLr(unit, port, &reg64));
   2876             *value = soc_reg64_field32_get(unit, MAC_TXCTRLr, reg64,
   2877                                            THROTDENOMf);
   2878             rv = SOC_E_NONE;
   2879         }
   2880         break;
   2881     default:
   2882         rv = SOC_E_UNAVAIL;
   2883         break;
   2884     }
   2885 
   2886  LOG_VERBOSE(BSL_LS_SOC_10G,
   2887              (BSL_META_U(unit,
   2888              "gxmac_control_get: unit %d port %s: %d = %d: rv = %d\n"),
   2889               unit, SOC_PORT_NAME(unit, port),
   2890               type, *value, rv));
   2891 
   2892  return rv;
   2893 }
   2894 /* Exported XGS MAC driver structure */
   2895 
   2896 mac_driver_t soc_mac_gx = {
   2897     "12G/10G/2.5G/1G MAC Driver",  /* drv_name */
   2898     gxmac_init,                    /* md_init  */
   2899     gxmac_enable_set,              /* md_enable_set */
   2900     gxmac_enable_get,              /* md_enable_get */
   2901     gxmac_duplex_set,              /* md_duplex_set */
   2902     gxmac_duplex_get,              /* md_duplex_get */
   2903     gxmac_speed_set,               /* md_speed_set */
   2904     gxmac_speed_get,               /* md_speed_get */
   2905     gxmac_pause_set,               /* md_pause_set */
   2906     gxmac_pause_get,               /* md_pause_get */
   2907     gxmac_pause_addr_set,          /* md_pause_addr_set */
   2908     gxmac_pause_addr_get,          /* md_pause_addr_get */
   2909     gxmac_loopback_set,            /* md_lb_set */
   2910     gxmac_loopback_get,            /* md_lb_get */
   2911     gxmac_interface_set,           /* md_interface_set */
   2912     gxmac_interface_get,           /* md_interface_get */
   2913     NULL,                          /* md_ability_get - Deprecated */
   2914     gxmac_frame_max_set,           /* md_frame_max_set */
   2915     gxmac_frame_max_get,           /* md_frame_max_get */
   2916     gxmac_ifg_set,                 /* md_ifg_set */
   2917     gxmac_ifg_get,                 /* md_ifg_get */
   2918     gxmac_encap_set,               /* md_encap_set */
   2919     gxmac_encap_get,               /* md_encap_get */
   2920     gxmac_control_set,             /* md_control_set */
   2921     gxmac_control_get,             /* md_control_get */
   2922     gxmac_ability_local_get,       /* md_ability_local_get */
   2923     NULL                           /* md_timesync_tx_info_get */
   2924 };
   2925 #endif /* BCM_GXPORT_SUPPORT */