Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Aug 2010 19:18:50 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r211717 - head/sys/dev/xl
Message-ID:  <201008231918.o7NJIobo050141@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Aug 23 19:18:50 2010
New Revision: 211717
URL: http://svn.freebsd.org/changeset/base/211717

Log:
  Implement basic WOL support. Note, not all xl(4) controllers
  support WOL. Some controllers require additional 3-wire auxiliary
  remote wakeup connector to draw power. More recent xl(4)
  controllers may not need the wakeup connector though.

Modified:
  head/sys/dev/xl/if_xl.c
  head/sys/dev/xl/if_xlreg.h

Modified: head/sys/dev/xl/if_xl.c
==============================================================================
--- head/sys/dev/xl/if_xl.c	Mon Aug 23 18:51:31 2010	(r211716)
+++ head/sys/dev/xl/if_xl.c	Mon Aug 23 19:18:50 2010	(r211717)
@@ -246,6 +246,7 @@ static int xl_watchdog(struct xl_softc *
 static int xl_shutdown(device_t);
 static int xl_suspend(device_t);
 static int xl_resume(device_t);
+static void xl_setwol(struct xl_softc *);
 
 #ifdef DEVICE_POLLING
 static int xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
@@ -1145,10 +1146,10 @@ static int
 xl_attach(device_t dev)
 {
 	u_char			eaddr[ETHER_ADDR_LEN];
-	u_int16_t		xcvr[2];
+	u_int16_t		sinfo2, xcvr[2];
 	struct xl_softc		*sc;
 	struct ifnet		*ifp;
-	int			media;
+	int			media, pmcap;
 	int			unit, error = 0, rid, res;
 	uint16_t		did;
 
@@ -1405,6 +1406,18 @@ xl_attach(device_t dev)
 	else
 		sc->xl_type = XL_TYPE_90X;
 
+	/* Check availability of WOL. */
+	if ((sc->xl_caps & XL_CAPS_PWRMGMT) != 0 &&
+	    pci_find_extcap(dev, PCIY_PMG, &pmcap) == 0) {
+		sc->xl_pmcap = pmcap;
+		sc->xl_flags |= XL_FLAG_WOL;
+		sinfo2 = 0;
+		xl_read_eeprom(sc, (caddr_t)&sinfo2, XL_EE_SOFTINFO2, 1, 0);
+		if ((sinfo2 & XL_SINFO2_AUX_WOL_CON) == 0 && bootverbose)
+			device_printf(dev,
+			    "No auxiliary remote wakeup connector!\n");
+	}
+
 	/* Set the TX start threshold for best performance. */
 	sc->xl_tx_thresh = XL_MIN_FRAMELEN;
 
@@ -1419,6 +1432,8 @@ xl_attach(device_t dev)
 		ifp->if_capabilities |= IFCAP_HWCSUM;
 #endif
 	}
+	if ((sc->xl_flags & XL_FLAG_WOL) != 0)
+		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
 	ifp->if_capenable = ifp->if_capabilities;
 #ifdef DEVICE_POLLING
 	ifp->if_capabilities |= IFCAP_POLLING;
@@ -2765,6 +2780,15 @@ xl_init_locked(struct xl_softc *sc)
 	if (sc->xl_miibus != NULL)
 		mii = device_get_softc(sc->xl_miibus);
 
+	/*
+	 * Clear WOL status and disable all WOL feature as WOL
+	 * would interfere Rx operation under normal environments.
+	 */
+	if ((sc->xl_flags & XL_FLAG_WOL) != 0) {
+		XL_SEL_WIN(7);
+		CSR_READ_2(sc, XL_W7_BM_PME);
+		CSR_WRITE_2(sc, XL_W7_BM_PME, 0);
+	}
 	/* Init our MAC address */
 	XL_SEL_WIN(2);
 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
@@ -3187,6 +3211,9 @@ xl_ioctl(struct ifnet *ifp, u_long comma
 		if ((mask & IFCAP_RXCSUM) != 0 &&
 		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0)
 			ifp->if_capenable ^= IFCAP_RXCSUM;
+		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
+		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
+			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
 		XL_UNLOCK(sc);
 		break;
 	default:
@@ -3329,15 +3356,8 @@ xl_stop(struct xl_softc *sc)
 static int
 xl_shutdown(device_t dev)
 {
-	struct xl_softc		*sc;
-
-	sc = device_get_softc(dev);
-
-	XL_LOCK(sc);
-	xl_stop(sc);
-	XL_UNLOCK(sc);
 
-	return (0);
+	return (xl_suspend(dev));
 }
 
 static int
@@ -3349,6 +3369,7 @@ xl_suspend(device_t dev)
 
 	XL_LOCK(sc);
 	xl_stop(sc);
+	xl_setwol(sc);
 	XL_UNLOCK(sc);
 
 	return (0);
@@ -3374,3 +3395,34 @@ xl_resume(device_t dev)
 
 	return (0);
 }
+
+static void
+xl_setwol(struct xl_softc *sc)
+{
+	struct ifnet		*ifp;
+	u_int16_t		cfg, pmstat;
+
+	if ((sc->xl_flags & XL_FLAG_WOL) == 0)
+		return;
+
+	ifp = sc->xl_ifp;
+	XL_SEL_WIN(7);
+	/* Clear any pending PME events. */
+	CSR_READ_2(sc, XL_W7_BM_PME);
+	cfg = 0;
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		cfg |= XL_BM_PME_MAGIC;
+	CSR_WRITE_2(sc, XL_W7_BM_PME, cfg);
+	/* Enable RX. */
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
+	/* Request PME. */
+	pmstat = pci_read_config(sc->xl_dev,
+	    sc->xl_pmcap + PCIR_POWER_STATUS, 2);
+	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+		pmstat |= PCIM_PSTAT_PMEENABLE;
+	else
+		pmstat &= ~PCIM_PSTAT_PMEENABLE;
+	pci_write_config(sc->xl_dev,
+	    sc->xl_pmcap + PCIR_POWER_STATUS, pmstat, 2);
+}

Modified: head/sys/dev/xl/if_xlreg.h
==============================================================================
--- head/sys/dev/xl/if_xlreg.h	Mon Aug 23 18:51:31 2010	(r211716)
+++ head/sys/dev/xl/if_xlreg.h	Mon Aug 23 19:18:50 2010	(r211717)
@@ -81,6 +81,17 @@
 #define XL_CAPS_100MBPS		0x1000
 #define XL_CAPS_PWRMGMT		0x2000
 
+/*
+ * Bits in the software information 2 word
+ */
+#define	XL_SINFO2_FIXED_BCAST_RX_BUG	0x0002
+#define	XL_SINFO2_FIXED_ENDEC_LOOP_BUG	0x0004
+#define	XL_SINFO2_AUX_WOL_CON		0x0008
+#define	XL_SINFO2_PME_PULSED		0x0010
+#define	XL_SINFO2_FIXED_MWI_BUG		0x0020
+#define	XL_SINFO2_WOL_AFTER_PWR_LOSS	0x0040
+#define	XL_SINFO2_AUTO_RST_TO_D0	0x0080
+
 #define XL_PACKET_SIZE 1540
 #define XL_MAX_FRAMELEN	(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN)
 
@@ -408,7 +419,12 @@
 #define XL_W7_BM_LEN		0x06
 #define XL_W7_BM_STATUS		0x0B
 #define XL_W7_BM_TIMEr		0x0A
+#define XL_W7_BM_PME		0x0C
 
+#define	XL_BM_PME_WAKE		0x0001
+#define	XL_BM_PME_MAGIC		0x0002
+#define	XL_BM_PME_LINKCHG	0x0004
+#define	XL_BM_PME_WAKETIMER	0x0008
 /*
  * bus master control registers
  */
@@ -577,6 +593,7 @@ struct xl_mii_frame {
 #define XL_FLAG_NO_XCVR_PWR		0x0080
 #define XL_FLAG_USE_MMIO		0x0100
 #define	XL_FLAG_NO_MMIO			0x0200
+#define	XL_FLAG_WOL			0x0400
 
 #define XL_NO_XCVR_PWR_MAGICBITS	0x0900
 
@@ -599,6 +616,7 @@ struct xl_softc {
 	u_int16_t		xl_caps;
 	u_int8_t		xl_stats_no_timeout;
 	u_int16_t		xl_tx_thresh;
+	int			xl_pmcap;
 	int			xl_if_flags;
 	struct xl_list_data	xl_ldata;
 	struct xl_chain_data	xl_cdata;



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