Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/ic Pad small packets with a static buffer at the end...



details:   https://anonhg.NetBSD.org/src/rev/cfe603cd855a
branches:  trunk
changeset: 580936:cfe603cd855a
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon May 16 15:56:38 2005 +0000

description:
Pad small packets with a static buffer at the end of the S/G list.
Avoids leaking kernel memory when small packets are transmitted.
Tested on a ibook G4.

diffstat:

 sys/dev/ic/gem.c    |  101 +++++++++++++++++++++++++++++++++++++++------------
 sys/dev/ic/gemvar.h |    4 +-
 2 files changed, 79 insertions(+), 26 deletions(-)

diffs (251 lines):

diff -r 171eadd5e420 -r cfe603cd855a sys/dev/ic/gem.c
--- a/sys/dev/ic/gem.c  Mon May 16 15:36:57 2005 +0000
+++ b/sys/dev/ic/gem.c  Mon May 16 15:56:38 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gem.c,v 1.39 2005/05/02 15:34:31 yamt Exp $ */
+/*     $NetBSD: gem.c,v 1.40 2005/05/16 15:56:38 bouyer Exp $ */
 
 /*
  *
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.39 2005/05/02 15:34:31 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.40 2005/05/16 15:56:38 bouyer Exp $");
 
 #include "opt_inet.h"
 #include "bpfilter.h"
@@ -128,6 +128,8 @@
 #define        DPRINTF(sc, x)  /* nothing */
 #endif
 
+#define ETHER_MIN_TX (ETHERMIN + sizeof(struct ether_header))
+
 
 /*
  * gem_attach:
@@ -145,6 +147,7 @@
        struct ifmedia_entry *ifm;
        int i, error;
        u_int32_t v;
+       char *nullbuf;
 
        /* Make sure the chip is stopped. */
        ifp->if_softc = sc;
@@ -152,11 +155,12 @@
 
        /*
         * Allocate the control data structures, and create and load the
-        * DMA map for it.
+        * DMA map for it. gem_control_data is 9216 bytes, we have space for
+        * the padding buffer in the bus_dmamem_alloc()'d memory.
         */
        if ((error = bus_dmamem_alloc(sc->sc_dmatag,
-           sizeof(struct gem_control_data), PAGE_SIZE, 0, &sc->sc_cdseg,
-           1, &sc->sc_cdnseg, 0)) != 0) {
+           sizeof(struct gem_control_data) + ETHER_MIN_TX, PAGE_SIZE,
+           0, &sc->sc_cdseg, 1, &sc->sc_cdnseg, 0)) != 0) {
                aprint_error(
                   "%s: unable to allocate control data, error = %d\n",
                    sc->sc_dev.dv_xname, error);
@@ -172,6 +176,9 @@
                goto fail_1;
        }
 
+       nullbuf =
+           (caddr_t)sc->sc_control_data + sizeof(struct gem_control_data);
+
        if ((error = bus_dmamap_create(sc->sc_dmatag,
            sizeof(struct gem_control_data), 1,
            sizeof(struct gem_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
@@ -189,6 +196,25 @@
                goto fail_3;
        }
 
+       memset(nullbuf, 0, ETHER_MIN_TX);
+       if ((error = bus_dmamap_create(sc->sc_dmatag,
+           ETHER_MIN_TX, 1, ETHER_MIN_TX, 0, 0, &sc->sc_nulldmamap)) != 0) {
+               aprint_error("%s: unable to create padding DMA map, "
+                   "error = %d\n", sc->sc_dev.dv_xname, error);
+               goto fail_4;
+       }
+
+       if ((error = bus_dmamap_load(sc->sc_dmatag, sc->sc_nulldmamap,
+           nullbuf, ETHER_MIN_TX, NULL, 0)) != 0) {
+               aprint_error(
+                   "%s: unable to load padding DMA map, error = %d\n",
+                   sc->sc_dev.dv_xname, error);
+               goto fail_5;
+       }
+
+       bus_dmamap_sync(sc->sc_dmatag, sc->sc_nulldmamap, 0, ETHER_MIN_TX,
+           BUS_DMASYNC_PREWRITE);
+
        /*
         * Initialize the transmit job descriptors.
         */
@@ -209,7 +235,7 @@
                    &txs->txs_dmamap)) != 0) {
                        aprint_error("%s: unable to create tx DMA map %d, "
                            "error = %d\n", sc->sc_dev.dv_xname, i, error);
-                       goto fail_4;
+                       goto fail_6;
                }
                SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
        }
@@ -222,7 +248,7 @@
                    MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
                        aprint_error("%s: unable to create rx DMA map %d, "
                            "error = %d\n", sc->sc_dev.dv_xname, i, error);
-                       goto fail_5;
+                       goto fail_7;
                }
                sc->sc_rxsoft[i].rxs_mbuf = NULL;
        }
@@ -416,19 +442,23 @@
         * Free any resources we've allocated during the failed attach
         * attempt.  Do this in reverse order and fall through.
         */
- fail_5:
+ fail_7:
        for (i = 0; i < GEM_NRXDESC; i++) {
                if (sc->sc_rxsoft[i].rxs_dmamap != NULL)
                        bus_dmamap_destroy(sc->sc_dmatag,
                            sc->sc_rxsoft[i].rxs_dmamap);
        }
- fail_4:
+ fail_6:
        for (i = 0; i < GEM_TXQUEUELEN; i++) {
                if (sc->sc_txsoft[i].txs_dmamap != NULL)
                        bus_dmamap_destroy(sc->sc_dmatag,
                            sc->sc_txsoft[i].txs_dmamap);
        }
        bus_dmamap_unload(sc->sc_dmatag, sc->sc_cddmamap);
+ fail_5:
+       bus_dmamap_destroy(sc->sc_dmatag, sc->sc_nulldmamap);
+ fail_4:
+       bus_dmamem_unmap(sc->sc_dmatag, (caddr_t)nullbuf, ETHER_MIN_TX);
  fail_3:
        bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cddmamap);
  fail_2:
@@ -1002,6 +1032,7 @@
        struct gem_txsoft *txs, *last_txs;
        bus_dmamap_t dmamap;
        int error, firsttx, nexttx, lasttx = -1, ofree, seg;
+       uint64_t flags = 0;
 
        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
                return;
@@ -1040,7 +1071,9 @@
                 * again.
                 */
                if (bus_dmamap_load_mbuf(sc->sc_dmatag, dmamap, m0,
-                     BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) {
+                     BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0 ||
+                     (m0->m_pkthdr.len < ETHER_MIN_TX &&
+                      dmamap->dm_nsegs == GEM_NTXSEGS)) {
                        if (m0->m_pkthdr.len > MCLBYTES) {
                                printf("%s: unable to allocate jumbo Tx "
                                    "cluster\n", sc->sc_dev.dv_xname);
@@ -1079,7 +1112,8 @@
                 * Ensure we have enough descriptors free to describe
                 * the packet.
                 */
-               if (dmamap->dm_nsegs > sc->sc_txfree) {
+               if (dmamap->dm_nsegs > ((m0->m_pkthdr.len < ETHER_MIN_TX) ?
+                    (sc->sc_txfree - 1) : sc->sc_txfree)) {
                        /*
                         * Not enough free descriptors to transmit this
                         * packet.  We haven't committed to anything yet,
@@ -1117,7 +1151,6 @@
                for (nexttx = sc->sc_txnext, seg = 0;
                     seg < dmamap->dm_nsegs;
                     seg++, nexttx = GEM_NEXTTX(nexttx)) {
-                       uint64_t flags;
 
                        /*
                         * If this is the first descriptor we're
@@ -1169,14 +1202,42 @@
                        }
                        if (seg == dmamap->dm_nsegs - 1) {
                                flags |= GEM_TD_END_OF_PACKET;
+                       } else {
+                               /* last flag set outside of loop */
+                               sc->sc_txdescs[nexttx].gd_flags =
+                                       GEM_DMA_WRITE(sc, flags);
                        }
-                       sc->sc_txdescs[nexttx].gd_flags =
-                               GEM_DMA_WRITE(sc, flags);
                        lasttx = nexttx;
                }
+               if (m0->m_pkthdr.len < ETHER_MIN_TX) {
+                       /* add padding buffer at end of chain */
+                       flags &= ~GEM_TD_END_OF_PACKET;
+                       sc->sc_txdescs[lasttx].gd_flags =
+                           GEM_DMA_WRITE(sc, flags);
+
+                       sc->sc_txdescs[nexttx].gd_addr =
+                           GEM_DMA_WRITE(sc,
+                           sc->sc_nulldmamap->dm_segs[0].ds_addr);
+                       flags = ((ETHER_MIN_TX - m0->m_pkthdr.len) &
+                           GEM_TD_BUFSIZE) | GEM_TD_END_OF_PACKET;
+                       lasttx = nexttx;
+                       nexttx = GEM_NEXTTX(nexttx);
+                       seg++;
+               }
+               sc->sc_txdescs[lasttx].gd_flags = GEM_DMA_WRITE(sc, flags);
 
                KASSERT(lasttx != -1);
 
+               /*
+                * Store a pointer to the packet so we can free it later,
+                * and remember what txdirty will be once the packet is
+                * done.
+                */
+               txs->txs_mbuf = m0;
+               txs->txs_firstdesc = sc->sc_txnext;
+               txs->txs_lastdesc = lasttx;
+               txs->txs_ndescs = seg;
+
 #ifdef GEM_DEBUG
                if (ifp->if_flags & IFF_DEBUG) {
                        printf("     gem_start %p transmit chain:\n", txs);
@@ -1196,18 +1257,8 @@
                GEM_CDTXSYNC(sc, sc->sc_txnext, dmamap->dm_nsegs,
                    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 
-               /*
-                * Store a pointer to the packet so we can free it later,
-                * and remember what txdirty will be once the packet is
-                * done.
-                */
-               txs->txs_mbuf = m0;
-               txs->txs_firstdesc = sc->sc_txnext;
-               txs->txs_lastdesc = lasttx;
-               txs->txs_ndescs = dmamap->dm_nsegs;
-
                /* Advance the tx pointer. */
-               sc->sc_txfree -= dmamap->dm_nsegs;
+               sc->sc_txfree -= txs->txs_ndescs;
                sc->sc_txnext = nexttx;
 
                SIMPLEQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q);
diff -r 171eadd5e420 -r cfe603cd855a sys/dev/ic/gemvar.h
--- a/sys/dev/ic/gemvar.h       Mon May 16 15:36:57 2005 +0000
+++ b/sys/dev/ic/gemvar.h       Mon May 16 15:56:38 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gemvar.h,v 1.11 2005/02/04 02:10:36 perry Exp $ */
+/*     $NetBSD: gemvar.h,v 1.12 2005/05/16 15:56:38 bouyer Exp $ */
 
 /*
  *
@@ -150,6 +150,8 @@
        bus_dmamap_t sc_cddmamap;       /* control data DMA map */
 #define        sc_cddma        sc_cddmamap->dm_segs[0].ds_addr
 
+       bus_dmamap_t sc_nulldmamap;     /* for small packets padding */
+
        /*
         * Software state for transmit and receive descriptors.
         */



Home | Main Index | Thread Index | Old Index