Source-Changes-HG archive

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

[src/trunk]: src/sys/dev Add EEE(802.3az) support for I350, I210, I211, PCH2 ...



details:   https://anonhg.NetBSD.org/src/rev/adc4aaf389aa
branches:  trunk
changeset: 838203:adc4aaf389aa
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Mon Jan 07 01:43:22 2019 +0000

description:
Add EEE(802.3az) support for I350, I210, I211, PCH2 and newer.

 Not yet for I354(C2000). It'll be supported after implementing MI MII clause
45 register read/write API.

diffstat:

 sys/dev/mii/inbmphyreg.h |   15 ++-
 sys/dev/pci/if_wm.c      |  318 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 287 insertions(+), 46 deletions(-)

diffs (truncated from 553 to 300 lines):

diff -r e90fe7e932dc -r adc4aaf389aa sys/dev/mii/inbmphyreg.h
--- a/sys/dev/mii/inbmphyreg.h  Mon Jan 07 01:39:26 2019 +0000
+++ b/sys/dev/mii/inbmphyreg.h  Mon Jan 07 01:43:22 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: inbmphyreg.h,v 1.15 2018/12/20 09:32:12 msaitoh Exp $  */
+/*     $NetBSD: inbmphyreg.h,v 1.16 2019/01/07 01:43:22 msaitoh Exp $  */
 /*******************************************************************************
 Copyright (c) 2001-2015, Intel Corporation 
 All rights reserved.
@@ -78,6 +78,19 @@
 #define BME1000_PSCR_DOWNSHIFT_COUNTER_MASK     0x7000
 #define BME1000_PSCR_DOWNSHIFT_COUNTER_SHIFT    12
 
+/* Extended Management Interface (EMI) Registers */
+#define I82579_EMI_ADDR        0x10
+#define I82579_EMI_DATA        0x11
+#define I82579_EEE_ADVERTISEMENT 0x040e  /* IEEE MMD Register 7.60 */
+#define I82579_EEE_LP_ABILITY  0x040f   /* IEEE MMD Register 7.61 */
+#define I82579_EEE_PCS_STATUS  0x182e
+#define I82579_LPI_PLL_SHUT    0x4412
+#define I82579_LPI_PLL_SHUT_100                __BIT(2) /* 100M LPI PLL Shut Enable */
+#define I217_EEE_PCS_STATUS    0x9401   /* IEEE MMD Register 3.1 */
+#define I217_EEE_CAPABILITY    0x8000   /* IEEE MMD Register 3.20 */
+#define I217_EEE_ADVERTISEMENT 0x8001   /* IEEE MMD Register 7.60 */
+#define I217_EEE_LP_ABILITY    0x8002   /* IEEE MMD Register 7.61 */
+
 /* BM PHY Copper Specific Status */
 #define BM_CS_STATUS           BME1000_REG(0, 17)
 #define BM_CS_STATUS_LINK_UP   0x0400
diff -r e90fe7e932dc -r adc4aaf389aa sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c       Mon Jan 07 01:39:26 2019 +0000
+++ b/sys/dev/pci/if_wm.c       Mon Jan 07 01:43:22 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wm.c,v 1.613 2019/01/03 08:46:03 msaitoh Exp $      */
+/*     $NetBSD: if_wm.c,v 1.614 2019/01/07 01:43:22 msaitoh Exp $      */
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -83,7 +83,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.613 2019/01/03 08:46:03 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.614 2019/01/07 01:43:22 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -129,6 +129,7 @@
 #include <machine/endian.h>
 
 #include <dev/mii/mii.h>
+#include <dev/mii/mdio.h>
 #include <dev/mii/miivar.h>
 #include <dev/mii/miidevs.h>
 #include <dev/mii/mii_bitbang.h>
@@ -514,7 +515,9 @@
        int sc_funcid;                  /* unit number of the chip (0 to 3) */
        int sc_flags;                   /* flags; see below */
        int sc_if_flags;                /* last if_flags */
+       int sc_ec_capenable;            /* last ec_capenable */
        int sc_flowflags;               /* 802.3x flow control flags */
+       uint16_t eee_lp_ability;        /* EEE link partner's ability */
        int sc_align_tweak;
 
        void *sc_ihs[WM_MAX_NINTR];     /*
@@ -852,10 +855,16 @@
 static int     wm_kmrn_readreg_locked(struct wm_softc *, int, uint16_t *);
 static int     wm_kmrn_writereg(struct wm_softc *, int, uint16_t);
 static int     wm_kmrn_writereg_locked(struct wm_softc *, int, uint16_t);
+/* EMI register related */
+static int     wm_access_emi_reg_locked(device_t, int, uint16_t *, bool);
+static int     wm_read_emi_reg_locked(device_t, int, uint16_t *);
+static int     wm_write_emi_reg_locked(device_t, int, uint16_t);
 /* SGMII */
 static bool    wm_sgmii_uses_mdio(struct wm_softc *);
 static int     wm_sgmii_readreg(device_t, int, int);
+static int     wm_sgmii_readreg_locked(device_t, int, int, uint16_t *);
 static void    wm_sgmii_writereg(device_t, int, int, int);
+static int     wm_sgmii_writereg_locked(device_t, int, int, uint16_t);
 /* TBI related */
 static bool    wm_tbi_havesignal(struct wm_softc *, uint32_t);
 static void    wm_tbi_mediainit(struct wm_softc *);
@@ -967,7 +976,9 @@
 /* LPLU (Low Power Link Up) */
 static void    wm_lplu_d0_disable(struct wm_softc *);
 /* EEE */
-static void    wm_set_eee_i350(struct wm_softc *);
+static int     wm_set_eee_i350(struct wm_softc *);
+static int     wm_set_eee_pchlan(struct wm_softc *);
+static int     wm_set_eee(struct wm_softc *);
 
 /*
  * Workarounds (mainly PHY related).
@@ -2758,12 +2769,22 @@
                        sc->sc_mediatype = WM_MEDIATYPE_COPPER;
                }
        }
-       snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags);
-       aprint_verbose_dev(sc->sc_dev, "%s\n", buf);
+
+       if (sc->sc_type >= WM_T_PCH2)
+               sc->sc_flags |= WM_F_EEE;
+       else if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211)
+           && (sc->sc_mediatype == WM_MEDIATYPE_COPPER)) {
+               /* XXX: Need special handling for I354. (not yet) */
+               if (sc->sc_type != WM_T_I354)
+                       sc->sc_flags |= WM_F_EEE;
+       }
 
        /* Set device properties (macflags) */
        prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
 
+       snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags);
+       aprint_verbose_dev(sc->sc_dev, "%s\n", buf);
+
        /* Initialize the media structures accordingly. */
        if (sc->sc_mediatype == WM_MEDIATYPE_COPPER)
                wm_gmii_mediainit(sc, wmp->wmp_product);
@@ -2854,6 +2875,9 @@
                sc->sc_ethercom.ec_capabilities |=
                    ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING;
 
+       if ((sc->sc_flags & WM_F_EEE) != 0)
+               sc->sc_ethercom.ec_capabilities |= ETHERCAP_EEE;
+
        /*
         * We can perform TCPv4 and UDPv4 checkums in-bound.  Only
         * on i82543 and later.
@@ -3256,6 +3280,8 @@
 {
        struct ifnet *ifp = &ec->ec_if;
        struct wm_softc *sc = ifp->if_softc;
+       int iffchange, ecchange;
+       bool needreset = false;
        int rc = 0;
 
        DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
@@ -3263,20 +3289,38 @@
 
        WM_CORE_LOCK(sc);
 
-       int change = ifp->if_flags ^ sc->sc_if_flags;
+       /*
+        * Check for if_flags.
+        * Main usage is to prevent linkdown when opening bpf.
+        */
+       iffchange = ifp->if_flags ^ sc->sc_if_flags;
        sc->sc_if_flags = ifp->if_flags;
-
-       if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
-               rc = ENETRESET;
-               goto out;
-       }
-
-       if ((change & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
+       if ((iffchange & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
+               needreset = true;
+               goto ec;
+       }
+
+       /* iff related updates */
+       if ((iffchange & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
                wm_set_filter(sc);
 
        wm_set_vlan(sc);
 
+ec:
+       /* Check for ec_capenable. */
+       ecchange = ec->ec_capenable ^ sc->sc_ec_capenable;
+       sc->sc_ec_capenable = ec->ec_capenable;
+       if ((ecchange & ~ETHERCAP_EEE) != 0) {
+               needreset = true;
+               goto out;
+       }
+
+       /* ec related updates */
+       wm_set_eee(sc);
+       
 out:
+       if (needreset)
+               rc = ENETRESET;
        WM_CORE_UNLOCK(sc);
 
        return rc;
@@ -4992,13 +5036,7 @@
        /* reload sc_ctrl */
        sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
 
-       if (sc->sc_type == WM_T_I354) {
-#if 0
-               /* I354 uses an external PHY */
-               wm_set_eee_i354(sc);
-#endif
-       } else if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))
-               wm_set_eee_i350(sc);
+       wm_set_eee(sc);
 
        /*
         * For PCH, this write will make sure that any noise will be detected
@@ -5624,6 +5662,7 @@
 wm_init_locked(struct ifnet *ifp)
 {
        struct wm_softc *sc = ifp->if_softc;
+       struct ethercom *ec = &sc->sc_ethercom;
        int i, j, trynum, error = 0;
        uint32_t reg;
 
@@ -6098,7 +6137,7 @@
            || (sc->sc_type == WM_T_I210))
                sc->sc_rctl |= RCTL_SECRC;
 
-       if (((sc->sc_ethercom.ec_capabilities & ETHERCAP_JUMBO_MTU) != 0)
+       if (((ec->ec_capabilities & ETHERCAP_JUMBO_MTU) != 0)
            && (ifp->if_mtu > ETHERMTU)) {
                sc->sc_rctl |= RCTL_LPE;
                if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
@@ -6181,7 +6220,9 @@
        ifp->if_flags &= ~IFF_OACTIVE;
 
  out:
+       /* Save last flags for the callback */
        sc->sc_if_flags = ifp->if_flags;
+       sc->sc_ec_capenable = ec->ec_capenable;
        if (error)
                log(LOG_ERR, "%s: interface not running\n",
                    device_xname(sc->sc_dev));
@@ -9002,6 +9043,9 @@
                            ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
                }
 
+               /* Clear link partner's EEE ability */
+               sc->eee_lp_ability = 0;
+
                /* FEXTNVM6 K1-off workaround */
                if (sc->sc_type == WM_T_PCH_SPT) {
                        reg = CSR_READ(sc, WMREG_FEXTNVM6);
@@ -9027,6 +9071,11 @@
                default:
                        break;
                }
+
+               /* Enable/Disable EEE after link up */
+               if (sc->sc_phytype > WMPHY_82579)
+                       wm_set_eee_pchlan(sc);
+
        } else if (icr & ICR_RXSEQ) {
                DPRINTF(WM_DEBUG_LINK, ("%s: LINK Receive sequence error\n",
                        device_xname(sc->sc_dev)));
@@ -9932,6 +9981,9 @@
        if (new_readreg == wm_gmii_hv_readreg) {
                sc->phy.readreg_locked = wm_gmii_hv_readreg_locked;
                sc->phy.writereg_locked = wm_gmii_hv_writereg_locked;
+       } else if (new_readreg == wm_sgmii_readreg) {
+               sc->phy.readreg_locked = wm_sgmii_readreg_locked;
+               sc->phy.writereg_locked = wm_sgmii_writereg_locked;
        } else if (new_readreg == wm_gmii_i82544_readreg) {
                sc->phy.readreg_locked = wm_gmii_i82544_readreg_locked;
                sc->phy.writereg_locked = wm_gmii_i82544_writereg_locked;
@@ -11286,6 +11338,41 @@
        return 0;
 }
 
+/*
+ * EMI register related (82579, WMPHY_I217(PCH2 and newer))
+ * This access method is different from IEEE MMD.
+ */
+static int
+wm_access_emi_reg_locked(device_t dev, int reg, uint16_t *val, bool rd)
+{
+       struct wm_softc *sc = device_private(dev);
+       int rv;
+
+       rv = sc->phy.writereg_locked(dev, 2, I82579_EMI_ADDR, reg);
+       if (rv != 0)
+               return rv;
+
+       if (rd)
+               rv = sc->phy.readreg_locked(dev, 2, I82579_EMI_DATA, val);
+       else
+               rv = sc->phy.writereg_locked(dev, 2, I82579_EMI_DATA, *val);
+       return rv;
+}
+
+static int
+wm_read_emi_reg_locked(device_t dev, int reg, uint16_t *val)
+{
+
+       return wm_access_emi_reg_locked(dev, reg, val, true);
+}
+
+static int
+wm_write_emi_reg_locked(device_t dev, int reg, uint16_t val)
+{
+
+       return wm_access_emi_reg_locked(dev, reg, &val, false);
+}
+
 /* SGMII related */
 
 /*



Home | Main Index | Thread Index | Old Index