Skip site navigation (1)Skip section navigation (2)
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$>