summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2021-09-11 17:28:45 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2021-09-11 17:28:45 +0000
commit79b9dda637c4dfa6e17818425e96d0f4d0b1f1d5 (patch)
tree062d9f35d3dcf5694e2c42db258638be2eaf50ba /sys
parent377fd17869708ed812b1bd6fcf428cc5ccdee0bc (diff)
Zero out iwx(4) Tx descriptors of frames which are done.
This will hopefully prevent the device from ever writing to the former DMA address of a buffer which has been taken off the Tx ring. As far as I understand, the Linux driver unmaps (parts of) Tx descriptors that are done. We use a static DMA mapping for the entire descriptor array, so unmapping is not an option for us. Tested by several as part of my Tx aggregation support patch.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwx.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c
index a71b7d0e614..5b58d964d12 100644
--- a/sys/dev/pci/if_iwx.c
+++ b/sys/dev/pci/if_iwx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwx.c,v 1.108 2021/09/11 17:28:04 stsp Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.109 2021/09/11 17:28:44 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -4385,6 +4385,25 @@ iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_rx_packet *pkt,
if (txfail)
ifp->if_oerrors++;
}
+
+void
+iwx_clear_tx_desc(struct iwx_softc *sc, struct iwx_tx_ring *ring, int idx)
+{
+ struct iwx_tfh_tfd *desc = &ring->desc[idx];
+ uint8_t num_tbs = le16toh(desc->num_tbs) & 0x1f;
+ int i;
+
+ /* First TB is never cleared - it is bidirectional DMA data. */
+ for (i = 1; i < num_tbs; i++) {
+ struct iwx_tfh_tb *tb = &desc->tbs[i];
+ memset(tb, 0, sizeof(*tb));
+ }
+ desc->num_tbs = 0;
+
+ bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
+ (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
+ sizeof(*desc), BUS_DMASYNC_PREWRITE);
+}
void
iwx_txd_done(struct iwx_softc *sc, struct iwx_tx_data *txd)
@@ -4442,6 +4461,7 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_packet *pkt,
txd = &ring->data[ring->tail];
if (txd->m != NULL) {
iwx_txd_done(sc, txd);
+ iwx_clear_tx_desc(sc, ring, ring->tail);
iwx_tx_update_byte_tbl(ring, ring->tail, 0, 0);
ring->queued--;
}