Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Nov 2010 17:14:10 -0800
From:      Pyun YongHyeon <pyunyh@gmail.com>
To:        Yamagi Burmeister <lists@yamagi.org>
Cc:        freebsd-net@freebsd.org
Subject:   Re: [patch] WOL support for nfe(4)
Message-ID:  <20101109011410.GB1275@michelle.cdnetworks.com>
In-Reply-To: <alpine.BSF.2.00.1011051057350.9984@saya.home.yamagi.org>
References:  <alpine.BSF.2.00.1011051057350.9984@saya.home.yamagi.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--HcAYCG3uE/tztfnV
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Nov 05, 2010 at 11:10:37AM +0100, Yamagi Burmeister wrote:
> 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.
> 

Thanks for the patch. I attached slightly modified the code to
better match other WOL capable drivers in tree. Because data sheet
is not available I blindly made a patch based on your code. I have
a couple of questions which I can't verify it on real hardware(I
have no more access to the hardware).

o If you established a gigabit link with link partner and shutdown
  your box, does the established link automatically change to 10 or
  100Mbps? You can check it on your link partner. If your link
  partner still reports it established 1000Mbps link, we have to
  do other necessary work in driver(i.e. manually switching to
  10/100Mbps).
o When you put your box into suspend mode, can you wake up your box
  with WOL magic packet?
o When your system boots up with/without WOL magic packet, sending
  WOL magic packets from other hosts can hang your box?
o If you disabled WOL with ifconfig before system shutdown, can you
  still wakeup your box with WOL magic packet?
o If you reprogram your station address with ifconfig(i.e. ifconfig
  nfe0 ether xx:xx:xx:xx:xx:xx), can you still wakeup your box with
  WOL magic packet?

The patch I made didn't take into account management firmware so
if you use the patch with IMPI, IMPI wouldn't work. But I think
that's not an issue since all other parts of nfe(4) also ignores
management firmware at this moment.

--HcAYCG3uE/tztfnV
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="nfe.wol.patch"

Index: sys/dev/nfe/if_nfe.c
===================================================================
--- sys/dev/nfe/if_nfe.c	(revision 214989)
+++ sys/dev/nfe/if_nfe.c	(working copy)
@@ -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_set_wol(struct nfe_softc *);
 
 #ifdef NFE_DEBUG
 static int nfedebug = 0;
@@ -586,6 +587,9 @@
 		if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0)
 			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
 	}
+
+	if (pci_find_extcap(dev, PCIY_PMG, &reg) == 0)
+		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
 	ifp->if_capenable = ifp->if_capabilities;
 
 	/*
@@ -752,6 +756,7 @@
 
 	NFE_LOCK(sc);
 	nfe_stop(sc->nfe_ifp);
+	nfe_set_wol(sc);
 	sc->nfe_suspended = 1;
 	NFE_UNLOCK(sc);
 
@@ -768,6 +773,7 @@
 	sc = device_get_softc(dev);
 
 	NFE_LOCK(sc);
+	nfe_power(sc);
 	ifp = sc->nfe_ifp;
 	if (ifp->if_flags & IFF_UP)
 		nfe_init_locked(sc);
@@ -1714,6 +1720,10 @@
 			}
 		}
 #endif /* DEVICE_POLLING */
+		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
+		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
+			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+
 		if ((sc->nfe_flags & NFE_HW_CSUM) != 0 &&
 		    (mask & IFCAP_HWCSUM) != 0) {
 			ifp->if_capenable ^= IFCAP_HWCSUM;
@@ -2746,7 +2756,8 @@
 	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);
+	/* Disable WOL. */
+	NFE_WRITE(sc, NFE_WOL_CTL, 0);
 
 	sc->rxtxctl &= ~NFE_RXTX_BIT2;
 	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
@@ -2917,18 +2928,8 @@
 static int
 nfe_shutdown(device_t dev)
 {
-	struct nfe_softc *sc;
-	struct ifnet *ifp;
 
-	sc = device_get_softc(dev);
-
-	NFE_LOCK(sc);
-	ifp = sc->nfe_ifp;
-	nfe_stop(ifp);
-	/* nfe_reset(sc); */
-	NFE_UNLOCK(sc);
-
-	return (0);
+	return (nfe_suspend(dev));
 }
 
 
@@ -3212,3 +3213,39 @@
 		stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
 	}
 }
+
+static void
+nfe_set_wol(struct nfe_softc *sc)
+{
+	struct ifnet *ifp;
+	uint32_t wolctl;
+	int pmc;
+	uint16_t pmstat;
+
+	NFE_LOCK_ASSERT(sc);
+
+	if (pci_find_extcap(sc->nfe_dev, PCIY_PMG, &pmc) != 0)
+		return;
+	ifp = sc->nfe_ifp;
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		wolctl = NFE_WOL_MAGIC;
+	else
+		wolctl = 0;
+	NFE_WRITE(sc, NFE_WOL_CTL, wolctl);
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) {
+		if ((sc->nfe_flags & NFE_PWR_MGMT) != 0)
+			NFE_WRITE(sc, NFE_PWR2_CTL,
+			    NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS);
+		/* Enable RX. */
+		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0);
+		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0);
+		NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) |
+		    NFE_RX_START);
+	}
+	/* Request PME if WOL is requested. */
+	pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2);
+	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
+	if ((ifp->if_capenable & IFCAP_WOL) != 0)
+		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+	pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
+}
Index: sys/dev/nfe/if_nfereg.h
===================================================================
--- sys/dev/nfe/if_nfereg.h	(revision 214989)
+++ sys/dev/nfe/if_nfereg.h	(working copy)
@@ -190,6 +190,7 @@
 
 #define	NFE_PWR2_WAKEUP_MASK	0x0f11
 #define	NFE_PWR2_REVA3		(1 << 0)
+#define	NFE_PWR2_GATE_CLOCKS	0x0f00
 
 #define	NFE_MEDIA_SET		0x10000
 #define	NFE_MEDIA_1000T		0x00032

--HcAYCG3uE/tztfnV--



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