svn commit: r201871 - stable/8/sys/dev/vge

Pyun YongHyeon yongari at FreeBSD.org
Sat Jan 9 00:26:57 UTC 2010


Author: yongari
Date: Sat Jan  9 00:26:57 2010
New Revision: 201871
URL: http://svn.freebsd.org/changeset/base/201871

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/8/sys/dev/vge/if_vge.c
  stable/8/sys/dev/vge/if_vgereg.h
  stable/8/sys/dev/vge/if_vgevar.h
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:24:54 2010	(r201870)
+++ stable/8/sys/dev/vge/if_vge.c	Sat Jan  9 00:26:57 2010	(r201871)
@@ -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 *);
@@ -1011,6 +1013,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);
@@ -1069,6 +1076,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)
@@ -1098,6 +1107,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;
@@ -2211,9 +2222,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);
@@ -2279,6 +2298,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;
@@ -2365,7 +2393,7 @@ vge_suspend(device_t dev)
 
 	VGE_LOCK(sc);
 	vge_stop(sc);
-
+	vge_setwol(sc);
 	sc->vge_flags |= VGE_FLAG_SUSPENDED;
 	VGE_UNLOCK(sc);
 
@@ -2382,17 +2410,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);
 	}
@@ -2409,15 +2446,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)	\
@@ -2543,8 +2573,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,
@@ -2706,3 +2734,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/8/sys/dev/vge/if_vgereg.h
==============================================================================
--- stable/8/sys/dev/vge/if_vgereg.h	Sat Jan  9 00:24:54 2010	(r201870)
+++ stable/8/sys/dev/vge/if_vgereg.h	Sat Jan  9 00:26:57 2010	(r201871)
@@ -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/8/sys/dev/vge/if_vgevar.h
==============================================================================
--- stable/8/sys/dev/vge/if_vgevar.h	Sat Jan  9 00:24:54 2010	(r201870)
+++ stable/8/sys/dev/vge/if_vgevar.h	Sat Jan  9 00:26:57 2010	(r201871)
@@ -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;


More information about the svn-src-all mailing list