From owner-freebsd-bugs@FreeBSD.ORG Sun Jun 20 16:50:02 2010 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5EF771065675 for ; Sun, 20 Jun 2010 16:50:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 3B7A68FC24 for ; Sun, 20 Jun 2010 16:50:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id o5KGo2ur021573 for ; Sun, 20 Jun 2010 16:50:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id o5KGo2Sw021572; Sun, 20 Jun 2010 16:50:02 GMT (envelope-from gnats) Resent-Date: Sun, 20 Jun 2010 16:50:02 GMT Resent-Message-Id: <201006201650.o5KGo2Sw021572@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, David Naylor Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 620A5106566C for ; Sun, 20 Jun 2010 16:40:11 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id B78FE8FC1A for ; Sun, 20 Jun 2010 16:40:10 +0000 (UTC) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o5KGeAJ9033640 for ; Sun, 20 Jun 2010 16:40:10 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id o5KGeAvV033631; Sun, 20 Jun 2010 16:40:10 GMT (envelope-from nobody) Message-Id: <201006201640.o5KGeAvV033631@www.freebsd.org> Date: Sun, 20 Jun 2010 16:40:10 GMT From: David Naylor To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/148013: [patch] add WoL support to rl(4) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Jun 2010 16:50:02 -0000 >Number: 148013 >Category: kern >Synopsis: [patch] add WoL support to rl(4) >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: update >Submitter-Id: current-users >Arrival-Date: Sun Jun 20 16:50:01 UTC 2010 >Closed-Date: >Last-Modified: >Originator: David Naylor >Release: FreeBSD-9 >Organization: Private >Environment: FreeBSD dragon.dg 9.0-CURRENT FreeBSD 9.0-CURRENT #0: Sat Jun 19 19:08:38 SAST 2010 root@dragon.dg:/tmp/home/freebsd9/src/sys/DRAGON amd64 >Description: Add WoL support for the rl(4) driver. The relevant portions were taken from the re(4) driver (the Linux drivers [1] [2]) also had the same implementations. I removed what I considered irrelevant code for the rl(4) driver. I've tested this with 8139D. DISCLAIMER: I have no experience with coding drivers (or anything in the kernel). [1] rl(4) equivalent*: http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.34.y.git;a=blob_plain;f=drivers/net/8139too.c;hb=HEAD [2] re(4) equivalent*: http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.34.y.git;a=blob_plain;f=drivers/net/8139cp.c;hb=HEAD *) see the *_set_wol() function. >How-To-Repeat: n/a >Fix: n/a Patch attached with submission follows: --- /usr/src/sys/pci/if_rl.c 2010-06-20 18:25:03.000000000 +0200 +++ if_rl.c 2010-06-20 15:08:32.000000000 +0200 @@ -182,6 +182,7 @@ }; static int rl_attach(device_t); +static void rl_clrwol(struct rl_softc *); static int rl_detach(device_t); static void rl_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int rl_dma_alloc(struct rl_softc *); @@ -214,6 +215,7 @@ static int rl_resume(device_t); static int rl_rxeof(struct rl_softc *); static void rl_setmulti(struct rl_softc *); +static void rl_setwol(struct rl_softc *); static int rl_shutdown(device_t); static void rl_start(struct ifnet *); static void rl_start_locked(struct ifnet *); @@ -804,7 +806,7 @@ struct sysctl_ctx_list *ctx; struct sysctl_oid_list *children; int error = 0, i, rid; - int unit; + int unit, reg; uint16_t rl_did = 0; char tn[32]; @@ -938,6 +940,16 @@ ifp->if_start = rl_start; ifp->if_init = rl_init; ifp->if_capabilities = IFCAP_VLAN_MTU; + /* Enable WOL if PM and chipset (810[01]/8130B?/8139[BCD]) supported. */ + device_printf(sc->rl_dev, "RL_TYPE=0x%x\n", sc->rl_type); + device_printf(sc->rl_dev, "RL_HWREV=0x%x\n", CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV); + device_printf(sc->rl_dev, "PM=%d\n", pci_find_extcap(sc->rl_dev, PCIY_PMG, ®)); + if ((sc->rl_type == RL_8139) && + ((CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV) > RL_HWREV_8139AG) && + (pci_find_extcap(sc->rl_dev, PCIY_PMG, ®) == 0)) { + ifp->if_capabilities |= IFCAP_WOL; + device_printf(sc->rl_dev, "IFCAP_WOL\n"); + } ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; @@ -2066,6 +2078,7 @@ RL_LOCK(sc); rl_stop(sc); + rl_setwol(sc); sc->suspended = 1; RL_UNLOCK(sc); @@ -2087,6 +2100,12 @@ ifp = sc->rl_ifp; RL_LOCK(sc); + + /* + * Clear WOL matching such that normal Rx filtering + * wouldn't interfere with WOL patterns. + */ + rl_clrwol(sc); /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) @@ -2112,7 +2131,87 @@ RL_LOCK(sc); rl_stop(sc); + /* + * Mark interface as down since otherwise we will panic if + * interrupt comes in later on, which can happen in some + * cases. + */ + sc->rl_ifp->if_flags &= ~IFF_UP; + rl_setwol(sc); RL_UNLOCK(sc); return (0); } + + +static void +rl_setwol(struct rl_softc *sc) +{ + struct ifnet *ifp; + int pmc; + uint8_t v; + + RL_LOCK_ASSERT(sc); + + if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0) + return; + + ifp = sc->rl_ifp; + + /* Enable PME. */ + v = CSR_READ_1(sc, RL_CFG1); + v &= ~RL_CFG1_PME; + if ((ifp->if_capenable & IFCAP_WOL) != 0) + v |= RL_CFG1_PME; + CSR_WRITE_1(sc, RL_CFG1, v); + + v = CSR_READ_1(sc, RL_CFG3); + v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC); + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + v |= RL_CFG3_WOL_MAGIC; + CSR_WRITE_1(sc, RL_CFG3, v); + + /* Config register write done. */ + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); + + v = CSR_READ_1(sc, RL_CFG5); + v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST); + v &= ~RL_CFG5_WOL_LANWAKE; + if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0) + v |= RL_CFG5_WOL_UCAST; + if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) + v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST; + if ((ifp->if_capenable & IFCAP_WOL) != 0) + v |= RL_CFG5_WOL_LANWAKE; + CSR_WRITE_1(sc, RL_CFG5, v); + device_printf(sc->rl_dev, "WOL set: 0x%x\n", v); +} + +static void +rl_clrwol(struct rl_softc *sc) +{ + int pmc; + uint8_t v; + + RL_LOCK_ASSERT(sc); + + if (pci_find_extcap(sc->rl_dev, PCIY_PMG, &pmc) != 0) + return; + + /* Enable config register write. */ + CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE); + + v = CSR_READ_1(sc, RL_CFG3); + v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC); + CSR_WRITE_1(sc, RL_CFG3, v); + + /* Config register write done. */ + CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); + + v = CSR_READ_1(sc, RL_CFG5); + v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST); + v &= ~RL_CFG5_WOL_LANWAKE; + CSR_WRITE_1(sc, RL_CFG5, v); + + device_printf(sc->rl_dev, "WOL cleared\n"); +} >Release-Note: >Audit-Trail: >Unformatted: