From owner-svn-src-all@FreeBSD.ORG Sat Jan 9 00:02:41 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 156F4106568B; Sat, 9 Jan 2010 00:02:41 +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 02CB88FC24; Sat, 9 Jan 2010 00:02:41 +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 o0902eQo032280; Sat, 9 Jan 2010 00:02:40 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0902evS032278; Sat, 9 Jan 2010 00:02:40 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201001090002.o0902evS032278@svn.freebsd.org> From: Pyun YongHyeon Date: Sat, 9 Jan 2010 00:02:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201860 - stable/8/sys/dev/vge X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Jan 2010 00:02:41 -0000 Author: yongari Date: Sat Jan 9 00:02:40 2010 New Revision: 201860 URL: http://svn.freebsd.org/changeset/base/201860 Log: MFC r200551-200552,200555,200558,200609,200613 r200551: Whenever link state change interrupt is raised, vge_tick() is called and vge(4) used to drive auto-negotiation timer(mii_tick) in vge_tick(). Therefore the mii_tick was not called for every hz such that auto-negotiation complete was never handled in vge(4). Use mii_pollstat to extract current negotiated speed/duplex instead of mii_tick. The latter is valid only for auto-negotiation case. While I'm here change the confusing function name vge_tick() to vge_link_statchg(). r200552: Report media change result to caller instead of returning success without regard to the result. r200555: Don't report current link status if interface is not UP. If interface is not UP, the current link status wouldn't reflect the negotiated status. r200558: Tell upper layer vge(4) supports long frames. This should be done after ether_ifattach(), as ether_ifattach() initializes it with ETHER_HDR_LEN. While I'm here remove setting if_mtu, it's already handled in ether_ifattach(). r200609: All vge(4) controllers support RX/TX checksum offloading for VLAN tagged frames so add checksum offloading capabilities. Also add missing VLAN hardware tagging control in ioctl handler and let upper stack know current VLAN capabilities. r200613: Rewrite RX filter setup and simplify code. Now promiscuous mode and multicast handling is performed in single function, vge_rxfilter(). Modified: stable/8/sys/dev/vge/if_vge.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/dev/vge/if_vge.c ============================================================================== --- stable/8/sys/dev/vge/if_vge.c Sat Jan 9 00:01:35 2010 (r201859) +++ stable/8/sys/dev/vge/if_vge.c Sat Jan 9 00:02:40 2010 (r201860) @@ -168,6 +168,7 @@ static void vge_init(void *); static void vge_init_locked(struct vge_softc *); static void vge_intr(void *); static int vge_ioctl(struct ifnet *, u_long, caddr_t); +static void vge_link_statchg(void *); static int vge_miibus_readreg(device_t, int, int); static void vge_miibus_statchg(device_t); static int vge_miibus_writereg(device_t, int, int, int); @@ -178,11 +179,11 @@ static void vge_read_eeprom(struct vge_s static void vge_reset(struct vge_softc *); static int vge_rx_list_init(struct vge_softc *); static int vge_rxeof(struct vge_softc *, int); -static void vge_setmulti(struct vge_softc *); +static void vge_rxfilter(struct vge_softc *); +static void vge_setvlan(struct vge_softc *); static void vge_start(struct ifnet *); static void vge_start_locked(struct ifnet *); static void vge_stop(struct vge_softc *); -static void vge_tick(void *); static int vge_tx_list_init(struct vge_softc *); static void vge_txeof(struct vge_softc *); static void vge_watchdog(void *); @@ -504,38 +505,66 @@ fail: return (error); } +static void +vge_setvlan(struct vge_softc *sc) +{ + struct ifnet *ifp; + uint8_t cfg; + + VGE_LOCK_ASSERT(sc); + + ifp = sc->vge_ifp; + cfg = CSR_READ_1(sc, VGE_RXCFG); + if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) + cfg |= VGE_VTAG_OPT2; + else + cfg &= ~VGE_VTAG_OPT2; + CSR_WRITE_1(sc, VGE_RXCFG, cfg); +} + /* * Program the multicast filter. We use the 64-entry CAM filter * for perfect filtering. If there's more than 64 multicast addresses, * we use the hash filter instead. */ static void -vge_setmulti(struct vge_softc *sc) +vge_rxfilter(struct vge_softc *sc) { struct ifnet *ifp; - int error = 0/*, h = 0*/; struct ifmultiaddr *ifma; - uint32_t h, hashes[2] = { 0, 0 }; + uint32_t h, hashes[2]; + uint8_t rxcfg; + int error = 0; VGE_LOCK_ASSERT(sc); - ifp = sc->vge_ifp; - /* First, zot all the multicast entries. */ - vge_cam_clear(sc); - CSR_WRITE_4(sc, VGE_MAR0, 0); - CSR_WRITE_4(sc, VGE_MAR1, 0); + hashes[0] = 0; + hashes[1] = 0; + rxcfg = CSR_READ_1(sc, VGE_RXCTL); + rxcfg &= ~(VGE_RXCTL_RX_MCAST | VGE_RXCTL_RX_BCAST | + VGE_RXCTL_RX_PROMISC); /* - * If the user wants allmulti or promisc mode, enable reception - * of all multicast frames. + * Always allow VLAN oversized frames and frames for + * this host. */ - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { - CSR_WRITE_4(sc, VGE_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, VGE_MAR1, 0xFFFFFFFF); - return; + rxcfg |= VGE_RXCTL_RX_GIANT | VGE_RXCTL_RX_UCAST; + + ifp = sc->vge_ifp; + if ((ifp->if_flags & IFF_BROADCAST) != 0) + rxcfg |= VGE_RXCTL_RX_BCAST; + if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { + if ((ifp->if_flags & IFF_PROMISC) != 0) + rxcfg |= VGE_RXCTL_RX_PROMISC; + if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + hashes[0] = 0xFFFFFFFF; + hashes[1] = 0xFFFFFFFF; + } + goto done; } + vge_cam_clear(sc); /* Now program new ones */ if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { @@ -561,11 +590,15 @@ vge_setmulti(struct vge_softc *sc) else hashes[1] |= (1 << (h - 32)); } - - CSR_WRITE_4(sc, VGE_MAR0, hashes[0]); - CSR_WRITE_4(sc, VGE_MAR1, hashes[1]); } if_maddr_runlock(ifp); + +done: + if (hashes[0] != 0 || hashes[1] != 0) + rxcfg |= VGE_RXCTL_RX_MCAST; + CSR_WRITE_4(sc, VGE_MAR0, hashes[0]); + CSR_WRITE_4(sc, VGE_MAR1, hashes[1]); + CSR_WRITE_1(sc, VGE_RXCTL, rxcfg); } static void @@ -1045,13 +1078,13 @@ vge_attach(device_t dev) ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = vge_ioctl; ifp->if_capabilities = IFCAP_VLAN_MTU; ifp->if_start = vge_start; ifp->if_hwassist = VGE_CSUM_FEATURES; - ifp->if_capabilities |= IFCAP_HWCSUM|IFCAP_VLAN_HWTAGGING; + ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | + IFCAP_VLAN_HWTAGGING; ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; @@ -1066,6 +1099,9 @@ vge_attach(device_t dev) */ ether_ifattach(ifp, eaddr); + /* Tell the upper layer(s) we support long frames. */ + ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); + /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->vge_irq, INTR_TYPE_NET|INTR_MPSAFE, NULL, vge_intr, sc, &sc->vge_intrhand); @@ -1595,7 +1631,7 @@ vge_txeof(struct vge_softc *sc) } static void -vge_tick(void *xsc) +vge_link_statchg(void *xsc) { struct vge_softc *sc; struct ifnet *ifp; @@ -1606,7 +1642,7 @@ vge_tick(void *xsc) VGE_LOCK_ASSERT(sc); mii = device_get_softc(sc->vge_miibus); - mii_tick(mii); + mii_pollstat(mii); if ((sc->vge_flags & VGE_FLAG_LINK) != 0) { if (!(mii->mii_media_status & IFM_ACTIVE)) { sc->vge_flags &= ~VGE_FLAG_LINK; @@ -1735,7 +1771,7 @@ vge_intr(void *arg) } if (status & VGE_ISR_LINKSTS) - vge_tick(sc); + vge_link_statchg(sc); } /* Re-enable interrupts */ @@ -2008,7 +2044,7 @@ vge_init_locked(struct vge_softc *sc) * reception of VLAN tagged frames. */ CSR_CLRBIT_1(sc, VGE_RXCFG, VGE_RXCFG_FIFO_THR|VGE_RXCFG_VTAGOPT); - CSR_SETBIT_1(sc, VGE_RXCFG, VGE_RXFIFOTHR_128BYTES|VGE_VTAG_OPT2); + CSR_SETBIT_1(sc, VGE_RXCFG, VGE_RXFIFOTHR_128BYTES); /* Set DMA burst length */ CSR_CLRBIT_1(sc, VGE_DMACFG0, VGE_DMACFG0_BURSTLEN); @@ -2047,29 +2083,12 @@ vge_init_locked(struct vge_softc *sc) /* Enable the TX descriptor queue */ CSR_WRITE_2(sc, VGE_TXQCSRS, VGE_TXQCSR_RUN0); - /* Set up the receive filter -- allow large frames for VLANs. */ - CSR_WRITE_1(sc, VGE_RXCTL, VGE_RXCTL_RX_UCAST|VGE_RXCTL_RX_GIANT); - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_PROMISC); - } - - /* Set capture broadcast bit to capture broadcast frames. */ - if (ifp->if_flags & IFF_BROADCAST) { - CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_BCAST); - } - - /* Set multicast bit to capture multicast frames. */ - if (ifp->if_flags & IFF_MULTICAST) { - CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_MCAST); - } - /* Init the cam filter. */ vge_cam_clear(sc); - /* Init the multicast filter. */ - vge_setmulti(sc); + /* Set up receiver filter. */ + vge_rxfilter(sc); + vge_setvlan(sc); /* Enable flow control */ @@ -2153,14 +2172,15 @@ vge_ifmedia_upd(struct ifnet *ifp) { struct vge_softc *sc; struct mii_data *mii; + int error; sc = ifp->if_softc; VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); - mii_mediachg(mii); + error = mii_mediachg(mii); VGE_UNLOCK(sc); - return (0); + return (error); } /* @@ -2176,6 +2196,10 @@ vge_ifmedia_sts(struct ifnet *ifp, struc mii = device_get_softc(sc->vge_miibus); VGE_LOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0) { + VGE_UNLOCK(sc); + return; + } mii_pollstat(mii); VGE_UNLOCK(sc); ifmr->ifm_active = mii->mii_media_active; @@ -2235,7 +2259,7 @@ vge_ioctl(struct ifnet *ifp, u_long comm struct vge_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 SIOCSIFMTU: @@ -2245,25 +2269,15 @@ vge_ioctl(struct ifnet *ifp, u_long comm break; case SIOCSIFFLAGS: VGE_LOCK(sc); - if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->vge_if_flags & IFF_PROMISC)) { - CSR_SETBIT_1(sc, VGE_RXCTL, - VGE_RXCTL_RX_PROMISC); - vge_setmulti(sc); - } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->vge_if_flags & IFF_PROMISC) { - CSR_CLRBIT_1(sc, VGE_RXCTL, - VGE_RXCTL_RX_PROMISC); - vge_setmulti(sc); - } else + if ((ifp->if_flags & IFF_UP) != 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + ((ifp->if_flags ^ sc->vge_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) != 0) + vge_rxfilter(sc); + else vge_init_locked(sc); - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - vge_stop(sc); - } + } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + vge_stop(sc); sc->vge_if_flags = ifp->if_flags; VGE_UNLOCK(sc); break; @@ -2271,7 +2285,7 @@ vge_ioctl(struct ifnet *ifp, u_long comm case SIOCDELMULTI: VGE_LOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) - vge_setmulti(sc); + vge_rxfilter(sc); VGE_UNLOCK(sc); break; case SIOCGIFMEDIA: @@ -2280,8 +2294,7 @@ vge_ioctl(struct ifnet *ifp, u_long comm error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - { - int mask = ifr->ifr_reqcap ^ ifp->if_capenable; + mask = ifr->ifr_reqcap ^ ifp->if_capenable; #ifdef DEVICE_POLLING if (mask & IFCAP_POLLING) { if (ifr->ifr_reqcap & IFCAP_POLLING) { @@ -2318,8 +2331,16 @@ vge_ioctl(struct ifnet *ifp, u_long comm if ((mask & IFCAP_RXCSUM) != 0 && (ifp->if_capabilities & IFCAP_RXCSUM) != 0) ifp->if_capenable ^= IFCAP_RXCSUM; + if ((mask & IFCAP_VLAN_HWCSUM) != 0 && + (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) + ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; + if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && + (IFCAP_VLAN_HWTAGGING & ifp->if_capabilities) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + vge_setvlan(sc); + } VGE_UNLOCK(sc); - } + VLAN_CAPABILITIES(ifp); break; default: error = ether_ioctl(ifp, command, data);