Author: yongari
Date: Sat Jan  9 00:29:04 2010
New Revision: 201874
URL: http://svn.freebsd.org/changeset/base/201874

Log:
  MFC r200696,200740,200756,200758-200759,200972
  
  r200696:
    Add rudimentary WOL support. While I'm here remove enabling
    busmastering/memory address in resume path. Bus driver will handle
    that.
  
  r200740:
    Swap VGE_TXQTIMER and VGE_RXQTIMER register definition. Pending
    timer for Tx queue is at 0x3E.
  
  r200756:
    Correct fragment bit definition in comments.
  
  r200758:
    VT6130 datasheet was wrong. If VT6130 receive a jumbo frame the
    controller will split the jumbo frame into multiple RX buffers.
    However it seems the hardware always dma the frame to 8 bytes
    boundary for the split frames. Only the first part of the fragment
    can have 4 byte alignment and subsequent buffers should be 8 bytes
    aligned. Change RX buffer the alignment requirement to 8 bytes from
    4 bytes.
  
  r200759:
    Disable jumbo frame support for PCIe VT6130/VT6132 controllers.
    Quite contrary to VT6130 datasheet which says it supports up to 8K
    jumbo frame, VT6130 does not seem to send jumbo frame that is
    larger than 4K in length. Trying to send a frame that is larger
    than 4K cause TX MAC hang.
    Even though it's possible to allow 4K jumbo frame for VT6130, I
    think it's meaningless to allow 4K jumbo frame. I'm not sure VT6132
    also has the same limitation but I guess it uses the same MAC of
    VT6130.
  
  r200972:
    Remove wrong assertion.

Modified:
  stable/7/sys/dev/vge/if_vge.c
  stable/7/sys/dev/vge/if_vgereg.h
  stable/7/sys/dev/vge/if_vgevar.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/vge/if_vge.c
==============================================================================
--- stable/7/sys/dev/vge/if_vge.c       Sat Jan  9 00:28:05 2010        
(r201873)
+++ stable/7/sys/dev/vge/if_vge.c       Sat Jan  9 00:29:04 2010        
(r201874)
@@ -157,6 +157,7 @@ static int  vge_suspend(device_t);
 
 static void    vge_cam_clear(struct vge_softc *);
 static int     vge_cam_set(struct vge_softc *, uint8_t *);
+static void    vge_clrwol(struct vge_softc *);
 static void    vge_discard_rxbuf(struct vge_softc *, int);
 static int     vge_dma_alloc(struct vge_softc *);
 static void    vge_dma_free(struct vge_softc *);
@@ -190,6 +191,7 @@ static int  vge_rx_list_init(struct vge_s
 static int     vge_rxeof(struct vge_softc *, int);
 static void    vge_rxfilter(struct vge_softc *);
 static void    vge_setvlan(struct vge_softc *);
+static void    vge_setwol(struct vge_softc *);
 static void    vge_start(struct ifnet *);
 static void    vge_start_locked(struct ifnet *);
 static void    vge_stats_clear(struct vge_softc *);
@@ -1014,6 +1016,11 @@ vge_attach(device_t dev)
        if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) == 0) {
                sc->vge_flags |= VGE_FLAG_PCIE;
                sc->vge_expcap = cap;
+       } else
+               sc->vge_flags |= VGE_FLAG_JUMBO;
+       if (pci_find_extcap(dev, PCIY_PMG, &cap) == 0) {
+               sc->vge_flags |= VGE_FLAG_PMCAP;
+               sc->vge_pmcap = cap;
        }
        rid = 0;
        msic = pci_msi_count(dev);
@@ -1072,6 +1079,8 @@ vge_attach(device_t dev)
        else
                sc->vge_phyaddr = CSR_READ_1(sc, VGE_MIICFG) &
                    VGE_MIICFG_PHYADDR;
+       /* Clear WOL and take hardware from powerdown. */
+       vge_clrwol(sc);
        vge_sysctl_node(sc);
        error = vge_dma_alloc(sc);
        if (error)
@@ -1101,6 +1110,8 @@ vge_attach(device_t dev)
        ifp->if_hwassist = VGE_CSUM_FEATURES;
        ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM |
            IFCAP_VLAN_HWTAGGING;
+       if ((sc->vge_flags & VGE_FLAG_PMCAP) != 0)
+               ifp->if_capabilities |= IFCAP_WOL;
        ifp->if_capenable = ifp->if_capabilities;
 #ifdef DEVICE_POLLING
        ifp->if_capabilities |= IFCAP_POLLING;
@@ -2212,9 +2223,17 @@ vge_ioctl(struct ifnet *ifp, u_long comm
 
        switch (command) {
        case SIOCSIFMTU:
-               if (ifr->ifr_mtu > VGE_JUMBO_MTU)
+               VGE_LOCK(sc);
+               if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > VGE_JUMBO_MTU)
                        error = EINVAL;
-               ifp->if_mtu = ifr->ifr_mtu;
+               else if (ifp->if_mtu != ifr->ifr_mtu) {
+                       if (ifr->ifr_mtu > ETHERMTU &&
+                           (sc->vge_flags & VGE_FLAG_JUMBO) == 0)
+                               error = EINVAL;
+                       else
+                               ifp->if_mtu = ifr->ifr_mtu;
+               }
+               VGE_UNLOCK(sc);
                break;
        case SIOCSIFFLAGS:
                VGE_LOCK(sc);
@@ -2280,6 +2299,15 @@ 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_WOL_UCAST) != 0 &&
+                   (ifp->if_capabilities & IFCAP_WOL_UCAST) != 0)
+                       ifp->if_capenable ^= IFCAP_WOL_UCAST;
+               if ((mask & IFCAP_WOL_MCAST) != 0 &&
+                   (ifp->if_capabilities & IFCAP_WOL_MCAST) != 0)
+                       ifp->if_capenable ^= IFCAP_WOL_MCAST;
+               if ((mask & IFCAP_WOL_MAGIC) != 0 &&
+                   (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
+                       ifp->if_capenable ^= IFCAP_WOL_MAGIC;
                if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
                    (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0)
                        ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
@@ -2366,7 +2394,7 @@ vge_suspend(device_t dev)
 
        VGE_LOCK(sc);
        vge_stop(sc);
-
+       vge_setwol(sc);
        sc->vge_flags |= VGE_FLAG_SUSPENDED;
        VGE_UNLOCK(sc);
 
@@ -2383,17 +2411,26 @@ vge_resume(device_t dev)
 {
        struct vge_softc *sc;
        struct ifnet *ifp;
+       uint16_t pmstat;
 
        sc = device_get_softc(dev);
-       ifp = sc->vge_ifp;
-
-       /* reenable busmastering */
-       pci_enable_busmaster(dev);
-       pci_enable_io(dev, SYS_RES_MEMORY);
-
-       /* reinitialize interface if necessary */
        VGE_LOCK(sc);
-       if (ifp->if_flags & IFF_UP) {
+       if ((sc->vge_flags & VGE_FLAG_PMCAP) != 0) {
+               /* Disable PME and clear PME status. */
+               pmstat = pci_read_config(sc->vge_dev,
+                   sc->vge_pmcap + PCIR_POWER_STATUS, 2);
+               if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
+                       pmstat &= ~PCIM_PSTAT_PMEENABLE;
+                       pci_write_config(sc->vge_dev,
+                           sc->vge_pmcap + PCIR_POWER_STATUS, pmstat, 2);
+               }
+       }
+       vge_clrwol(sc);
+       /* Restart MII auto-polling. */
+       vge_miipoll_start(sc);
+       ifp = sc->vge_ifp;
+       /* Reinitialize interface if necessary. */
+       if ((ifp->if_flags & IFF_UP) != 0) {
                ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
                vge_init_locked(sc);
        }
@@ -2410,15 +2447,8 @@ vge_resume(device_t dev)
 static int
 vge_shutdown(device_t dev)
 {
-       struct vge_softc *sc;
 
-       sc = device_get_softc(dev);
-
-       VGE_LOCK(sc);
-       vge_stop(sc);
-       VGE_UNLOCK(sc);
-
-       return (0);
+       return (vge_suspend(dev));
 }
 
 #define        VGE_SYSCTL_STAT_ADD32(c, h, n, p, d)    \
@@ -2544,8 +2574,6 @@ vge_stats_clear(struct vge_softc *sc)
 {
        int i;
 
-       VGE_LOCK_ASSERT(sc);
-
        CSR_WRITE_1(sc, VGE_MIBCSR,
            CSR_READ_1(sc, VGE_MIBCSR) | VGE_MIBCSR_FREEZE);
        CSR_WRITE_1(sc, VGE_MIBCSR,
@@ -2707,3 +2735,154 @@ vge_intr_holdoff(struct vge_softc *sc)
                CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_HOLDOFF);
        }
 }
+
+static void
+vge_setlinkspeed(struct vge_softc *sc)
+{
+       struct mii_data *mii;
+       int aneg, i;
+
+       VGE_LOCK_ASSERT(sc);
+
+       mii = device_get_softc(sc->vge_miibus);
+       mii_pollstat(mii);
+       aneg = 0;
+       if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+           (IFM_ACTIVE | IFM_AVALID)) {
+               switch IFM_SUBTYPE(mii->mii_media_active) {
+               case IFM_10_T:
+               case IFM_100_TX:
+                       return;
+               case IFM_1000_T:
+                       aneg++;
+               default:
+                       break;
+               }
+       }
+       vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_100T2CR, 0);
+       vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_ANAR,
+           ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
+       vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_BMCR,
+           BMCR_AUTOEN | BMCR_STARTNEG);
+       DELAY(1000);
+       if (aneg != 0) {
+               /* Poll link state until vge(4) get a 10/100 link. */
+               for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
+                       mii_pollstat(mii);
+                       if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
+                           == (IFM_ACTIVE | IFM_AVALID)) {
+                               switch (IFM_SUBTYPE(mii->mii_media_active)) {
+                               case IFM_10_T:
+                               case IFM_100_TX:
+                                       return;
+                               default:
+                                       break;
+                               }
+                       }
+                       VGE_UNLOCK(sc);
+                       pause("vgelnk", hz);
+                       VGE_LOCK(sc);
+               }
+               if (i == MII_ANEGTICKS_GIGE)
+                       device_printf(sc->vge_dev, "establishing link failed, "
+                           "WOL may not work!");
+       }
+       /*
+        * No link, force MAC to have 100Mbps, full-duplex link.
+        * This is the last resort and may/may not work.
+        */
+       mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
+       mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
+}
+
+static void
+vge_setwol(struct vge_softc *sc)
+{
+       struct ifnet *ifp;
+       uint16_t pmstat;
+       uint8_t val;
+
+       VGE_LOCK_ASSERT(sc);
+
+       if ((sc->vge_flags & VGE_FLAG_PMCAP) == 0) {
+               /* No PME capability, PHY power down. */
+               vge_miibus_writereg(sc->vge_dev, sc->vge_phyaddr, MII_BMCR,
+                   BMCR_PDOWN);
+               vge_miipoll_stop(sc);
+               return;
+       }
+
+       ifp = sc->vge_ifp;
+
+       /* Clear WOL on pattern match. */
+       CSR_WRITE_1(sc, VGE_WOLCR0C, VGE_WOLCR0_PATTERN_ALL);
+       /* Disable WOL on magic/unicast packet. */
+       CSR_WRITE_1(sc, VGE_WOLCR1C, 0x0F);
+       CSR_WRITE_1(sc, VGE_WOLCFGC, VGE_WOLCFG_SAB | VGE_WOLCFG_SAM |
+           VGE_WOLCFG_PMEOVR);
+       if ((ifp->if_capenable & IFCAP_WOL) != 0) {
+               vge_setlinkspeed(sc);
+               val = 0;
+               if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
+                       val |= VGE_WOLCR1_UCAST;
+               if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
+                       val |= VGE_WOLCR1_MAGIC;
+               CSR_WRITE_1(sc, VGE_WOLCR1S, val);
+               val = 0;
+               if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
+                       val |= VGE_WOLCFG_SAM | VGE_WOLCFG_SAB;
+               CSR_WRITE_1(sc, VGE_WOLCFGS, val | VGE_WOLCFG_PMEOVR);
+               /* Disable MII auto-polling. */
+               vge_miipoll_stop(sc);
+       }
+       CSR_SETBIT_1(sc, VGE_DIAGCTL,
+           VGE_DIAGCTL_MACFORCE | VGE_DIAGCTL_FDXFORCE);
+       CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_GMII);
+
+       /* Clear WOL status on pattern match. */
+       CSR_WRITE_1(sc, VGE_WOLSR0C, 0xFF);
+       CSR_WRITE_1(sc, VGE_WOLSR1C, 0xFF);
+
+       val = CSR_READ_1(sc, VGE_PWRSTAT);
+       val |= VGE_STICKHW_SWPTAG;
+       CSR_WRITE_1(sc, VGE_PWRSTAT, val);
+       /* Put hardware into sleep. */
+       val = CSR_READ_1(sc, VGE_PWRSTAT);
+       val |= VGE_STICKHW_DS0 | VGE_STICKHW_DS1;
+       CSR_WRITE_1(sc, VGE_PWRSTAT, val);
+       /* Request PME if WOL is requested. */
+       pmstat = pci_read_config(sc->vge_dev, sc->vge_pmcap +
+           PCIR_POWER_STATUS, 2);
+       pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
+       if ((ifp->if_capenable & IFCAP_WOL) != 0)
+               pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+       pci_write_config(sc->vge_dev, sc->vge_pmcap + PCIR_POWER_STATUS,
+           pmstat, 2);
+}
+
+static void
+vge_clrwol(struct vge_softc *sc)
+{
+       uint8_t val;
+
+       val = CSR_READ_1(sc, VGE_PWRSTAT);
+       val &= ~VGE_STICKHW_SWPTAG;
+       CSR_WRITE_1(sc, VGE_PWRSTAT, val);
+       /* Disable WOL and clear power state indicator. */
+       val = CSR_READ_1(sc, VGE_PWRSTAT);
+       val &= ~(VGE_STICKHW_DS0 | VGE_STICKHW_DS1);
+       CSR_WRITE_1(sc, VGE_PWRSTAT, val);
+
+       CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_GMII);
+       CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE);
+
+       /* Clear WOL on pattern match. */
+       CSR_WRITE_1(sc, VGE_WOLCR0C, VGE_WOLCR0_PATTERN_ALL);
+       /* Disable WOL on magic/unicast packet. */
+       CSR_WRITE_1(sc, VGE_WOLCR1C, 0x0F);
+       CSR_WRITE_1(sc, VGE_WOLCFGC, VGE_WOLCFG_SAB | VGE_WOLCFG_SAM |
+           VGE_WOLCFG_PMEOVR);
+       /* Clear WOL status on pattern match. */
+       CSR_WRITE_1(sc, VGE_WOLSR0C, 0xFF);
+       CSR_WRITE_1(sc, VGE_WOLSR1C, 0xFF);
+}

Modified: stable/7/sys/dev/vge/if_vgereg.h
==============================================================================
--- stable/7/sys/dev/vge/if_vgereg.h    Sat Jan  9 00:28:05 2010        
(r201873)
+++ stable/7/sys/dev/vge/if_vgereg.h    Sat Jan  9 00:29:04 2010        
(r201874)
@@ -89,8 +89,8 @@
 #define VGE_RXQCSRC            0x36    /* RX queue ctl/status clear */
 #define VGE_RXDESC_ADDR_LO     0x38    /* RX desc base addr (lo 32 bits) */
 #define VGE_RXDESC_CONSIDX     0x3C    /* Current RX descriptor index */
-#define VGE_RXQTIMER           0x3E    /* RX queue timer pend register */
-#define VGE_TXQTIMER           0x3F    /* TX queue timer pend register */
+#define VGE_TXQTIMER           0x3E    /* TX queue timer pend register */
+#define VGE_RXQTIMER           0x3F    /* RX queue timer pend register */
 #define VGE_TXDESC_ADDR_LO0    0x40    /* TX desc0 base addr (lo 32 bits) */
 #define VGE_TXDESC_ADDR_LO1    0x44    /* TX desc1 base addr (lo 32 bits) */
 #define VGE_TXDESC_ADDR_LO2    0x48    /* TX desc2 base addr (lo 32 bits) */
@@ -590,6 +590,42 @@
 #define        VGE_MIB_DATA_MASK       0x00FFFFFF
 #define        VGE_MIB_DATA_IDX(x)     ((x) >> 24)
 
+/* Sticky bit shadow register */
+
+#define        VGE_STICKHW_DS0         0x01
+#define        VGE_STICKHW_DS1         0x02
+#define        VGE_STICKHW_WOL_ENB     0x04
+#define        VGE_STICKHW_WOL_STS     0x08
+#define        VGE_STICKHW_SWPTAG      0x10
+
+/* WOL pattern control */
+#define        VGE_WOLCR0_PATTERN0     0x01
+#define        VGE_WOLCR0_PATTERN1     0x02
+#define        VGE_WOLCR0_PATTERN2     0x04
+#define        VGE_WOLCR0_PATTERN3     0x08
+#define        VGE_WOLCR0_PATTERN4     0x10
+#define        VGE_WOLCR0_PATTERN5     0x20
+#define        VGE_WOLCR0_PATTERN6     0x40
+#define        VGE_WOLCR0_PATTERN7     0x80
+#define        VGE_WOLCR0_PATTERN_ALL  0xFF
+
+/* WOL event control */
+#define        VGE_WOLCR1_UCAST        0x01
+#define        VGE_WOLCR1_MAGIC        0x02
+#define        VGE_WOLCR1_LINKON       0x04
+#define        VGE_WOLCR1_LINKOFF      0x08
+
+/* Poweer management config */
+#define VGE_PWRCFG_LEGACY_WOLEN        0x01
+#define VGE_PWRCFG_WOL_PULSE   0x20
+#define VGE_PWRCFG_WOL_BUTTON  0x00
+
+/* WOL config register */
+#define        VGE_WOLCFG_PHYINT_ENB   0x01
+#define        VGE_WOLCFG_SAB          0x10
+#define        VGE_WOLCFG_SAM          0x20
+#define        VGE_WOLCFG_PMEOVR       0x80
+
 /* EEPROM control/status register */
 
 #define VGE_EECSR_EDO          0x01    /* data out pin */
@@ -725,8 +761,8 @@ struct vge_rx_desc {
 #define VGE_RDSTS_OWN          0x80000000      /* own bit. */
 
 #define VGE_RXPKT_ONEFRAG      0x00000000      /* only one fragment */
-#define VGE_RXPKT_EOF          0x00000100      /* first frag in frame */
-#define VGE_RXPKT_SOF          0x00000200      /* last frag in frame */
+#define VGE_RXPKT_EOF          0x00000100      /* last frag in frame */
+#define VGE_RXPKT_SOF          0x00000200      /* first frag in frame */
 #define VGE_RXPKT_MOF          0x00000300      /* intermediate frag */
 
 #define VGE_RDCTL_VLANID       0x0000FFFF      /* VLAN ID info */

Modified: stable/7/sys/dev/vge/if_vgevar.h
==============================================================================
--- stable/7/sys/dev/vge/if_vgevar.h    Sat Jan  9 00:28:05 2010        
(r201873)
+++ stable/7/sys/dev/vge/if_vgevar.h    Sat Jan  9 00:29:04 2010        
(r201874)
@@ -39,7 +39,7 @@
 #define VGE_TX_RING_ALIGN      64
 #define VGE_RX_RING_ALIGN      64
 #define VGE_MAXTXSEGS          6
-#define VGE_RX_BUF_ALIGN       sizeof(uint32_t)
+#define VGE_RX_BUF_ALIGN       sizeof(uint64_t)
 
 /*
  * VIA Velocity allows 64bit DMA addressing but high 16bits
@@ -186,9 +186,12 @@ struct vge_softc {
        int                     vge_flags;
 #define        VGE_FLAG_PCIE           0x0001
 #define        VGE_FLAG_MSI            0x0002
+#define        VGE_FLAG_PMCAP          0x0004
+#define        VGE_FLAG_JUMBO          0x0008
 #define        VGE_FLAG_SUSPENDED      0x4000
 #define        VGE_FLAG_LINK           0x8000
        int                     vge_expcap;
+       int                     vge_pmcap;
        int                     vge_camidx;
        int                     vge_int_holdoff;
        int                     vge_rx_coal_pkt;
_______________________________________________
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