From nobody@FreeBSD.org  Sun Jun 20 16:40:11 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 620A5106566C
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 20 Jun 2010 16:40:11 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id B78FE8FC1A
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 20 Jun 2010 16:40:10 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o5KGeAJ9033640
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 20 Jun 2010 16:40:10 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o5KGeAvV033631;
	Sun, 20 Jun 2010 16:40:10 GMT
	(envelope-from nobody)
Message-Id: <201006201640.o5KGeAvV033631@www.freebsd.org>
Date: Sun, 20 Jun 2010 16:40:10 GMT
From: David Naylor <naylor.b.david@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [patch] add WoL support to rl(4)
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         148013
>Category:       kern
>Synopsis:       [rl] [patch] add WoL support to rl(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    yongari
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jun 20 16:50:01 UTC 2010
>Closed-Date:    Sun Aug 15 23:35:11 UTC 2010
>Last-Modified:  Sun Aug 15 23:35:11 UTC 2010
>Originator:     David Naylor
>Release:        FreeBSD-9
>Organization:
Private
>Environment:
FreeBSD dragon.dg 9.0-CURRENT FreeBSD 9.0-CURRENT #0: Sat Jun 19 19:08:38 SAST 2010     root@dragon.dg:/tmp/home/freebsd9/src/sys/DRAGON  amd64
>Description:
Add WoL support for the rl(4) driver.  The relevant portions were taken from the re(4) driver (the Linux drivers [1] [2]) also had the same implementations.  I removed what I considered irrelevant code for the rl(4) driver.  

I've tested this with 8139D.  DISCLAIMER: I have no experience with coding drivers (or anything in the kernel).  

[1] rl(4) equivalent*: http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.34.y.git;a=blob_plain;f=drivers/net/8139too.c;hb=HEAD
[2] re(4) equivalent*: http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.34.y.git;a=blob_plain;f=drivers/net/8139cp.c;hb=HEAD

*) see the *_set_wol() function.  
>How-To-Repeat:
n/a
>Fix:
n/a

Patch attached with submission follows:

--- /usr/src/sys/pci/if_rl.c	2010-06-20 18:25:03.000000000 +0200
+++ if_rl.c	2010-06-20 15:08:32.000000000 +0200
@@ -182,6 +182,7 @@
 };
 
 static int rl_attach(device_t);
+static void rl_clrwol(struct rl_softc *);
 static int rl_detach(device_t);
 static void rl_dmamap_cb(void *, bus_dma_segment_t *, int, int);
 static int rl_dma_alloc(struct rl_softc *);
@@ -214,6 +215,7 @@
 static int rl_resume(device_t);
 static int rl_rxeof(struct rl_softc *);
 static void rl_setmulti(struct rl_softc *);
+static void rl_setwol(struct rl_softc *);
 static int rl_shutdown(device_t);
 static void rl_start(struct ifnet *);
 static void rl_start_locked(struct ifnet *);
@@ -804,7 +806,7 @@
 	struct sysctl_ctx_list	*ctx;
 	struct sysctl_oid_list	*children;
 	int			error = 0, i, rid;
-	int			unit;
+	int			unit, reg;
 	uint16_t		rl_did = 0;
 	char			tn[32];
 
@@ -938,6 +940,16 @@
 	ifp->if_start = rl_start;
 	ifp->if_init = rl_init;
 	ifp->if_capabilities = IFCAP_VLAN_MTU;
+	/* Enable WOL if PM and chipset (810[01]/8130B?/8139[BCD]) supported. */
+	device_printf(sc->rl_dev, "RL_TYPE=0x%x\n", sc->rl_type);
+	device_printf(sc->rl_dev, "RL_HWREV=0x%x\n", CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV);
+	device_printf(sc->rl_dev, "PM=%d\n", pci_find_extcap(sc->rl_dev, PCIY_PMG, &reg));
+	if ((sc->rl_type == RL_8139) &&
+	    ((CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV) > RL_HWREV_8139AG) && 
+	    (pci_find_extcap(sc->rl_dev, PCIY_PMG, &reg) == 0)) {
+		ifp->if_capabilities |= IFCAP_WOL;
+		device_printf(sc->rl_dev, "IFCAP_WOL\n");
+	}
 	ifp->if_capenable = ifp->if_capabilities;
 #ifdef DEVICE_POLLING
 	ifp->if_capabilities |= IFCAP_POLLING;
@@ -2066,6 +2078,7 @@
 
 	RL_LOCK(sc);
 	rl_stop(sc);
+	rl_setwol(sc);
 	sc->suspended = 1;
 	RL_UNLOCK(sc);
 
@@ -2087,6 +2100,12 @@
 	ifp = sc->rl_ifp;
 
 	RL_LOCK(sc);
+        
+	/*
+	 * Clear WOL matching such that normal Rx filtering
+	 * wouldn't interfere with WOL patterns.
+	 */
+	rl_clrwol(sc);
 
 	/* reinitialize interface if necessary */
 	if (ifp->if_flags & IFF_UP)
@@ -2112,7 +2131,87 @@
 
 	RL_LOCK(sc);
 	rl_stop(sc);
+	/*
+	 * Mark interface as down since otherwise we will panic if
+	 * interrupt comes in later on, which can happen in some
+	 * cases.
+	 */
+	sc->rl_ifp->if_flags &= ~IFF_UP;
+	rl_setwol(sc);
 	RL_UNLOCK(sc);
 
 	return (0);
 }
+
+
+static void
+rl_setwol(struct rl_softc *sc)
+{
+	struct ifnet		*ifp;
+	int			pmc;
+	uint8_t			v;
+
+	RL_LOCK_ASSERT(sc);
+
+	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
+		return;
+
+	ifp = sc->rl_ifp;
+
+	/* Enable PME. */
+	v = CSR_READ_1(sc, RL_CFG1);
+	v &= ~RL_CFG1_PME;
+	if ((ifp->if_capenable & IFCAP_WOL) != 0)
+		v |= RL_CFG1_PME;
+	CSR_WRITE_1(sc, RL_CFG1, v);
+
+	v = CSR_READ_1(sc, RL_CFG3);
+	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		v |= RL_CFG3_WOL_MAGIC;
+	CSR_WRITE_1(sc, RL_CFG3, v);
+
+	/* Config register write done. */
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+
+	v = CSR_READ_1(sc, RL_CFG5);
+	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
+	v &= ~RL_CFG5_WOL_LANWAKE;
+	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
+		v |= RL_CFG5_WOL_UCAST;
+	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
+		v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
+	if ((ifp->if_capenable & IFCAP_WOL) != 0)
+		v |= RL_CFG5_WOL_LANWAKE;
+	CSR_WRITE_1(sc, RL_CFG5, v);
+	device_printf(sc->rl_dev, "WOL set: 0x%x\n", v);
+}
+
+static void
+rl_clrwol(struct rl_softc *sc)
+{
+	int			pmc;
+	uint8_t			v;
+	
+	RL_LOCK_ASSERT(sc);
+	
+	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
+		return;
+	
+	/* Enable config register write. */
+	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
+	
+	v = CSR_READ_1(sc, RL_CFG3);
+	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
+	CSR_WRITE_1(sc, RL_CFG3, v);
+
+	/* Config register write done. */
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+
+	v = CSR_READ_1(sc, RL_CFG5);
+	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
+	v &= ~RL_CFG5_WOL_LANWAKE;
+	CSR_WRITE_1(sc, RL_CFG5, v);
+	
+	device_printf(sc->rl_dev, "WOL cleared\n");
+}


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Jun 21 04:15:37 UTC 2010 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148013 
State-Changed-From-To: open->feedback 
State-Changed-By: yongari 
State-Changed-When: Tue Jul 6 00:23:06 UTC 2010 
State-Changed-Why:  
Would you try the following patch and let me know how it goes? 
http://people.freebsd.org/~yongari/rl.wol.patch 


Responsible-Changed-From-To: freebsd-net->yongari 
Responsible-Changed-By: yongari 
Responsible-Changed-When: Tue Jul 6 00:23:06 UTC 2010 
Responsible-Changed-Why:  
Grab. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148013 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/148013: commit references a PR
Date: Mon, 19 Jul 2010 18:01:20 +0000 (UTC)

 Author: yongari
 Date: Mon Jul 19 18:01:06 2010
 New Revision: 210244
 URL: http://svn.freebsd.org/changeset/base/210244
 
 Log:
   Implement WOL. WOL is supported on RTL8139B or newer controllers.
   
   PR:	kern/148013
 
 Modified:
   head/sys/pci/if_rl.c
 
 Modified: head/sys/pci/if_rl.c
 ==============================================================================
 --- head/sys/pci/if_rl.c	Mon Jul 19 16:38:45 2010	(r210243)
 +++ head/sys/pci/if_rl.c	Mon Jul 19 18:01:06 2010	(r210244)
 @@ -222,6 +222,8 @@ static int rl_suspend(device_t);
  static void rl_tick(void *);
  static void rl_txeof(struct rl_softc *);
  static void rl_watchdog(struct rl_softc *);
 +static void rl_setwol(struct rl_softc *);
 +static void rl_clrwol(struct rl_softc *);
  
  #ifdef RL_USEIOSPACE
  #define RL_RES			SYS_RES_IOPORT
 @@ -803,7 +805,7 @@ rl_attach(device_t dev)
  	struct rl_type		*t;
  	struct sysctl_ctx_list	*ctx;
  	struct sysctl_oid_list	*children;
 -	int			error = 0, i, rid;
 +	int			error = 0, hwrev, i, pmc, rid;
  	int			unit;
  	uint16_t		rl_did = 0;
  	char			tn[32];
 @@ -938,6 +940,25 @@ rl_attach(device_t dev)
  	ifp->if_start = rl_start;
  	ifp->if_init = rl_init;
  	ifp->if_capabilities = IFCAP_VLAN_MTU;
 +	/* Check WOL for RTL8139B or newer controllers. */
 +	if (sc->rl_type == RL_8139 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
 +		switch (hwrev) {
 +		case RL_HWREV_8139B:
 +		case RL_HWREV_8130:
 +		case RL_HWREV_8139C:
 +		case RL_HWREV_8139D:
 +		case RL_HWREV_8101:
 +		case RL_HWREV_8100:
 +			ifp->if_capabilities |= IFCAP_WOL;
 +			/* Disable WOL. */
 +			rl_clrwol(sc);
 +			break;
 +		default:
 +			break;
 +		}
 +	}
  	ifp->if_capenable = ifp->if_capabilities;
  #ifdef DEVICE_POLLING
  	ifp->if_capabilities |= IFCAP_POLLING;
 @@ -1926,7 +1947,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  	struct ifreq		*ifr = (struct ifreq *)data;
  	struct mii_data		*mii;
  	struct rl_softc		*sc = ifp->if_softc;
 -	int			error = 0;
 +	int			error = 0, mask;
  
  	switch (command) {
  	case SIOCSIFFLAGS:
 @@ -1953,6 +1974,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
  		break;
  	case SIOCSIFCAP:
 +		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
  #ifdef DEVICE_POLLING
  		if (ifr->ifr_reqcap & IFCAP_POLLING &&
  		    !(ifp->if_capenable & IFCAP_POLLING)) {
 @@ -1978,6 +2000,15 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  			return (error);
  		}
  #endif /* DEVICE_POLLING */
 +		if ((mask & IFCAP_WOL) != 0 &&
 +		    (ifp->if_capabilities & IFCAP_WOL) != 0) {
 +			if ((mask & IFCAP_WOL_UCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_UCAST;
 +			if ((mask & IFCAP_WOL_MCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MCAST;
 +			if ((mask & IFCAP_WOL_MAGIC) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MAGIC;
 +		}
  		break;
  	default:
  		error = ether_ioctl(ifp, command, data);
 @@ -2066,6 +2097,7 @@ rl_suspend(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	rl_setwol(sc);
  	sc->suspended = 1;
  	RL_UNLOCK(sc);
  
 @@ -2082,12 +2114,31 @@ rl_resume(device_t dev)
  {
  	struct rl_softc		*sc;
  	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
  
  	sc = device_get_softc(dev);
  	ifp = sc->rl_ifp;
  
  	RL_LOCK(sc);
  
 +	if ((ifp->if_capabilities & IFCAP_WOL) != 0 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		/* Disable PME and clear PME status. */
 +		pmstat = pci_read_config(sc->rl_dev,
 +		    pmc + PCIR_POWER_STATUS, 2);
 +		if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
 +			pmstat &= ~PCIM_PSTAT_PMEENABLE;
 +			pci_write_config(sc->rl_dev,
 +			    pmc + PCIR_POWER_STATUS, pmstat, 2);
 +		}
 +		/*
 +		 * Clear WOL matching such that normal Rx filtering
 +		 * wouldn't interfere with WOL patterns.
 +		 */
 +		rl_clrwol(sc);
 +	}
 +
  	/* reinitialize interface if necessary */
  	if (ifp->if_flags & IFF_UP)
  		rl_init_locked(sc);
 @@ -2112,7 +2163,93 @@ rl_shutdown(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	/*
 +	 * Mark interface as down since otherwise we will panic if
 +	 * interrupt comes in later on, which can happen in some
 +	 * cases.
 +	 */
 +	sc->rl_ifp->if_flags &= ~IFF_UP;
 +	rl_setwol(sc);
  	RL_UNLOCK(sc);
  
  	return (0);
  }
 +
 +static void
 +rl_setwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
 +	uint8_t			v;
 +
 +	RL_LOCK_ASSERT(sc);
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	/* Enable PME. */
 +	v = CSR_READ_1(sc, RL_CFG1);
 +	v &= ~RL_CFG1_PME;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG1_PME;
 +	CSR_WRITE_1(sc, RL_CFG1, v);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
 +		v |= RL_CFG3_WOL_MAGIC;
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
 +		v |= RL_CFG5_WOL_UCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
 +		v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +	/* Request PME if WOL is requested. */
 +	pmstat = pci_read_config(sc->rl_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->rl_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
 +}
 +
 +static void
 +rl_clrwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	uint8_t			v;
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: feedback->patched 
State-Changed-By: yongari 
State-Changed-When: Mon Jul 19 18:17:20 UTC 2010 
State-Changed-Why:  
Patch committed to HEAD with modifications. 
Thanks a lot for submitting and testing the patch. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148013 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/148013: commit references a PR
Date: Sun, 15 Aug 2010 23:11:50 +0000 (UTC)

 Author: yongari
 Date: Sun Aug 15 23:11:38 2010
 New Revision: 211377
 URL: http://svn.freebsd.org/changeset/base/211377
 
 Log:
   MFC r210244:
     Implement WOL. WOL is supported on RTL8139B or newer controllers.
   
     PR:	kern/148013
 
 Modified:
   stable/8/sys/pci/if_rl.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cam/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
   stable/8/sys/dev/e1000/   (props changed)
   stable/8/sys/dev/xen/xenpci/   (props changed)
 
 Modified: stable/8/sys/pci/if_rl.c
 ==============================================================================
 --- stable/8/sys/pci/if_rl.c	Sun Aug 15 23:07:06 2010	(r211376)
 +++ stable/8/sys/pci/if_rl.c	Sun Aug 15 23:11:38 2010	(r211377)
 @@ -222,6 +222,8 @@ static int rl_suspend(device_t);
  static void rl_tick(void *);
  static void rl_txeof(struct rl_softc *);
  static void rl_watchdog(struct rl_softc *);
 +static void rl_setwol(struct rl_softc *);
 +static void rl_clrwol(struct rl_softc *);
  
  #ifdef RL_USEIOSPACE
  #define RL_RES			SYS_RES_IOPORT
 @@ -803,7 +805,7 @@ rl_attach(device_t dev)
  	struct rl_type		*t;
  	struct sysctl_ctx_list	*ctx;
  	struct sysctl_oid_list	*children;
 -	int			error = 0, i, rid;
 +	int			error = 0, hwrev, i, pmc, rid;
  	int			unit;
  	uint16_t		rl_did = 0;
  	char			tn[32];
 @@ -938,6 +940,25 @@ rl_attach(device_t dev)
  	ifp->if_start = rl_start;
  	ifp->if_init = rl_init;
  	ifp->if_capabilities = IFCAP_VLAN_MTU;
 +	/* Check WOL for RTL8139B or newer controllers. */
 +	if (sc->rl_type == RL_8139 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
 +		switch (hwrev) {
 +		case RL_HWREV_8139B:
 +		case RL_HWREV_8130:
 +		case RL_HWREV_8139C:
 +		case RL_HWREV_8139D:
 +		case RL_HWREV_8101:
 +		case RL_HWREV_8100:
 +			ifp->if_capabilities |= IFCAP_WOL;
 +			/* Disable WOL. */
 +			rl_clrwol(sc);
 +			break;
 +		default:
 +			break;
 +		}
 +	}
  	ifp->if_capenable = ifp->if_capabilities;
  #ifdef DEVICE_POLLING
  	ifp->if_capabilities |= IFCAP_POLLING;
 @@ -1926,7 +1947,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  	struct ifreq		*ifr = (struct ifreq *)data;
  	struct mii_data		*mii;
  	struct rl_softc		*sc = ifp->if_softc;
 -	int			error = 0;
 +	int			error = 0, mask;
  
  	switch (command) {
  	case SIOCSIFFLAGS:
 @@ -1953,6 +1974,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
  		break;
  	case SIOCSIFCAP:
 +		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
  #ifdef DEVICE_POLLING
  		if (ifr->ifr_reqcap & IFCAP_POLLING &&
  		    !(ifp->if_capenable & IFCAP_POLLING)) {
 @@ -1978,6 +2000,15 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  			return (error);
  		}
  #endif /* DEVICE_POLLING */
 +		if ((mask & IFCAP_WOL) != 0 &&
 +		    (ifp->if_capabilities & IFCAP_WOL) != 0) {
 +			if ((mask & IFCAP_WOL_UCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_UCAST;
 +			if ((mask & IFCAP_WOL_MCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MCAST;
 +			if ((mask & IFCAP_WOL_MAGIC) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MAGIC;
 +		}
  		break;
  	default:
  		error = ether_ioctl(ifp, command, data);
 @@ -2066,6 +2097,7 @@ rl_suspend(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	rl_setwol(sc);
  	sc->suspended = 1;
  	RL_UNLOCK(sc);
  
 @@ -2082,12 +2114,31 @@ rl_resume(device_t dev)
  {
  	struct rl_softc		*sc;
  	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
  
  	sc = device_get_softc(dev);
  	ifp = sc->rl_ifp;
  
  	RL_LOCK(sc);
  
 +	if ((ifp->if_capabilities & IFCAP_WOL) != 0 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		/* Disable PME and clear PME status. */
 +		pmstat = pci_read_config(sc->rl_dev,
 +		    pmc + PCIR_POWER_STATUS, 2);
 +		if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
 +			pmstat &= ~PCIM_PSTAT_PMEENABLE;
 +			pci_write_config(sc->rl_dev,
 +			    pmc + PCIR_POWER_STATUS, pmstat, 2);
 +		}
 +		/*
 +		 * Clear WOL matching such that normal Rx filtering
 +		 * wouldn't interfere with WOL patterns.
 +		 */
 +		rl_clrwol(sc);
 +	}
 +
  	/* reinitialize interface if necessary */
  	if (ifp->if_flags & IFF_UP)
  		rl_init_locked(sc);
 @@ -2112,7 +2163,93 @@ rl_shutdown(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	/*
 +	 * Mark interface as down since otherwise we will panic if
 +	 * interrupt comes in later on, which can happen in some
 +	 * cases.
 +	 */
 +	sc->rl_ifp->if_flags &= ~IFF_UP;
 +	rl_setwol(sc);
  	RL_UNLOCK(sc);
  
  	return (0);
  }
 +
 +static void
 +rl_setwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
 +	uint8_t			v;
 +
 +	RL_LOCK_ASSERT(sc);
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	/* Enable PME. */
 +	v = CSR_READ_1(sc, RL_CFG1);
 +	v &= ~RL_CFG1_PME;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG1_PME;
 +	CSR_WRITE_1(sc, RL_CFG1, v);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
 +		v |= RL_CFG3_WOL_MAGIC;
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
 +		v |= RL_CFG5_WOL_UCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
 +		v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +	/* Request PME if WOL is requested. */
 +	pmstat = pci_read_config(sc->rl_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->rl_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
 +}
 +
 +static void
 +rl_clrwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	uint8_t			v;
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/148013: commit references a PR
Date: Sun, 15 Aug 2010 23:13:24 +0000 (UTC)

 Author: yongari
 Date: Sun Aug 15 23:13:09 2010
 New Revision: 211378
 URL: http://svn.freebsd.org/changeset/base/211378
 
 Log:
   MFC r210244:
     Implement WOL. WOL is supported on RTL8139B or newer controllers.
   
     PR:	kern/148013
 
 Modified:
   stable/7/sys/pci/if_rl.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/pci/if_rl.c
 ==============================================================================
 --- stable/7/sys/pci/if_rl.c	Sun Aug 15 23:11:38 2010	(r211377)
 +++ stable/7/sys/pci/if_rl.c	Sun Aug 15 23:13:09 2010	(r211378)
 @@ -221,6 +221,8 @@ static int rl_suspend(device_t);
  static void rl_tick(void *);
  static void rl_txeof(struct rl_softc *);
  static void rl_watchdog(struct rl_softc *);
 +static void rl_setwol(struct rl_softc *);
 +static void rl_clrwol(struct rl_softc *);
  
  #ifdef RL_USEIOSPACE
  #define RL_RES			SYS_RES_IOPORT
 @@ -800,7 +802,7 @@ rl_attach(device_t dev)
  	struct ifnet		*ifp;
  	struct rl_softc		*sc;
  	struct rl_type		*t;
 -	int			error = 0, i, rid;
 +	int			error = 0, hwrev, i, pmc, rid;
  	int			unit;
  	uint16_t		rl_did = 0;
  
 @@ -926,6 +928,25 @@ rl_attach(device_t dev)
  	ifp->if_start = rl_start;
  	ifp->if_init = rl_init;
  	ifp->if_capabilities = IFCAP_VLAN_MTU;
 +	/* Check WOL for RTL8139B or newer controllers. */
 +	if (sc->rl_type == RL_8139 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV;
 +		switch (hwrev) {
 +		case RL_HWREV_8139B:
 +		case RL_HWREV_8130:
 +		case RL_HWREV_8139C:
 +		case RL_HWREV_8139D:
 +		case RL_HWREV_8101:
 +		case RL_HWREV_8100:
 +			ifp->if_capabilities |= IFCAP_WOL;
 +			/* Disable WOL. */
 +			rl_clrwol(sc);
 +			break;
 +		default:
 +			break;
 +		}
 +	}
  	ifp->if_capenable = ifp->if_capabilities;
  #ifdef DEVICE_POLLING
  	ifp->if_capabilities |= IFCAP_POLLING;
 @@ -1776,7 +1797,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  	struct ifreq		*ifr = (struct ifreq *)data;
  	struct mii_data		*mii;
  	struct rl_softc		*sc = ifp->if_softc;
 -	int			error = 0;
 +	int			error = 0, mask;
  
  	switch (command) {
  	case SIOCSIFFLAGS:
 @@ -1803,6 +1824,7 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
  		break;
  	case SIOCSIFCAP:
 +		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
  #ifdef DEVICE_POLLING
  		if (ifr->ifr_reqcap & IFCAP_POLLING &&
  		    !(ifp->if_capenable & IFCAP_POLLING)) {
 @@ -1828,6 +1850,15 @@ rl_ioctl(struct ifnet *ifp, u_long comma
  			return (error);
  		}
  #endif /* DEVICE_POLLING */
 +		if ((mask & IFCAP_WOL) != 0 &&
 +		    (ifp->if_capabilities & IFCAP_WOL) != 0) {
 +			if ((mask & IFCAP_WOL_UCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_UCAST;
 +			if ((mask & IFCAP_WOL_MCAST) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MCAST;
 +			if ((mask & IFCAP_WOL_MAGIC) != 0)
 +				ifp->if_capenable ^= IFCAP_WOL_MAGIC;
 +		}
  		break;
  	default:
  		error = ether_ioctl(ifp, command, data);
 @@ -1916,6 +1947,7 @@ rl_suspend(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	rl_setwol(sc);
  	sc->suspended = 1;
  	RL_UNLOCK(sc);
  
 @@ -1932,12 +1964,31 @@ rl_resume(device_t dev)
  {
  	struct rl_softc		*sc;
  	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
  
  	sc = device_get_softc(dev);
  	ifp = sc->rl_ifp;
  
  	RL_LOCK(sc);
  
 +	if ((ifp->if_capabilities & IFCAP_WOL) != 0 &&
 +	    pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) == 0) {
 +		/* Disable PME and clear PME status. */
 +		pmstat = pci_read_config(sc->rl_dev,
 +		    pmc + PCIR_POWER_STATUS, 2);
 +		if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
 +			pmstat &= ~PCIM_PSTAT_PMEENABLE;
 +			pci_write_config(sc->rl_dev,
 +			    pmc + PCIR_POWER_STATUS, pmstat, 2);
 +		}
 +		/*
 +		 * Clear WOL matching such that normal Rx filtering
 +		 * wouldn't interfere with WOL patterns.
 +		 */
 +		rl_clrwol(sc);
 +	}
 +
  	/* reinitialize interface if necessary */
  	if (ifp->if_flags & IFF_UP)
  		rl_init_locked(sc);
 @@ -1962,7 +2013,93 @@ rl_shutdown(device_t dev)
  
  	RL_LOCK(sc);
  	rl_stop(sc);
 +	/*
 +	 * Mark interface as down since otherwise we will panic if
 +	 * interrupt comes in later on, which can happen in some
 +	 * cases.
 +	 */
 +	sc->rl_ifp->if_flags &= ~IFF_UP;
 +	rl_setwol(sc);
  	RL_UNLOCK(sc);
  
  	return (0);
  }
 +
 +static void
 +rl_setwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	int			pmc;
 +	uint16_t		pmstat;
 +	uint8_t			v;
 +
 +	RL_LOCK_ASSERT(sc);
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +	if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	/* Enable PME. */
 +	v = CSR_READ_1(sc, RL_CFG1);
 +	v &= ~RL_CFG1_PME;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG1_PME;
 +	CSR_WRITE_1(sc, RL_CFG1, v);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
 +		v |= RL_CFG3_WOL_MAGIC;
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
 +		v |= RL_CFG5_WOL_UCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
 +		v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
 +	if ((ifp->if_capenable & IFCAP_WOL) != 0)
 +		v |= RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +	/* Request PME if WOL is requested. */
 +	pmstat = pci_read_config(sc->rl_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->rl_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
 +}
 +
 +static void
 +rl_clrwol(struct rl_softc *sc)
 +{
 +	struct ifnet		*ifp;
 +	uint8_t			v;
 +
 +	ifp = sc->rl_ifp;
 +	if ((ifp->if_capabilities & IFCAP_WOL) == 0)
 +		return;
 +
 +	/* Enable config register write. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
 +
 +	v = CSR_READ_1(sc, RL_CFG3);
 +	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
 +	CSR_WRITE_1(sc, RL_CFG3, v);
 +
 +	/* Config register write done. */
 +	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 +
 +	v = CSR_READ_1(sc, RL_CFG5);
 +	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
 +	v &= ~RL_CFG5_WOL_LANWAKE;
 +	CSR_WRITE_1(sc, RL_CFG5, v);
 +}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: yongari 
State-Changed-When: Sun Aug 15 23:34:29 UTC 2010 
State-Changed-Why:  
MFC to stable/8 and stable/7 done. 
Thanks a lot for submitting patch and testing! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148013 
>Unformatted:
