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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to