Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Sep 2010 00:34:45 +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: r212167 - head/sys/dev/sis
Message-ID:  <201009030034.o830Yj1K027051@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Fri Sep  3 00:34:45 2010
New Revision: 212167
URL: http://svn.freebsd.org/changeset/base/212167

Log:
  Initial WOL support. NS DP8315 was tested but SiS900/SiS7016 was
  not tested.
  While I'm here, clean up SIOCSIFCAP handler.

Modified:
  head/sys/dev/sis/if_sis.c
  head/sys/dev/sis/if_sisreg.h

Modified: head/sys/dev/sis/if_sis.c
==============================================================================
--- head/sys/dev/sis/if_sis.c	Thu Sep  2 22:37:13 2010	(r212166)
+++ head/sys/dev/sis/if_sis.c	Fri Sep  3 00:34:45 2010	(r212167)
@@ -147,12 +147,15 @@ static void sis_initl(struct sis_softc *
 static void sis_intr(void *);
 static int sis_ioctl(struct ifnet *, u_long, caddr_t);
 static int sis_newbuf(struct sis_softc *, struct sis_rxdesc *);
+static int sis_resume(device_t);
 static int sis_rxeof(struct sis_softc *);
 static void sis_start(struct ifnet *);
 static void sis_startl(struct ifnet *);
 static void sis_stop(struct sis_softc *);
+static int sis_suspend(device_t);
 static void sis_add_sysctls(struct sis_softc *);
 static void sis_watchdog(struct sis_softc *);
+static void sis_wol(struct sis_softc *);
 
 
 static struct resource_spec sis_res_spec[] = {
@@ -935,6 +938,9 @@ sis_reset(struct sis_softc *sc)
 	if (sc->sis_type == SIS_TYPE_83815) {
 		CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS);
 		CSR_WRITE_4(sc, NS_CLKRUN, 0);
+	} else {
+		/* Disable WOL functions. */
+		CSR_WRITE_4(sc, SIS_PWRMAN_CTL, 0);
 	}
 }
 
@@ -971,7 +977,7 @@ sis_attach(device_t dev)
 	u_char			eaddr[ETHER_ADDR_LEN];
 	struct sis_softc	*sc;
 	struct ifnet		*ifp;
-	int			error = 0, waittime = 0;
+	int			error = 0, pmc, waittime = 0;
 
 	waittime = 0;
 	sc = device_get_softc(dev);
@@ -1147,6 +1153,14 @@ sis_attach(device_t dev)
 	ifp->if_snd.ifq_drv_maxlen = SIS_TX_LIST_CNT - 1;
 	IFQ_SET_READY(&ifp->if_snd);
 
+	if (pci_find_extcap(sc->sis_dev, PCIY_PMG, &pmc) == 0) {
+		if (sc->sis_type == SIS_TYPE_83815)
+			ifp->if_capabilities |= IFCAP_WOL;
+		else
+			ifp->if_capabilities |= IFCAP_WOL_MAGIC;
+		ifp->if_capenable = ifp->if_capabilities;
+	}
+
 	/*
 	 * Do MII setup.
 	 */
@@ -2227,7 +2241,7 @@ sis_ioctl(struct ifnet *ifp, u_long comm
 	struct sis_softc	*sc = ifp->if_softc;
 	struct ifreq		*ifr = (struct ifreq *) data;
 	struct mii_data		*mii;
-	int			error = 0;
+	int			error = 0, mask;
 
 	switch (command) {
 	case SIOCSIFFLAGS:
@@ -2264,32 +2278,37 @@ sis_ioctl(struct ifnet *ifp, u_long comm
 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
 		break;
 	case SIOCSIFCAP:
-		/* ok, disable interrupts */
+		SIS_LOCK(sc);
+		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
 #ifdef DEVICE_POLLING
-		if (ifr->ifr_reqcap & IFCAP_POLLING &&
-		    !(ifp->if_capenable & IFCAP_POLLING)) {
-			error = ether_poll_register(sis_poll, ifp);
-			if (error)
-				return (error);
-			SIS_LOCK(sc);
-			/* Disable interrupts */
-			CSR_WRITE_4(sc, SIS_IER, 0);
-			ifp->if_capenable |= IFCAP_POLLING;
-			SIS_UNLOCK(sc);
-			return (error);
-
-		}
-		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
-		    ifp->if_capenable & IFCAP_POLLING) {
-			error = ether_poll_deregister(ifp);
-			/* Enable interrupts. */
-			SIS_LOCK(sc);
-			CSR_WRITE_4(sc, SIS_IER, 1);
-			ifp->if_capenable &= ~IFCAP_POLLING;
-			SIS_UNLOCK(sc);
-			return (error);
+		if ((mask & IFCAP_POLLING) != 0 &&
+		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
+			ifp->if_capenable ^= IFCAP_POLLING;
+			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
+				error = ether_poll_register(sis_poll, ifp);
+				if (error != 0) {
+					SIS_UNLOCK(sc);
+					break;
+				}
+				/* Disable interrupts. */
+				CSR_WRITE_4(sc, SIS_IER, 0);
+                        } else {
+                                error = ether_poll_deregister(ifp);
+                                /* Enable interrupts. */
+				CSR_WRITE_4(sc, SIS_IER, 1);
+                        }
 		}
 #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;
+		}
+		SIS_UNLOCK(sc);
 		break;
 	default:
 		error = ether_ioctl(ifp, command, data);
@@ -2384,13 +2403,8 @@ sis_stop(struct sis_softc *sc)
 static int
 sis_shutdown(device_t dev)
 {
-	struct sis_softc	*sc;
 
-	sc = device_get_softc(dev);
-	SIS_LOCK(sc);
-	sis_stop(sc);
-	SIS_UNLOCK(sc);
-	return (0);
+	return (sis_suspend(dev));
 }
 
 static int
@@ -2401,6 +2415,7 @@ sis_suspend(device_t dev)
 	sc = device_get_softc(dev);
 	SIS_LOCK(sc);
 	sis_stop(sc);
+	sis_wol(sc);
 	SIS_UNLOCK(sc);
 	return (0);
 }
@@ -2423,6 +2438,56 @@ sis_resume(device_t dev)
 }
 
 static void
+sis_wol(struct sis_softc *sc)
+{
+	struct ifnet		*ifp;
+	uint32_t		val;
+	uint16_t		pmstat;
+	int			pmc;
+
+	ifp = sc->sis_ifp;
+	if ((ifp->if_capenable & IFCAP_WOL) == 0)
+		return;
+
+	if (sc->sis_type == SIS_TYPE_83815) {
+		/* Reset RXDP. */
+		CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0);
+
+		/* Configure WOL events. */
+		CSR_READ_4(sc, NS_WCSR);
+		val = 0;
+		if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
+			val |= NS_WCSR_WAKE_UCAST;
+		if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
+			val |= NS_WCSR_WAKE_MCAST;
+		if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+			val |= NS_WCSR_WAKE_MAGIC;
+		CSR_WRITE_4(sc, NS_WCSR, val);
+		/* Enable PME and clear PMESTS. */
+		val = CSR_READ_4(sc, NS_CLKRUN);
+		val |= NS_CLKRUN_PMEENB | NS_CLKRUN_PMESTS;
+		CSR_WRITE_4(sc, NS_CLKRUN, val);
+		/* Enable silent RX mode. */
+		SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+	} else {
+		if (pci_find_extcap(sc->sis_dev, PCIY_PMG, &pmc) != 0)
+			return;
+		val = 0;
+		if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+			val |= SIS_PWRMAN_WOL_MAGIC;
+		CSR_WRITE_4(sc, SIS_PWRMAN_CTL, val);
+		/* Request PME. */
+		pmstat = pci_read_config(sc->sis_dev,
+		    pmc + PCIR_POWER_STATUS, 2);
+		pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
+		if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+			pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+		pci_write_config(sc->sis_dev,
+		    pmc + PCIR_POWER_STATUS, pmstat, 2);
+	}
+}
+
+static void
 sis_add_sysctls(struct sis_softc *sc)
 {
 	struct sysctl_ctx_list *ctx;

Modified: head/sys/dev/sis/if_sisreg.h
==============================================================================
--- head/sys/dev/sis/if_sisreg.h	Thu Sep  2 22:37:13 2010	(r212166)
+++ head/sys/dev/sis/if_sisreg.h	Fri Sep  3 00:34:45 2010	(r212167)
@@ -77,6 +77,7 @@
 /* NS DP83815/6 registers */
 #define NS_IHR			0x1C
 #define NS_CLKRUN		0x3C
+#define	NS_WCSR			0x40
 #define NS_SRR			0x58
 #define NS_BMCR			0x80
 #define NS_BMSR			0x84
@@ -99,6 +100,29 @@
 #define NS_CLKRUN_PMEENB	0x00000100
 #define NS_CLNRUN_CLKRUN_ENB	0x00000001
 
+#define	NS_WCSR_WAKE_PHYINTR	0x00000001
+#define	NS_WCSR_WAKE_UCAST	0x00000002
+#define	NS_WCSR_WAKE_MCAST	0x00000004
+#define	NS_WCSR_WAKE_BCAST	0x00000008
+#define	NS_WCSR_WAKE_ARP	0x00000010
+#define	NS_WCSR_WAKE_PATTERN0	0x00000020
+#define	NS_WCSR_WAKE_PATTERN1	0x00000040
+#define	NS_WCSR_WAKE_PATTERN2	0x00000080
+#define	NS_WCSR_WAKE_PATTERN3	0x00000100
+#define	NS_WCSR_WAKE_MAGIC	0x00000200
+#define	NS_WCSR_WAKE_MAGIC_SEC	0x00000400
+#define	NS_WCSR_DET_MAGIC_SECH	0x00100000
+#define	NS_WCSR_DET_PHYINTR	0x00400000
+#define	NS_WCSR_DET_UCAST	0x00800000
+#define	NS_WCSR_DET_MCAST	0x01000000
+#define	NS_WCSR_DET_BCAST	0x02000000
+#define	NS_WCSR_DET_ARP		0x04000000
+#define	NS_WCSR_DET_PATTERN0	0x08000000
+#define	NS_WCSR_DET_PATTERN1	0x10000000
+#define	NS_WCSR_DET_PATTERN2	0x20000000
+#define	NS_WCSR_DET_PATTERN3	0x40000000
+#define	NS_WCSR_DET_MAGIC	0x80000000
+
 /* NS silicon revisions */
 #define NS_SRR_15C		0x302
 #define NS_SRR_15D		0x403
@@ -303,6 +327,10 @@
 #define NS_FILTADDR_FMEM_LO	0x00000200
 #define NS_FILTADDR_FMEM_HI	0x000003FE
 
+#define	SIS_PWRMAN_WOL_LINK_OFF	0x00000001
+#define	SIS_PWRMAN_WOL_LINK_ON	0x00000002
+#define	SIS_PWRMAN_WOL_MAGIC	0x00000400
+
 /*
  * TX/RX DMA descriptor structures.
  */



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