summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2016-03-21 21:16:30 +0000
committerstsp <stsp@openbsd.org>2016-03-21 21:16:30 +0000
commitae48e37c4181e873bd137c45d9c1d1b6244c1e79 (patch)
treedc64488ff7d6f7624a9d8c8c35f03e6bfd0b0023
parentFix watchdog timeouts and dropped frames under load with RT2860 ral(4). (diff)
downloadwireguard-openbsd-ae48e37c4181e873bd137c45d9c1d1b6244c1e79.tar.xz
wireguard-openbsd-ae48e37c4181e873bd137c45d9c1d1b6244c1e79.zip
In ral(4) RT2860 code, replace custom defrag with m_defrag().
This fixes an error in the existing code: the "hopeless case" guard equivales 'ring now full', so oactive is never set: the code drops any mbuf that would fill the ring. This occurs often in practice. The new code avoids some hoop-jumping. Currently, one tx dma-map can fill the tx ring. Therefore an mbuf that fits a dma-map may yet not fit into the tx ring's remaining space. To be sure it can, we must in general count the mbuf's fragments and, if necessary, defrag it and reload the dmamap. Patch by Richard Procter via bugs@ Tested by Richard on RT2860 and by me on RT3090 and RT2700. ok mpi@ dlg@
-rw-r--r--sys/dev/ic/rt2860.c92
-rw-r--r--sys/dev/ic/rt2860var.h8
2 files changed, 33 insertions, 67 deletions
diff --git a/sys/dev/ic/rt2860.c b/sys/dev/ic/rt2860.c
index a0512627a89..373d9ae9ca0 100644
--- a/sys/dev/ic/rt2860.c
+++ b/sys/dev/ic/rt2860.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860.c,v 1.88 2016/03/21 21:16:01 stsp Exp $ */
+/* $OpenBSD: rt2860.c,v 1.89 2016/03/21 21:16:30 stsp Exp $ */
/*-
* Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -567,7 +567,7 @@ rt2860_alloc_tx_pool(struct rt2860_softc *sc)
error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
RT2860_MAX_SCATTER, MCLBYTES, 0, BUS_DMA_NOWAIT,
- &data->map);
+ &data->map); /* <0> */
if (error != 0) {
printf("%s: could not create DMA map\n",
sc->sc_dev.dv_xname);
@@ -1171,7 +1171,7 @@ rt2860_tx_intr(struct rt2860_softc *sc, int qid)
}
sc->sc_tx_timer = 0;
- if (ring->queued < RT2860_TX_RING_MAX)
+ if (ring->queued <= RT2860_TX_RING_ONEMORE)
sc->qfullmsk &= ~(1 << qid);
ifq_clr_oactive(&ifp->if_snd);
rt2860_start(ifp);
@@ -1481,12 +1481,11 @@ rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
struct rt2860_txd *txd;
struct rt2860_txwi *txwi;
struct ieee80211_frame *wh;
- struct mbuf *m1;
bus_dma_segment_t *seg;
u_int hdrlen;
uint16_t qos, dur;
uint8_t type, qsel, mcs, pid, tid, qid;
- int nsegs, ntxds, hasqos, ridx, ctl_ridx, error;
+ int nsegs, hasqos, ridx, ctl_ridx;
/* the data pool contains at least one element, pick the first */
data = SLIST_FIRST(&sc->data_pool);
@@ -1606,63 +1605,27 @@ rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
memcpy(txwi + 1, wh, hdrlen);
m_adj(m, hdrlen);
- error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
- BUS_DMA_NOWAIT);
- if (__predict_false(error != 0 && error != EFBIG)) {
- printf("%s: can't map mbuf (error %d)\n",
- sc->sc_dev.dv_xname, error);
- m_freem(m);
- return error;
- }
- if (__predict_true(error == 0)) {
- /* determine how many TXDs are required */
- ntxds = 1 + (data->map->dm_nsegs / 2);
-
- if (ring->queued + ntxds >= RT2860_TX_RING_MAX) {
- /* not enough free TXDs, force mbuf defrag */
- bus_dmamap_unload(sc->sc_dmat, data->map);
- error = EFBIG;
- }
- }
- if (__predict_false(error != 0)) {
- /* too many fragments, linearize */
- MGETHDR(m1, M_DONTWAIT, MT_DATA);
- if (m1 == NULL) {
- m_freem(m);
- return ENOBUFS;
- }
- if (m->m_pkthdr.len > MHLEN) {
- MCLGET(m1, M_DONTWAIT);
- if (!(m1->m_flags & M_EXT)) {
- m_freem(m);
- m_freem(m1);
- return ENOBUFS;
- }
- }
- m_copydata(m, 0, m->m_pkthdr.len, mtod(m1, caddr_t));
- m1->m_pkthdr.len = m1->m_len = m->m_pkthdr.len;
- m_freem(m);
- m = m1;
-
- error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
- BUS_DMA_NOWAIT);
- if (__predict_false(error != 0)) {
- printf("%s: can't map mbuf (error %d)\n",
- sc->sc_dev.dv_xname, error);
- m_freem(m);
- return error;
- }
-
- /* determine how many TXDs are now required */
- ntxds = 1 + (data->map->dm_nsegs / 2);
-
- if (ring->queued + ntxds >= RT2860_TX_RING_MAX) {
- /* this is a hopeless case, drop the mbuf! */
- bus_dmamap_unload(sc->sc_dmat, data->map);
- m_freem(m);
- return ENOBUFS;
- }
- }
+ KASSERT (ring->queued <= RT2860_TX_RING_ONEMORE); /* <1> */
+
+ if (bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m, BUS_DMA_NOWAIT)) {
+ if (m_defrag(m, M_DONTWAIT))
+ return (ENOBUFS);
+ if (bus_dmamap_load_mbuf(sc->sc_dmat,
+ data->map, m, BUS_DMA_NOWAIT))
+ return (EFBIG);
+ }
+
+ /* The map will fit into the tx ring: (a "full" ring may have a few
+ * unused descriptors, at most (txds(MAX_SCATTER) - 1))
+ *
+ * ring->queued + txds(data->map->nsegs)
+ * <= { <0> data->map->nsegs <= MAX_SCATTER }
+ * ring->queued + txds(MAX_SCATTER)
+ * <= { <1> ring->queued <= TX_RING_MAX - txds(MAX_SCATTER) }
+ * TX_RING_MAX - txds(MAX_SCATTER) + txds(MAX_SCATTER)
+ * <= { arithmetic }
+ * TX_RING_MAX
+ */
qsel = (qid < EDCA_NUM_AC) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_MGMT;
@@ -1713,8 +1676,8 @@ rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
qid, txwi->wcid, data->map->dm_nsegs, ridx));
ring->cur = (ring->cur + 1) % RT2860_TX_RING_COUNT;
- ring->queued += ntxds;
- if (ring->queued >= RT2860_TX_RING_MAX)
+ ring->queued += 1 + (data->map->dm_nsegs / 2);
+ if (ring->queued > RT2860_TX_RING_ONEMORE)
sc->qfullmsk |= 1 << qid;
/* kick Tx */
@@ -1771,6 +1734,7 @@ sendit:
bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
#endif
if (rt2860_tx(sc, m, ni) != 0) {
+ m_freem(m);
ieee80211_release_node(ic, ni);
ifp->if_oerrors++;
continue;
diff --git a/sys/dev/ic/rt2860var.h b/sys/dev/ic/rt2860var.h
index 39b9a7a4460..7888091e453 100644
--- a/sys/dev/ic/rt2860var.h
+++ b/sys/dev/ic/rt2860var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860var.h,v 1.22 2016/03/21 21:16:01 stsp Exp $ */
+/* $OpenBSD: rt2860var.h,v 1.23 2016/03/21 21:16:30 stsp Exp $ */
/*-
* Copyright (c) 2007
@@ -17,13 +17,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define RT2860_MAX_SCATTER 15
+#define RT2860_MAX_SCATTER_TXD (1 + (RT2860_MAX_SCATTER / 2))
+
#define RT2860_RX_RING_COUNT 128
#define RT2860_TX_RING_COUNT 64
#define RT2860_TX_RING_MAX (RT2860_TX_RING_COUNT - 1)
+#define RT2860_TX_RING_ONEMORE (RT2860_TX_RING_MAX - RT2860_MAX_SCATTER_TXD)
#define RT2860_TX_POOL_COUNT (RT2860_TX_RING_COUNT * 2)
-#define RT2860_MAX_SCATTER ((RT2860_TX_RING_COUNT * 2) - 1)
-
/* HW supports up to 255 STAs */
#define RT2860_WCID_MAX 254
#define RT2860_AID2WCID(aid) ((aid) & 0xff)