Author: yongari
Date: Mon Mar 28 19:08:53 2011
New Revision: 220106
URL: http://svn.freebsd.org/changeset/base/220106

Log:
  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

Modified:
  head/sys/dev/dc/if_dc.c

Modified: head/sys/dev/dc/if_dc.c
==============================================================================
--- head/sys/dev/dc/if_dc.c     Mon Mar 28 19:03:56 2011        (r220105)
+++ head/sys/dev/dc/if_dc.c     Mon Mar 28 19:08:53 2011        (r220106)
@@ -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.
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to