Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Add SFP support part 2.



details:   https://anonhg.NetBSD.org/src/rev/ab0834d9b8be
branches:  trunk
changeset: 466107:ab0834d9b8be
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Thu Dec 12 09:32:54 2019 +0000

description:
Add SFP support part 2.

 - Add code for 1000BASE-T SFP. It uses SGMII.
 - Add extra delay in wm_serdes_power_up_link_82575(). Same as other OSes.

TODO:
 - Module insertion/removal support. Currently, SFP detection is only done
  in the driver's attach phase.

diffstat:

 sys/dev/pci/if_wm.c |  149 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 103 insertions(+), 46 deletions(-)

diffs (truncated from 323 to 300 lines):

diff -r 7f79293fa56e -r ab0834d9b8be sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c       Thu Dec 12 09:25:37 2019 +0000
+++ b/sys/dev/pci/if_wm.c       Thu Dec 12 09:32:54 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wm.c,v 1.655 2019/12/11 10:28:19 msaitoh Exp $      */
+/*     $NetBSD: if_wm.c,v 1.656 2019/12/12 09:32:54 msaitoh Exp $      */
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.655 2019/12/11 10:28:19 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.656 2019/12/12 09:32:54 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -156,6 +156,7 @@
 #define        WM_DEBUG_LOCK           __BIT(7)
 int    wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII
     | WM_DEBUG_MANAGE | WM_DEBUG_NVM | WM_DEBUG_INIT | WM_DEBUG_LOCK;
+#endif
 
 #define        DPRINTF(x, y)   do { if (wm_debug & (x)) printf y; } while (0)
 #else
@@ -467,6 +468,7 @@
        int (*readreg_locked)(device_t, int, int, uint16_t *);
        int (*writereg_locked)(device_t, int, int, uint16_t);
        int reset_delay_us;
+       bool no_errprint;
 };
 
 struct wm_nvmop {
@@ -2607,6 +2609,8 @@
 
        if (sc->sc_type >= WM_T_82575) {
                if (wm_nvm_read(sc, NVM_OFF_COMPAT, 1, &nvmword) == 0) {
+                       aprint_debug_dev(sc->sc_dev, "COMPAT = %hx\n",
+                           nvmword);
                        if ((sc->sc_type == WM_T_82575) ||
                            (sc->sc_type == WM_T_82576)) {
                                /* Check NVM for autonegotiation */
@@ -2786,6 +2790,10 @@
                else
                        reg &= ~CTRL_EXT_I2C_ENA;
                CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+               if ((sc->sc_flags & WM_F_SGMII) != 0) {
+                       wm_gmii_setup_phytype(sc, 0, 0);
+                       wm_reset_mdicnfg_82580(sc);
+               }
        } else if (sc->sc_type < WM_T_82543 ||
            (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) {
                if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) {
@@ -5827,6 +5835,11 @@
        if (error)
                goto out;
 
+       if (((sc->sc_flags & WM_F_SGMII) == 0) &&
+           (sc->sc_mediatype == WM_MEDIATYPE_SERDES) &&
+           (sc->sc_type >= WM_T_82575))
+               wm_serdes_power_up_link_82575(sc);
+
        /* Clear out the VLAN table -- we don't use it (yet). */
        CSR_WRITE(sc, WMREG_VET, 0);
        if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
@@ -9940,10 +9953,18 @@
        uint16_t doubt_phytype = WMPHY_UNKNOWN;
        mii_readreg_t new_readreg;
        mii_writereg_t new_writereg;
+       bool dodiag = true;
 
        DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                device_xname(sc->sc_dev), __func__));
 
+       /*
+        * 1000BASE-T SFP uses SGMII and the first asumed PHY type is always
+        * incorrect. So don't print diag output when it's 2nd call.
+        */
+       if ((sc->sc_sfptype != 0) && (phy_oui == 0) && (phy_model == 0))
+               dodiag = false;
+
        if (mii->mii_readreg == NULL) {
                /*
                 *  This is the first call of this function. For ICH and PCH
@@ -10060,16 +10081,20 @@
                default:
                        break;
                }
-               if (new_phytype == WMPHY_UNKNOWN)
-                       aprint_verbose_dev(dev,
-                           "%s: unknown PHY model. OUI=%06x, model=%04x\n",
-                           __func__, phy_oui, phy_model);
-
-               if ((sc->sc_phytype != WMPHY_UNKNOWN)
-                   && (sc->sc_phytype != new_phytype )) {
-                       aprint_error_dev(dev, "Previously assumed PHY type(%u)"
-                           "was incorrect. PHY type from PHY ID = %u\n",
-                           sc->sc_phytype, new_phytype);
+
+               if (dodiag) {
+                       if (new_phytype == WMPHY_UNKNOWN)
+                               aprint_verbose_dev(dev,
+                                   "%s: Unknown PHY model. OUI=%06x, "
+                                   "model=%04x\n", __func__, phy_oui,
+                                   phy_model);
+
+                       if ((sc->sc_phytype != WMPHY_UNKNOWN)
+                           && (sc->sc_phytype != new_phytype)) {
+                               aprint_error_dev(dev, "Previously assumed PHY "
+                                   "type(%u) was incorrect. PHY type from PHY"
+                                    "ID = %u\n", sc->sc_phytype, new_phytype);
+                       }
                }
        }
 
@@ -10138,22 +10163,26 @@
        }
 
        /* Diag output */
-       if (doubt_phytype != WMPHY_UNKNOWN)
-               aprint_error_dev(dev, "Assumed new PHY type was "
-                   "incorrect. old = %u, new = %u\n", sc->sc_phytype,
-                   new_phytype);
-       else if ((sc->sc_phytype != WMPHY_UNKNOWN)
-           && (sc->sc_phytype != new_phytype ))
-               aprint_error_dev(dev, "Previously assumed PHY type(%u)"
-                   "was incorrect. New PHY type = %u\n",
-                   sc->sc_phytype, new_phytype);
-
-       if ((mii->mii_readreg != NULL) && (new_phytype == WMPHY_UNKNOWN))
-               aprint_error_dev(dev, "PHY type is still unknown.\n");
-
-       if ((mii->mii_readreg != NULL) && (mii->mii_readreg != new_readreg))
-               aprint_error_dev(dev, "Previously assumed PHY read/write "
-                   "function was incorrect.\n");
+       if (dodiag) {
+               if (doubt_phytype != WMPHY_UNKNOWN)
+                       aprint_error_dev(dev, "Assumed new PHY type was "
+                           "incorrect. old = %u, new = %u\n", sc->sc_phytype,
+                           new_phytype);
+               else if ((sc->sc_phytype != WMPHY_UNKNOWN)
+                   && (sc->sc_phytype != new_phytype ))
+                       aprint_error_dev(dev, "Previously assumed PHY type(%u)"
+                           "was incorrect. New PHY type = %u\n",
+                           sc->sc_phytype, new_phytype);
+
+               if ((mii->mii_readreg != NULL) &&
+                   (new_phytype == WMPHY_UNKNOWN))
+                       aprint_error_dev(dev, "PHY type is still unknown.\n");
+
+               if ((mii->mii_readreg != NULL) &&
+                   (mii->mii_readreg != new_readreg))
+                       aprint_error_dev(dev, "Previously assumed PHY "
+                           "read/write function was incorrect.\n");
+       }
 
        /* Update now */
        sc->sc_phytype = new_phytype;
@@ -10221,7 +10250,6 @@
        device_t dev = sc->sc_dev;
        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        struct mii_data *mii = &sc->sc_mii;
-       uint32_t reg;
 
        DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
                device_xname(sc->sc_dev), __func__));
@@ -10234,15 +10262,6 @@
        else
                sc->sc_tipg = TIPG_1000T_DFLT;
 
-       /* XXX Not for I354? FreeBSD's e1000_82575.c doesn't include it */
-       if ((sc->sc_type == WM_T_82580)
-           || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
-           || (sc->sc_type == WM_T_I211)) {
-               reg = CSR_READ(sc, WMREG_PHPM);
-               reg &= ~PHPM_GO_LINK_D;
-               CSR_WRITE(sc, WMREG_PHPM, reg);
-       }
-
        /*
         * Let the chip set speed/duplex on its own based on
         * signals from the PHY.
@@ -10295,11 +10314,19 @@
                                CSR_WRITE_FLUSH(sc);
                                delay(300*1000); /* XXX too long */
 
-                               /* From 1 to 8 */
+                               /*
+                                * From 1 to 8.
+                                *
+                                * I2C access fails with I2C register's ERROR
+                                * bit set, so prevent error message while
+                                * scanning.
+                                */
+                               sc->phy.no_errprint = true;
                                for (i = 1; i < 8; i++)
                                        mii_attach(sc->sc_dev, &sc->sc_mii,
                                            0xffffffff, i, MII_OFFSET_ANY,
                                            MIIF_DOPAUSE);
+                               sc->phy.no_errprint = false;
 
                                /* Restore previous sfp cage power state */
                                CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
@@ -10368,6 +10395,7 @@
 {
        struct wm_softc *sc = ifp->if_softc;
        struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+       uint32_t reg;
        int rc;
 
        DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
@@ -10375,6 +10403,15 @@
        if ((ifp->if_flags & IFF_UP) == 0)
                return 0;
 
+       /* XXX Not for I354? FreeBSD's e1000_82575.c doesn't include it */
+       if ((sc->sc_type == WM_T_82580)
+           || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
+           || (sc->sc_type == WM_T_I211)) {
+               reg = CSR_READ(sc, WMREG_PHPM);
+               reg &= ~PHPM_GO_LINK_D;
+               CSR_WRITE(sc, WMREG_PHPM, reg);
+       }
+
        /* Disable D0 LPLU. */
        wm_lplu_d0_disable(sc);
 
@@ -10408,9 +10445,19 @@
        }
        CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
        CSR_WRITE_FLUSH(sc);
-       if (sc->sc_type <= WM_T_82543)
+
+       if ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211))
+               wm_serdes_mediachange(ifp);
+
+       if (sc->sc_type <= WM_T_82543) 
                wm_gmii_reset(sc);
-
+       else if ((sc->sc_type >= WM_T_82575) && (sc->sc_type <= WM_T_I211)
+           && ((sc->sc_flags & WM_F_SGMII) != 0)) {
+               /* allow time for SFP cage time to power up phy */
+               delay(300 * 1000);
+               wm_gmii_reset(sc);
+       }
+               
        if ((rc = mii_mediachg(&sc->sc_mii)) == ENXIO)
                return 0;
        return rc;
@@ -11674,7 +11721,8 @@
                rv = ETIMEDOUT;
        }
        if ((i2ccmd & I2CCMD_ERROR) != 0) {
-               device_printf(dev, "I2CCMD Error bit set\n");
+               if (!sc->phy.no_errprint)
+                       device_printf(dev, "I2CCMD Error bit set\n");
                rv = EIO;
        }
 
@@ -12185,6 +12233,7 @@
 
        /* Flush the write to verify completion */
        CSR_WRITE_FLUSH(sc);
+       delay(1000);
 }
 
 static int
@@ -12194,19 +12243,26 @@
        bool pcs_autoneg = true; /* XXX */
        uint32_t ctrl_ext, pcs_lctl, reg;
 
+       if ((sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+           && ((sc->sc_flags & WM_F_SGMII) == 0))
+               return 0;
+
        /* XXX Currently, this function is not called on 8257[12] */
        if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572)
            || (sc->sc_type >= WM_T_82575))
                CSR_WRITE(sc, WMREG_SCTL, SCTL_DISABLE_SERDES_LOOPBACK);
 
-       wm_serdes_power_up_link_82575(sc);
+       /* Power on the sfp cage if present */
+       ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+       ctrl_ext &= ~CTRL_EXT_SWDPIN(3);
+       ctrl_ext |= CTRL_EXT_I2C_ENA;
+       CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
 
        sc->sc_ctrl |= CTRL_SLU;
 
        if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
                sc->sc_ctrl |= CTRL_SWDPIN(0) | CTRL_SWDPIN(1);
 
-       ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
        pcs_lctl = CSR_READ(sc, WMREG_PCS_LCTL);
        switch (ctrl_ext & CTRL_EXT_LINK_MODE_MASK) {
        case CTRL_EXT_LINK_MODE_SGMII:
@@ -12232,6 +12288,9 @@
        }
        CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);



Home | Main Index | Thread Index | Old Index