Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 5 Jan 2012 00:01:50 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r229542 - stable/7/sys/dev/vge
Message-ID:  <201201050001.q0501oem005097@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Thu Jan  5 00:01:49 2012
New Revision: 229542
URL: http://svn.freebsd.org/changeset/base/229542

Log:
  MFC r227828,227835,227837:
  r227828:
    Always start MII auto polling before accessing any MII registers.
  
  r227835:
    Rework link establishment and link state detection logic.
     - Remove MIIBUS statchg callback and program VGE_DIAGCTL before
       initiating link establishment.  Previously driver used to
       program VGE_DIAGCTL after getting a link in statchg callback.
       It seems the VGE_DIAGCTL register works like a kind of MII
       register such that it requires setting a 'to be' mode in advance
       rather than relying on resolved speed/duplex of established link.
       This means the statchg callback is not needed in driver.  In
       addition, if there was no link at the time of media change, this
       was not called at all.
     - Introduce vge_ifmedia_upd_locked() to change current media to
       configured one.  Actual media change is performed only after PHY
       reset and VGE_DIAGCTL setup.
     - In WOL configuration, make sure to clear forced mode such that
       controller can rely on auto-negotiation.
     - Unlike most other drivers that use miibus(4), vge(4) used
       controller's auto-polling feature for link state tracking via
       interrupt.  This came from controller's inefficient mechanism to
       access MII registers.  On link state change interrupt, vge(4)
       used to get current link state with series of MII register
       accesses.  Because vge(4) already enabled auto polling, read PHY
       status register to resolved speed/duplex/flow control parameters.
  
    vge(4) still does not drive MII_TICK to reduce number of MII
    register accesses which in turn means the driver does not know the
    status of auto-negotiation.  This was a one of long standing
    issue of vge(4).  Probably driver may be able to implement a timer
    that keeps track of auto-negotiation state and restart
    auto-negotiation when driver couldn't establish a link within a
    specified period.  However the controller does not provide a
    reliable way to detect auto-negotiation failure so I'm not sure
    whether it's worth to implement it in driver.
  
    Alternatively driver can completely disable MII auto-polling and
    let miibus(4) poll link state by driving MII_TICK.  This may reduce
    unnecessary overhead of stopping/restarting MII auto-polling of
    controller.  Unfortunately it was known that some variants of
    controller does not work correctly if MII auto-polling is disabled.
  
  r227837:
    Announce flow control capability to underlying PHY driver.
    Pause timer value is initialized to 0xFFFF. Controller allows just
    4 different TX pause thresholds. The lowest possible threshold
    value looks too aggressive so use next available threshold value.

Modified:
  stable/7/sys/dev/vge/if_vge.c
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/vge/if_vge.c
==============================================================================
--- stable/7/sys/dev/vge/if_vge.c	Thu Jan  5 00:00:30 2012	(r229541)
+++ stable/7/sys/dev/vge/if_vge.c	Thu Jan  5 00:01:49 2012	(r229542)
@@ -173,6 +173,7 @@ static __inline void
 static void	vge_freebufs(struct vge_softc *);
 static void	vge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 static int	vge_ifmedia_upd(struct ifnet *);
+static int	vge_ifmedia_upd_locked(struct vge_softc *);
 static void	vge_init(void *);
 static void	vge_init_locked(struct vge_softc *);
 static void	vge_intr(void *);
@@ -180,7 +181,6 @@ static void	vge_intr_holdoff(struct vge_
 static int	vge_ioctl(struct ifnet *, u_long, caddr_t);
 static void	vge_link_statchg(void *);
 static int	vge_miibus_readreg(device_t, int, int);
-static void	vge_miibus_statchg(device_t);
 static int	vge_miibus_writereg(device_t, int, int, int);
 static void	vge_miipoll_start(struct vge_softc *);
 static void	vge_miipoll_stop(struct vge_softc *);
@@ -190,6 +190,7 @@ static void	vge_reset(struct vge_softc *
 static int	vge_rx_list_init(struct vge_softc *);
 static int	vge_rxeof(struct vge_softc *, int);
 static void	vge_rxfilter(struct vge_softc *);
+static void	vge_setmedia(struct vge_softc *);
 static void	vge_setvlan(struct vge_softc *);
 static void	vge_setwol(struct vge_softc *);
 static void	vge_start(struct ifnet *);
@@ -218,7 +219,6 @@ static device_method_t vge_methods[] = {
 	/* MII interface */
 	DEVMETHOD(miibus_readreg,	vge_miibus_readreg),
 	DEVMETHOD(miibus_writereg,	vge_miibus_writereg),
-	DEVMETHOD(miibus_statchg,	vge_miibus_statchg),
 
 	{ 0, 0 }
 };
@@ -1102,10 +1102,11 @@ vge_attach(device_t dev)
 		goto fail;
 	}
 
+	vge_miipoll_start(sc);
 	/* Do MII setup */
 	error = mii_attach(dev, &sc->vge_miibus, ifp, vge_ifmedia_upd,
 	    vge_ifmedia_sts, BMSR_DEFCAPMASK, sc->vge_phyaddr, MII_OFFSET_ANY,
-	    0);
+	    MIIF_DOPAUSE);
 	if (error != 0) {
 		device_printf(dev, "attaching PHYs failed\n");
 		goto fail;
@@ -1663,30 +1664,41 @@ vge_link_statchg(void *xsc)
 {
 	struct vge_softc *sc;
 	struct ifnet *ifp;
-	struct mii_data *mii;
+	uint8_t physts;
 
 	sc = xsc;
 	ifp = sc->vge_ifp;
 	VGE_LOCK_ASSERT(sc);
-	mii = device_get_softc(sc->vge_miibus);
 
-	mii_pollstat(mii);
-	if ((sc->vge_flags & VGE_FLAG_LINK) != 0) {
-		if (!(mii->mii_media_status & IFM_ACTIVE)) {
+	physts = CSR_READ_1(sc, VGE_PHYSTS0);
+	if ((physts & VGE_PHYSTS_RESETSTS) == 0) {
+		if ((physts & VGE_PHYSTS_LINK) == 0) {
 			sc->vge_flags &= ~VGE_FLAG_LINK;
 			if_link_state_change(sc->vge_ifp,
 			    LINK_STATE_DOWN);
-		}
-	} else {
-		if (mii->mii_media_status & IFM_ACTIVE &&
-		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+		} else {
 			sc->vge_flags |= VGE_FLAG_LINK;
 			if_link_state_change(sc->vge_ifp,
 			    LINK_STATE_UP);
+			CSR_WRITE_1(sc, VGE_CRC2, VGE_CR2_FDX_TXFLOWCTL_ENABLE |
+			    VGE_CR2_FDX_RXFLOWCTL_ENABLE);
+			if ((physts & VGE_PHYSTS_FDX) != 0) {
+				if ((physts & VGE_PHYSTS_TXFLOWCAP) != 0)
+					CSR_WRITE_1(sc, VGE_CRS2,
+					    VGE_CR2_FDX_TXFLOWCTL_ENABLE);
+				if ((physts & VGE_PHYSTS_RXFLOWCAP) != 0)
+					CSR_WRITE_1(sc, VGE_CRS2,
+					    VGE_CR2_FDX_RXFLOWCTL_ENABLE);
+			}
 			if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 				vge_start_locked(ifp);
 		}
 	}
+	/*
+	 * Restart MII auto-polling because link state change interrupt
+	 * will disable it.
+	 */
+	vge_miipoll_start(sc);
 }
 
 #ifdef DEVICE_POLLING
@@ -2029,6 +2041,7 @@ vge_init_locked(struct vge_softc *sc)
 	 */
 	vge_stop(sc);
 	vge_reset(sc);
+	vge_miipoll_start(sc);
 
 	/*
 	 * Initialize the RX and TX descriptors and mbufs.
@@ -2100,9 +2113,16 @@ vge_init_locked(struct vge_softc *sc)
 	vge_rxfilter(sc);
 	vge_setvlan(sc);
 
-	/* Enable flow control */
-
-	CSR_WRITE_1(sc, VGE_CRS2, 0x8B);
+	/* Initialize pause timer. */
+	CSR_WRITE_2(sc, VGE_TX_PAUSE_TIMER, 0xFFFF);
+	/*
+	 * Initialize flow control parameters.
+	 *  TX XON high threshold : 48
+	 *  TX pause low threshold : 24
+	 *  Disable hald-duplex flow control
+	 */
+	CSR_WRITE_1(sc, VGE_CRC2, 0xFF);
+	CSR_WRITE_1(sc, VGE_CRS2, VGE_CR2_XON_ENABLE | 0x0B);
 
 	/* Enable jumbo frame reception (if desired) */
 
@@ -2130,7 +2150,7 @@ vge_init_locked(struct vge_softc *sc)
 	CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK);
 
 	sc->vge_flags &= ~VGE_FLAG_LINK;
-	mii_mediachg(mii);
+	vge_ifmedia_upd_locked(sc);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@@ -2144,14 +2164,28 @@ static int
 vge_ifmedia_upd(struct ifnet *ifp)
 {
 	struct vge_softc *sc;
-	struct mii_data *mii;
 	int error;
 
 	sc = ifp->if_softc;
 	VGE_LOCK(sc);
+	error = vge_ifmedia_upd_locked(sc);
+	VGE_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+vge_ifmedia_upd_locked(struct vge_softc *sc)
+{
+	struct mii_data *mii;
+	struct mii_softc *miisc;
+	int error;
+
 	mii = device_get_softc(sc->vge_miibus);
+	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+		mii_phy_reset(miisc);
+	vge_setmedia(sc);
 	error = mii_mediachg(mii);
-	VGE_UNLOCK(sc);
 
 	return (error);
 }
@@ -2180,13 +2214,11 @@ vge_ifmedia_sts(struct ifnet *ifp, struc
 }
 
 static void
-vge_miibus_statchg(device_t dev)
+vge_setmedia(struct vge_softc *sc)
 {
-	struct vge_softc *sc;
 	struct mii_data *mii;
 	struct ifmedia_entry *ife;
 
-	sc = device_get_softc(dev);
 	mii = device_get_softc(sc->vge_miibus);
 	ife = mii->mii_media.ifm_cur;
 
@@ -2220,7 +2252,7 @@ vge_miibus_statchg(device_t dev)
 		}
 		break;
 	default:
-		device_printf(dev, "unknown media type: %x\n",
+		device_printf(sc->vge_dev, "unknown media type: %x\n",
 		    IFM_SUBTYPE(ife->ifm_media));
 		break;
 	}
@@ -2773,6 +2805,9 @@ vge_setlinkspeed(struct vge_softc *sc)
 			break;
 		}
 	}
+	/* Clear forced MAC speed/duplex configuration. */
+	CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE);
+	CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE);
 	vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_100T2CR, 0);
 	vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_ANAR,
 	    ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201050001.q0501oem005097>