The branch main has been updated by imp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=445bed5c4d859575951361e432024396b938f863

commit 445bed5c4d859575951361e432024396b938f863
Author:     Stephan de Wit <[email protected]>
AuthorDate: 2024-02-02 19:17:14 +0000
Commit:     Warner Losh <[email protected]>
CommitDate: 2024-02-02 19:21:00 +0000

    axgbe: Various link stability and module compatibilty improvements
    
    Move the phy_stop() routine to if_detach() to prevent link interruptions
    when configuring the interface. Accompanying this is a sanity check
    using phy_started, which was already there but remained unused. We do
    not move phy_start(), as the logic there is needed for any init routine,
    be it attach or start.
    
    Also bring in the linux PMA_PLL change which addresses the flapping of
    back-to-back fiber connections.
    
    Use miibus for SFP PHYs up to 1G copper. We retry in cases where the PHY
    is not directly reachable.  Set the correct IFM_100_SGMII flag when the
    phy speed has been set to 100. We remove xgbe_phy_start_aneg() since
    it's handled by miibus.
    
    Add support for 100 and 1000 BASE-BX fiber modules
    
    Add support for 25G multirate DACs which are capable of 10G.
    
    While here, also fixup the LINK_ERR state. It was impossible to recover
    from this previously.
    
    [[ Note: light style fixes by imp, slight commit message adjustment,
       and a warning that I don't have the hardware to validate, but
       the changes do track the commit message and seem otherwise OK ]]
    
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/768
---
 sys/dev/axgbe/if_axgbe_pci.c |   4 +-
 sys/dev/axgbe/xgbe-common.h  |   8 ++
 sys/dev/axgbe/xgbe-i2c.c     |   5 +-
 sys/dev/axgbe/xgbe-mdio.c    |  12 +-
 sys/dev/axgbe/xgbe-phy-v2.c  | 271 ++++++++++++++++++++++++++++++-------------
 5 files changed, 209 insertions(+), 91 deletions(-)

diff --git a/sys/dev/axgbe/if_axgbe_pci.c b/sys/dev/axgbe/if_axgbe_pci.c
index dcf769d14f75..beb4ff338dc7 100644
--- a/sys/dev/axgbe/if_axgbe_pci.c
+++ b/sys/dev/axgbe/if_axgbe_pci.c
@@ -1534,6 +1534,7 @@ axgbe_if_detach(if_ctx_t ctx)
        mac_res[0] = pdata->xgmac_res;
        mac_res[1] = pdata->xpcs_res;
 
+       phy_if->phy_stop(pdata);
        phy_if->phy_exit(pdata);
 
        /* Free Interrupts */
@@ -1605,7 +1606,6 @@ axgbe_pci_stop(if_ctx_t ctx)
 {
        struct axgbe_if_softc   *sc = iflib_get_softc(ctx);
         struct xgbe_prv_data    *pdata = &sc->pdata;
-       struct xgbe_phy_if      *phy_if = &pdata->phy_if;
        struct xgbe_hw_if       *hw_if = &pdata->hw_if;
        int ret;
 
@@ -1620,8 +1620,6 @@ axgbe_pci_stop(if_ctx_t ctx)
        hw_if->disable_tx(pdata);
        hw_if->disable_rx(pdata);
 
-       phy_if->phy_stop(pdata);
-
        ret = hw_if->exit(pdata);
        if (ret)
                axgbe_error("%s: exit error %d\n", __func__, ret);
diff --git a/sys/dev/axgbe/xgbe-common.h b/sys/dev/axgbe/xgbe-common.h
index 0f497e53cb6f..4d504682d1af 100644
--- a/sys/dev/axgbe/xgbe-common.h
+++ b/sys/dev/axgbe/xgbe-common.h
@@ -1363,6 +1363,10 @@
 #define MDIO_VEND2_PMA_CDR_CONTROL     0x8056
 #endif
 
+#ifndef MDIO_VEND2_PMA_MISC_CTRL0
+#define MDIO_VEND2_PMA_MISC_CTRL0      0x8090
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G             (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
@@ -1415,6 +1419,10 @@
 #define XGBE_PMA_CDR_TRACK_EN_OFF      0x00
 #define XGBE_PMA_CDR_TRACK_EN_ON       0x01
 
+#define XGBE_PMA_PLL_CTRL_MASK         BIT(15)
+#define XGBE_PMA_PLL_CTRL_ENABLE       BIT(15)
+#define XGBE_PMA_PLL_CTRL_DISABLE      0x0000
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
diff --git a/sys/dev/axgbe/xgbe-i2c.c b/sys/dev/axgbe/xgbe-i2c.c
index 59c767d0efc7..5883e96ed37e 100644
--- a/sys/dev/axgbe/xgbe-i2c.c
+++ b/sys/dev/axgbe/xgbe-i2c.c
@@ -438,11 +438,10 @@ xgbe_i2c_xfer(struct xgbe_prv_data *pdata, struct 
xgbe_i2c_op *op)
        }
 
        ret = state->ret;
-       axgbe_printf(3, "%s: i2c xfer ret %d abrt_source 0x%x \n", __func__,
+       axgbe_printf(3, "%s: i2c xfer ret %d abrt_source 0x%x\n", __func__,
            ret, state->tx_abort_source);
        if (ret) {
-
-               axgbe_error("%s: i2c xfer ret %d abrt_source 0x%x \n", __func__,
+               axgbe_printf(1, "%s: i2c xfer ret %d abrt_source 0x%x\n", 
__func__,
                    ret, state->tx_abort_source);
                if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK)
                        ret = -ENOTCONN;
diff --git a/sys/dev/axgbe/xgbe-mdio.c b/sys/dev/axgbe/xgbe-mdio.c
index 16488055e2c6..a5a9fdd016bc 100644
--- a/sys/dev/axgbe/xgbe-mdio.c
+++ b/sys/dev/axgbe/xgbe-mdio.c
@@ -734,11 +734,6 @@ xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
        if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
                pdata->an_state = XGBE_AN_COMPLETE;
                pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
-
-               /* If SGMII is enabled, check the link status */
-               if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
-                   !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
-                       pdata->an_state = XGBE_AN_NO_LINK;
        }
 
        axgbe_printf(2, "%s: CL37 AN %s\n", __func__,
@@ -1364,6 +1359,7 @@ xgbe_phy_status(struct xgbe_prv_data *pdata)
        if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
                axgbe_error("%s: LINK_ERR\n", __func__);
                pdata->phy.link = 0;
+               clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
                goto adjust_link;
        }
 
@@ -1443,7 +1439,10 @@ xgbe_phy_stop(struct xgbe_prv_data *pdata)
 static int
 xgbe_phy_start(struct xgbe_prv_data *pdata)
 {
-       int ret;
+       int ret = 0;
+
+       if (pdata->phy_started)
+               return (ret);
 
        DBGPR("-->xgbe_phy_start\n");
 
@@ -1588,6 +1587,7 @@ xgbe_phy_init(struct xgbe_prv_data *pdata)
                pdata->phy.duplex = DUPLEX_FULL;
        }
 
+       pdata->phy_started = 0;
        pdata->phy.link = 0;
 
        pdata->phy.pause_autoneg = pdata->pause_autoneg;
diff --git a/sys/dev/axgbe/xgbe-phy-v2.c b/sys/dev/axgbe/xgbe-phy-v2.c
index 9a057c34c6c9..d8c372cac642 100644
--- a/sys/dev/axgbe/xgbe-phy-v2.c
+++ b/sys/dev/axgbe/xgbe-phy-v2.c
@@ -150,6 +150,9 @@ struct mtx xgbe_phy_comm_lock;
 /* RRC frequency during link status check */
 #define XGBE_RRC_FREQUENCY             10
 
+/* SFP port max PHY probe retries */
+#define XGBE_SFP_PHY_RETRY_MAX         5
+
 enum xgbe_port_mode {
        XGBE_PORT_MODE_RSVD = 0,
        XGBE_PORT_MODE_BACKPLANE,
@@ -186,10 +189,16 @@ enum xgbe_sfp_cable {
 
 enum xgbe_sfp_base {
        XGBE_SFP_BASE_UNKNOWN = 0,
+       XGBE_SFP_BASE_PX,
+       XGBE_SFP_BASE_BX10,
+       XGBE_SFP_BASE_100_FX,
+       XGBE_SFP_BASE_100_LX10,
+       XGBE_SFP_BASE_100_BX,
        XGBE_SFP_BASE_1000_T,
        XGBE_SFP_BASE_1000_SX,
        XGBE_SFP_BASE_1000_LX,
        XGBE_SFP_BASE_1000_CX,
+       XGBE_SFP_BASE_1000_BX,
        XGBE_SFP_BASE_10000_SR,
        XGBE_SFP_BASE_10000_LR,
        XGBE_SFP_BASE_10000_LRM,
@@ -199,9 +208,11 @@ enum xgbe_sfp_base {
 
 enum xgbe_sfp_speed {
        XGBE_SFP_SPEED_UNKNOWN = 0,
+       XGBE_SFP_SPEED_100,
        XGBE_SFP_SPEED_100_1000,
        XGBE_SFP_SPEED_1000,
        XGBE_SFP_SPEED_10000,
+       XGBE_SFP_SPEED_25000,
 };
 
 /* SFP Serial ID Base ID values relative to an offset of 0 */
@@ -225,16 +236,31 @@ enum xgbe_sfp_speed {
 #define XGBE_SFP_BASE_1GBE_CC_LX               BIT(1)
 #define XGBE_SFP_BASE_1GBE_CC_CX               BIT(2)
 #define XGBE_SFP_BASE_1GBE_CC_T                        BIT(3)
+#define XGBE_SFP_BASE_100M_CC_LX10             BIT(4)
+#define XGBE_SFP_BASE_100M_CC_FX               BIT(5)
+#define XGBE_SFP_BASE_CC_BX10                  BIT(6)
+#define XGBE_SFP_BASE_CC_PX                    BIT(7)
 
 #define XGBE_SFP_BASE_CABLE                    8
 #define XGBE_SFP_BASE_CABLE_PASSIVE            BIT(2)
 #define XGBE_SFP_BASE_CABLE_ACTIVE             BIT(3)
 
 #define XGBE_SFP_BASE_BR                       12
+#define XGBE_SFP_BASE_BR_100M_MIN              0x1
+#define XGBE_SFP_BASE_BR_100M_MAX              0x2
 #define XGBE_SFP_BASE_BR_1GBE_MIN              0x0a
 #define XGBE_SFP_BASE_BR_1GBE_MAX              0x0d
 #define XGBE_SFP_BASE_BR_10GBE_MIN             0x64
 #define XGBE_SFP_BASE_BR_10GBE_MAX             0x68
+#define XGBE_SFP_BASE_BR_25GBE                 0xFF
+
+/* Single mode, length of fiber in units of km */
+#define XGBE_SFP_BASE_SM_LEN_KM                        14
+#define XGBE_SFP_BASE_SM_LEN_KM_MIN            0x0A
+
+/* Single mode, length of fiber in units of 100m */
+#define XGBE_SFP_BASE_SM_LEN_100M              15
+#define XGBE_SFP_BASE_SM_LEN_100M_MIN          0x64
 
 #define XGBE_SFP_BASE_CU_CABLE_LEN             18
 
@@ -245,6 +271,14 @@ enum xgbe_sfp_speed {
 #define XGBE_SFP_BASE_VENDOR_REV               56
 #define XGBE_SFP_BASE_VENDOR_REV_LEN           4
 
+/*
+ * Optical specification compliance - denotes wavelength
+ * for optical tranceivers
+ */
+#define XGBE_SFP_BASE_OSC                      60
+#define XGBE_SFP_BASE_OSC_LEN                  2
+#define XGBE_SFP_BASE_OSC_1310                 0x051E
+
 #define XGBE_SFP_BASE_CC                       63
 
 /* SFP Serial ID Extended ID values relative to an offset of 64 */
@@ -365,6 +399,7 @@ struct xgbe_phy_data {
        enum xgbe_mdio_reset mdio_reset;
        unsigned int mdio_reset_addr;
        unsigned int mdio_reset_gpio;
+       int sfp_phy_retries;
 
        /* Re-driver support */
        unsigned int redrv;
@@ -382,6 +417,8 @@ struct xgbe_phy_data {
 
 static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata);
 static int xgbe_phy_reset(struct xgbe_prv_data *pdata);
+static int axgbe_ifmedia_upd(struct ifnet *ifp);
+static void axgbe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
 
 static int
 xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *i2c_op)
@@ -756,6 +793,14 @@ xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
        }
 
        switch (phy_data->sfp_base) {
+       case XGBE_SFP_BASE_100_FX:
+       case XGBE_SFP_BASE_100_LX10:
+       case XGBE_SFP_BASE_100_BX:
+               pdata->phy.speed = SPEED_100;
+               pdata->phy.duplex = DUPLEX_FULL;
+               pdata->phy.autoneg = AUTONEG_DISABLE;
+               pdata->phy.pause_autoneg = AUTONEG_DISABLE;
+               break;
        case XGBE_SFP_BASE_1000_T:
        case XGBE_SFP_BASE_1000_SX:
        case XGBE_SFP_BASE_1000_LX:
@@ -777,6 +822,13 @@ xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
                                XGBE_SET_SUP(&pdata->phy, 1000baseX_Full);
                }
                break;
+       case XGBE_SFP_BASE_1000_BX:
+       case XGBE_SFP_BASE_PX:
+               pdata->phy.speed = SPEED_1000;
+               pdata->phy.duplex = DUPLEX_FULL;
+               pdata->phy.autoneg = AUTONEG_DISABLE;
+               pdata->phy.pause_autoneg = AUTONEG_DISABLE;
+               break;
        case XGBE_SFP_BASE_10000_SR:
        case XGBE_SFP_BASE_10000_LR:
        case XGBE_SFP_BASE_10000_LRM:
@@ -844,6 +896,10 @@ xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
        sfp_base = sfp_eeprom->base;
 
        switch (sfp_speed) {
+       case XGBE_SFP_SPEED_100:
+               min = XGBE_SFP_BASE_BR_100M_MIN;
+               max = XGBE_SFP_BASE_BR_100M_MAX;
+               break;
        case XGBE_SFP_SPEED_1000:
                min = XGBE_SFP_BASE_BR_1GBE_MIN;
                max = XGBE_SFP_BASE_BR_1GBE_MAX;
@@ -852,6 +908,10 @@ xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
                min = XGBE_SFP_BASE_BR_10GBE_MIN;
                max = XGBE_SFP_BASE_BR_10GBE_MAX;
                break;
+       case XGBE_SFP_SPEED_25000:
+               min = XGBE_SFP_BASE_BR_25GBE;
+               max = XGBE_SFP_BASE_BR_25GBE;
+               break;
        default:
                return (false);
        }
@@ -867,6 +927,11 @@ xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata)
 
        if (phy_data->phydev)
                phy_data->phydev = 0;
+
+       if (pdata->axgbe_miibus != NULL) {
+               device_delete_child(pdata->dev, pdata->axgbe_miibus);
+               pdata->axgbe_miibus = NULL;
+       }
 }
 
 static bool
@@ -1009,49 +1074,6 @@ xgbe_get_phy_id(struct xgbe_prv_data *pdata)
        return (0);
 }
 
-static int
-xgbe_phy_start_aneg(struct xgbe_prv_data *pdata)
-{
-       uint16_t ctl = 0;
-       int changed = 0;
-       int ret;
-
-       if (AUTONEG_ENABLE != pdata->phy.autoneg) {
-               if (SPEED_1000 == pdata->phy.speed)
-                       ctl |= BMCR_SPEED1;
-               else if (SPEED_100 == pdata->phy.speed)
-                       ctl |= BMCR_SPEED100;
-
-               if (DUPLEX_FULL == pdata->phy.duplex)
-                       ctl |= BMCR_FDX;
-
-               ret = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR);
-               if (ret)
-                       return (ret);
-
-               ret = xgbe_phy_mii_write(pdata, pdata->mdio_addr, MII_BMCR,
-                   (ret & ~(~(BMCR_LOOP | BMCR_ISO | BMCR_PDOWN))) | ctl);
-       }
-
-       ctl = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR);
-       if (ctl < 0)
-               return (ctl);
-
-       if (!(ctl & BMCR_AUTOEN) || (ctl & BMCR_ISO))
-               changed = 1;
-
-       if (changed > 0) {
-               ret = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR);
-               if (ret)
-                       return (ret);
-
-               ret = xgbe_phy_mii_write(pdata, pdata->mdio_addr, MII_BMCR,
-                   (ret & ~(BMCR_ISO)) | (BMCR_AUTOEN | BMCR_STARTNEG));
-       }
-
-       return (0);
-}
-
 static int
 xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
 {
@@ -1102,7 +1124,6 @@ xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
 
        phy_data->phydev = 1;
        xgbe_phy_external_phy_quirks(pdata);
-       xgbe_phy_start_aneg(pdata);
 
        return (0);
 }
@@ -1115,7 +1136,7 @@ xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
 
        axgbe_printf(3, "%s: sfp_changed: 0x%x\n", __func__,
            phy_data->sfp_changed);
-       if (!phy_data->sfp_changed)
+       if (!phy_data->sfp_phy_retries && !phy_data->sfp_changed)
                return;
 
        phy_data->sfp_phy_avail = 0;
@@ -1126,13 +1147,26 @@ xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata)
        /* Check access to the PHY by reading CTRL1 */
        ret = xgbe_phy_i2c_mii_read(pdata, MII_BMCR);
        if (ret < 0) {
-               axgbe_error("%s: ext phy fail %d\n", __func__, ret);
+               phy_data->sfp_phy_retries++;
+               if (phy_data->sfp_phy_retries >= XGBE_SFP_PHY_RETRY_MAX)
+                       phy_data->sfp_phy_retries = 0;
+               axgbe_printf(1, "%s: ext phy fail %d. retrying.\n", __func__, 
ret);
                return;
        }
 
        /* Successfully accessed the PHY */
        phy_data->sfp_phy_avail = 1;
        axgbe_printf(3, "Successfully accessed External PHY\n");
+
+       /* Attach external PHY to the miibus */
+       ret = mii_attach(pdata->dev, &pdata->axgbe_miibus, pdata->netdev,
+               (ifm_change_cb_t)axgbe_ifmedia_upd,
+               (ifm_stat_cb_t)axgbe_ifmedia_sts, BMSR_DEFCAPMASK,
+               pdata->mdio_addr, MII_OFFSET_ANY, MIIF_FORCEANEG);
+
+       if (ret) {
+               axgbe_error("mii attach failed with err=(%d)\n", ret);
+       }
 }
 
 static bool
@@ -1187,6 +1221,7 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
        uint8_t *sfp_base;
+       uint16_t wavelen = 0;
 
        sfp_base = sfp_eeprom->base;
 
@@ -1211,14 +1246,19 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
        } else
                phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
 
+       wavelen = (sfp_base[XGBE_SFP_BASE_OSC] << 8) | 
sfp_base[XGBE_SFP_BASE_OSC + 1];
+
        /*
         * Determine the type of SFP. Certain 10G SFP+ modules read as
         * 1000BASE-CX. To prevent 10G DAC cables to be recognized as
         * 1G, we first check if it is a DAC and the bitrate is 10G.
+        * If it's greater than 10G, we assume the DAC is capable
+        * of multiple bitrates, set the MAC to 10G and hope for the best.
         */
        if (((sfp_base[XGBE_SFP_BASE_CV] & XGBE_SFP_BASE_CV_CP) ||
-           (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) &&
-           xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000))
+               (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) &&
+               (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000) ||
+               xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_25000)))
                phy_data->sfp_base = XGBE_SFP_BASE_10000_CR;
        else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR)
                phy_data->sfp_base = XGBE_SFP_BASE_10000_SR;
@@ -1236,14 +1276,44 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
                phy_data->sfp_base = XGBE_SFP_BASE_1000_CX;
        else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T)
                phy_data->sfp_base = XGBE_SFP_BASE_1000_T;
+       else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_LX10)
+               phy_data->sfp_base = XGBE_SFP_BASE_100_LX10;
+       else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_FX)
+               phy_data->sfp_base = XGBE_SFP_BASE_100_FX;
+       else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_BX10) {
+               /* BX10 can be either 100 or 1000 */
+               if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100)) {
+                       phy_data->sfp_base = XGBE_SFP_BASE_100_BX;
+               } else {
+                       /* default to 1000 */
+                       phy_data->sfp_base = XGBE_SFP_BASE_1000_BX;
+               }
+       } else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_PX)
+               phy_data->sfp_base = XGBE_SFP_BASE_PX;
+       else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_1000)
+                       && (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= 
XGBE_SFP_BASE_SM_LEN_KM_MIN
+                       || sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= 
XGBE_SFP_BASE_SM_LEN_100M_MIN)
+                       && wavelen >= XGBE_SFP_BASE_OSC_1310)
+               phy_data->sfp_base = XGBE_SFP_BASE_1000_BX;
+       else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100)
+                       && (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= 
XGBE_SFP_BASE_SM_LEN_KM_MIN
+                       || sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= 
XGBE_SFP_BASE_SM_LEN_100M_MIN)
+                       && wavelen >= XGBE_SFP_BASE_OSC_1310)
+               phy_data->sfp_base = XGBE_SFP_BASE_100_BX;
 
        switch (phy_data->sfp_base) {
+       case XGBE_SFP_BASE_100_FX:
+       case XGBE_SFP_BASE_100_LX10:
+       case XGBE_SFP_BASE_100_BX:
+               phy_data->sfp_speed = XGBE_SFP_SPEED_100;
        case XGBE_SFP_BASE_1000_T:
                phy_data->sfp_speed = XGBE_SFP_SPEED_100_1000;
                break;
+       case XGBE_SFP_BASE_PX:
        case XGBE_SFP_BASE_1000_SX:
        case XGBE_SFP_BASE_1000_LX:
        case XGBE_SFP_BASE_1000_CX:
+       case XGBE_SFP_BASE_1000_BX:
                phy_data->sfp_speed = XGBE_SFP_SPEED_1000;
                break;
        case XGBE_SFP_BASE_10000_SR:
@@ -1269,29 +1339,29 @@ xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data *pdata,
        struct xgbe_sfp_ascii sfp_ascii;
        char *sfp_data = (char *)&sfp_ascii;
 
-       axgbe_printf(3, "SFP detected:\n");
+       axgbe_printf(0, "SFP detected:\n");
        memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
               XGBE_SFP_BASE_VENDOR_NAME_LEN);
        sfp_data[XGBE_SFP_BASE_VENDOR_NAME_LEN] = '\0';
-       axgbe_printf(3, "  vendor:       %s\n",
+       axgbe_printf(0, "  vendor:       %s\n",
            sfp_data);
 
        memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
               XGBE_SFP_BASE_VENDOR_PN_LEN);
        sfp_data[XGBE_SFP_BASE_VENDOR_PN_LEN] = '\0';
-       axgbe_printf(3, "  part number:    %s\n",
+       axgbe_printf(0, "  part number:    %s\n",
            sfp_data);
 
        memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_REV],
               XGBE_SFP_BASE_VENDOR_REV_LEN);
        sfp_data[XGBE_SFP_BASE_VENDOR_REV_LEN] = '\0';
-       axgbe_printf(3, "  revision level: %s\n",
+       axgbe_printf(0, "  revision level: %s\n",
            sfp_data);
 
        memcpy(sfp_data, &sfp_eeprom->extd[XGBE_SFP_BASE_VENDOR_SN],
               XGBE_SFP_BASE_VENDOR_SN_LEN);
        sfp_data[XGBE_SFP_BASE_VENDOR_SN_LEN] = '\0';
-       axgbe_printf(3, "  serial number:  %s\n",
+       axgbe_printf(0, "  serial number:  %s\n",
            sfp_data);
 }
 
@@ -1337,14 +1407,15 @@ xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata)
            &eeprom_addr, sizeof(eeprom_addr),
            &sfp_eeprom, sizeof(sfp_eeprom));
 
-       eeprom = &sfp_eeprom;
-       base = eeprom->base;
-       dump_sfp_eeprom(pdata, base);
        if (ret) {
                axgbe_error("I2C error reading SFP EEPROM\n");
                goto put;
        }
 
+       eeprom = &sfp_eeprom;
+       base = eeprom->base;
+       dump_sfp_eeprom(pdata, base);
+
        /* Validate the contents read */
        if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[XGBE_SFP_BASE_CC],
            sfp_eeprom.base, sizeof(sfp_eeprom.base) - 1)) {
@@ -1610,17 +1681,17 @@ xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
                }
                break;
        case XGBE_SGMII_AN_LINK_SPEED_1000:
+       default:
+               /* Default to 1000 */
                if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
                        XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Full);
                        mode = XGBE_MODE_SGMII_1000;
                } else {
                        /* Half-duplex not supported */
                        XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Half);
-                       mode = XGBE_MODE_UNKNOWN;
+                       mode = XGBE_MODE_SGMII_1000;
                }
                break;
-       default:
-               mode = XGBE_MODE_UNKNOWN;
        }
 
        return (mode);
@@ -1913,7 +1984,6 @@ xgbe_phy_an_config(struct xgbe_prv_data *pdata)
        if (!phy_data->phydev)
                return (0);
 
-       ret = xgbe_phy_start_aneg(pdata);
        return (ret);
 }
 
@@ -2022,6 +2092,16 @@ xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata)
        xgbe_phy_put_comm_ownership(pdata);
 }
 
+static void
+xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable)
+{
+       XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0,
+                                       XGBE_PMA_PLL_CTRL_MASK,
+                                       enable ? XGBE_PMA_PLL_CTRL_ENABLE
+                                              : XGBE_PMA_PLL_CTRL_DISABLE);
+       DELAY(200);
+}
+
 static void
 xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd,
     unsigned int sub_cmd)
@@ -2029,6 +2109,8 @@ xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, 
unsigned int cmd,
        unsigned int s0 = 0;
        unsigned int wait;
 
+       xgbe_phy_pll_ctrl(pdata, false);
+
        /* Log if a previous command did not complete */
        if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
                axgbe_error("firmware mailbox not ready for command\n");
@@ -2047,13 +2129,16 @@ xgbe_phy_perform_ratechange(struct xgbe_prv_data 
*pdata, unsigned int cmd,
        while (wait--) {
                if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
                        axgbe_printf(3, "%s: Rate change done\n", __func__);
-                       return;
+                       goto reenable_pll;
                }
 
                DELAY(2000);
        }
 
        axgbe_printf(3, "firmware mailbox command did not complete\n");
+
+reenable_pll:
+       xgbe_phy_pll_ctrl(pdata, true);
 }
 
 static void
@@ -2436,7 +2521,7 @@ xgbe_phy_get_type(struct xgbe_prv_data *pdata, struct 
ifmediareq * ifmr)
                if(phy_data->port_mode == XGBE_PORT_MODE_NBASE_T)
                        ifmr->ifm_active |= IFM_100_T;
                else if(phy_data->port_mode == XGBE_PORT_MODE_SFP)
-                       ifmr->ifm_active |= IFM_1000_SGMII;
+                       ifmr->ifm_active |= IFM_100_SGMII;
                else
                        ifmr->ifm_active |= IFM_OTHER;
                break;
@@ -2631,7 +2716,8 @@ xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data 
*phy_data, int speed)
 
        switch (speed) {
        case SPEED_100:
-               return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000);
+               return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100) ||
+                       (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000));
        case SPEED_1000:
                return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000) ||
                    (phy_data->sfp_speed == XGBE_SFP_SPEED_1000));
@@ -2698,6 +2784,7 @@ xgbe_upd_link(struct xgbe_prv_data *pdata)
 
        axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link);
        reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR);
+       reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR);
        if (reg < 0)
                return (reg);
 
@@ -2823,6 +2910,25 @@ xgbe_phy_read_status(struct xgbe_prv_data *pdata)
        return (0);
 }
 
+static void
+xgbe_rrc(struct xgbe_prv_data *pdata)
+{
+       struct xgbe_phy_data *phy_data = pdata->phy_data;
+       int ret;
+
+       if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
+               axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n",
+                       phy_data->rrc_count);
+               phy_data->rrc_count = 0;
+               if (pdata->link_workaround) {
+                       ret = xgbe_phy_reset(pdata);
+                       if (ret)
+                               axgbe_error("Error resetting phy\n");
+               } else
+                       xgbe_phy_rrc(pdata);
+       }
+}
+
 static int
 xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
 {
@@ -2848,16 +2954,28 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int 
*an_restart)
                        axgbe_printf(1, "%s: SFP absent 0x%x & sfp_rx_los 
0x%x\n",
                            __func__, phy_data->sfp_mod_absent,
                            phy_data->sfp_rx_los);
+
+                       if (!phy_data->sfp_mod_absent) {
+                               xgbe_rrc(pdata);
+                       }
+
                        return (0);
                }
-       } else {
+       }
+
+       if (phy_data->phydev || phy_data->port_mode != XGBE_PORT_MODE_SFP) {
+               if (pdata->axgbe_miibus == NULL) {
+                       axgbe_printf(1, "%s: miibus not initialized", __func__);
+                       goto mdio_read;
+               }
+
                mii = device_get_softc(pdata->axgbe_miibus);
                mii_tick(mii);
-       
+
                ret = xgbe_phy_read_status(pdata);
                if (ret) {
-                       axgbe_printf(2, "Link: Read status returned %d\n", ret);
-                       return (ret);
+                       axgbe_error("Link: Read status returned %d\n", ret);
+                       return (0);
                }
 
                axgbe_printf(2, "%s: link speed %#x duplex %#x media %#x "
@@ -2869,9 +2987,14 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int 
*an_restart)
                if ((pdata->phy.autoneg == AUTONEG_ENABLE) && !ret)
                        return (0);
 
-               return (pdata->phy.link);
+               if (pdata->phy.link)
+                       return (1);
+
+               xgbe_rrc(pdata);
        }
 
+mdio_read:
+
        /* Link status is latched low, so read once to clear
         * and then read again to get current state
         */
@@ -2882,17 +3005,7 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int 
*an_restart)
                return (1);
 
        /* No link, attempt a receiver reset cycle */
-       if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
-               axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n",
-                   phy_data->rrc_count);
-               phy_data->rrc_count = 0;
-               if (pdata->link_workaround) {
-                       ret = xgbe_phy_reset(pdata);
-                       if (ret)
-                               axgbe_error("Error resetting phy\n");
-               } else
-                       xgbe_phy_rrc(pdata);
-       }
+       xgbe_rrc(pdata);
 
        return (0);
 }

Reply via email to