diff options
author | adrian <adrian@FreeBSD.org> | 2016-06-13 00:13:20 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2016-06-13 00:13:20 +0000 |
commit | 7a215a20fc05b86e1894a98263f5fc71dbc9e300 (patch) | |
tree | 99b19e2257a0c89e508a88147a805c140a90afc5 /sys/dev/iwm/if_iwm.c | |
parent | 891559e499c0d2d1d6203ec3540ff759160338f3 (diff) | |
download | FreeBSD-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
Diffstat (limited to 'sys/dev/iwm/if_iwm.c')
-rw-r--r-- | sys/dev/iwm/if_iwm.c | 52 |
1 files changed, 37 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; } |