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