Date: Mon, 28 Apr 2008 19:17:47 +0100 From: "Stuart Fraser" <stuart@stuartfraser.net> To: "'Jonathan Hogg'" <jonathan@onegoodidea.com>, "'FreeBSD Current'" <freebsd-current@freebsd.org> Subject: RE: vge(4) gigabit on VIA EPIA SN 18000 board (again) Message-ID: <4a1601c8a95c$30290860$907b1920$@net> In-Reply-To: <21E3C9BA-8DE2-470C-AEA1-58FE3D192EC7@onegoodidea.com> References: <21E3C9BA-8DE2-470C-AEA1-58FE3D192EC7@onegoodidea.com>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multipart message in MIME format. ------=_NextPart_000_4A17_01C8A964.91ED7060 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi Sorry I always meant to post a summary of the solution back to the list, never quite found the time. So to make amends here is the status: Pyun looked into it for me and we broke it down into two parts: First there required a patch to the ip1000phy physical layer, which I believe he has committed to cvs HEAD a few weeks back. Secondly there is a patch to the vge(4) driver which mostly fixes the 1G issues. What I was finding is that if I configured the interface in rc.conf it wouldn't come up in 1G mode it would auto select 100FullDuplex. Anytime after that it seemed to configure fine - go figure so I just config it in a later /usr/local/etc/rc.d script. I have tried to soak test as much as I can and it appears stable underload. Anyways I know the patches are based not based on the most recent versions of the code but with a little patience I managed to apply them manually and recompiled the kernel. I'm sure he said I could pass on the code so you should find it attached, as I say a little manual patching required perhaps. Rgds Stuart -----Original Message----- From: owner-freebsd-current@freebsd.org [mailto:owner-freebsd-current@freebsd.org] On Behalf Of Jonathan Hogg Sent: 28 April 2008 18:01 To: FreeBSD Current Subject: vge(4) gigabit on VIA EPIA SN 18000 board (again) Hi all, I noticed a previous discussion here regarding the vge driver and problems with the EPIA SN 18000 board: http://groups.google.com/group/mailing.freebsd.current/browse_thread/thread/ e2b3ddb38ad55fbc That thread kind of tails off inconclusively, and I just wondered whether anyone had gotten any further with it? I have the same board and the same problem - though, in addition, I also get a fair number of watchdog timeouts under load at 100Mb. I'd very much like to get this port working (reliably and) at 1Gb and would be willing to help debug the driver if I can (I'm a developer, but have no expertise in the FreeBSD kernel). Alternatively, I'd happily create an account on this box if someone can learn more about it by poking around. I'm using CURRENT as of a couple of weeks ago (recompiling from last night's at the moment). Cheers, Jonathan (Shout if I should be addressing this question to another list.) _______________________________________________ freebsd-current@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-current To unsubscribe, send any mail to "freebsd-current-unsubscribe@freebsd.org" ------=_NextPart_000_4A17_01C8A964.91ED7060 Content-Type: application/octet-stream; name="ip1000phy.patch2" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ip1000phy.patch2" --- sys/dev/mii/miidevs.orig 2008-03-07 06:42:48.000000000 +0900 +++ sys/dev/mii/miidevs 2008-04-02 17:48:19.000000000 +0900 @@ -51,6 +51,7 @@ oui ALTIMA 0x0010a9 Altima Communications oui AMD 0x00001a Advanced Micro Devices +oui ATHEROS 0x001374 Atheros Communications oui BROADCOM 0x001018 Broadcom Corporation oui CICADA 0x0003F1 Cicada Semiconductor oui DAVICOM 0x00606e Davicom Semiconductor @@ -112,6 +113,9 @@ model AMD 79c978 0x0039 Am79c978 HomePNA PHY model xxAMD 79C873 0x0000 Am79C873/DM9101 10/100 media interface +/* Atheros Communucations/Attansic PHYs. */ +model ATHEROS F1 0x0001 Atheros F1 10/100/1000 media interface + /* Broadcom Corp. PHYs. */ model BROADCOM 3C905B 0x0012 3c905B 10/100 internal PHY model BROADCOM 3C905C 0x0017 3c905C 10/100 internal PHY @@ -159,6 +163,7 @@ /* IC Plus Corp. PHYs */ model ICPLUS IP101 0x0005 IC Plus 10/100 PHY model ICPLUS IP1000A 0x0008 IC Plus 10/100/1000 media interface +model ICPLUS IP1001 0x0019 IC Plus IP1001 10/100/1000 media interface /* Intel PHYs */ model xxINTEL I82553AB 0x0000 i83553 10/100 media interface --- sys/dev/mii/ip1000phy.c.orig 2006-12-03 00:32:33.000000000 +0900 +++ sys/dev/mii/ip1000phy.c 2008-04-03 13:30:58.000000000 +0900 @@ -57,6 +57,12 @@ static int ip1000phy_probe(device_t); static int ip1000phy_attach(device_t); +struct ip1000phy_softc { + struct mii_softc mii_sc; + int model; + int revision; +}; + static device_method_t ip1000phy_methods[] = { /* device interface */ DEVMETHOD(device_probe, ip1000phy_probe), @@ -82,6 +88,7 @@ static const struct mii_phydesc ip1000phys[] = { MII_PHY_DESC(ICPLUS, IP1000A), + MII_PHY_DESC(ICPLUS, IP1001), MII_PHY_END }; @@ -95,11 +102,13 @@ static int ip1000phy_attach(device_t dev) { + struct ip1000phy_softc *isc; struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - sc = device_get_softc(dev); + isc = device_get_softc(dev); + sc = &isc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); mii = device_get_softc(sc->mii_dev); @@ -114,6 +123,9 @@ mii->mii_instance++; + isc->model = MII_MODEL(ma->mii_id2); + isc->revision = MII_REV(ma->mii_id2); + device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -302,10 +314,13 @@ static void ip1000phy_status(struct mii_softc *sc) { + struct ip1000phy_softc *isc; struct mii_data *mii = sc->mii_pdata; uint32_t bmsr, bmcr, stat; uint32_t ar, lpar; + isc = (struct ip1000phy_softc *)sc; + mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; @@ -326,25 +341,44 @@ } } - stat = PHY_READ(sc, STGE_PhyCtrl); - switch (PC_LinkSpeed(stat)) { - case PC_LinkSpeed_Down: - mii->mii_media_active |= IFM_NONE; - return; - case PC_LinkSpeed_10: - mii->mii_media_active |= IFM_10_T; - break; - case PC_LinkSpeed_100: - mii->mii_media_active |= IFM_100_TX; - break; - case PC_LinkSpeed_1000: - mii->mii_media_active |= IFM_1000_T; - break; + if (isc->model == MII_MODEL_ICPLUS_IP1001) { + stat = PHY_READ(sc, IP1000PHY_LSR); + switch (stat & IP1000PHY_LSR_SPEED_MASK) { + case IP1000PHY_LSR_SPEED_10: + mii->mii_media_active |= IFM_10_T; + break; + case IP1000PHY_LSR_SPEED_100: + mii->mii_media_active |= IFM_100_TX; + break; + case IP1000PHY_LSR_SPEED_1000: + mii->mii_media_active |= IFM_1000_T; + break; + } + if ((stat & IP1000PHY_LSR_FULL_DUPLEX) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + } else { + stat = PHY_READ(sc, STGE_PhyCtrl); + switch (PC_LinkSpeed(stat)) { + case PC_LinkSpeed_Down: + mii->mii_media_active |= IFM_NONE; + return; + case PC_LinkSpeed_10: + mii->mii_media_active |= IFM_10_T; + break; + case PC_LinkSpeed_100: + mii->mii_media_active |= IFM_100_TX; + break; + case PC_LinkSpeed_1000: + mii->mii_media_active |= IFM_1000_T; + break; + } + if ((stat & PC_PhyDuplexStatus) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } - if ((stat & PC_PhyDuplexStatus) != 0) - mii->mii_media_active |= IFM_FDX; - else - mii->mii_media_active |= IFM_HDX; ar = PHY_READ(sc, IP1000PHY_MII_ANAR); lpar = PHY_READ(sc, IP1000PHY_MII_ANLPAR); @@ -410,10 +444,12 @@ static void ip1000phy_reset(struct mii_softc *sc) { + struct ip1000phy_softc *isc; struct stge_softc *stge_sc; struct mii_data *mii; uint32_t reg; + isc = (struct ip1000phy_softc *)sc; mii_phy_reset(sc); /* clear autoneg/full-duplex as we don't want it after reset */ @@ -426,7 +462,8 @@ * XXX There should be more general way to pass PHY specific * data via mii interface. */ - if (strcmp(mii->mii_ifp->if_dname, "stge") == 0) { + if (isc->model == MII_MODEL_ICPLUS_IP1000A && + strcmp(mii->mii_ifp->if_dname, "stge") == 0) { stge_sc = mii->mii_ifp->if_softc; if (stge_sc->sc_rev >= 0x40 && stge_sc->sc_rev <= 0x4e) ip1000phy_load_dspcode(sc); --- sys/dev/mii/ip1000phyreg.h.orig 2006-07-25 09:16:09.000000000 +0900 +++ sys/dev/mii/ip1000phyreg.h 2008-04-03 13:17:52.000000000 +0900 @@ -138,4 +138,49 @@ #define IP1000PHY_EXTSTS_1000X 0x4000 #define IP1000PHY_EXTSTS_1000X_FDX 0x8000 +/* PHY specific control & status register. IP1001 only. */ +#define IP1000PHY_SCSR 0x10 +#define IP1000PHY_SCSR_RXPHASE_SEL 0x0001 +#define IP1000PHY_SCSR_TXPHASE_SEL 0x0002 +#define IP1000PHY_SCSR_REPEATOR_MODE 0x0004 +#define IP1000PHY_SCSR_RESERVED1_DEF 0x0008 +#define IP1000PHY_SCSR_RXCLK_DRV_MASK 0x0060 +#define IP1000PHY_SCSR_RXCLK_DRV_DEF 0x0040 +#define IP1000PHY_SCSR_RXD_DRV_MASK 0x0180 +#define IP1000PHY_SCSR_RXD_DRV_DEF 0x0100 +#define IP1000PHY_SCSR_JABBER_ENB 0x0200 +#define IP1000PHY_SCSR_HEART_BEAT_ENB 0x0400 +#define IP1000PHY_SCSR_DOWNSHIFT_ENB 0x0800 +#define IP1000PHY_SCSR_RESERVED2_DEF 0x1000 +#define IP1000PHY_SCSR_LED_DRV_4MA 0x0000 +#define IP1000PHY_SCSR_LED_DRV_8MA 0x2000 +#define IP1000PHY_SCSR_LED_MODE_MASK 0xC000 +#define IP1000PHY_SCSR_LED_MODE_DEF 0x0000 + +/* PHY link status register. IP1001 only. */ +#define IP1000PHY_LSR 0x11 +#define IP1000PHY_LSR_JABBER_DET 0x0200 +#define IP1000PHY_LSR_APS_SLEEP 0x0400 +#define IP1000PHY_LSR_MDIX 0x0800 +#define IP1000PHY_LSR_FULL_DUPLEX 0x1000 +#define IP1000PHY_LSR_SPEED_10 0x0000 +#define IP1000PHY_LSR_SPEED_100 0x2000 +#define IP1000PHY_LSR_SPEED_1000 0x4000 +#define IP1000PHY_LSR_SPEED_MASK 0x6000 +#define IP1000PHY_LSR_LINKUP 0x8000 + +/* PHY specific control register 2. IP1001 only. */ +#define IP1000PHY_SCR +#define IP1000PHY_SCR_SEW_RATE_MASK 0x0003 +#define IP1000PHY_SCR_SEW_RATE_DEF 0x0003 +#define IP1000PHY_SCR_AUTO_XOVER 0x0004 +#define IP1000PHY_SCR_SPEED_10_100_ENB 0x0040 +#define IP1000PHY_SCR_FIFO_LATENCY_2 0x0000 +#define IP1000PHY_SCR_FIFO_LATENCY_3 0x0080 +#define IP1000PHY_SCR_FIFO_LATENCY_4 0x0100 +#define IP1000PHY_SCR_FIFO_LATENCY_5 0x0180 +#define IP1000PHY_SCR_MDIX_ENB 0x0200 +#define IP1000PHY_SCR_RESERVED_DEF 0x0400 +#define IP1000PHY_SCR_APS_ON 0x0800 + #endif /* _DEV_MII_IP1000PHYREG_H_ */ ------=_NextPart_000_4A17_01C8A964.91ED7060 Content-Type: application/octet-stream; name="vge.link.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="vge.link.patch" --- if_vge.c.orig 2007-12-08 10:25:45.000000000 +0900 +++ if_vge.c 2008-04-03 13:38:06.000000000 +0900 @@ -164,8 +164,9 @@ static void vge_start (struct ifnet *); static int vge_ioctl (struct ifnet *, u_long, caddr_t); static void vge_init (void *); +static void vge_init_locked (struct vge_softc *); static void vge_stop (struct vge_softc *); -static void vge_watchdog (struct ifnet *); +static void vge_watchdog (struct vge_softc *); static int vge_suspend (device_t); static int vge_resume (device_t); static int vge_shutdown (device_t); @@ -177,7 +178,9 @@ #endif static void vge_read_eeprom (struct vge_softc *, caddr_t, int, int, int); +#if 0 static void vge_miipoll_start (struct vge_softc *); +#endif static void vge_miipoll_stop (struct vge_softc *); static int vge_miibus_readreg (device_t, int, int); static int vge_miibus_writereg (device_t, int, int, int); @@ -207,6 +210,7 @@ /* MII interface */ DEVMETHOD(miibus_readreg, vge_miibus_readreg), DEVMETHOD(miibus_writereg, vge_miibus_writereg), + DEVMETHOD(miibus_linkchg, vge_miibus_statchg), DEVMETHOD(miibus_statchg, vge_miibus_statchg), { 0, 0 } @@ -325,6 +329,7 @@ return; } +#if 0 static void vge_miipoll_start(sc) struct vge_softc *sc; @@ -364,6 +369,7 @@ return; } +#endif static int vge_miibus_readreg(dev, phy, reg) @@ -376,11 +382,12 @@ sc = device_get_softc(dev); - if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) + if (phy != sc->vge_phyaddr) return(0); - VGE_LOCK(sc); +#if 0 vge_miipoll_stop(sc); +#endif /* Specify the register we want to read. */ CSR_WRITE_1(sc, VGE_MIIADDR, reg); @@ -400,8 +407,9 @@ else rval = CSR_READ_2(sc, VGE_MIIDATA); +#if 0 vge_miipoll_start(sc); - VGE_UNLOCK(sc); +#endif return (rval); } @@ -416,11 +424,12 @@ sc = device_get_softc(dev); - if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) + if (phy != sc->vge_phyaddr) return(0); - VGE_LOCK(sc); +#if 0 vge_miipoll_stop(sc); +#endif /* Specify the register we want to write. */ CSR_WRITE_1(sc, VGE_MIIADDR, reg); @@ -443,8 +452,9 @@ rval = EIO; } +#if 0 vge_miipoll_start(sc); - VGE_UNLOCK(sc); +#endif return (rval); } @@ -455,6 +465,8 @@ { int i; + VGE_LOCK_ASSERT(sc); + /* * Turn off all the mask bits. This tells the chip * that none of the entries in the CAM filter are valid. @@ -489,6 +501,8 @@ { int i, error = 0; + VGE_LOCK_ASSERT(sc); + if (sc->vge_camidx == VGE_CAM_MAXADDRS) return(ENOSPC); @@ -552,6 +566,8 @@ struct ifmultiaddr *ifma; u_int32_t h, hashes[2] = { 0, 0 }; + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; /* First, zot all the multicast entries. */ @@ -932,7 +948,8 @@ sc->vge_dev = dev; mtx_init(&sc->vge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); + callout_init_mtx(&sc->vge_callout, &sc->vge_mtx, 0); /* * Map control/status registers. */ @@ -972,6 +989,10 @@ sc->vge_unit = unit; + /* Save PHY address. */ + sc->vge_phyaddr = CSR_READ_1(sc, VGE_MIICFG) & VGE_MIICFG_PHYADDR; + /* Stop MII Auto-poll. */ + vge_miipoll_stop(sc); /* * Allocate the parent bus DMA tag appropriate for PCI. */ @@ -1022,7 +1043,6 @@ #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif - ifp->if_watchdog = vge_watchdog; ifp->if_init = vge_init; IFQ_SET_MAXLEN(&ifp->if_snd, VGE_IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = VGE_IFQ_MAXLEN; @@ -1078,6 +1098,7 @@ /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { + VGE_LOCK(sc); vge_stop(sc); /* * Force off the IFF_UP flag here, in case someone @@ -1092,6 +1113,8 @@ * anymore. */ ifp->if_flags &= ~IFF_UP; + VGE_UNLOCK(sc); + callout_drain(&sc->vge_callout); ether_ifdetach(ifp); } if (sc->vge_miibus) @@ -1231,6 +1254,8 @@ vge_tx_list_init(sc) struct vge_softc *sc; { + VGE_LOCK_ASSERT(sc); + bzero ((char *)sc->vge_ldata.vge_tx_list, VGE_TX_LIST_SZ); bzero ((char *)&sc->vge_ldata.vge_tx_mbuf, (VGE_TX_DESC_CNT * sizeof(struct mbuf *))); @@ -1250,6 +1275,8 @@ { int i; + VGE_LOCK_ASSERT(sc); + bzero ((char *)sc->vge_ldata.vge_rx_list, VGE_RX_LIST_SZ); bzero ((char *)&sc->vge_ldata.vge_rx_mbuf, (VGE_RX_DESC_CNT * sizeof(struct mbuf *))); @@ -1496,6 +1523,8 @@ u_int32_t txstat; int idx; + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; idx = sc->vge_ldata.vge_tx_considx; @@ -1531,7 +1560,7 @@ if (idx != sc->vge_ldata.vge_tx_considx) { sc->vge_ldata.vge_tx_considx = idx; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - ifp->if_timer = 0; + sc->vge_watchdog_timer = 0; } /* @@ -1556,32 +1585,13 @@ struct mii_data *mii; sc = xsc; + VGE_LOCK_ASSERT(sc); ifp = sc->vge_ifp; - VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); mii_tick(mii); - if (sc->vge_link) { - if (!(mii->mii_media_status & IFM_ACTIVE)) { - sc->vge_link = 0; - if_link_state_change(sc->vge_ifp, - LINK_STATE_DOWN); - } - } else { - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->vge_link = 1; - if_link_state_change(sc->vge_ifp, - LINK_STATE_UP); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue(taskqueue_swi, - &sc->vge_txtask); - } - } - - VGE_UNLOCK(sc); - - return; + vge_watchdog(sc); + callout_reset(&sc->vge_callout, hz, vge_tick, sc); } #ifdef DEVICE_POLLING @@ -1615,7 +1625,7 @@ if (status & VGE_ISR_TXDMA_STALL || status & VGE_ISR_RXDMA_STALL) - vge_init(sc); + vge_init_locked(sc); if (status & (VGE_ISR_RXOFLOW|VGE_ISR_RXNODESC)) { vge_rxeof(sc); @@ -1687,10 +1697,7 @@ vge_txeof(sc); if (status & (VGE_ISR_TXDMA_STALL|VGE_ISR_RXDMA_STALL)) - vge_init(sc); - - if (status & VGE_ISR_LINKSTS) - vge_tick(sc); + vge_init_locked(sc); } /* Re-enable interrupts */ @@ -1715,6 +1722,8 @@ bus_dmamap_t map; int error; + VGE_LOCK_ASSERT(sc); + if (sc->vge_ldata.vge_tx_free <= 2) return (EFBIG); @@ -1877,26 +1886,38 @@ */ CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_TIMER0_ENABLE); - VGE_UNLOCK(sc); - /* * Set a timeout in case the chip goes out to lunch. */ - ifp->if_timer = 5; + sc->vge_watchdog_timer = 5; + + VGE_UNLOCK(sc); return; } + static void vge_init(xsc) void *xsc; { - struct vge_softc *sc = xsc; + struct vge_softc *sc; + + sc = xsc; + VGE_LOCK(sc); + vge_init_locked(sc); + VGE_UNLOCK(sc); +} + +static void +vge_init_locked(sc) + struct vge_softc *sc; +{ struct ifnet *ifp = sc->vge_ifp; struct mii_data *mii; int i; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); mii = device_get_softc(sc->vge_miibus); /* @@ -2056,7 +2077,7 @@ sc->vge_if_flags = 0; sc->vge_link = 0; - VGE_UNLOCK(sc); + callout_reset(&sc->vge_callout, hz, vge_tick, sc); return; } @@ -2070,14 +2091,41 @@ { struct vge_softc *sc; struct mii_data *mii; + struct ifmedia_entry *ife; + int error; sc = ifp->if_softc; VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); - mii_mediachg(mii); + + ife = mii->mii_media.ifm_cur; + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_1000_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_100_TX: + case IFM_10_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } else { + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } + break; + default: + device_printf(sc->vge_dev, "unknown media type: %x\n", + IFM_SUBTYPE(ife->ifm_media)); + break; + } + error = mii_mediachg(mii); VGE_UNLOCK(sc); - return (0); + return (error); } /* @@ -2092,9 +2140,11 @@ struct mii_data *mii; sc = ifp->if_softc; + VGE_LOCK(sc); mii = device_get_softc(sc->vge_miibus); mii_pollstat(mii); + VGE_UNLOCK(sc); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; @@ -2107,48 +2157,79 @@ { struct vge_softc *sc; struct mii_data *mii; - struct ifmedia_entry *ife; + struct ifnet *ifp; + uint8_t cfg; sc = device_get_softc(dev); mii = device_get_softc(sc->vge_miibus); - ife = mii->mii_media.ifm_cur; + ifp = sc->vge_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + return; + } - /* - * If the user manually selects a media mode, we need to turn - * on the forced MAC mode bit in the DIAGCTL register. If the - * user happens to choose a full duplex mode, we also need to - * set the 'force full duplex' bit. This applies only to - * 10Mbps and 100Mbps speeds. In autoselect mode, forced MAC - * mode is disabled, and in 1000baseT mode, full duplex is - * always implied, so we turn on the forced mode bit but leave - * the FDX bit cleared. - */ + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->vge_link = 1; + } else + sc->vge_link = 0; - switch (IFM_SUBTYPE(ife->ifm_media)) { - case IFM_AUTO: - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - break; - case IFM_1000_T: - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - break; - case IFM_100_TX: - case IFM_10_T: - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); - if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { - CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); - } else { - CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + /* STOP MAC & RESTART MAC */ + if (sc->vge_link != 0) { + /* + * If the user manually selects a media mode, we need to turn + * on the forced MAC mode bit in the DIAGCTL register. If the + * user happens to choose a full duplex mode, we also need to + * set the 'force full duplex' bit. This applies only to + * 10Mbps and 100Mbps speeds. In autoselect mode, forced MAC + * mode is disabled, and in 1000baseT mode, full duplex is + * always implied, so we turn on the forced mode bit but leave + * the FDX bit cleared. + */ +#if 0 + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_1000_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + break; + case IFM_100_TX: + case IFM_10_T: + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { + CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } else { + CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); + } + break; + default: + device_printf(dev, "unknown media type: %x\n", + IFM_SUBTYPE(ife->ifm_media)); + break; + } +#endif + /* Reprgroam MAC as resolved media type. */ + cfg = CSR_READ_1(sc, VGE_DIAGCTL); +#if 1 + cfg &= ~(VGE_DIAGCTL_FDXFORCE | VGE_DIAGCTL_GMII); + cfg |= VGE_DIAGCTL_MACFORCE; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { + cfg |= VGE_DIAGCTL_FDXFORCE; + /* TODO Enable flow-control */ + } + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + cfg |= VGE_DIAGCTL_GMII; + break; } - break; - default: - device_printf(dev, "unknown media type: %x\n", - IFM_SUBTYPE(ife->ifm_media)); - break; - } - return; + CSR_WRITE_1(sc, VGE_DIAGCTL, cfg); +#endif + /* XXX Restart TX/RX MAC. */ + } } static int @@ -2169,6 +2250,7 @@ ifp->if_mtu = ifr->ifr_mtu; 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 && @@ -2183,16 +2265,19 @@ VGE_RXCTL_RX_PROMISC); vge_setmulti(sc); } else - vge_init(sc); + vge_init_locked(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) vge_stop(sc); } sc->vge_if_flags = ifp->if_flags; + VGE_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: + VGE_LOCK(sc); vge_setmulti(sc); + VGE_UNLOCK(sc); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -2246,13 +2331,17 @@ } static void -vge_watchdog(ifp) - struct ifnet *ifp; +vge_watchdog(sc) + struct vge_softc *sc; { - struct vge_softc *sc; + struct ifnet *ifp; - sc = ifp->if_softc; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); + + if (sc->vge_watchdog_timer == 0 || --sc->vge_watchdog_timer) + return; + + ifp = sc->vge_ifp; printf("vge%d: watchdog timeout\n", sc->vge_unit); ifp->if_oerrors++; @@ -2277,10 +2366,12 @@ register int i; struct ifnet *ifp; - VGE_LOCK(sc); + VGE_LOCK_ASSERT(sc); + ifp = sc->vge_ifp; - ifp->if_timer = 0; + sc->vge_watchdog_timer = 0; + callout_stop(&sc->vge_callout); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); @@ -2317,8 +2408,6 @@ } } - VGE_UNLOCK(sc); - return; } --- if_vgereg.h.orig 2005-01-06 10:43:31.000000000 +0900 +++ if_vgereg.h 2008-02-27 13:59:49.000000000 +0900 @@ -299,7 +299,7 @@ #define VGE_INTRS (VGE_ISR_TXOK0|VGE_ISR_RXOK|VGE_ISR_STOPPED| \ VGE_ISR_RXOFLOW|VGE_ISR_PHYINT| \ - VGE_ISR_LINKSTS|VGE_ISR_RXNODESC| \ + VGE_ISR_RXNODESC| \ VGE_ISR_RXDMA_STALL|VGE_ISR_TXDMA_STALL| \ VGE_ISR_MIBOFLOW|VGE_ISR_TIMER0) --- if_vgevar.h.orig 2005-06-11 01:49:16.000000000 +0900 +++ if_vgevar.h 2008-02-27 15:11:28.000000000 +0900 @@ -110,6 +110,9 @@ bus_dma_tag_t vge_tag; u_int8_t vge_unit; /* interface number */ u_int8_t vge_type; + struct callout vge_callout; + int vge_watchdog_timer; + int vge_phyaddr; int vge_if_flags; int vge_rx_consumed; int vge_link; ------=_NextPart_000_4A17_01C8A964.91ED7060--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4a1601c8a95c$30290860$907b1920$>