summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2016-06-13 00:13:20 +0000
committeradrian <adrian@FreeBSD.org>2016-06-13 00:13:20 +0000
commit7a215a20fc05b86e1894a98263f5fc71dbc9e300 (patch)
tree99b19e2257a0c89e508a88147a805c140a90afc5
parent891559e499c0d2d1d6203ec3540ff759160338f3 (diff)
downloadFreeBSD-src-7a215a20fc05b86e1894a98263f5fc71dbc9e300.zip
FreeBSD-src-7a215a20fc05b86e1894a98263f5fc71dbc9e300.tar.gz
[iwm] Fix up busdma use in the RX path
When allocating a new mbuf or bus_dmamap_load()-ing it fails, we can just keep the old mbuf since we are dropping that packet anyway. Instead of doing bus_dmamap_create() and bus_dmamap_destroy() all the time, create an extra bus_dmamap_t which we can use to safely try bus_dmamap_load()-ing the new mbuf. On success we just swap the spare bus_dmamap_t with the data->map of that ring entry. Tested: Tested with Intel AC7260, verified with vmstat -m that new kernel no longer visibly leaks memory from the M_DEVBUF malloc type. Before, leakage was 1KB every few seconds while ping(8)-ing over the wlan connection. Submitted by: Imre Vadasz <imre@vdsz.com> Approved by: re@ Obtained from: DragonflyBSD.git cc440b26818b5dfdd9af504d71c1b0e6522b53ef Differential Revision: https://reviews.freebsd.org/D6742
-rw-r--r--sys/dev/iwm/if_iwm.c52
-rw-r--r--sys/dev/iwm/if_iwmvar.h1
2 files changed, 38 insertions, 15 deletions
diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c
index b60d053..5821555 100644
--- a/sys/dev/iwm/if_iwm.c
+++ b/sys/dev/iwm/if_iwm.c
@@ -866,10 +866,28 @@ iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
goto fail;
}
+ /* Allocate spare bus_dmamap_t for iwm_rx_addbuf() */
+ error = bus_dmamap_create(ring->data_dmat, 0, &ring->spare_map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not create RX buf DMA map, error %d\n",
+ __func__, error);
+ goto fail;
+ }
/*
* Allocate and map RX buffers.
*/
for (i = 0; i < IWM_RX_RING_COUNT; i++) {
+ struct iwm_rx_data *data = &ring->data[i];
+ error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not create RX buf DMA map, error %d\n",
+ __func__, error);
+ goto fail;
+ }
+ data->m = NULL;
+
if ((error = iwm_rx_addbuf(sc, IWM_RBUF_SIZE, i)) != 0) {
goto fail;
}
@@ -923,6 +941,10 @@ iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
data->map = NULL;
}
}
+ if (ring->spare_map != NULL) {
+ bus_dmamap_destroy(ring->data_dmat, ring->spare_map);
+ ring->spare_map = NULL;
+ }
if (ring->data_dmat != NULL) {
bus_dma_tag_destroy(ring->data_dmat);
ring->data_dmat = NULL;
@@ -2119,6 +2141,7 @@ iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx)
struct iwm_rx_ring *ring = &sc->rxq;
struct iwm_rx_data *data = &ring->data[idx];
struct mbuf *m;
+ bus_dmamap_t dmamap = NULL;
int error;
bus_addr_t paddr;
@@ -2126,28 +2149,26 @@ iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx)
if (m == NULL)
return ENOBUFS;
- if (data->m != NULL)
- bus_dmamap_unload(ring->data_dmat, data->map);
-
m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
- error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
- if (error != 0) {
- device_printf(sc->sc_dev,
- "%s: could not create RX buf DMA map, error %d\n",
- __func__, error);
- goto fail;
- }
- data->m = m;
- error = bus_dmamap_load(ring->data_dmat, data->map,
- mtod(data->m, void *), IWM_RBUF_SIZE, iwm_dma_map_addr,
+ error = bus_dmamap_load(ring->data_dmat, ring->spare_map,
+ mtod(m, void *), IWM_RBUF_SIZE, iwm_dma_map_addr,
&paddr, BUS_DMA_NOWAIT);
if (error != 0 && error != EFBIG) {
device_printf(sc->sc_dev,
- "%s: can't not map mbuf, error %d\n", __func__,
- error);
+ "%s: can't map mbuf, error %d\n", __func__, error);
goto fail;
}
+
+ if (data->m != NULL)
+ bus_dmamap_unload(ring->data_dmat, data->map);
+
+ /* Swap ring->spare_map with data->map */
+ dmamap = data->map;
+ data->map = ring->spare_map;
+ ring->spare_map = dmamap;
+
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREREAD);
+ data->m = m;
/* Update RX descriptor. */
ring->desc[idx] = htole32(paddr >> 8);
@@ -2156,6 +2177,7 @@ iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx)
return 0;
fail:
+ m_free(m);
return error;
}
diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h
index ef2eac4..e923aa4 100644
--- a/sys/dev/iwm/if_iwmvar.h
+++ b/sys/dev/iwm/if_iwmvar.h
@@ -289,6 +289,7 @@ struct iwm_rx_ring {
uint32_t *desc;
struct iwm_rb_status *stat;
struct iwm_rx_data data[IWM_RX_RING_COUNT];
+ bus_dmamap_t spare_map; /* for iwm_rx_addbuf() */
bus_dma_tag_t data_dmat;
int cur;
};
OpenPOWER on IntegriCloud