--- sys/pci/if_rlreg.h.ORIG 2008-01-06 15:13:57.000000000 +0100 +++ sys/pci/if_rlreg.h 2008-01-06 20:57:24.000000000 +0100 @@ -76,7 +76,11 @@ #define RL_EECMD 0x0050 /* EEPROM command register */ #define RL_CFG0 0x0051 /* config register #0 */ #define RL_CFG1 0x0052 /* config register #1 */ - /* 0053-0057 reserved */ +#define RL_CFG2 0x0053 /* config register #2 */ +#define RL_CFG3 0x0054 /* config register #3 */ +#define RL_CFG4 0x0055 /* config register #4 */ +#define RL_CFG5 0x0056 /* config register #5 */ + /* 0057 reserved */ #define RL_MEDIASTAT 0x0058 /* media status register (8139) */ /* 0059-005A reserved */ #define RL_MII 0x005A /* 8129 chip only */ @@ -357,7 +361,7 @@ /* * Config 1 register */ -#define RL_CFG1_PWRDWN 0x01 +#define RL_CFG1_PWRDWN 0x01 /* Power Management Enable */ #define RL_CFG1_SLEEP 0x02 #define RL_CFG1_IOMAP 0x04 #define RL_CFG1_MEMMAP 0x08 @@ -368,6 +372,22 @@ #define RL_CFG1_LED1 0x80 /* + * Config 3 register + */ +#define RL_CFG3_WAKE_ON_MAGIC 0x20 /* Wake up when receives a Magic Packet */ +#define RL_CFG3_WAKE_ON_LINK 0x10 /* Wake up when the cable connection is re-established */ + +/* + * Config 5 register + */ +#define RL_CFG5_WAKE_BCAST 0x40 /* Accept Broadcast wakeup frame */ +#define RL_CFG5_WAKE_MCAST 0x20 /* Accept Multicast wakeup frame */ +#define RL_CFG5_WAKE_UCAST 0x10 /* Accept Unicast wakeup frame */ +#define RL_CFG5_WAKE_ANY 0x02 /* LanWake enable/disable */ +#define RL_CFG5_PMESTATUS 0x01 /* PME status can be reset by PCI RST# */ + + +/* * 8139C+ register definitions */ @@ -741,6 +761,8 @@ struct mtx rl_intlock; int rl_txstart; int rl_link; + int rl_wolsupport; /* Chip supports WOL. */ + u_int32_t rl_wolevents; /* Wake on Lan status */ }; #define RL_LOCK(_sc) mtx_lock(&(_sc)->rl_mtx) @@ -989,3 +1011,5 @@ #define RL_PSTATE_D3 0x0003 #define RL_PME_EN 0x0010 #define RL_PME_STATUS 0x8000 + +#define ISSET(t, f) ((t) & (f)) --- sys/dev/re/if_re.c.orig 2008-01-24 10:14:48.000000000 +0100 +++ sys/dev/re/if_re.c 2008-01-30 23:52:52.000000000 +0100 @@ -162,6 +162,8 @@ #define RE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) +#define RE_SUPPORTED_WOL_EVENTS (IFWOL_WAKE_ON_UNICAST | IFWOL_WAKE_ON_MULTICAST | IFWOL_WAKE_ON_BROADCAST | IFWOL_WAKE_ON_MAGIC | IFWOL_WAKE_ON_LINK) + /* * Various supported device vendors/types and their names. */ @@ -278,6 +280,10 @@ static int re_diag (struct rl_softc *); #endif +static int re_set_wolopts(struct rl_softc *, struct if_wolopts *); +static void re_get_wolopts(struct rl_softc *, struct if_wolopts *); +static void re_enable_wol(struct rl_softc *); + #ifdef RE_USEIOSPACE #define RL_RES SYS_RES_IOPORT #define RL_RID RL_PCI_LOIO @@ -2474,6 +2480,25 @@ CSR_WRITE_1(sc, RL_CFG1, CSR_READ_1(sc, RL_CFG1) | RL_CFG1_DRVLOAD); + /* Read initial WOL settings */ + sc->rl_wolevents = 0; + if (ISSET(CSR_READ_1(sc, RL_CFG1), RL_CFG1_PWRDWN)) { + u_int32_t cfg; + + cfg = CSR_READ_1(sc, RL_CFG3); + if (ISSET(cfg, RL_CFG3_WAKE_ON_LINK)) + sc->rl_wolevents |= IFWOL_WAKE_ON_LINK; + if (ISSET(cfg, RL_CFG3_WAKE_ON_MAGIC)) + sc->rl_wolevents |= IFWOL_WAKE_ON_MAGIC; + cfg = CSR_READ_1(sc, RL_CFG5); + if (ISSET(cfg, RL_CFG5_WAKE_UCAST)) + sc->rl_wolevents |= IFWOL_WAKE_ON_UNICAST; + if (ISSET(cfg, RL_CFG5_WAKE_MCAST)) + sc->rl_wolevents |= IFWOL_WAKE_ON_MULTICAST; + if (ISSET(cfg, RL_CFG5_WAKE_BCAST)) + sc->rl_wolevents |= IFWOL_WAKE_ON_BROADCAST; + } + ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -2614,6 +2639,21 @@ #endif } break; + case SIOCGIFWOLSUPP: + ifr->ifr_wolopts.ifwol_supported = RE_SUPPORTED_WOL_EVENTS; + error = 0; + break; + case SIOCGIFWOLOPTS: + RL_LOCK(sc); + re_get_wolopts(sc, &ifr->ifr_wolopts); + RL_UNLOCK(sc); + error = 0; + break; + case SIOCSIFWOLOPTS: + RL_LOCK(sc); + error = re_set_wolopts(sc, &ifr->ifr_wolopts); + RL_UNLOCK(sc); + break; default: error = ether_ioctl(ifp, command, data); break; @@ -2706,6 +2746,7 @@ RL_LOCK(sc); re_stop(sc); + re_enable_wol(sc); sc->suspended = 1; RL_UNLOCK(sc); @@ -2760,5 +2801,87 @@ * cases. */ sc->rl_ifp->if_flags &= ~IFF_UP; + re_enable_wol(sc); RL_UNLOCK(sc); } + +static void +re_enable_wol(struct rl_softc *sc) +{ + u_int32_t ocfg1, ocfg3, ocfg5, cfg1, cfg3, cfg5; + + RL_LOCK_ASSERT(sc); + + /* Check whether wake on lan is available + * and whether events have been set. */ + if (!sc->rl_wolsupport) + return; + + ocfg1 = cfg1 = CSR_READ_1(sc, RL_CFG1); + ocfg3 = cfg3 = CSR_READ_1(sc, RL_CFG3); + ocfg5 = cfg5 = CSR_READ_1(sc, RL_CFG5); + + cfg1 &= (RL_CFG1_PWRDWN); + cfg3 &= (RL_CFG3_WAKE_ON_LINK | RL_CFG3_WAKE_ON_MAGIC); + cfg5 &= (RL_CFG5_WAKE_UCAST | RL_CFG5_WAKE_MCAST + | RL_CFG5_WAKE_BCAST | RL_CFG5_WAKE_ANY); + + if (sc->rl_wolevents != 0) { + if (ISSET(sc->rl_wolevents, IFWOL_WAKE_ON_UNICAST)) + cfg5 |= RL_CFG5_WAKE_UCAST; + if (ISSET(sc->rl_wolevents, IFWOL_WAKE_ON_MULTICAST)) + cfg5 |= RL_CFG5_WAKE_BCAST; + if (ISSET(sc->rl_wolevents, IFWOL_WAKE_ON_BROADCAST)) + cfg5 |= RL_CFG5_WAKE_BCAST; + cfg5 |= RL_CFG5_WAKE_ANY; + if (ISSET(sc->rl_wolevents, IFWOL_WAKE_ON_MAGIC)) + cfg3 |= RL_CFG3_WAKE_ON_MAGIC; + if (ISSET(sc->rl_wolevents, IFWOL_WAKE_ON_LINK)) + cfg3 |= RL_CFG3_WAKE_ON_LINK; + cfg1 |= RL_CFG1_PWRDWN; + }; + + /* Don't write to EEPROM unless necesary */ + if (ocfg3 != cfg3 || ocfg5 != cfg5 || ocfg1 != cfg1) { + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG); + if (ocfg3 != cfg3) + CSR_WRITE_1(sc, RL_CFG3, cfg3); + if (ocfg5 != cfg5) + CSR_WRITE_1(sc, RL_CFG5, cfg5); + if (ocfg1 != cfg1) + CSR_WRITE_1(sc, RL_CFG1, cfg1); + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); + } +} + +/* + * Write current wake on lan settings into an if_wolopts structure. + */ +static void +re_get_wolopts(struct rl_softc *sc, struct if_wolopts *wolopts) +{ + RL_LOCK_ASSERT(sc); + + wolopts->ifwol_events = sc->rl_wolevents; + return; +} + +/* + * Set wake on lan options. + */ +static int +re_set_wolopts(struct rl_softc *sc, struct if_wolopts *wolopts) +{ + RL_LOCK_ASSERT(sc); + + if (wolopts->ifwol_events == IFWOL_DISABLE) + sc->rl_wolevents = 0; + else { + if ((wolopts->ifwol_events & ~RE_SUPPORTED_WOL_EVENTS) != 0) + return EINVAL; + sc->rl_wolevents = wolopts->ifwol_events; + } + + return 0; +} +