From owner-svn-src-all@FreeBSD.ORG Sat Jan 9 00:26:57 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 C5C681065676; Sat, 9 Jan 2010 00:26:57 +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 B32F28FC12; Sat, 9 Jan 2010 00:26:57 +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 o090Qvqo038401; Sat, 9 Jan 2010 00:26:57 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o090Qv1d038397; Sat, 9 Jan 2010 00:26:57 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201001090026.o090Qv1d038397@svn.freebsd.org> From: Pyun YongHyeon Date: Sat, 9 Jan 2010 00:26:57 +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: r201871 - 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:26:57 -0000 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;