Module Name: src
Committed By: msaitoh
Date: Tue Jun 2 14:19:26 UTC 2015
Modified Files:
src/sys/dev/pci: if_wm.c if_wmreg.h if_wmvar.h
Log Message:
Fix a lot of bugs to 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.
To generate a diff of this commit:
cvs rdiff -u -r1.324 -r1.325 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.72 -r1.73 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.24 -r1.25 src/sys/dev/pci/if_wmvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.324 src/sys/dev/pci/if_wm.c:1.325
--- src/sys/dev/pci/if_wm.c:1.324 Tue Jun 2 13:26:36 2015
+++ src/sys/dev/pci/if_wm.c Tue Jun 2 14:19:26 2015
@@ -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 @@ struct wm_softc {
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_txintr(struct wm_softc *)
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 @@ static int wm_intr(void *);
* 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 bool wm_sgmii_uses_mdio(struct wm
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_k1_gig_workaround_hv(stru
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 @@ wm_attach(device_t parent, device_t self
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 @@ wm_attach(device_t parent, device_t self
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 @@ wm_attach(device_t parent, device_t self
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 @@ wm_attach(device_t parent, device_t self
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 @@ wm_tick(void *arg)
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 @@ wm_reset(struct wm_softc *sc)
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 @@ wm_reset(struct wm_softc *sc)
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 @@ wm_reset(struct wm_softc *sc)
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 @@ wm_linkintr_tbi(struct wm_softc *sc, uin
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_tbi(struct wm_softc *sc, uin
}
/*
+ * 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 @@ wm_linkintr(struct wm_softc *sc, uint32_
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);
}
@@ -6118,6 +6225,28 @@ wm_intr(void *arg)
* GMII, SGMII, TBI (and SERDES)
*/
+/* Common */
+
+/*
+ * wm_tbi_serdes_set_linkled:
+ *
+ * Update the link LED on TBI and SERDES devices.
+ */
+static void
+wm_tbi_serdes_set_linkled(struct wm_softc *sc)
+{
+
+ if (sc->sc_tbi_linkup)
+ sc->sc_ctrl |= CTRL_SWDPIN(0);
+ else
+ sc->sc_ctrl &= ~CTRL_SWDPIN(0);
+
+ /* 82540 or newer devices are active low */
+ sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
+
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+}
+
/* GMII related */
/*
@@ -7498,14 +7627,19 @@ wm_tbi_mediainit(struct wm_softc *sc)
else
sc->sc_tipg = TIPG_LG_DFLT;
- sc->sc_tbi_anegticks = 5;
+ sc->sc_tbi_serdes_anegticks = 5;
/* Initialize our media structures */
sc->sc_mii.mii_ifp = ifp;
-
sc->sc_ethercom.ec_mii = &sc->sc_mii;
- ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange,
- wm_tbi_mediastatus);
+
+ if ((sc->sc_type >= WM_T_82575)
+ && (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
+ ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+ wm_serdes_mediachange, wm_serdes_mediastatus);
+ else
+ ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+ wm_tbi_mediachange, wm_tbi_mediastatus);
/*
* SWD Pins:
@@ -7514,7 +7648,11 @@ wm_tbi_mediainit(struct wm_softc *sc)
* 1 = Loss Of Signal (input)
*/
sc->sc_ctrl |= CTRL_SWDPIO(0);
- sc->sc_ctrl &= ~CTRL_SWDPIO(1);
+
+ /* XXX Perhaps this is only for TBI */
+ if (sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+ sc->sc_ctrl &= ~CTRL_SWDPIO(1);
+
if (sc->sc_mediatype == WM_MEDIATYPE_SERDES)
sc->sc_ctrl &= ~CTRL_LRST;
@@ -7558,15 +7696,16 @@ wm_tbi_mediachange(struct ifnet *ifp)
uint32_t status;
int i;
- if (sc->sc_mediatype == WM_MEDIATYPE_SERDES)
- return 0;
+ if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
+ /* XXX need some work for >= 82571 and < 82575 */
+ if (sc->sc_type < WM_T_82575)
+ return 0;
+ }
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);
- /* XXX power_up_serdes_link_82575() */
-
sc->sc_ctrl &= ~CTRL_LRST;
sc->sc_txcw = TXCW_ANE;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
@@ -7650,7 +7789,7 @@ wm_tbi_mediachange(struct ifnet *ifp)
sc->sc_tbi_linkup = 0;
}
- wm_tbi_set_linkled(sc);
+ wm_tbi_serdes_set_linkled(sc);
return 0;
}
@@ -7692,7 +7831,7 @@ wm_tbi_mediastatus(struct ifnet *ifp, st
ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
}
-/* XXX Currently TBI only */
+/* XXX TBI only */
static int
wm_check_for_link(struct wm_softc *sc)
{
@@ -7703,8 +7842,11 @@ wm_check_for_link(struct wm_softc *sc)
uint32_t sig;
if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
- sc->sc_tbi_linkup = 1;
- return 0;
+ /* XXX need some work for >= 82571 */
+ if (sc->sc_type >= WM_T_82571) {
+ sc->sc_tbi_linkup = 1;
+ return 0;
+ }
}
rxcw = CSR_READ(sc, WMREG_RXCW);
@@ -7769,43 +7911,20 @@ wm_check_for_link(struct wm_softc *sc)
}
/*
- * wm_tbi_set_linkled:
+ * wm_tbi_tick:
*
- * Update the link LED on 1000BASE-X devices.
+ * Check the link on TBI devices.
+ * This function acts as mii_tick().
*/
static void
-wm_tbi_set_linkled(struct wm_softc *sc)
+wm_tbi_tick(struct wm_softc *sc)
{
-
- if (sc->sc_tbi_linkup)
- sc->sc_ctrl |= CTRL_SWDPIN(0);
- else
- sc->sc_ctrl &= ~CTRL_SWDPIN(0);
-
- /* 82540 or newer devices are active low */
- sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
-
- CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
-}
-
-/*
- * wm_tbi_check_link:
- *
- * Check the link on 1000BASE-X devices.
- */
-static void
-wm_tbi_check_link(struct wm_softc *sc)
-{
- struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+ struct mii_data *mii = &sc->sc_mii;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
uint32_t status;
KASSERT(WM_TX_LOCKED(sc));
- if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) {
- sc->sc_tbi_linkup = 1;
- return;
- }
-
status = CSR_READ(sc, WMREG_STATUS);
/* XXX is this needed? */
@@ -7824,36 +7943,225 @@ wm_tbi_check_link(struct wm_softc *sc)
device_xname(sc->sc_dev),
(status & STATUS_FD) ? "FDX" : "HDX"));
sc->sc_tbi_linkup = 1;
+ sc->sc_tbi_serdes_ticks = 0;
}
- if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP)
- && ((status & STATUS_LU) == 0)) {
+ if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP) == 0)
+ goto setled;
+
+ if ((status & STATUS_LU) == 0) {
sc->sc_tbi_linkup = 0;
- if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
- /* If the timer expired, retry autonegotiation */
- if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) {
- DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
- sc->sc_tbi_ticks = 0;
- /*
- * Reset the link, and let autonegotiation do
- * its thing
- */
- sc->sc_ctrl |= CTRL_LRST;
- CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
- CSR_WRITE_FLUSH(sc);
- delay(1000);
- sc->sc_ctrl &= ~CTRL_LRST;
- CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
- CSR_WRITE_FLUSH(sc);
- delay(1000);
- CSR_WRITE(sc, WMREG_TXCW,
- sc->sc_txcw & ~TXCW_ANE);
- CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
- }
+ /* If the timer expired, retry autonegotiation */
+ if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
+ && (++sc->sc_tbi_serdes_ticks
+ >= sc->sc_tbi_serdes_anegticks)) {
+ DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+ sc->sc_tbi_serdes_ticks = 0;
+ /*
+ * Reset the link, and let autonegotiation do
+ * its thing
+ */
+ sc->sc_ctrl |= CTRL_LRST;
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+ CSR_WRITE_FLUSH(sc);
+ delay(1000);
+ sc->sc_ctrl &= ~CTRL_LRST;
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+ CSR_WRITE_FLUSH(sc);
+ delay(1000);
+ CSR_WRITE(sc, WMREG_TXCW,
+ sc->sc_txcw & ~TXCW_ANE);
+ CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
}
}
- wm_tbi_set_linkled(sc);
+setled:
+ wm_tbi_serdes_set_linkled(sc);
+}
+
+/* SERDES related */
+static void
+wm_serdes_power_up_link_82575(struct wm_softc *sc)
+{
+ uint32_t reg;
+
+ if ((sc->sc_mediatype != WM_MEDIATYPE_SERDES)
+ && ((sc->sc_flags & WM_F_SGMII) == 0))
+ return;
+
+ reg = CSR_READ(sc, WMREG_PCS_CFG);
+ reg |= PCS_CFG_PCS_EN;
+ CSR_WRITE(sc, WMREG_PCS_CFG, reg);
+
+ reg = CSR_READ(sc, WMREG_CTRL_EXT);
+ reg &= ~CTRL_EXT_SWDPIN(3);
+ CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+ CSR_WRITE_FLUSH(sc);
+}
+
+static int
+wm_serdes_mediachange(struct ifnet *ifp)
+{
+ struct wm_softc *sc = ifp->if_softc;
+ bool pcs_autoneg = true; /* XXX */
+ uint32_t ctrl_ext, pcs_lctl, reg;
+
+ /* 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);
+
+ 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:
+ pcs_autoneg = true;
+ pcs_lctl &= ~PCS_LCTL_AN_TIMEOUT;
+ break;
+ case CTRL_EXT_LINK_MODE_1000KX:
+ pcs_autoneg = false;
+ /* FALLTHROUGH */
+ default:
+ if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)){
+ if ((sc->sc_flags & WM_F_PCS_DIS_AUTONEGO) != 0)
+ pcs_autoneg = false;
+ }
+ sc->sc_ctrl |= CTRL_SPEED_1000 | CTRL_FRCSPD | CTRL_FD
+ | CTRL_FRCFDX;
+ pcs_lctl |= PCS_LCTL_FSV_1000 | PCS_LCTL_FDV_FULL;
+ }
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+
+ if (pcs_autoneg) {
+ pcs_lctl |= PCS_LCTL_AN_ENABLE | PCS_LCTL_AN_RESTART;
+ pcs_lctl &= ~PCS_LCTL_FORCE_FC;
+
+ reg = CSR_READ(sc, WMREG_PCS_ANADV);
+ reg &= ~(TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE);
+ reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE;
+ CSR_WRITE(sc, WMREG_PCS_ANADV, reg);
+ } else
+ pcs_lctl |= PCS_LCTL_FSD | PCS_LCTL_FORCE_FC;
+
+ CSR_WRITE(sc, WMREG_PCS_LCTL, pcs_lctl);
+
+
+ return 0;
+}
+
+static void
+wm_serdes_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct wm_softc *sc = ifp->if_softc;
+ 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;
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ /* Check PCS */
+ reg = CSR_READ(sc, WMREG_PCS_LSTS);
+ if ((reg & PCS_LSTS_LINKOK) == 0) {
+ ifmr->ifm_active |= IFM_NONE;
+ sc->sc_tbi_linkup = 0;
+ goto setled;
+ }
+
+ sc->sc_tbi_linkup = 1;
+ ifmr->ifm_status |= IFM_ACTIVE;
+ ifmr->ifm_active |= IFM_1000_SX; /* XXX */
+ if ((reg & PCS_LSTS_FDX) != 0)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+ mii->mii_media_active &= ~IFM_ETH_FMASK;
+ if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+ /* Check flow */
+ reg = CSR_READ(sc, WMREG_PCS_LSTS);
+ if ((reg & PCS_LSTS_AN_COMP) == 0) {
+ printf("XXX LINKOK but not ACOMP\n");
+ goto setled;
+ }
+ pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV);
+ pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB);
+ printf("XXX AN result(2) %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;
+ } else {
+ }
+ }
+ ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK)
+ | (mii->mii_media_active & IFM_ETH_FMASK);
+setled:
+ wm_tbi_serdes_set_linkled(sc);
+}
+
+/*
+ * wm_serdes_tick:
+ *
+ * Check the link on serdes devices.
+ */
+static void
+wm_serdes_tick(struct wm_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct mii_data *mii = &sc->sc_mii;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ uint32_t reg;
+
+ KASSERT(WM_TX_LOCKED(sc));
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ /* 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;
+ sc->sc_tbi_serdes_ticks = 0;
+ mii->mii_media_active |= IFM_1000_SX; /* XXX */
+ if ((reg & PCS_LSTS_FDX) != 0)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ } else {
+ mii->mii_media_status |= IFM_NONE;
+ sc->sc_tbi_linkup = 0;
+ /* If the timer expired, retry autonegotiation */
+ if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
+ && (++sc->sc_tbi_serdes_ticks
+ >= sc->sc_tbi_serdes_anegticks)) {
+ DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+ sc->sc_tbi_serdes_ticks = 0;
+ /* XXX */
+ wm_serdes_mediachange(ifp);
+ }
+ }
+
+ wm_tbi_serdes_set_linkled(sc);
}
/* SFP related */
@@ -9814,3 +10122,29 @@ wm_reset_init_script_82575(struct wm_sof
wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00);
wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
}
+
+static void
+wm_reset_mdicnfg_82580(struct wm_softc *sc)
+{
+ uint32_t reg;
+ uint16_t nvmword;
+ int rv;
+
+ if ((sc->sc_flags & WM_F_SGMII) == 0)
+ return;
+
+ rv = wm_nvm_read(sc, NVM_OFF_LAN_FUNC_82580(sc->sc_funcid)
+ + NVM_OFF_CFG3_PORTA, 1, &nvmword);
+ if (rv != 0) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n",
+ __func__);
+ return;
+ }
+
+ reg = CSR_READ(sc, WMREG_MDICNFG);
+ if (nvmword & NVM_CFG3_PORTA_EXT_MDIO)
+ reg |= MDICNFG_DEST;
+ if (nvmword & NVM_CFG3_PORTA_COM_MDIO)
+ reg |= MDICNFG_COM_MDIO;
+ CSR_WRITE(sc, WMREG_MDICNFG, reg);
+}
Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.72 src/sys/dev/pci/if_wmreg.h:1.73
--- src/sys/dev/pci/if_wmreg.h:1.72 Fri May 22 03:15:43 2015
+++ src/sys/dev/pci/if_wmreg.h Tue Jun 2 14:19:26 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.72 2015/05/22 03:15:43 msaitoh Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.73 2015/06/02 14:19:26 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -798,6 +798,28 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_TLPIC 0x4148 /* EEE Tx LPI Count */
#define WMREG_RLPIC 0x414c /* EEE Rx LPI Count */
+#define WMREG_PCS_CFG 0x4200 /* PCS Configuration */
+#define PCS_CFG_PCS_EN __BIT(3)
+
+#define WMREG_PCS_LCTL 0x4208 /* PCS Link Control */
+#define PCS_LCTL_FSV_1000 __BIT(2) /* AN Timeout Enable */
+#define PCS_LCTL_FDV_FULL __BIT(3) /* AN Timeout Enable */
+#define PCS_LCTL_FSD __BIT(4) /* AN Timeout Enable */
+#define PCS_LCTL_FORCE_FC __BIT(7) /* AN Timeout Enable */
+#define PCS_LCTL_AN_ENABLE __BIT(16) /* AN Timeout Enable */
+#define PCS_LCTL_AN_RESTART __BIT(17) /* AN Timeout Enable */
+#define PCS_LCTL_AN_TIMEOUT __BIT(18) /* AN Timeout Enable */
+
+#define WMREG_PCS_LSTS 0x420c /* PCS Link Status */
+#define PCS_LSTS_LINKOK __BIT(0)
+#define PCS_LSTS_SPEED_100 __BIT(1)
+#define PCS_LSTS_SPEED_1000 __BIT(2)
+#define PCS_LSTS_FDX __BIT(3)
+#define PCS_LSTS_AN_COMP __BIT(16)
+
+#define WMREG_PCS_ANADV 0x4218 /* AN Advertsement */
+#define WMREG_PCS_LPAB 0x421c /* Link Partnet Ability */
+
#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */
#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */
#define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */
@@ -981,6 +1003,8 @@ struct livengood_tcpip_ctxdesc {
#define NVM_CFG2_MNGM_NCSI 1
#define NVM_CFG2_MNGM_PT 2
+#define NVM_COMPAT_SERDES_FORCE_MODE __BIT(14) /* Don't use autonego */
+
#define NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM 0x0040
#define NVM_K1_CONFIG_ENABLE 0x01
@@ -992,6 +1016,8 @@ struct livengood_tcpip_ctxdesc {
#define NVM_3GIO_3_ASPM_MASK (0x3 << 2) /* Active State PM Support */
#define NVM_CFG3_APME (1U << 10)
+#define NVM_CFG3_PORTA_EXT_MDIO (1U << 2) /* External MDIO Interface */
+#define NVM_CFG3_PORTA_COM_MDIO (1U << 3) /* MDIO Interface is shared */
#define NVM_OFF_MACADDR_82571(x) (3 * (x))
Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.24 src/sys/dev/pci/if_wmvar.h:1.25
--- src/sys/dev/pci/if_wmvar.h:1.24 Sat May 16 22:41:59 2015
+++ src/sys/dev/pci/if_wmvar.h Tue Jun 2 14:19:26 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmvar.h,v 1.24 2015/05/16 22:41:59 msaitoh Exp $ */
+/* $NetBSD: if_wmvar.h,v 1.25 2015/06/02 14:19:26 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -97,6 +97,7 @@
#define WM_F_EEE 0x00400000 /* Energy Efficiency Ethernet */
#define WM_F_ATTACHED 0x00800000 /* attach() finished successfully */
#define WM_F_EEPROM_INVM 0x01000000 /* NVM is iNVM */
+#define WM_F_PCS_DIS_AUTONEGO 0x02000000 /* PCS Disable Autonego */
/*