Author: yongari
Date: Thu Apr 29 18:14:14 2010
New Revision: 207380
URL: http://svn.freebsd.org/changeset/base/207380

Log:
  Enable VLAN hardware tag insertion/stripping. Due to lack of SiS190
  controller, I'm not sure whether this is also applicable to SiS190
  so this feature is only activated on SiS191 controller.
  In theory, controller reinitialization is not needed when VLAN tag
  configuration is changed, but xclin said controller was not stable
  whenever toggling VLAN tag bit. To address that, sge(4)
  reinitialize controller for VLAN configuration which seems to work
  as expected. VLAN tag information for TX/RX descriptor and
  configure bit of RxMacControl register was found by xclin.
  
  Submitted by: xclin <xclin <> cs dot nctu dot edu dot tw > (initial version)
  Tested by:    xclin <xclin <> cs dot nctu dot edu dot tw >

Modified:
  head/sys/dev/sge/if_sge.c
  head/sys/dev/sge/if_sgereg.h

Modified: head/sys/dev/sge/if_sge.c
==============================================================================
--- head/sys/dev/sge/if_sge.c   Thu Apr 29 18:00:42 2010        (r207379)
+++ head/sys/dev/sge/if_sge.c   Thu Apr 29 18:14:14 2010        (r207380)
@@ -137,6 +137,7 @@ static int  sge_get_mac_addr_eeprom(struc
 static uint16_t        sge_read_eeprom(struct sge_softc *, int);
 
 static void    sge_rxfilter(struct sge_softc *);
+static void    sge_setvlan(struct sge_softc *);
 static void    sge_reset(struct sge_softc *);
 static int     sge_list_rx_init(struct sge_softc *);
 static int     sge_list_rx_free(struct sge_softc *);
@@ -484,6 +485,25 @@ sge_rxfilter(struct sge_softc *sc)
 }
 
 static void
+sge_setvlan(struct sge_softc *sc)
+{
+       struct ifnet *ifp;
+       uint16_t rxfilt;
+
+       SGE_LOCK_ASSERT(sc);
+
+       ifp = sc->sge_ifp;
+       if ((ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0)
+               return;
+       rxfilt = CSR_READ_2(sc, RxMacControl);
+       if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
+               rxfilt |= RXMAC_STRIP_VLAN;
+       else
+               rxfilt &= ~RXMAC_STRIP_VLAN;
+       CSR_WRITE_2(sc, RxMacControl, rxfilt);
+}
+
+static void
 sge_reset(struct sge_softc *sc)
 {
 
@@ -619,6 +639,9 @@ sge_attach(device_t dev)
        ether_ifattach(ifp, eaddr);
 
        /* VLAN setup. */
+       if ((sc->sge_flags & SGE_FLAG_SIS190) == 0)
+               ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING |
+                   IFCAP_VLAN_HWCSUM;
        ifp->if_capabilities |= IFCAP_VLAN_MTU;
        ifp->if_capenable = ifp->if_capabilities;
        /* Tell the upper layer(s) we support long frames. */
@@ -1175,9 +1198,12 @@ sge_rxeof(struct sge_softc *sc)
                                m->m_pkthdr.csum_data = 0xffff;
                        }
                }
-               /*
-                * TODO : VLAN hardware tag stripping.
-                */
+               /* Check for VLAN tagged frame. */
+               if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 &&
+                   (rxstat & RDS_VLAN) != 0) {
+                       m->m_pkthdr.ether_vtag = rxinfo & RDC_VLAN_MASK;
+                       m->m_flags |= M_VLANTAG;
+               }
                if ((sc->sge_flags & SGE_FLAG_SIS190) == 0) {
                        /*
                         * Account for 10bytes auto padding which is used
@@ -1422,6 +1448,11 @@ sge_encap(struct sge_softc *sc, struct m
        desc->sge_flags = htole32(txsegs[0].ds_len);
        if (prod == SGE_TX_RING_CNT - 1)
                desc->sge_flags |= htole32(RING_END);
+       /* Configure VLAN. */
+       if(((*m_head)->m_flags & M_VLANTAG) != 0) {
+               cflags |= (*m_head)->m_pkthdr.ether_vtag;
+               desc->sge_sts_size |= htole32(TDS_INS_VLAN);
+       }
        desc->sge_cmdsts = htole32(TDC_DEF | TDC_CRC | TDC_PAD | cflags);
 #if 1
        if ((sc->sge_flags & SGE_FLAG_SPEED_1000) != 0)
@@ -1563,6 +1594,7 @@ sge_init_locked(struct sge_softc *sc)
                rxfilt |= RXMAC_STRIP_FCS | RXMAC_PAD_ENB;
        CSR_WRITE_2(sc, RxMacControl, rxfilt);
        sge_rxfilter(sc);
+       sge_setvlan(sc);
 
        /* Initialize default speed/duplex information. */
        if ((sc->sge_flags & SGE_FLAG_FASTETHER) == 0)
@@ -1653,7 +1685,7 @@ sge_ioctl(struct ifnet *ifp, u_long comm
        struct sge_softc *sc;
        struct ifreq *ifr;
        struct mii_data *mii;
-       int error = 0, mask;
+       int error = 0, mask, reinit;
 
        sc = ifp->if_softc;
        ifr = (struct ifreq *)data;
@@ -1675,6 +1707,7 @@ sge_ioctl(struct ifnet *ifp, u_long comm
                break;
        case SIOCSIFCAP:
                SGE_LOCK(sc);
+               reinit = 0;
                mask = ifr->ifr_reqcap ^ ifp->if_capenable;
                if ((mask & IFCAP_TXCSUM) != 0 &&
                    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
@@ -1687,7 +1720,24 @@ sge_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 &&
+                   (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
+                       /*
+                        * Due to unknown reason, toggling VLAN hardware
+                        * tagging require interface reinitialization.
+                        */
+                       ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+                       reinit = 1;
+               }
+               if (reinit > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+                       ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+                       sge_init_locked(sc);
+               }
                SGE_UNLOCK(sc);
+               VLAN_CAPABILITIES(ifp);
                break;
        case SIOCADDMULTI:
        case SIOCDELMULTI:

Modified: head/sys/dev/sge/if_sgereg.h
==============================================================================
--- head/sys/dev/sge/if_sgereg.h        Thu Apr 29 18:00:42 2010        
(r207379)
+++ head/sys/dev/sge/if_sgereg.h        Thu Apr 29 18:14:14 2010        
(r207380)
@@ -137,6 +137,7 @@
 #define        AcceptAllPhys           0x0100
 #define        AcceptErr               0x0020
 #define        AcceptRunt              0x0010
+#define        RXMAC_STRIP_VLAN        0x0020
 #define        RXMAC_STRIP_FCS         0x0010
 #define        RXMAC_PAD_ENB           0x0004
 
@@ -187,12 +188,14 @@
 #define        TDC_COL                 0x00040000
 #define        TDC_CRC                 0x00020000
 #define        TDC_PAD                 0x00010000
+#define        TDC_VLAN_MASK           0x0000FFFF
 
 #define        SGE_TX_INTR_FRAMES      32
 
 /*
  * TX descriptor status bits.
  */
+#define        TDS_INS_VLAN            0x80000000
 #define        TDS_OWC                 0x00080000
 #define        TDS_ABT                 0x00040000
 #define        TDS_FIFO                0x00020000
@@ -219,11 +222,12 @@
 #define        RDC_UCAST               0x00040000
 #define        RDC_CRCOFF              0x00020000
 #define        RDC_PREADD              0x00010000
+#define        RDC_VLAN_MASK           0x0000FFFF
 
 /*
  * RX descriptor status bits
  */
-#define        RDS_TAGON               0x80000000
+#define        RDS_VLAN                0x80000000
 #define        RDS_DESCS               0x3f000000
 #define        RDS_ABORT               0x00800000
 #define        RDS_SHORT               0x00400000
@@ -240,7 +244,7 @@
 #define        RX_ERR_BITS             "\20"                                   
\
                                "\21CRCOK\22COLON\23NIBON\24OVRUN"      \
                                "\25MIIER\26LIMIT\27SHORT\30ABORT"      \
-                               "\40TAGON"
+                               "\40VLAN"
 
 #define        RING_END                0x80000000
 #define        SGE_RX_BYTES(x)         ((x) & 0xFFFF)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to