Index: sbin/ifconfig/Makefile =================================================================== RCS file: /usr/local/ncvs/src/sbin/ifconfig/Makefile,v retrieving revision 1.29 diff -u -r1.29 Makefile --- sbin/ifconfig/Makefile 5 Jun 2005 03:32:51 -0000 1.29 +++ sbin/ifconfig/Makefile 6 May 2006 11:08:41 -0000 @@ -28,6 +28,8 @@ SRCS+= ifbridge.c # bridge support +SRCS+= ifwol.c # wake on lan support + .if !defined(RELEASE_CRUNCH) SRCS+= af_ipx.c # IPX support DPADD= ${LIBIPX} Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /usr/local/ncvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.95.2.14 diff -u -r1.95.2.14 ifconfig.8 --- sbin/ifconfig/ifconfig.8 10 Mar 2006 22:05:53 -0000 1.95.2.14 +++ sbin/ifconfig/ifconfig.8 6 May 2006 10:49:48 -0000 @@ -896,6 +896,27 @@ If that is the case, then the first four keys (1-4) will be the standard temporary keys and any others will be adaptor specific keys such as permanent keys stored in NVRAM. +.It Cm wakeon Ar events +Enable Wake On Lan support, if available. The +.Ar events +argument is a comma seperated list of package types that shall +trigger wake events. The set of valid package types is +.Dq Li unicast , +.Dq Li multicast , +.Dq Li broadcast , +and +.Dq Li magic . +These enable wake on unicast, multicast, broadcast and Magic Packet(tm), +respectively. +A SecureOn password, if supported, can be be enabled using the +.Dq Li sopasswd: +event. +SecureOn passwords only work in combination with +.Dq Li magic . +The password must consist of 12 hexadecimal digits. +.It Fl wakeon +Disable Wake On Lan. +.Pp .It Cm wme Enable Wireless Multimedia Extensions (WME) support, if available, for the specified interface. @@ -903,7 +924,6 @@ efficient communication of realtime and multimedia data. To disable WME support, use .Fl wme . -.Pp The following parameters are meaningful only when WME support is in use. Parameters are specified per-AC (Access Category) and split into those that are used by a station when acting Index: sbin/ifconfig/ifwol.c =================================================================== RCS file: sbin/ifconfig/ifwol.c diff -N sbin/ifconfig/ifwol.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sbin/ifconfig/ifwol.c 20 Oct 2006 10:29:10 -0000 @@ -0,0 +1,229 @@ +/* $Id$ */ + +/* + * Copyright (c) 2005 Stefan Sperling. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifconfig.h" + +static void wol_status(int s); +static void setwol(const char *, int, int, const struct afswtch *); +static void parse_args(const char *, struct if_wolopts *); +static void parse_sopasswd(const char *, u_char *); +static void unsetwol(const char *, int, int, const struct afswtch *); +static void print_wol_events(uint32_t events); + +/* + * Print wake on lan capabilities and events the device currently heeds. + */ +static void +wol_status(int s) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLSUPP, &ifr) < 0) + /* Device does not support wake on lan */ + return; + + printf("\tsupported wake events:"); + print_wol_events(ifr.ifr_wolopts.ifwol_supported); + printf("\n"); + + if (ioctl(s, SIOCGIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCGIFWOLOPTS"); + + if (ifr.ifr_wolopts.ifwol_events == 0) + return; + + printf("\twill wake on:"); + print_wol_events(ifr.ifr_wolopts.ifwol_events); + printf("\n"); +} + +static void +print_wol_events(uint32_t events) +{ + if (events & IFWOL_WAKE_ON_UNICAST) + printf(" unicast"); + if (events & IFWOL_WAKE_ON_MULTICAST) + printf(" multicast"); + if (events & IFWOL_WAKE_ON_BROADCAST) + printf(" broadcast"); + if (events & IFWOL_WAKE_ON_MAGIC) { + printf(" magic"); + if (events & IFWOL_ENABLE_SOPASSWD) + printf("[SecureOn password]"); + } +} + +/* + * Set wake on lan events. + */ +static void +setwol(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLSUPP, &ifr) < 0) + err(EX_USAGE, "device does not support wake on lan"); + + parse_args(val, &ifr.ifr_wolopts); + if (ioctl(s, SIOCSIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCSIFWOLOPTS"); +} + +/* + * Parse the argument string, which may contain one or more of the + * following: + * + * unicast,multicast,broadcast,magic,sopasswd:xxxxxxxxxxxx, + * + * and fill the wolopts structure accordingly. + * + */ +static void +parse_args(const char* args, struct if_wolopts *wolopts) +{ + uint32_t wol_events = 0; + char* opt; + + for (opt = strdup(args); (opt = strtok(opt, ",")) != NULL; opt = NULL) { + if (strcmp(opt, "unicast") == 0) + wol_events |= IFWOL_WAKE_ON_UNICAST; + else if (strcmp(opt, "multicast") == 0) + wol_events |= IFWOL_WAKE_ON_MULTICAST; + else if (strcmp(opt, "broadcast") == 0) + wol_events |= IFWOL_WAKE_ON_BROADCAST; + else if (strcmp(opt, "magic") == 0) + wol_events |= IFWOL_WAKE_ON_MAGIC; + else if (strcmp(opt, "sopasswd") == 0) + errx(EX_USAGE, "no SecureOn password specfied."); + else if (strncmp(opt, "sopasswd:", strlen("sopasswd:")) == 0) { + wol_events |= IFWOL_ENABLE_SOPASSWD; + parse_sopasswd(opt + strlen("sopasswd:"), wolopts->ifwol_sopasswd); + } else { + errx(EX_USAGE, "unknown wake event %s", opt); + } + } + free(opt); + wolopts->ifwol_events = wol_events; +} + +/* SecureOn passwords are not like plain text passwords. Instead, they consist + * of 6 bytes (ie unsigned char). Try to prevent users from giving anything other + * than a string of six concatenated unsigned chars in hex as password. + */ +static void +parse_sopasswd(const char *pw, u_char *dest) { + char substr[3]; + int len, i, n; + + len = strlen(pw) / 2; + if (len != 6) + errx(EX_USAGE, "Invalid SecureOn password."); + + for (i = 0; i < len; i++) { + (void)strncpy(substr, pw, 2); + substr[2] = '\0'; + if (sscanf(substr, "%x", &n) != 1) + errx(EX_USAGE, "Invalid SecureOn password."); + if (n < 0x0 || n > 0xff) + /* Should never happen, but just in case... */ + errx(EX_USAGE, "Invalid SecureOn password."); + *dest++ = (u_char)n; + pw += 2; + } +} + +/* + * Unset all wake on lan events. + */ +static void +unsetwol(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, name, IFNAMSIZ); + + if (ioctl(s, SIOCGIFWOLSUPP, &ifr) < 0) + err(EX_USAGE, "device does not support wake on lan"); + + ifr.ifr_wolopts.ifwol_events = IFWOL_DISABLE; + if (ioctl(s, SIOCSIFWOLOPTS, &ifr) < 0) + err(EX_USAGE, "SIOCSIFWOLOPTS"); +} + +static struct cmd wol_cmds[] = { + DEF_CMD_ARG("wakeon", setwol), + DEF_CMD("-wakeon", 0, unsetwol) +}; +static struct afswtch af_wol = { + .af_name = "af_wol", + .af_af = AF_UNSPEC, + .af_other_status = wol_status, +}; + +static __constructor void +ifwol_ctor(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(wol_cmds); i++) + cmd_register(&wol_cmds[i]); + af_register(&af_wol); +#undef N +} Index: sys/dev/nve/if_nve.c =================================================================== RCS file: /usr/local/ncvs/src/sys/dev/nve/if_nve.c,v retrieving revision 1.7.2.8 diff -u -r1.7.2.8 if_nve.c --- sys/dev/nve/if_nve.c 25 Dec 2005 21:57:03 -0000 1.7.2.8 +++ sys/dev/nve/if_nve.c 5 May 2006 23:05:57 -0000 @@ -179,6 +179,10 @@ static NV_SINT32 nve_oslockrelease(PNV_VOID, NV_SINT32, PNV_VOID); static PNV_VOID nve_osreturnbufvirt(PNV_VOID, PNV_VOID); +static void nve_enable_wol(struct nve_softc *); +static void nve_get_wolopts(struct nve_softc *, struct if_wolopts *); +static int nve_set_wolopts(struct nve_softc *, struct if_wolopts *); + static device_method_t nve_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nve_probe), @@ -718,6 +722,10 @@ sc = device_get_softc(dev); + NVE_LOCK(sc); + nve_enable_wol(sc); + NVE_UNLOCK(sc); + /* Stop hardware activity */ NVE_LOCK(sc); nve_stop(sc); @@ -1018,6 +1026,21 @@ mii = device_get_softc(sc->miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; + case SIOCGIFWOLSUPP: + ifr->ifr_wolopts.ifwol_supported = NVE_SUPPORTED_WOL_EVENTS; + error = 0; + break; + case SIOCGIFWOLOPTS: + NVE_LOCK(sc); + nve_get_wolopts(sc, &ifr->ifr_wolopts); + NVE_UNLOCK(sc); + error = 0; + break; + case SIOCSIFWOLOPTS: + NVE_LOCK(sc); + error = nve_set_wolopts(sc, &ifr->ifr_wolopts); + NVE_UNLOCK(sc); + break; default: /* Everything else we forward to generic ether ioctl */ @@ -1736,3 +1759,49 @@ } /* --- End on NVOSAPI interface --- */ + +/* + * Enable Wake On Lan. + */ +static void +nve_enable_wol(struct nve_softc *sc) +{ + ADAPTER_POWERSTATE pstate = {0}; + + if (sc->wol_events == 0) + return; + + if (sc->wol_events & IFWOL_WAKE_ON_MAGIC) { + pstate.ulPowerFlags = POWER_STATE_D3; + pstate.ulMagicPacketWakeUpFlags = POWER_STATE_ALL; + pstate.ulLinkChangeWakeUpFlags = 0; + pstate.ulPatternWakeUpFlags = 0; + sc->hwapi->pfnSetPowerState(sc->hwapi->pADCX, &pstate); + } +} + +/* + * Write current wake on lan settings into an if_wolopts structure. + */ +static void +nve_get_wolopts(struct nve_softc *sc, struct if_wolopts *wolopts) +{ + wolopts->ifwol_events = sc->wol_events; +} + +/* + * Set wake on lan options. + */ +static int +nve_set_wolopts(struct nve_softc *sc, struct if_wolopts *wolopts) +{ + if (wolopts->ifwol_events == IFWOL_DISABLE) + sc->wol_events = 0; + else { + if ((wolopts->ifwol_events & ~NVE_SUPPORTED_WOL_EVENTS) != 0) + return EINVAL; + sc->wol_events = wolopts->ifwol_events; + } + + return 0; +} Index: sys/dev/nve/if_nvereg.h =================================================================== RCS file: /usr/local/ncvs/src/sys/dev/nve/if_nvereg.h,v retrieving revision 1.3.2.1 diff -u -r1.3.2.1 if_nvereg.h --- sys/dev/nve/if_nvereg.h 12 Dec 2005 19:40:04 -0000 1.3.2.1 +++ sys/dev/nve/if_nvereg.h 5 May 2006 23:05:57 -0000 @@ -67,6 +67,8 @@ #define NVE_DEBUG_MII 0x0100 #define NVE_DEBUG_ALL 0xFFFF +#define NVE_SUPPORTED_WOL_EVENTS IFWOL_WAKE_ON_MAGIC + #if NVE_DEBUG #define DEBUGOUT(level, fmt, args...) if (NVE_DEBUG & level) \ printf(fmt, ## args) @@ -141,6 +143,8 @@ struct mtx mtx; + uint32_t wol_events; + /* Stuff for dealing with the NVIDIA OS API */ struct callout ostimer; PTIMER_FUNC ostimer_func; Index: sys/net/if.c =================================================================== RCS file: /usr/local/ncvs/src/sys/net/if.c,v retrieving revision 1.234.2.13 diff -u -r1.234.2.13 if.c --- sys/net/if.c 15 Feb 2006 03:37:15 -0000 1.234.2.13 +++ sys/net/if.c 5 May 2006 23:05:57 -0000 @@ -1436,6 +1436,7 @@ case SIOCSLIFPHYADDR: case SIOCSIFMEDIA: case SIOCSIFGENERIC: + case SIOCSIFWOLOPTS: error = suser(td); if (error) return (error); @@ -1457,6 +1458,8 @@ case SIOCGLIFPHYADDR: case SIOCGIFMEDIA: case SIOCGIFGENERIC: + case SIOCGIFWOLOPTS: + case SIOCGIFWOLSUPP: if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); IFF_LOCKGIANT(ifp); Index: sys/net/if.h =================================================================== RCS file: /usr/local/ncvs/src/sys/net/if.h,v retrieving revision 1.96.2.4 diff -u -r1.96.2.4 if.h --- sys/net/if.h 15 Feb 2006 03:37:15 -0000 1.96.2.4 +++ sys/net/if.h 5 May 2006 23:05:57 -0000 @@ -254,6 +254,28 @@ #define IFAN_DEPARTURE 1 /* interface departure */ /* + * Wake on Lan related options. + */ +struct if_wolopts { + uint32_t ifwol_supported;/* indicates wol capabilities */ + uint32_t ifwol_events; /* indicates desired wake events */ + + /* Supported wake on lan events. + * A given device may not support all of these, + * or even support wake events not listed here. + * If you add wake more events, make to sure to teach + * ifconfig about them too. */ +#define IFWOL_DISABLE 0x01 /* clears all other events */ +#define IFWOL_WAKE_ON_UNICAST 0x02 +#define IFWOL_WAKE_ON_MULTICAST 0x04 +#define IFWOL_WAKE_ON_BROADCAST 0x08 +#define IFWOL_WAKE_ON_MAGIC 0x10 /* wake on Magic Packet(tm) */ +#define IFWOL_ENABLE_SOPASSWD 0x20 /* whether to set SecureOn password */ + + u_char ifwol_sopasswd[6]; /* SecureOn password */ +}; + +/* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The @@ -265,6 +287,7 @@ struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; + struct if_wolopts ifru_wolopts; short ifru_flags[2]; short ifru_index; int ifru_metric; @@ -277,6 +300,7 @@ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_wolopts ifr_ifru.ifru_wolopts /* wake on lan related options */ #define ifr_flags ifr_ifru.ifru_flags[0] /* flags (low 16 bits) */ #define ifr_flagshigh ifr_ifru.ifru_flags[1] /* flags (high 16 bits) */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ Index: sys/pci/if_sis.c =================================================================== RCS file: /usr/local/ncvs/src/sys/pci/if_sis.c,v retrieving revision 1.132.2.7 diff -u -r1.132.2.7 if_sis.c --- sys/pci/if_sis.c 17 Mar 2006 21:30:57 -0000 1.132.2.7 +++ sys/pci/if_sis.c 5 May 2006 23:05:57 -0000 @@ -126,6 +126,10 @@ static void sis_startl(struct ifnet *); static void sis_stop(struct sis_softc *); static void sis_watchdog(struct ifnet *); +static void sis_get_wolopts(struct sis_softc *, struct if_wolopts *); +static int sis_set_wolopts(struct sis_softc *, struct if_wolopts *); +static void sis_enable_wol(struct sis_softc *); +static uint32_t sis_translate_wol_events(uint32_t); #ifdef SIS_USEIOSPACE #define SIS_RES SYS_RES_IOPORT @@ -170,7 +174,7 @@ static void sis_dma_map_ring(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - u_int32_t *p; + uint32_t *p; p = arg; *p = segs->ds_addr; @@ -258,7 +262,7 @@ sis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest) { int i; - u_int16_t word = 0; + uint16_t word = 0; /* Force EEPROM to idle state. */ sis_eeprom_idle(sc); @@ -301,11 +305,11 @@ sis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap) { int i; - u_int16_t word = 0, *ptr; + uint16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { sis_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); + ptr = (uint16_t *)(dest + (i * 2)); if (swap) *ptr = ntohs(word); else @@ -354,7 +358,7 @@ sis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt) { device_t bridge; - u_int8_t reg; + uint8_t reg; int i; bus_space_tag_t btag; @@ -383,7 +387,7 @@ static void sis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest) { - u_int32_t filtsave, csrsave; + uint32_t filtsave, csrsave; filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); csrsave = CSR_READ_4(sc, SIS_CSR); @@ -394,11 +398,11 @@ CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); - ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); - ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); - ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); CSR_WRITE_4(sc, SIS_CSR, csrsave); @@ -731,7 +735,7 @@ { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h = 0, i, filtsave; + uint32_t h = 0, i, filtsave; int bit, index; ifp = sc->sis_ifp; @@ -782,8 +786,8 @@ { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h, i, n, ctl; - u_int16_t hashes[16]; + uint32_t h, i, n, ctl; + uint16_t hashes[16]; ifp = sc->sis_ifp; @@ -984,7 +988,7 @@ * Why? Who the hell knows. */ { - u_int16_t tmp[4]; + uint16_t tmp[4]; sis_read_eeprom(sc, (caddr_t)&tmp, NS_EE_NODEADDR, 4, 0); @@ -1406,7 +1410,7 @@ struct ifnet *ifp; struct sis_desc *cur_rx; int total_len = 0; - u_int32_t rxstat; + uint32_t rxstat; SIS_LOCK_ASSERT(sc); @@ -1501,7 +1505,7 @@ sis_txeof(struct sis_softc *sc) { struct ifnet *ifp; - u_int32_t idx; + uint32_t idx; SIS_LOCK_ASSERT(sc); ifp = sc->sis_ifp; @@ -1605,7 +1609,7 @@ sis_startl(ifp); if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { - u_int32_t status; + uint32_t status; /* Reading the ISR register clears all interrupts. */ status = CSR_READ_4(sc, SIS_ISR); @@ -1631,7 +1635,7 @@ { struct sis_softc *sc; struct ifnet *ifp; - u_int32_t status; + uint32_t status; sc = arg; ifp = sc->sis_ifp; @@ -1785,7 +1789,7 @@ { struct sis_softc *sc; struct mbuf *m_head = NULL; - u_int32_t idx, queued = 0; + uint32_t idx, queued = 0; sc = ifp->if_softc; @@ -1872,23 +1876,23 @@ if (sc->sis_type == SIS_TYPE_83815) { CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); } else { CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); } /* Init circular TX/RX lists. */ @@ -2162,6 +2166,21 @@ } #endif /* DEVICE_POLLING */ break; + case SIOCGIFWOLSUPP: + ifr->ifr_wolopts.ifwol_supported = NS_SUPPORTED_WOL_EVENTS; + error = 0; + break; + case SIOCGIFWOLOPTS: + SIS_LOCK(sc); + sis_get_wolopts(sc, &ifr->ifr_wolopts); + SIS_UNLOCK(sc); + error = 0; + break; + case SIOCSIFWOLOPTS: + SIS_LOCK(sc); + error = sis_set_wolopts(sc, &ifr->ifr_wolopts); + SIS_UNLOCK(sc); + break; default: error = ether_ioctl(ifp, command, data); break; @@ -2271,9 +2290,141 @@ SIS_LOCK(sc); sis_reset(sc); sis_stop(sc); + sis_enable_wol(sc); SIS_UNLOCK(sc); } +/* + * Translate wake on lan events defined in if.h + * into flags the chip understands. + */ +static uint32_t +sis_translate_wol_events(uint32_t wol_events) +{ + uint32_t sis_wol_events = 0; + + if (wol_events & IFWOL_WAKE_ON_UNICAST) + sis_wol_events |= NS_WCSR_WAKE_UCAST; + if (wol_events & IFWOL_WAKE_ON_MULTICAST) + sis_wol_events |= NS_WCSR_WAKE_MCAST; + if (wol_events & IFWOL_WAKE_ON_BROADCAST) + sis_wol_events |= NS_WCSR_WAKE_BCAST; + if (wol_events & IFWOL_WAKE_ON_MAGIC) + sis_wol_events |= NS_WCSR_WAKE_MAGIC; + + return sis_wol_events; +} + +/* + * Write current wake on lan settings into an if_wolopts structure. + * Note that the sopasswd field in the structure is cleared, because + * the password is confidential. + */ +static void +sis_get_wolopts(struct sis_softc *sc, struct if_wolopts *wolopts) +{ + int i; + + SIS_LOCK_ASSERT(sc); + + wolopts->ifwol_events = sc->ns_wol_events; + + /* Do not disclose Secure On password. */ +#define N(a) (sizeof(a) / sizeof(a[0])) + for (i = 0; i < N(wolopts->ifwol_sopasswd); i++) + wolopts->ifwol_sopasswd[i] = '\0'; +#undef N +} + +/* + * Set wake on lan options. + */ +static int +sis_set_wolopts(struct sis_softc *sc, struct if_wolopts *wolopts) +{ + SIS_LOCK_ASSERT(sc); + + /* FIXME: handle sopasswd */ + + if (wolopts->ifwol_events == IFWOL_DISABLE) + sc->ns_wol_events = 0; + else { + if ((wolopts->ifwol_events & ~NS_SUPPORTED_WOL_EVENTS) != 0) + return EINVAL; + sc->ns_wol_events = wolopts->ifwol_events; + } + + return 0; +} + +/* + * Enable Wake On Lan on the DP83815, + * if any wake on lan options have been set. + */ +static void +sis_enable_wol(struct sis_softc *sc) +{ + SIS_LOCK_ASSERT(sc); + + if (sc->sis_type != SIS_TYPE_83815) + return; + + /* Check whether any wake on lan events have been set. */ + if (sc->ns_wol_events == 0) + return; + + /* + * Configure the recieve filter to accept potential wake packets, + * configure wake events and enter low-power state. + */ + + /* Stop reciever. */ + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_DISABLE); + + /* Reset recieve pointer */ + CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); + + /* Re-enable reciever (now in "silent recieve mode.") */ + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); + + /* Clear recieve filter register, so that the enable bit is unset. + * Other bits in this register can only be configured while the enable + * bit is zero. */ + CSR_WRITE_4(sc, SIS_RXFILT_CTL, 0); + + /* + * Accept unicast packets. The datasheet seems to be inaccurate. + * It suggests simply setting the unicast bit in NS_RXFILTCTL, + * but this does not seem to work. Instead, we "perfect match" + * our own mac address, which makes the rx filter accept unicast + * packets. (section below copy pasted from sis_initl routine) + */ + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[0]); + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[1]); + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, + ((uint16_t *)IFP2ENADDR(sc->sis_ifp))[2]); + SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT); + + /* Allow broadcast and multicast packets, too. */ + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); + + /* Re-enable RX filter. */ + SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); + + /* Configure wake on lan events */ + CSR_WRITE_4(sc, NS_WCSR, sis_translate_wol_events(sc->ns_wol_events)); + + /* Set appropriate power state, so the card stays active + * after system shutdown. */ + CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS | NS_CLKRUN_PMEENB); +} + static device_method_t sis_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sis_probe), Index: sys/pci/if_sisreg.h =================================================================== RCS file: /usr/local/ncvs/src/sys/pci/if_sisreg.h,v retrieving revision 1.33.2.1 diff -u -r1.33.2.1 if_sisreg.h --- sys/pci/if_sisreg.h 29 Sep 2005 18:52:21 -0000 1.33.2.1 +++ sys/pci/if_sisreg.h 6 May 2006 10:59:50 -0000 @@ -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 @@ -463,6 +464,7 @@ #endif int in_tick; struct mtx sis_mtx; + uint32_t ns_wol_events; }; #define SIS_LOCK(_sc) mtx_lock(&(_sc)->sis_mtx) @@ -523,3 +525,17 @@ #define SIS_PSTATE_D3 0x0003 #define SIS_PME_EN 0x0010 #define SIS_PME_STATUS 0x8000 + +/* DP83815 pci config space power management register */ +#define NS_PMCSR 0x44 + +/* DP83815 Wake On Lan Command/Status register */ +#define NS_WCSR_WAKE_UCAST 0x00000002 +#define NS_WCSR_WAKE_MCAST 0x00000004 +#define NS_WCSR_WAKE_BCAST 0x00000008 +#define NS_WCSR_WAKE_MAGIC 0x00000200 + +/* FIXME: handle sopasswd */ +#define NS_SUPPORTED_WOL_EVENTS (IFWOL_WAKE_ON_UNICAST | IFWOL_WAKE_ON_MULTICAST \ + | IFWOL_WAKE_ON_BROADCAST | IFWOL_WAKE_ON_MAGIC) + Index: sys/pci/if_vr.c =================================================================== RCS file: /usr/local/ncvs/src/sys/pci/if_vr.c,v retrieving revision 1.104.2.6 diff -u -r1.104.2.6 if_vr.c --- sys/pci/if_vr.c 17 Mar 2006 21:30:57 -0000 1.104.2.6 +++ sys/pci/if_vr.c 5 May 2006 23:05:57 -0000 @@ -169,6 +169,10 @@ static int vr_list_rx_init(struct vr_softc *); static int vr_list_tx_init(struct vr_softc *); +static int vr_set_wolopts(struct vr_softc *, struct if_wolopts *); +static void vr_get_wolopts(struct vr_softc *, struct if_wolopts *); +static void vr_enable_wol(struct vr_softc *); + #ifdef VR_USEIOSPACE #define VR_RES SYS_RES_IOPORT #define VR_RID VR_PCI_LOIO @@ -710,7 +714,7 @@ #endif /* - * Windows may put the chip in suspend mode when it + * Windows or WOL may put the chip in suspend mode when it * shuts down. Be sure to kick it in the head to wake it * up again. */ @@ -761,6 +765,13 @@ sc->suspended = 0; + /* Check Wake on Lan support. */ + if (sc->vr_revid >= REV_ID_VT6102 ) { + sc->wol_support = 1; + if (sc->vr_revid >= REV_ID_VT6105_B0) + sc->wol_6patterns = 1; + } + /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, vr_intr, sc, &sc->vr_intrhand); @@ -1618,6 +1629,21 @@ } #endif /* DEVICE_POLLING */ break; + case SIOCGIFWOLSUPP: + ifr->ifr_wolopts.ifwol_supported = VR_SUPPORTED_WOL_EVENTS; + error = 0; + break; + case SIOCGIFWOLOPTS: + VR_LOCK(sc); + vr_get_wolopts(sc, &ifr->ifr_wolopts); + VR_UNLOCK(sc); + error = 0; + break; + case SIOCSIFWOLOPTS: + VR_LOCK(sc); + error = vr_set_wolopts(sc, &ifr->ifr_wolopts); + VR_UNLOCK(sc); + break; default: error = ether_ioctl(ifp, command, data); break; @@ -1702,6 +1728,92 @@ static void vr_shutdown(device_t dev) { + struct vr_softc *sc; + sc = device_get_softc(dev); + VR_LOCK(sc); + vr_enable_wol(sc); + VR_UNLOCK(sc); vr_detach(dev); } + +static void +vr_enable_wol(struct vr_softc *sc) +{ + VR_LOCK_ASSERT(sc); + + /* Check whether wake on lan is available + * and whether events have been set. */ + if (!sc->wol_support || sc->wol_events == 0) + return; + + /* Set the chip to power state D0 */ + VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); + + /* Clear WOL configuration */ + CSR_WRITE_1(sc, VR_WOLCRCLR, 0xFF); + if (sc->wol_6patterns) + CSR_WRITE_1(sc, VR_WOLCRCLR1, 0x03); + + /* Clear power-event status. */ + CSR_WRITE_1(sc, VR_PWRCSRCLR, 0xFF); + + /* Don't use extra patterns. */ + if (sc->wol_6patterns) + CSR_WRITE_1(sc, VR_WOLCGCLR, 0x04); + + /* Set unicast wake event if applicable. */ + if (sc->wol_events & IFWOL_WAKE_ON_UNICAST) + VR_SETBIT(sc, VR_WOLCRSET, VR_WAKE_UCAST); + + /* Set magic wake event if applicable. */ + if (sc->wol_events & IFWOL_WAKE_ON_MAGIC) { + VR_SETBIT(sc, VR_WOLCRSET, VR_WAKE_MAGIC); + /* enable EEPROM-controlled wake-up */ + VR_SETBIT(sc, VR_CONFIG, 0x03); + } +#if 0 + /* Set broadcast/multicast wake event if applicable. */ + /* Does not work for some reason :( */ + if (sc->wol_events & IFWOL_WAKE_ON_BROADCAST || + sc->wol_events & IFWOL_WAKE_ON_MULTICAST) + CSR_WRITE_1(sc, VR_WOLCGSET, VR_WAKE_BMCAST); +#endif + /* Enable Wake On Lan. */ + CSR_WRITE_1(sc, VR_PWCFGSET, 0x01); + VR_SETBIT(sc, VR_STICKHW, VR_STICKHW_WOL_ENB); + + /* Set power state to D3 */ + VR_SETBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); +} + + +/* + * Write current wake on lan settings into an if_wolopts structure. + */ +static void +vr_get_wolopts(struct vr_softc *sc, struct if_wolopts *wolopts) +{ + VR_LOCK_ASSERT(sc); + wolopts->ifwol_events = sc->wol_events; +} + +/* + * Set wake on lan options. + */ +static int +vr_set_wolopts(struct vr_softc *sc, struct if_wolopts *wolopts) +{ + VR_LOCK_ASSERT(sc); + + if (wolopts->ifwol_events == IFWOL_DISABLE) + sc->wol_events = 0; + else { + if ((wolopts->ifwol_events & ~VR_SUPPORTED_WOL_EVENTS) != 0) + return EINVAL; + sc->wol_events = wolopts->ifwol_events; + } + + return 0; +} + Index: sys/pci/if_vrreg.h =================================================================== RCS file: /usr/local/ncvs/src/sys/pci/if_vrreg.h,v retrieving revision 1.22.2.1 diff -u -r1.22.2.1 if_vrreg.h --- sys/pci/if_vrreg.h 8 Nov 2005 16:05:56 -0000 1.22.2.1 +++ sys/pci/if_vrreg.h 5 May 2006 23:05:58 -0000 @@ -283,6 +283,21 @@ #define VR_STICKHW_WOL_STS 0x08 #define VR_STICKHW_LEGWOL_ENB 0x80 +/* Wake on Lan definitions (snooped from Linux driver) */ +#define VR_WOLCRSET 0xA0 +#define VR_PWCFGSET 0xA1 +#define VR_WOLCGSET 0xA3 +#define VR_WOLCRCLR 0xA4 +#define VR_WOLCRCLR1 0xA6 +#define VR_WOLCGCLR 0xA7 +#define VR_PWRCSRCLR 0xAC +#define VR_WAKE_UCAST 0x10 +#define VR_WAKE_MAGIC 0x20 +#define VR_WAKE_BMCAST 0x30 +#define VR_WAKE_LINKON 0x40 +#define VR_WAKE_LINKOFF 0x80 +#define VR_SUPPORTED_WOL_EVENTS (IFWOL_WAKE_ON_UNICAST | IFWOL_WAKE_ON_MAGIC) + /* * BCR0 register bits. (At least for the VT6102 chip.) */ @@ -471,6 +486,10 @@ #ifdef DEVICE_POLLING int rxcycles; #endif + int wol_support; /* Chip supports WOL. */ + uint32_t wol_events; /* Wake on Lan satus */ + int wol_6patterns; /* some chips have 6 patterns + for WOL instead of 4 */ }; #define VR_F_RESTART 0x01 /* Restart unit on next tick */ @@ -545,10 +564,14 @@ #define REV_ID_VT3065_A 0x40 #define REV_ID_VT3065_B 0x41 #define REV_ID_VT3065_C 0x42 +#define REV_ID_VT6102 0x40 #define REV_ID_VT6102_APOLLO 0x74 #define REV_ID_VT3106 0x80 #define REV_ID_VT3106_J 0x80 /* 0x80-0x8F */ #define REV_ID_VT3106_S 0x90 /* 0x90-0xA0 */ +#define REV_ID_VT6105 0x80 +#define REV_ID_VT6105_B0 0x83 + /* * PCI low memory base and low I/O base register, and Index: sys/sys/sockio.h =================================================================== RCS file: /usr/local/ncvs/src/sys/sys/sockio.h,v retrieving revision 1.28.2.1 diff -u -r1.28.2.1 sockio.h --- sys/sys/sockio.h 15 Feb 2006 03:37:15 -0000 1.28.2.1 +++ sys/sys/sockio.h 5 May 2006 23:05:58 -0000 @@ -117,4 +117,11 @@ #define SIOCIFDESTROY _IOW('i', 121, struct ifreq) /* destroy clone if */ #define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */ +#define SIOCGIFWOLOPTS _IOWR('i', 124, struct ifreq) /* get wake on lan + options */ +#define SIOCSIFWOLOPTS _IOW('i', 125, struct ifreq) /* set wake on lan + options */ +#define SIOCGIFWOLSUPP _IOWR('i', 126, struct ifreq) /* get wake on lan + modes supported by + device */ #endif /* !_SYS_SOCKIO_H_ */