Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci Fix a lot of bugs to make 82575 and newer's SERD...



details:   https://anonhg.NetBSD.org/src/rev/13833f27e7be
branches:  trunk
changeset: 338643:13833f27e7be
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Tue Jun 02 14:19:26 2015 +0000

description:
Fix a lot of bugs to make 82575 and newer's SERDES based systems work.
 - Add SERDES specific functions.
 - Fix IO pin configuration.
 - Reset autonego timer when link becomes up.

TODO:
 - Fix a bug that SFP ROM can't read.
 - Perhaps some work is required for 8257[12] serdes systems.
 - Remove duplicated code in TBI's link related functions.

diffstat:

 sys/dev/pci/if_wm.c    |  540 +++++++++++++++++++++++++++++++++++++++---------
 sys/dev/pci/if_wmreg.h |   28 ++-
 sys/dev/pci/if_wmvar.h |    3 +-
 3 files changed, 466 insertions(+), 105 deletions(-)

diffs (truncated from 828 to 300 lines):

diff -r 4a486920a1ca -r 13833f27e7be sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c       Tue Jun 02 14:07:48 2015 +0000
+++ b/sys/dev/pci/if_wm.c       Tue Jun 02 14:19:26 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wm.c,v 1.324 2015/06/02 13:26:36 msaitoh Exp $      */
+/*     $NetBSD: if_wm.c,v 1.325 2015/06/02 14:19:26 msaitoh Exp $      */
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -81,7 +81,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.324 2015/06/02 13:26:36 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.325 2015/06/02 14:19:26 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -392,8 +392,8 @@
        uint32_t sc_pba;                /* prototype PBA register */
 
        int sc_tbi_linkup;              /* TBI link status */
-       int sc_tbi_anegticks;           /* autonegotiation ticks */
-       int sc_tbi_ticks;               /* tbi ticks */
+       int sc_tbi_serdes_anegticks;    /* autonegotiation ticks */
+       int sc_tbi_serdes_ticks;        /* tbi ticks */
 
        int sc_mchash_type;             /* multicast filter offset */
 
@@ -595,6 +595,7 @@
 static void    wm_rxintr(struct wm_softc *);
 static void    wm_linkintr_gmii(struct wm_softc *, uint32_t);
 static void    wm_linkintr_tbi(struct wm_softc *, uint32_t);
+static void    wm_linkintr_serdes(struct wm_softc *, uint32_t);
 static void    wm_linkintr(struct wm_softc *, uint32_t);
 static int     wm_intr(void *);
 
@@ -602,6 +603,8 @@
  * Media related.
  * GMII, SGMII, TBI, SERDES and SFP.
  */
+/* Common */
+static void    wm_tbi_serdes_set_linkled(struct wm_softc *);
 /* GMII related */
 static void    wm_gmii_reset(struct wm_softc *);
 static int     wm_get_phy_id_82575(struct wm_softc *);
@@ -631,12 +634,16 @@
 static int     wm_sgmii_readreg(device_t, int, int);
 static void    wm_sgmii_writereg(device_t, int, int, int);
 /* TBI related */
-static int     wm_check_for_link(struct wm_softc *);
 static void    wm_tbi_mediainit(struct wm_softc *);
 static int     wm_tbi_mediachange(struct ifnet *);
 static void    wm_tbi_mediastatus(struct ifnet *, struct ifmediareq *);
-static void    wm_tbi_set_linkled(struct wm_softc *);
-static void    wm_tbi_check_link(struct wm_softc *);
+static int     wm_check_for_link(struct wm_softc *);
+static void    wm_tbi_tick(struct wm_softc *);
+/* SERDES related */
+static void    wm_serdes_power_up_link_82575(struct wm_softc *);
+static int     wm_serdes_mediachange(struct ifnet *);
+static void    wm_serdes_mediastatus(struct ifnet *, struct ifmediareq *);
+static void    wm_serdes_tick(struct wm_softc *);
 /* SFP related */
 static int     wm_sfp_read_data_byte(struct wm_softc *, uint16_t, uint8_t *);
 static uint32_t        wm_sfp_get_media_type(struct wm_softc *);
@@ -728,6 +735,7 @@
 static void    wm_set_mdio_slow_mode_hv(struct wm_softc *);
 static void    wm_configure_k1_ich8lan(struct wm_softc *, int);
 static void    wm_reset_init_script_82575(struct wm_softc *);
+static void    wm_reset_mdicnfg_82580(struct wm_softc *);
 
 CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@@ -1366,7 +1374,7 @@
        prop_data_t ea;
        prop_number_t pn;
        uint8_t enaddr[ETHER_ADDR_LEN];
-       uint16_t cfg1, cfg2, swdpin, io3;
+       uint16_t cfg1, cfg2, swdpin, nvmword;
        pcireg_t preg, memtype;
        uint16_t eeprom_data, apme_mask;
        bool force_clear_smbi;
@@ -2046,6 +2054,14 @@
                printf("WOL\n");
 #endif
 
+       if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
+               /* Check NVM for autonegotiation */
+               if (wm_nvm_read(sc, NVM_OFF_COMPAT, 1, &nvmword) == 0) {
+                       if ((nvmword & NVM_COMPAT_SERDES_FORCE_MODE) != 0)
+                               sc->sc_flags |= WM_F_PCS_DIS_AUTONEGO;
+               }
+       }
+
        /*
         * XXX need special handling for some multiple port cards
         * to disable a paticular port.
@@ -2067,17 +2083,37 @@
 
        if (cfg1 & NVM_CFG1_ILOS)
                sc->sc_ctrl |= CTRL_ILOS;
-       if (sc->sc_type >= WM_T_82544) {
-               sc->sc_ctrl |=
-                   ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) <<
-                   CTRL_SWDPIO_SHIFT;
-               sc->sc_ctrl |=
-                   ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) <<
-                   CTRL_SWDPINS_SHIFT;
-       } else {
-               sc->sc_ctrl |=
-                   ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) <<
-                   CTRL_SWDPIO_SHIFT;
+
+       /*
+        * XXX
+        * This code isn't correct because pin 2 and 3 are located
+        * in different position on newer chips. Check all datasheet.
+        *
+        * Until resolve this problem, check if a chip < 82580
+        */
+       if (sc->sc_type <= WM_T_82580) {
+               if (sc->sc_type >= WM_T_82544) {
+                       sc->sc_ctrl |=
+                           ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) <<
+                           CTRL_SWDPIO_SHIFT;
+                       sc->sc_ctrl |=
+                           ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) <<
+                           CTRL_SWDPINS_SHIFT;
+               } else {
+                       sc->sc_ctrl |=
+                           ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) <<
+                           CTRL_SWDPIO_SHIFT;
+               }
+       }
+
+       /* XXX For other than 82580? */
+       if (sc->sc_type == WM_T_82580) {
+               wm_nvm_read(sc, NVM_OFF_CFG3_PORTA, 1, &nvmword);
+               printf("CFG3 = %08x\n", (uint32_t)nvmword);
+               if (nvmword & __BIT(13)) {
+                       printf("SET ILOS\n");
+                       sc->sc_ctrl |= CTRL_ILOS;
+               }
        }
 
 #if 0
@@ -2255,8 +2291,8 @@
        switch (sc->sc_type) {
        case WM_T_82573:
                /* XXX limited to 9234 if ASPM is disabled */
-               wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &io3);
-               if ((io3 & NVM_3GIO_3_ASPM_MASK) != 0)
+               wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &nvmword);
+               if ((nvmword & NVM_3GIO_3_ASPM_MASK) != 0)
                        sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU;
                break;
        case WM_T_82571:
@@ -2655,8 +2691,11 @@
 
        if (sc->sc_flags & WM_F_HAS_MII)
                mii_tick(&sc->sc_mii);
+       else if ((sc->sc_type >= WM_T_82575)
+           && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
+               wm_serdes_tick(sc);
        else
-               wm_tbi_check_link(sc);
+               wm_tbi_tick(sc);
 
 out:
        WM_TX_UNLOCK(sc);
@@ -3772,9 +3811,7 @@
        switch (sc->sc_type) {
        case WM_T_82575:
        case WM_T_82576:
-#if 0 /* XXX */
        case WM_T_82580:
-#endif
        case WM_T_I350:
        case WM_T_I354:
        case WM_T_ICH8:
@@ -3782,11 +3819,7 @@
                if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
                        /* Not found */
                        sc->sc_flags |= WM_F_EEPROM_INVALID;
-                       if ((sc->sc_type == WM_T_82575)
-                           || (sc->sc_type == WM_T_82576)
-                           || (sc->sc_type == WM_T_82580)
-                           || (sc->sc_type == WM_T_I350)
-                           || (sc->sc_type == WM_T_I354))
+                       if (sc->sc_type == WM_T_82575)
                                wm_reset_init_script_82575(sc);
                }
                break;
@@ -3824,7 +3857,7 @@
        if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
                CSR_WRITE(sc, WMREG_WUC, 0);
 
-       /* XXX need special handling for 82580 */
+       wm_reset_mdicnfg_82580(sc);
 }
 
 /*
@@ -6015,7 +6048,8 @@
                            device_xname(sc->sc_dev)));
                        sc->sc_tbi_linkup = 0;
                }
-               wm_tbi_set_linkled(sc);
+               /* Update LED */
+               wm_tbi_serdes_set_linkled(sc);
        } else if (icr & ICR_RXSEQ) {
                DPRINTF(WM_DEBUG_LINK,
                    ("%s: LINK: Receive sequence error\n",
@@ -6024,6 +6058,76 @@
 }
 
 /*
+ * wm_linkintr_serdes:
+ *
+ *     Helper; handle link interrupts for TBI mode.
+ */
+static void
+wm_linkintr_serdes(struct wm_softc *sc, uint32_t icr)
+{
+       struct mii_data *mii = &sc->sc_mii;
+       struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+       uint32_t pcs_adv, pcs_lpab, reg;
+
+       DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev),
+               __func__));
+
+       if (icr & ICR_LSC) {
+               /* Check PCS */
+               reg = CSR_READ(sc, WMREG_PCS_LSTS);
+               if ((reg & PCS_LSTS_LINKOK) != 0) {
+                       mii->mii_media_status |= IFM_ACTIVE;
+                       sc->sc_tbi_linkup = 1;
+               } else {
+                       mii->mii_media_status |= IFM_NONE;
+                       sc->sc_tbi_linkup = 0;
+                       wm_tbi_serdes_set_linkled(sc);
+                       return;
+               }
+               mii->mii_media_active |= IFM_1000_SX;
+               if ((reg & PCS_LSTS_FDX) != 0)
+                       mii->mii_media_active |= IFM_FDX;
+               else
+                       mii->mii_media_active |= IFM_HDX;
+               if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+                       /* Check flow */
+                       reg = CSR_READ(sc, WMREG_PCS_LSTS);
+                       if ((reg & PCS_LSTS_AN_COMP) == 0) {
+                               DPRINTF(WM_DEBUG_LINK,
+                                   ("XXX LINKOK but not ACOMP\n"));
+                               return;
+                       }
+                       pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV);
+                       pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB);
+                       DPRINTF(WM_DEBUG_LINK,
+                           ("XXX AN result %08x, %08x\n", pcs_adv, pcs_lpab));
+                       if ((pcs_adv & TXCW_SYM_PAUSE)
+                           && (pcs_lpab & TXCW_SYM_PAUSE)) {
+                               mii->mii_media_active |= IFM_FLOW
+                                   | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
+                       } else if (((pcs_adv & TXCW_SYM_PAUSE) == 0)
+                           && (pcs_adv & TXCW_ASYM_PAUSE)
+                           && (pcs_lpab & TXCW_SYM_PAUSE)
+                           && (pcs_lpab & TXCW_ASYM_PAUSE))
+                               mii->mii_media_active |= IFM_FLOW
+                                   | IFM_ETH_TXPAUSE;
+                       else if ((pcs_adv & TXCW_SYM_PAUSE)
+                           && (pcs_adv & TXCW_ASYM_PAUSE)
+                           && ((pcs_lpab & TXCW_SYM_PAUSE) == 0)
+                           && (pcs_lpab & TXCW_ASYM_PAUSE))
+                               mii->mii_media_active |= IFM_FLOW
+                                   | IFM_ETH_RXPAUSE;
+               }
+               /* Update LED */
+               wm_tbi_serdes_set_linkled(sc);
+       } else {
+               DPRINTF(WM_DEBUG_LINK,
+                   ("%s: LINK: Receive sequence error\n",
+                   device_xname(sc->sc_dev)));
+       }
+}
+
+/*
  * wm_linkintr:
  *
  *     Helper; handle link interrupts.
@@ -6034,6 +6138,9 @@
 
        if (sc->sc_flags & WM_F_HAS_MII)
                wm_linkintr_gmii(sc, icr);
+       else if ((sc->sc_mediatype == WM_MEDIATYPE_SERDES)
+           && (sc->sc_type >= WM_T_82575))     
+               wm_linkintr_serdes(sc, icr);
        else
                wm_linkintr_tbi(sc, icr);
 }



Home | Main Index | Thread Index | Old Index