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>