Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Apr 2011 09:35:42 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r220513 - stable/8/sys/dev/dc
Message-ID:  <201104100935.p3A9ZgN3042121@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marius
Date: Sun Apr 10 09:35:42 2011
New Revision: 220513
URL: http://svn.freebsd.org/changeset/base/220513

Log:
  MFC: r220046, r220106
  
  Wait until the DMA engine is stopped before unmapping buffers and
  descriptors, which fixes DMA errors seen on sparc64.

Modified:
  stable/8/sys/dev/dc/if_dc.c
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)

Modified: stable/8/sys/dev/dc/if_dc.c
==============================================================================
--- stable/8/sys/dev/dc/if_dc.c	Sun Apr 10 03:53:06 2011	(r220512)
+++ stable/8/sys/dev/dc/if_dc.c	Sun Apr 10 09:35:42 2011	(r220513)
@@ -279,6 +279,7 @@ static void dc_miibus_statchg(device_t);
 static void dc_miibus_mediainit(device_t);
 
 static void dc_setcfg(struct dc_softc *, int);
+static void dc_netcfg_wait(struct dc_softc *);
 static uint32_t dc_mchash_le(struct dc_softc *, const uint8_t *);
 static uint32_t dc_mchash_be(const uint8_t *);
 static void dc_setfilt_21143(struct dc_softc *);
@@ -1370,6 +1371,32 @@ dc_setfilt(struct dc_softc *sc)
 		dc_setfilt_xircom(sc);
 }
 
+static void
+dc_netcfg_wait(struct dc_softc *sc)
+{
+	uint32_t isr;
+	int i;
+
+	for (i = 0; i < DC_TIMEOUT; i++) {
+		isr = CSR_READ_4(sc, DC_ISR);
+		if (isr & DC_ISR_TX_IDLE &&
+		    ((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED ||
+		    (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT))
+			break;
+		DELAY(10);
+	}
+	if (i == DC_TIMEOUT) {
+		if (!(isr & DC_ISR_TX_IDLE) && !DC_IS_ASIX(sc))
+			device_printf(sc->dc_dev,
+			    "%s: failed to force tx to idle state\n", __func__);
+		if (!((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED ||
+		    (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT) &&
+		    !DC_HAS_BROKEN_RXSTATE(sc))
+			device_printf(sc->dc_dev,
+			    "%s: failed to force rx to idle state\n", __func__);
+	}
+}
+
 /*
  * In order to fiddle with the 'full-duplex' and '100Mbps' bits in
  * the netconfig register, we first have to put the transmit and/or
@@ -1378,8 +1405,7 @@ dc_setfilt(struct dc_softc *sc)
 static void
 dc_setcfg(struct dc_softc *sc, int media)
 {
-	int i, restart = 0, watchdogreg;
-	uint32_t isr;
+	int restart = 0, watchdogreg;
 
 	if (IFM_SUBTYPE(media) == IFM_NONE)
 		return;
@@ -1387,28 +1413,7 @@ dc_setcfg(struct dc_softc *sc, int media
 	if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)) {
 		restart = 1;
 		DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON));
-
-		for (i = 0; i < DC_TIMEOUT; i++) {
-			isr = CSR_READ_4(sc, DC_ISR);
-			if (isr & DC_ISR_TX_IDLE &&
-			    ((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED ||
-			    (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT))
-				break;
-			DELAY(10);
-		}
-
-		if (i == DC_TIMEOUT) {
-			if (!(isr & DC_ISR_TX_IDLE) && !DC_IS_ASIX(sc))
-				device_printf(sc->dc_dev,
-				    "%s: failed to force tx to idle state\n",
-				    __func__);
-			if (!((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED ||
-			    (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT) &&
-			    !DC_HAS_BROKEN_RXSTATE(sc))
-				device_printf(sc->dc_dev,
-				    "%s: failed to force rx to idle state\n",
-				    __func__);
-		}
+		dc_netcfg_wait(sc);
 	}
 
 	if (IFM_SUBTYPE(media) == IFM_100_TX) {
@@ -3917,7 +3922,7 @@ dc_stop(struct dc_softc *sc)
 	struct dc_list_data *ld;
 	struct dc_chain_data *cd;
 	int i;
-	uint32_t ctl;
+	uint32_t ctl, netcfg;
 
 	DC_LOCK_ASSERT(sc);
 
@@ -3928,14 +3933,21 @@ dc_stop(struct dc_softc *sc)
 	callout_stop(&sc->dc_stat_ch);
 	callout_stop(&sc->dc_wdog_ch);
 	sc->dc_wdog_timer = 0;
+	sc->dc_link = 0;
 
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 
-	DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON));
+	netcfg = CSR_READ_4(sc, DC_NETCFG);
+	if (netcfg & (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON))
+		CSR_WRITE_4(sc, DC_NETCFG,
+		   netcfg & ~(DC_NETCFG_RX_ON | DC_NETCFG_TX_ON));
 	CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+	/* Wait the completion of TX/RX SM. */
+	if (netcfg & (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON))
+		dc_netcfg_wait(sc);
+
 	CSR_WRITE_4(sc, DC_TXADDR, 0x00000000);
 	CSR_WRITE_4(sc, DC_RXADDR, 0x00000000);
-	sc->dc_link = 0;
 
 	/*
 	 * Free data in the RX lists.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104100935.p3A9ZgN3042121>