From owner-svn-src-head@FreeBSD.ORG Thu Sep 30 17:37:08 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8A18C106566B; Thu, 30 Sep 2010 17:37:08 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 661338FC17; Thu, 30 Sep 2010 17:37:08 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8UHb8io076468; Thu, 30 Sep 2010 17:37:08 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8UHb8OD076466; Thu, 30 Sep 2010 17:37:08 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201009301737.o8UHb8OD076466@svn.freebsd.org> From: Pyun YongHyeon Date: Thu, 30 Sep 2010 17:37:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213306 - head/sys/pci X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Sep 2010 17:37:08 -0000 Author: yongari Date: Thu Sep 30 17:37:08 2010 New Revision: 213306 URL: http://svn.freebsd.org/changeset/base/213306 Log: Rename rl_setmulti() to rl_rxfilter() as rl_rxfilter() will handle IFF_ALLMULTI/IFF_PROMISC as well as multicast filter configuration. Rewrite RX filter logic to reduce number of register accesses and make it handle promiscuous/allmulti toggling without controller reinitialization. Previously rl(4) counted on controller reinitialization to reprogram promiscuous configuration but r211767 resulted in avoiding controller reinitialization whenever promiscuous mode is toggled. To address this, keep track of driver's view of interface state and handle IFF_ALLMULTI/IFF_PROMISC changes without reinitializing controller. This should fix a regression introduced in r211267. While I'm here remove unnecessary variable reassignment in ioctl handler. PR: kern/151079 MFC after: 1 week Modified: head/sys/pci/if_rl.c Modified: head/sys/pci/if_rl.c ============================================================================== --- head/sys/pci/if_rl.c Thu Sep 30 17:05:23 2010 (r213305) +++ head/sys/pci/if_rl.c Thu Sep 30 17:37:08 2010 (r213306) @@ -203,7 +203,7 @@ static void rl_read_eeprom(struct rl_sof static void rl_reset(struct rl_softc *); static int rl_resume(device_t); static int rl_rxeof(struct rl_softc *); -static void rl_setmulti(struct rl_softc *); +static void rl_rxfilter(struct rl_softc *); static int rl_shutdown(device_t); static void rl_start(struct ifnet *); static void rl_start_locked(struct ifnet *); @@ -655,54 +655,51 @@ rl_miibus_statchg(device_t dev) * Program the 64-bit multicast hash filter. */ static void -rl_setmulti(struct rl_softc *sc) +rl_rxfilter(struct rl_softc *sc) { struct ifnet *ifp = sc->rl_ifp; int h = 0; uint32_t hashes[2] = { 0, 0 }; struct ifmultiaddr *ifma; uint32_t rxfilt; - int mcnt = 0; RL_LOCK_ASSERT(sc); rxfilt = CSR_READ_4(sc, RL_RXCFG); - + rxfilt &= ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_BROAD | + RL_RXCFG_RX_MULTI); + /* Always accept frames destined for this host. */ + rxfilt |= RL_RXCFG_RX_INDIV; + /* Set capture broadcast bit to capture broadcast frames. */ + if (ifp->if_flags & IFF_BROADCAST) + rxfilt |= RL_RXCFG_RX_BROAD; if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { rxfilt |= RL_RXCFG_RX_MULTI; - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); - CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); - return; - } - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, RL_MAR0, 0); - CSR_WRITE_4(sc, RL_MAR4, 0); - - /* now program new ones */ - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; + if (ifp->if_flags & IFF_PROMISC) + rxfilt |= RL_RXCFG_RX_ALLPHYS; + hashes[0] = 0xFFFFFFFF; + hashes[1] = 0xFFFFFFFF; + } else { + /* Now program new ones. */ + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + } + if_maddr_runlock(ifp); + if (hashes[0] != 0 || hashes[1] != 0) + rxfilt |= RL_RXCFG_RX_MULTI; } - if_maddr_runlock(ifp); - - if (mcnt) - rxfilt |= RL_RXCFG_RX_MULTI; - else - rxfilt &= ~RL_RXCFG_RX_MULTI; - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); CSR_WRITE_4(sc, RL_MAR0, hashes[0]); CSR_WRITE_4(sc, RL_MAR4, hashes[1]); + CSR_WRITE_4(sc, RL_RXCFG, rxfilt); } static void @@ -1807,7 +1804,6 @@ rl_init_locked(struct rl_softc *sc) { struct ifnet *ifp = sc->rl_ifp; struct mii_data *mii; - uint32_t rxcfg = 0; uint32_t eaddr[2]; RL_LOCK_ASSERT(sc); @@ -1864,30 +1860,8 @@ rl_init_locked(struct rl_softc *sc) CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); - /* Set the individual bit to receive frames for this host only. */ - rxcfg = CSR_READ_4(sc, RL_RXCFG); - rxcfg |= RL_RXCFG_RX_INDIV; - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - rxcfg |= RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* Set capture broadcast bit to capture broadcast frames. */ - if (ifp->if_flags & IFF_BROADCAST) { - rxcfg |= RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* Program the multicast filter, if necessary. */ - rl_setmulti(sc); + /* Set RX filter. */ + rl_rxfilter(sc); #ifdef DEVICE_POLLING /* Disable interrupts if we are polling. */ @@ -1966,20 +1940,22 @@ rl_ioctl(struct ifnet *ifp, u_long comma case SIOCSIFFLAGS: RL_LOCK(sc); if (ifp->if_flags & IFF_UP) { - rl_init_locked(sc); - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - rl_stop(sc); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + ((ifp->if_flags ^ sc->rl_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI))) + rl_rxfilter(sc); + else + rl_init_locked(sc); + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rl_stop(sc); + sc->rl_if_flags = ifp->if_flags; RL_UNLOCK(sc); - error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: RL_LOCK(sc); - rl_setmulti(sc); + rl_rxfilter(sc); RL_UNLOCK(sc); - error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: