Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Use a workqueue(9) to defer allocation of TX pac...



details:   https://anonhg.NetBSD.org/src/rev/e63c390ca74c
branches:  trunk
changeset: 767321:e63c390ca74c
user:      jym <jym%NetBSD.org@localhost>
date:      Fri Jul 15 11:29:31 2011 +0000

description:
Use a workqueue(9) to defer allocation of TX packets. Loosely inspired
from the OpenBSD bnx(4) driver.

Tested by Roger Pau Monn?, roger.pau at entel.upc.edu.

Fixes kern/45051.

diffstat:

 sys/dev/pci/if_bnx.c    |  66 +++++++++++++++++++++++++++++++-----------------
 sys/dev/pci/if_bnxvar.h |   5 ++-
 2 files changed, 47 insertions(+), 24 deletions(-)

diffs (188 lines):

diff -r e77c29cba5e6 -r e63c390ca74c sys/dev/pci/if_bnx.c
--- a/sys/dev/pci/if_bnx.c      Fri Jul 15 11:27:23 2011 +0000
+++ b/sys/dev/pci/if_bnx.c      Fri Jul 15 11:29:31 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_bnx.c,v 1.43 2011/05/02 09:03:10 jym Exp $  */
+/*     $NetBSD: if_bnx.c,v 1.44 2011/07/15 11:29:31 jym Exp $  */
 /*     $OpenBSD: if_bnx.c,v 1.85 2009/11/09 14:32:41 dlg Exp $ */
 
 /*-
@@ -35,7 +35,7 @@
 #if 0
 __FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.3 2006/04/13 14:12:26 ru Exp $");
 #endif
-__KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1.43 2011/05/02 09:03:10 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1.44 2011/07/15 11:29:31 jym Exp $");
 
 /*
  * The following controllers are supported by this driver:
@@ -397,7 +397,7 @@
 void   bnx_tick(void *);
 
 struct pool *bnx_tx_pool = NULL;
-int    bnx_alloc_pkts(struct bnx_softc *);
+void   bnx_alloc_pkts(struct work *, void *);
 
 /****************************************************************************/
 /* OpenBSD device dispatch table.                                           */
@@ -705,6 +705,13 @@
        }
        aprint_normal_dev(sc->bnx_dev, "interrupting at %s\n", intrstr);
 
+       /* create workqueue to handle packet allocations */
+       if (workqueue_create(&sc->bnx_wq, device_xname(self),
+           bnx_alloc_pkts, sc, PRI_NONE, IPL_NONE, WQ_MPSAFE) != 0) {
+               aprint_error_dev(self, "failed to create workqueue\n");
+               goto bnx_attach_fail;
+       }
+
        sc->bnx_mii.mii_ifp = ifp;
        sc->bnx_mii.mii_readreg = bnx_miibus_read_reg;
        sc->bnx_mii.mii_writereg = bnx_miibus_write_reg;
@@ -799,6 +806,7 @@
        pmf_device_deregister(dev);
        callout_destroy(&sc->bnx_timeout);
        ether_ifdetach(ifp);
+       workqueue_destroy(sc->bnx_wq);
 
        /* Delete all remaining media. */
        ifmedia_delete_instance(&sc->bnx_mii.mii_media, IFM_INST_ANY);
@@ -3839,21 +3847,22 @@
        return(rc);
 }
 
-int
-bnx_alloc_pkts(struct bnx_softc *sc)
+void
+bnx_alloc_pkts(struct work * unused, void * arg)
 {
+       struct bnx_softc *sc = arg;
        struct ifnet *ifp = &sc->bnx_ec.ec_if;
        struct bnx_pkt *pkt;
-       int i;
+       int i, s;
 
        for (i = 0; i < 4; i++) { /* magic! */
-               pkt = pool_get(bnx_tx_pool, PR_NOWAIT);
+               pkt = pool_get(bnx_tx_pool, PR_WAITOK);
                if (pkt == NULL)
                        break;
 
                if (bus_dmamap_create(sc->bnx_dmatag,
                    MCLBYTES * BNX_MAX_SEGMENTS, USABLE_TX_BD,
-                   MCLBYTES, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+                   MCLBYTES, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
                    &pkt->pkt_dmamap) != 0)
                        goto put;
 
@@ -3866,13 +3875,23 @@
                mutex_exit(&sc->tx_pkt_mtx);
        }
 
-       return (i == 0) ? ENOMEM : 0;
+       mutex_enter(&sc->tx_pkt_mtx);
+       CLR(sc->bnx_flags, BNX_ALLOC_PKTS_FLAG);
+       mutex_exit(&sc->tx_pkt_mtx);
+
+       /* fire-up TX now that allocations have been done */
+       s = splnet();
+       if (!IFQ_IS_EMPTY(&ifp->if_snd))
+               bnx_start(ifp);
+       splx(s);
+
+       return;
 
 stopping:
        bus_dmamap_destroy(sc->bnx_dmatag, pkt->pkt_dmamap);
 put:
        pool_put(bnx_tx_pool, pkt);
-       return (i == 0) ? ENOMEM : 0;
+       return;
 }
 
 /****************************************************************************/
@@ -3933,7 +3952,7 @@
        DBPRINT(sc, BNX_VERBOSE_RESET, "Entering %s()\n", __func__);
 
        /* Force an allocation of some dmamaps for tx up front */
-       bnx_alloc_pkts(sc);
+       bnx_alloc_pkts(NULL, sc);
 
        /* Set the initial TX producer/consumer indices. */
        sc->tx_prod = 0;
@@ -4805,8 +4824,8 @@
        if ((error = ether_mediachange(ifp)) != 0)
                goto bnx_init_exit;
 
-       ifp->if_flags |= IFF_RUNNING;
-       ifp->if_flags &= ~IFF_OACTIVE;
+       SET(ifp->if_flags, IFF_RUNNING);
+       CLR(ifp->if_flags, IFF_OACTIVE);
 
        callout_reset(&sc->bnx_timeout, hz, bnx_tick, sc);
 
@@ -4839,8 +4858,8 @@
        u_int32_t               addr, prod_bseq;
        int                     i, error;
        struct m_tag            *mtag;
-
-again:
+       static struct work      bnx_wk; /* Dummy work. Statically allocated. */
+
        mutex_enter(&sc->tx_pkt_mtx);
        pkt = TAILQ_FIRST(&sc->tx_free_pkts);
        if (pkt == NULL) {
@@ -4848,14 +4867,15 @@
                        mutex_exit(&sc->tx_pkt_mtx);
                        return ENETDOWN;
                }
-               if (sc->tx_pkt_count <= TOTAL_TX_BD) {
-                       mutex_exit(&sc->tx_pkt_mtx);
-                       if (bnx_alloc_pkts(sc) == 0)
-                               goto again;
-               } else {
-                       mutex_exit(&sc->tx_pkt_mtx);
+
+               if (sc->tx_pkt_count <= TOTAL_TX_BD &&
+                   !ISSET(sc->bnx_flags, BNX_ALLOC_PKTS_FLAG)) {
+                       workqueue_enqueue(sc->bnx_wq, &bnx_wk, NULL);
+                       SET(sc->bnx_flags, BNX_ALLOC_PKTS_FLAG);
                }
-               return (ENOMEM);
+
+               mutex_exit(&sc->tx_pkt_mtx);
+               return ENOMEM;
        }
        TAILQ_REMOVE(&sc->tx_free_pkts, pkt, pkt_entry);
        mutex_exit(&sc->tx_pkt_mtx);
@@ -5082,7 +5102,7 @@
                /* XXX set an ifflags callback and let ether_ioctl
                 * handle all of this.
                 */
-               if (ifp->if_flags & IFF_UP) {
+               if (ISSET(ifp->if_flags, IFF_UP)) {
                        if (ifp->if_flags & IFF_RUNNING)
                                error = ENETRESET;
                        else
diff -r e77c29cba5e6 -r e63c390ca74c sys/dev/pci/if_bnxvar.h
--- a/sys/dev/pci/if_bnxvar.h   Fri Jul 15 11:27:23 2011 +0000
+++ b/sys/dev/pci/if_bnxvar.h   Fri Jul 15 11:29:31 2011 +0000
@@ -46,7 +46,7 @@
 #include <sys/device.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
-//#include <sys/workqueue.h>
+#include <sys/workqueue.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -126,6 +126,9 @@
 
        void                    *bnx_intrhand;          /* Interrupt handler */
 
+       /* packet allocation workqueue */
+       struct workqueue        *bnx_wq;
+
        /* ASIC Chip ID. */
        u_int32_t               bnx_chipid;
 



Home | Main Index | Thread Index | Old Index