Author: adrian
Date: Sun Mar 15 20:40:11 2015
New Revision: 280071
URL: https://svnweb.freebsd.org/changeset/base/280071

Log:
  Add separate lock for TX queues.
  
  PR:           kern/197143
  Submitted by: Andriy Voskoboinyk <s3er...@gmail.com>

Modified:
  head/sys/dev/wpi/if_wpi.c
  head/sys/dev/wpi/if_wpivar.h

Modified: head/sys/dev/wpi/if_wpi.c
==============================================================================
--- head/sys/dev/wpi/if_wpi.c   Sun Mar 15 20:35:25 2015        (r280070)
+++ head/sys/dev/wpi/if_wpi.c   Sun Mar 15 20:40:11 2015        (r280071)
@@ -384,6 +384,7 @@ wpi_attach(device_t dev)
        }
 
        WPI_LOCK_INIT(sc);
+       WPI_TXQ_LOCK_INIT(sc);
 
        /* Allocate DMA memory for firmware transfers. */
        if ((error = wpi_alloc_fwmem(sc)) != 0) {
@@ -679,6 +680,7 @@ wpi_detach(device_t dev)
                if_free(ifp);
 
        DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__);
+       WPI_TXQ_LOCK_DESTROY(sc);
        WPI_LOCK_DESTROY(sc);
        return 0;
 }
@@ -2151,6 +2153,7 @@ wpi_wakeup_intr(struct wpi_softc *sc)
                sc->rxq.update = 0;
                wpi_update_rx_ring(sc);
        }
+       WPI_TXQ_LOCK(sc);
        for (qid = 0; qid < WPI_DRV_NTXQUEUES; qid++) {
                struct wpi_tx_ring *ring = &sc->txq[qid];
 
@@ -2159,6 +2162,7 @@ wpi_wakeup_intr(struct wpi_softc *sc)
                        wpi_update_tx_ring(sc, ring);
                }
        }
+       WPI_TXQ_UNLOCK(sc);
 
        WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ);
 }
@@ -2220,11 +2224,13 @@ wpi_fatal_intr(struct wpi_softc *sc)
        wpi_nic_unlock(sc);
        /* Dump driver status (TX and RX rings) while we're here. */
        printf("driver status:\n");
+       WPI_TXQ_LOCK(sc);
        for (i = 0; i < WPI_DRV_NTXQUEUES; i++) {
                struct wpi_tx_ring *ring = &sc->txq[i];
                printf("  tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n",
                    i, ring->qid, ring->cur, ring->queued);
        }
+       WPI_TXQ_UNLOCK(sc);
        printf("  rx ring: cur=%d\n", sc->rxq.cur);
 }
 
@@ -2302,8 +2308,16 @@ wpi_cmd2(struct wpi_softc *sc, struct wp
 
        WPI_LOCK_ASSERT(sc);
 
+       WPI_TXQ_LOCK(sc);
+
        DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__);
 
+       if (sc->txq_active == 0) {
+               /* wpi_stop() was called */
+               error = ENETDOWN;
+               goto fail;
+       }
+
        wh = mtod(buf->m, struct ieee80211_frame *);
        hdrlen = ieee80211_anyhdrsize(wh);
        totlen = buf->m->m_pkthdr.len;
@@ -2336,8 +2350,7 @@ wpi_cmd2(struct wpi_softc *sc, struct wp
        if (error != 0 && error != EFBIG) {
                device_printf(sc->sc_dev,
                    "%s: can't map mbuf (error %d)\n", __func__, error);
-               m_freem(buf->m);
-               return error;
+               goto fail;
        }
        if (error != 0) {
                /* Too many DMA segments, linearize mbuf. */
@@ -2345,8 +2358,8 @@ wpi_cmd2(struct wpi_softc *sc, struct wp
                if (m1 == NULL) {
                        device_printf(sc->sc_dev,
                            "%s: could not defrag mbuf\n", __func__);
-                       m_freem(buf->m);
-                       return ENOBUFS;
+                       error = ENOBUFS;
+                       goto fail;
                }
                buf->m = m1;
 
@@ -2356,8 +2369,7 @@ wpi_cmd2(struct wpi_softc *sc, struct wp
                        device_printf(sc->sc_dev,
                            "%s: can't map mbuf (error %d)\n", __func__,
                            error);
-                       m_freem(buf->m);
-                       return error;
+                       goto fail;
                }
        }
 
@@ -2400,7 +2412,17 @@ wpi_cmd2(struct wpi_softc *sc, struct wp
 
        DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__);
 
+       WPI_TXQ_UNLOCK(sc);
+
        return 0;
+
+fail:  m_freem(buf->m);
+
+       DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__);
+
+       WPI_TXQ_UNLOCK(sc);
+
+       return error;
 }
 
 /*
@@ -2867,8 +2889,16 @@ wpi_cmd(struct wpi_softc *sc, int code, 
        bus_addr_t paddr;
        int totlen, error;
 
+       WPI_TXQ_LOCK(sc);
+
        DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__);
 
+       if (sc->txq_active == 0) {
+               /* wpi_stop() was called */
+               error = 0;
+               goto fail;
+       }
+
        if (async == 0)
                WPI_LOCK_ASSERT(sc);
 
@@ -2888,17 +2918,21 @@ wpi_cmd(struct wpi_softc *sc, int code, 
 
        if (size > sizeof cmd->data) {
                /* Command is too large to fit in a descriptor. */
-               if (totlen > MCLBYTES)
-                       return EINVAL;
+               if (totlen > MCLBYTES) {
+                       error = EINVAL;
+                       goto fail;
+               }
                m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
-               if (m == NULL)
-                       return ENOMEM;
+               if (m == NULL) {
+                       error = ENOMEM;
+                       goto fail;
+               }
                cmd = mtod(m, struct wpi_tx_cmd *);
                error = bus_dmamap_load(ring->data_dmat, data->map, cmd,
                    totlen, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT);
                if (error != 0) {
                        m_freem(m);
-                       return error;
+                       goto fail;
                }
                data->m = m;
        } else {
@@ -2932,12 +2966,20 @@ wpi_cmd(struct wpi_softc *sc, int code, 
 
        DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__);
 
+       WPI_TXQ_UNLOCK(sc);
+
        if (async) {
                sc->flags &= ~WPI_FLAG_BUSY;
                return 0;
        }
 
        return mtx_sleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz);
+
+fail:  DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__);
+
+       WPI_TXQ_UNLOCK(sc);
+
+       return error;
 }
 
 /*
@@ -4817,6 +4859,7 @@ wpi_init_locked(struct wpi_softc *sc)
        }
 
        /* Configure adapter now that it is ready. */
+       sc->txq_active = 1;
        if ((error = wpi_config(sc)) != 0) {
                device_printf(sc->sc_dev,
                    "%s: could not configure device, error %d\n", __func__,
@@ -4859,6 +4902,10 @@ wpi_stop_locked(struct wpi_softc *sc)
 
        WPI_LOCK_ASSERT(sc);
 
+       WPI_TXQ_LOCK(sc);
+       sc->txq_active = 0;
+       WPI_TXQ_UNLOCK(sc);
+
        sc->sc_scan_timer = 0;
        sc->sc_tx_timer = 0;
        callout_stop(&sc->watchdog_to);

Modified: head/sys/dev/wpi/if_wpivar.h
==============================================================================
--- head/sys/dev/wpi/if_wpivar.h        Sun Mar 15 20:35:25 2015        
(r280070)
+++ head/sys/dev/wpi/if_wpivar.h        Sun Mar 15 20:40:11 2015        
(r280071)
@@ -163,6 +163,9 @@ struct wpi_softc {
        struct wpi_shared       *shared;
 
        struct wpi_tx_ring      txq[WPI_NTXQUEUES];
+       struct mtx              txq_mtx;
+       uint32_t                txq_active;
+
        struct wpi_rx_ring      rxq;
 
        /* TX Thermal Callibration. */
@@ -222,6 +225,8 @@ struct wpi_softc {
        char                    domain[4];      /* Regulatory domain. */
 };
 
+/* WPI_LOCK > WPI_TXQ_LOCK */
+
 #define WPI_LOCK_INIT(_sc) \
        mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
            MTX_NETWORK_LOCK, MTX_DEF)
@@ -229,3 +234,9 @@ struct wpi_softc {
 #define WPI_UNLOCK(_sc)                mtx_unlock(&(_sc)->sc_mtx)
 #define WPI_LOCK_ASSERT(sc)    mtx_assert(&(sc)->sc_mtx, MA_OWNED)
 #define WPI_LOCK_DESTROY(_sc)  mtx_destroy(&(_sc)->sc_mtx)
+
+#define WPI_TXQ_LOCK_INIT(_sc) \
+       mtx_init(&(_sc)->txq_mtx, "txq/cmdq lock", NULL, MTX_DEF)
+#define WPI_TXQ_LOCK(_sc)              mtx_lock(&(_sc)->txq_mtx)
+#define WPI_TXQ_UNLOCK(_sc)            mtx_unlock(&(_sc)->txq_mtx)
+#define WPI_TXQ_LOCK_DESTROY(_sc)      mtx_destroy(&(_sc)->txq_mtx)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to