summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwm.c61
-rw-r--r--sys/dev/pci/if_iwmvar.h3
2 files changed, 45 insertions, 19 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c
index 43a5e045fd5..2a276915cfe 100644
--- a/sys/dev/pci/if_iwm.c
+++ b/sys/dev/pci/if_iwm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwm.c,v 1.294 2020/02/12 15:36:15 tobhe Exp $ */
+/* $OpenBSD: if_iwm.c,v 1.295 2020/02/12 16:02:51 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -1276,6 +1276,7 @@ iwm_alloc_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring, int qid)
ring->qid = qid;
ring->queued = 0;
ring->cur = 0;
+ ring->tail = 0;
/* Allocate TX descriptors (256-byte aligned). */
size = IWM_TX_RING_COUNT * sizeof (struct iwm_tfd);
@@ -1377,6 +1378,7 @@ iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
}
ring->queued = 0;
ring->cur = 0;
+ ring->tail = 0;
}
void
@@ -4193,6 +4195,25 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
}
void
+iwm_txd_done(struct iwm_softc *sc, struct iwm_tx_data *txd)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, txd->map);
+ m_freem(txd->m);
+ txd->m = NULL;
+
+ KASSERT(txd->in);
+ ieee80211_release_node(ic, &txd->in->in_ni);
+ txd->in = NULL;
+
+ KASSERT(txd->done == 0);
+ txd->done = 1;
+}
+
+void
iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
struct iwm_rx_data *data)
{
@@ -4202,31 +4223,35 @@ iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
int idx = cmd_hdr->idx;
int qid = cmd_hdr->qid;
struct iwm_tx_ring *ring = &sc->txq[qid];
- struct iwm_tx_data *txd = &ring->data[idx];
- struct iwm_node *in = txd->in;
-
- if (txd->done)
- return;
+ struct iwm_tx_data *txd;
bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
BUS_DMASYNC_POSTREAD);
sc->sc_tx_timer = 0;
- iwm_rx_tx_cmd_single(sc, pkt, in);
-
- bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sc_dmat, txd->map);
- m_freem(txd->m);
+ txd = &ring->data[idx];
+ if (txd->done)
+ return;
- KASSERT(txd->done == 0);
- txd->done = 1;
- KASSERT(txd->in);
+ iwm_rx_tx_cmd_single(sc, pkt, txd->in);
+ iwm_txd_done(sc, txd);
- txd->m = NULL;
- txd->in = NULL;
- ieee80211_release_node(ic, &in->in_ni);
+ /*
+ * XXX Sometimes we miss Tx completion interrupts.
+ * We cannot check Tx success/failure for affected frames; just free
+ * the associated mbuf and release the associated node reference.
+ */
+ while (ring->tail != idx) {
+ txd = &ring->data[ring->tail];
+ if (!txd->done) {
+ DPRINTF(("%s: missed Tx completion: tail=%d idx=%d\n",
+ __func__, ring->tail, idx));
+ iwm_txd_done(sc, txd);
+ ring->queued--;
+ }
+ ring->tail = (ring->tail + 1) % IWM_TX_RING_COUNT;
+ }
if (--ring->queued < IWM_TX_RING_LOMARK) {
sc->qfullmsk &= ~(1 << ring->qid);
diff --git a/sys/dev/pci/if_iwmvar.h b/sys/dev/pci/if_iwmvar.h
index 5206d9ac72a..aa586f131ed 100644
--- a/sys/dev/pci/if_iwmvar.h
+++ b/sys/dev/pci/if_iwmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmvar.h,v 1.49 2019/12/18 09:52:15 stsp Exp $ */
+/* $OpenBSD: if_iwmvar.h,v 1.50 2020/02/12 16:02:51 stsp Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -270,6 +270,7 @@ struct iwm_tx_ring {
int qid;
int queued;
int cur;
+ int tail;
};
#define IWM_RX_MQ_RING_COUNT 512