[patch] WOL support for nfe(4)

Yamagi Burmeister lists at yamagi.org
Fri Nov 5 10:10:52 UTC 2010


Hi,

some time ago we migrated a lot of boxes from Linux to FreeBSD. Those
machines have a "NVIDIA nForce4 CK804 MCP4" network adapter, supported
by nfe(4). Even if nfe(4) at least tries to enable the WOL capability of
the NIC it doesn't work and nfe(4) doesn't integrate with FreeBSDs (new)
WOL framework. Since we are in need of WOL I spend some minutes to
implement it the correct way.

Attached are two patches:
- if_nfe_wol_8.1.diff against FreeBSD 8.1-RELEASE-p1, this one is used
   on our servers.
- if_nfe_wol_current.diff against -CURRENT r214831. This one is
   _untested_! But it should work...

In case that the patches a stripped by mailman they can be found here:
http://deponie.yamagi.org/freebsd/nfe/

This patch works reliable on our machines and nfe(4) runs without any
problems with it. But nevertheless my skills in writting network drivers
are somewhat limited therefor a review by somewhat with better knowledge
of the WOL framework and maybe nfe(4) itself is highly anticipated.

Ciao,
Yamagi

-- 
Homepage:     www.yamagi.org
Jabber:       yamagi at yamagi.org
GnuPG/GPG:    0xEFBCCBCB
-------------- next part --------------
--- if_nfe.c	2010-11-05 10:41:04.672351879 +0100
+++ if_nfe.c	2010-11-05 10:41:09.259689584 +0100
@@ -125,6 +125,7 @@
 static void nfe_sysctl_node(struct nfe_softc *);
 static void nfe_stats_clear(struct nfe_softc *);
 static void nfe_stats_update(struct nfe_softc *);
+static void nfe_enable_wol(struct nfe_softc *);
 
 #ifdef NFE_DEBUG
 static int nfedebug = 0;
@@ -599,6 +600,10 @@
 	ifp->if_capabilities |= IFCAP_POLLING;
 #endif
 
+	/* Wake on LAN support */
+	ifp->if_capabilities |= IFCAP_WOL_MAGIC;
+	ifp->if_capenable = ifp->if_capabilities;
+
 	/* Do MII setup */
 	error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd,
 	    nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
@@ -769,6 +774,10 @@
 
 	NFE_LOCK(sc);
 	ifp = sc->nfe_ifp;
+
+	/* Disable WOL bits */
+	NFE_WRITE(sc, NFE_WOL_CTL, 0);
+
 	if (ifp->if_flags & IFF_UP)
 		nfe_init_locked(sc);
 	sc->nfe_suspended = 0;
@@ -1752,6 +1761,12 @@
 				ifp->if_hwassist &= ~CSUM_TSO;
 		}
 
+		if ((mask & IFCAP_WOL) != 0 &&
+			(ifp->if_capabilities & IFCAP_WOL) != 0) {
+				if ((mask & IFCAP_WOL_MAGIC) != 0)
+					ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+		}
+
 		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 			nfe_init(sc);
@@ -2746,7 +2761,6 @@
 	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
 
 	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
-	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
 
 	sc->rxtxctl &= ~NFE_RXTX_BIT2;
 	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
@@ -2806,12 +2820,6 @@
 	/* abort Tx */
 	NFE_WRITE(sc, NFE_TX_CTL, 0);
 
-	/* disable Rx */
-	NFE_WRITE(sc, NFE_RX_CTL, 0);
-
-	/* disable interrupts */
-	nfe_disable_intr(sc);
-
 	sc->nfe_link = 0;
 
 	/* free Rx and Tx mbufs still in the queues. */
@@ -2923,9 +2931,12 @@
 	sc = device_get_softc(dev);
 
 	NFE_LOCK(sc);
+	nfe_enable_wol(sc);
+	NFE_UNLOCK(sc);
+
+	NFE_LOCK(sc);
 	ifp = sc->nfe_ifp;
 	nfe_stop(ifp);
-	/* nfe_reset(sc); */
 	NFE_UNLOCK(sc);
 
 	return (0);
@@ -3212,3 +3223,17 @@
 		stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
 	}
 }
+
+static void
+nfe_enable_wol(struct nfe_softc *sc)
+{
+	struct ifnet *ifp;
+
+	NFE_LOCK_ASSERT(sc);
+
+	ifp = sc->nfe_ifp;
+
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
+}
+
-------------- next part --------------
--- if_nfe.c	2010-11-05 10:36:43.300738161 +0100
+++ if_nfe.c	2010-11-05 10:39:04.712603916 +0100
@@ -125,6 +125,7 @@
 static void nfe_sysctl_node(struct nfe_softc *);
 static void nfe_stats_clear(struct nfe_softc *);
 static void nfe_stats_update(struct nfe_softc *);
+static void nfe_enable_wol(struct nfe_softc *);
 
 #ifdef NFE_DEBUG
 static int nfedebug = 0;
@@ -600,6 +601,10 @@
 	ifp->if_capabilities |= IFCAP_POLLING;
 #endif
 
+	/* Wake on LAN support */
+	ifp->if_capabilities |= IFCAP_WOL_MAGIC;
+	ifp->if_capenable = ifp->if_capabilities;
+
 	/* Do MII setup */
 	if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd,
 	    nfe_ifmedia_sts)) {
@@ -770,6 +775,10 @@
 
 	NFE_LOCK(sc);
 	ifp = sc->nfe_ifp;
+
+	/* Disable WOL bits */
+	NFE_WRITE(sc, NFE_WOL_CTL, 0);
+
 	if (ifp->if_flags & IFF_UP)
 		nfe_init_locked(sc);
 	sc->nfe_suspended = 0;
@@ -1753,6 +1762,12 @@
 				ifp->if_hwassist &= ~CSUM_TSO;
 		}
 
+		if ((mask & IFCAP_WOL) != 0 &&
+			(ifp->if_capabilities & IFCAP_WOL) != 0) {
+				if ((mask & IFCAP_WOL_MAGIC) != 0)
+					ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+		}
+
 		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 			nfe_init(sc);
@@ -2747,7 +2762,6 @@
 	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
 
 	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
-	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
 
 	sc->rxtxctl &= ~NFE_RXTX_BIT2;
 	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
@@ -2807,12 +2821,6 @@
 	/* abort Tx */
 	NFE_WRITE(sc, NFE_TX_CTL, 0);
 
-	/* disable Rx */
-	NFE_WRITE(sc, NFE_RX_CTL, 0);
-
-	/* disable interrupts */
-	nfe_disable_intr(sc);
-
 	sc->nfe_link = 0;
 
 	/* free Rx and Tx mbufs still in the queues. */
@@ -2924,9 +2932,12 @@
 	sc = device_get_softc(dev);
 
 	NFE_LOCK(sc);
+	nfe_enable_wol(sc);
+	NFE_UNLOCK(sc);
+
+	NFE_LOCK(sc);
 	ifp = sc->nfe_ifp;
 	nfe_stop(ifp);
-	/* nfe_reset(sc); */
 	NFE_UNLOCK(sc);
 
 	return (0);
@@ -3213,3 +3224,17 @@
 		stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
 	}
 }
+
+static void
+nfe_enable_wol(struct nfe_softc *sc)
+{
+	struct ifnet *ifp;
+
+	NFE_LOCK_ASSERT(sc);
+
+	ifp = sc->nfe_ifp;
+
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
+}
+


More information about the freebsd-net mailing list