summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2011-03-28 19:08:53 +0000
committeryongari <yongari@FreeBSD.org>2011-03-28 19:08:53 +0000
commit067233645bc62aec8b8f4ff426c3b1d065af39f4 (patch)
treeef5f1fbd831b05ac876a40a9be9c1ec2f4afcdff
parent55ffee0ed1dddaabd36f936b297206f1fe608ad9 (diff)
downloadFreeBSD-src-067233645bc62aec8b8f4ff426c3b1d065af39f4.zip
FreeBSD-src-067233645bc62aec8b8f4ff426c3b1d065af39f4.tar.gz
Revise r220046 by introducing dc_netcfg_wait() which waits the end
of active DMA cycle. dc_setcfg() also has to wait until the DMA engine is stopped so using a common function to handle the job is better than duplicating the code. No objection from: marius
-rw-r--r--sys/dev/dc/if_dc.c90
1 files changed, 39 insertions, 51 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 6d0ebc0..772eede 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -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, isr;
+ uint32_t ctl, netcfg;
DC_LOCK_ASSERT(sc);
@@ -3928,38 +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));
-
- for (i = 0; i < DC_TIMEOUT; i++) {
- isr = CSR_READ_4(sc, DC_ISR);
- if ((isr & DC_ISR_TX_IDLE ||
- (isr & DC_ISR_TX_STATE) == DC_TXSTATE_RESET) &&
- (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED)
- break;
- DELAY(10);
- }
-
- if (i == DC_TIMEOUT) {
- if (!((isr & DC_ISR_TX_IDLE) ||
- (isr & DC_ISR_TX_STATE) == DC_TXSTATE_RESET) &&
- !DC_IS_ASIX(sc) && !DC_IS_DAVICOM(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) &&
- !DC_HAS_BROKEN_RXSTATE(sc))
- device_printf(sc->dc_dev,
- "%s: failed to force rx to idle state\n",
- __func__);
- }
-
+ 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.
OpenPOWER on IntegriCloud