bge: Improve TX performance on certain low end chips
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 29 Jun 2012 07:39:10 +0000 (15:39 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 29 Jun 2012 07:39:10 +0000 (15:39 +0800)
These chips, e.g. BCM5761, only allow one outstanding DMA read operation,
so on TX path, mbuf chain should be packed to reduce number of DMA reads
from chip to improve performance.

hw.bgeX.force_defrag is added for PCI-E chips to enable this mbuf chain
packing.  It is not enabled by default.

Obtained-from: FreeBSD 200088

sys/dev/netif/bge/if_bge.c
sys/dev/netif/bge/if_bgereg.h

index f433b44..b081fdd 100644 (file)
@@ -2178,6 +2178,30 @@ bge_attach(device_t dev)
                        sc, 0, bge_sysctl_tx_max_coal_bds, "I",
                        "Transmit max coalesced BD count.");
 
+       if (sc->bge_flags & BGE_FLAG_PCIE) {
+               /*
+                * A common design characteristic for many Broadcom
+                * client controllers is that they only support a
+                * single outstanding DMA read operation on the PCIe
+                * bus. This means that it will take twice as long to
+                * fetch a TX frame that is split into header and
+                * payload buffers as it does to fetch a single,
+                * contiguous TX frame (2 reads vs. 1 read). For these
+                * controllers, coalescing buffers to reduce the number
+                * of memory reads is effective way to get maximum
+                * performance(about 940Mbps).  Without collapsing TX
+                * buffers the maximum TCP bulk transfer performance
+                * is about 850Mbps. However forcing coalescing mbufs
+                * consumes a lot of CPU cycles, so leave it off by
+                * default.
+                */
+               SYSCTL_ADD_INT(&sc->bge_sysctl_ctx,
+                              SYSCTL_CHILDREN(sc->bge_sysctl_tree),
+                              OID_AUTO, "force_defrag", CTLFLAG_RW,
+                              &sc->bge_force_defrag, 0,
+                              "Force defragment on TX path");
+       }
+
        /*
         * Call MI attach routine.
         */
@@ -2869,6 +2893,21 @@ bge_encap(struct bge_softc *sc, struct mbuf **m_head0, uint32_t *txidx)
                        goto back;
        }
 
+       if (sc->bge_force_defrag && (sc->bge_flags & BGE_FLAG_PCIE) &&
+           m_head->m_next != NULL) {
+               struct mbuf *m_new;
+
+               /*
+                * Forcefully defragment mbuf chain to overcome hardware
+                * limitation which only support a single outstanding
+                * DMA read operation.  If it fails, keep moving on using
+                * the original mbuf chain.
+                */
+               m_new = m_defrag(m_head, MB_DONTWAIT);
+               if (m_new != NULL)
+                       *m_head0 = m_head = m_new;
+       }
+
        error = bus_dmamap_load_mbuf_defrag(sc->bge_cdata.bge_tx_mtag, map,
                        m_head0, segs, maxsegs, &nsegs, BUS_DMA_NOWAIT);
        if (error)
index 4668b0a..2718646 100644 (file)
@@ -2495,6 +2495,7 @@ struct bge_softc {
        uint32_t                bge_rx_max_coal_bds;
        uint32_t                bge_tx_max_coal_bds;
        uint32_t                bge_tx_buf_ratio;
+       int                     bge_force_defrag;
        int                     bge_if_flags;
        int                     bge_txcnt;
        int                     bge_link;