svn commit: r306591 - in head/sys: dev/bwi dev/bwn dev/iwm dev/iwn dev/otus dev/ral dev/urtwn dev/usb/wlan dev/wpi net80211

Andriy Voskoboinyk avos at FreeBSD.org
Sun Oct 2 20:35:59 UTC 2016


Author: avos
Date: Sun Oct  2 20:35:55 2016
New Revision: 306591
URL: https://svnweb.freebsd.org/changeset/base/306591

Log:
  net80211: ieee80211_ratectl*: switch to reusable KPI
  
  Replace various void * / int argument combinations with common structures:
  - ieee80211_ratectl_tx_status for *_tx_complete();
  - ieee80211_ratectl_tx_stats for *_tx_update();
  
  While here, improve amrr_tx_update() for a bit:
  1. In case, if receiver is not known (typical for Ralink USB drivers),
  refresh Tx rate for all nodes on the interface.
  2. There was a misuse:
  - otus(4) sends non-decreasing counters (as originally intended);
  - but ural(4), rum(4) and run(4) are using 'read & clear' registers
  to obtain statistics for some period of time (and those 'last period'
  values are used as arguments for tx_update()). If arguments are not big
  enough, they are just discarded after the next call.
  
  Fix: move counting into *_tx_update()
  (now otus(4) will zero out all node counters after every tx_update() call)
  
  Tested with:
  - Intel 3945BG (wpi(4)), STA mode.
  - WUSB54GC (rum(4)), STA / HOSTAP mode.
  - RTL8188EU (urtwn(4)), STA mode.
  
  Reviewed by:	adrian
  Differential Revision:	https://reviews.freebsd.org/D8037

Modified:
  head/sys/dev/bwi/if_bwi.c
  head/sys/dev/bwn/if_bwn.c
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwmvar.h
  head/sys/dev/iwn/if_iwn.c
  head/sys/dev/iwn/if_iwnvar.h
  head/sys/dev/otus/if_otus.c
  head/sys/dev/otus/if_otusreg.h
  head/sys/dev/ral/if_ral_pci.c
  head/sys/dev/ral/rt2560.c
  head/sys/dev/ral/rt2560var.h
  head/sys/dev/ral/rt2661.c
  head/sys/dev/ral/rt2661var.h
  head/sys/dev/ral/rt2860.c
  head/sys/dev/ral/rt2860var.h
  head/sys/dev/urtwn/if_urtwn.c
  head/sys/dev/urtwn/if_urtwnreg.h
  head/sys/dev/urtwn/if_urtwnvar.h
  head/sys/dev/usb/wlan/if_rum.c
  head/sys/dev/usb/wlan/if_rumvar.h
  head/sys/dev/usb/wlan/if_run.c
  head/sys/dev/usb/wlan/if_runvar.h
  head/sys/dev/usb/wlan/if_ural.c
  head/sys/dev/usb/wlan/if_uralvar.h
  head/sys/dev/usb/wlan/if_zyd.c
  head/sys/dev/usb/wlan/if_zydreg.h
  head/sys/dev/wpi/if_wpi.c
  head/sys/dev/wpi/if_wpivar.h
  head/sys/net80211/ieee80211_amrr.c
  head/sys/net80211/ieee80211_ratectl.h
  head/sys/net80211/ieee80211_ratectl_none.c
  head/sys/net80211/ieee80211_rssadapt.c

Modified: head/sys/dev/bwi/if_bwi.c
==============================================================================
--- head/sys/dev/bwi/if_bwi.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/bwi/if_bwi.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -3321,7 +3321,6 @@ _bwi_txeof(struct bwi_softc *sc, uint16_
 	struct bwi_txbuf *tb;
 	int ring_idx, buf_idx;
 	struct ieee80211_node *ni;
-	struct ieee80211vap *vap;
 
 	if (tx_id == 0) {
 		device_printf(sc->sc_dev, "%s: zero tx id\n", __func__);
@@ -3348,7 +3347,7 @@ _bwi_txeof(struct bwi_softc *sc, uint16_
 	if ((ni = tb->tb_ni) != NULL) {
 		const struct bwi_txbuf_hdr *hdr =
 		    mtod(tb->tb_mbuf, const struct bwi_txbuf_hdr *);
-		vap = ni->ni_vap;
+		struct ieee80211_ratectl_tx_status txs;
 
 		/* NB: update rate control only for unicast frames */
 		if (hdr->txh_mac_ctrl & htole32(BWI_TXH_MAC_C_ACK)) {
@@ -3359,9 +3358,15 @@ _bwi_txeof(struct bwi_softc *sc, uint16_
 			 * well so to avoid over-aggressive downshifting we
 			 * treat any number of retries as "1".
 			 */
-			ieee80211_ratectl_tx_complete(vap, ni,
-			    (data_txcnt > 1) ? IEEE80211_RATECTL_TX_SUCCESS :
-			        IEEE80211_RATECTL_TX_FAILURE, &acked, NULL);
+			txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
+			txs.long_retries = acked;
+			if (data_txcnt > 1)
+				txs.status = IEEE80211_RATECTL_TX_SUCCESS;
+			else {
+				txs.status =
+				    IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+			}
+			ieee80211_ratectl_tx_complete(ni, &txs);
 		}
 		ieee80211_tx_complete(ni, tb->tb_mbuf, !acked);
 		tb->tb_ni = NULL;

Modified: head/sys/dev/bwn/if_bwn.c
==============================================================================
--- head/sys/dev/bwn/if_bwn.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/bwn/if_bwn.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -258,6 +258,8 @@ static int	bwn_dma_newbuf(struct bwn_dma
 static void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
 		    bus_size_t, int);
 static uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
+static void	bwn_ratectl_tx_complete(const struct ieee80211_node *,
+		    const struct bwn_txstatus *);
 static void	bwn_dma_handle_txeof(struct bwn_mac *,
 		    const struct bwn_txstatus *);
 static int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
@@ -5891,6 +5893,33 @@ drop:
 }
 
 static void
+bwn_ratectl_tx_complete(const struct ieee80211_node *ni,
+    const struct bwn_txstatus *status)
+{
+	struct ieee80211_ratectl_tx_status txs;
+	int retrycnt = 0;
+
+	/*
+	 * If we don't get an ACK, then we should log the
+	 * full framecnt.  That may be 0 if it's a PHY
+	 * failure, so ensure that gets logged as some
+	 * retry attempt.
+	 */
+	txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
+	if (status->ack) {
+		txs.status = IEEE80211_RATECTL_TX_SUCCESS;
+		retrycnt = status->framecnt - 1;
+	} else {
+		txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+		retrycnt = status->framecnt;
+		if (retrycnt == 0)
+			retrycnt = 1;
+	}
+	txs.long_retries = retrycnt;
+	ieee80211_ratectl_tx_complete(ni, &txs);
+}
+
+static void
 bwn_dma_handle_txeof(struct bwn_mac *mac,
     const struct bwn_txstatus *status)
 {
@@ -5900,7 +5929,6 @@ bwn_dma_handle_txeof(struct bwn_mac *mac
 	struct bwn_dmadesc_meta *meta;
 	struct bwn_softc *sc = mac->mac_sc;
 	int slot;
-	int retrycnt = 0;
 
 	BWN_ASSERT_LOCKED(sc);
 
@@ -5925,24 +5953,7 @@ bwn_dma_handle_txeof(struct bwn_mac *mac
 			KASSERT(meta->mt_m != NULL,
 			    ("%s:%d: fail", __func__, __LINE__));
 
-			/*
-			 * If we don't get an ACK, then we should log the
-			 * full framecnt.  That may be 0 if it's a PHY
-			 * failure, so ensure that gets logged as some
-			 * retry attempt.
-			 */
-			if (status->ack) {
-				retrycnt = status->framecnt - 1;
-			} else {
-				retrycnt = status->framecnt;
-				if (retrycnt == 0)
-					retrycnt = 1;
-			}
-			ieee80211_ratectl_tx_complete(meta->mt_ni->ni_vap, meta->mt_ni,
-			    status->ack ?
-			      IEEE80211_RATECTL_TX_SUCCESS :
-			      IEEE80211_RATECTL_TX_FAILURE,
-			    &retrycnt, 0);
+			bwn_ratectl_tx_complete(meta->mt_ni, status);
 			ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
 			meta->mt_ni = NULL;
 			meta->mt_m = NULL;
@@ -5970,7 +5981,6 @@ bwn_pio_handle_txeof(struct bwn_mac *mac
 	struct bwn_pio_txqueue *tq;
 	struct bwn_pio_txpkt *tp = NULL;
 	struct bwn_softc *sc = mac->mac_sc;
-	int retrycnt = 0;
 
 	BWN_ASSERT_LOCKED(sc);
 
@@ -5981,31 +5991,14 @@ bwn_pio_handle_txeof(struct bwn_mac *mac
 	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
 	tq->tq_free++;
 
+	/* XXX ieee80211_tx_complete()? */
 	if (tp->tp_ni != NULL) {
 		/*
 		 * Do any tx complete callback.  Note this must
 		 * be done before releasing the node reference.
 		 */
 
-		/*
-		 * If we don't get an ACK, then we should log the
-		 * full framecnt.  That may be 0 if it's a PHY
-		 * failure, so ensure that gets logged as some
-		 * retry attempt.
-		 */
-		if (status->ack) {
-			retrycnt = status->framecnt - 1;
-		} else {
-			retrycnt = status->framecnt;
-			if (retrycnt == 0)
-				retrycnt = 1;
-		}
-		ieee80211_ratectl_tx_complete(tp->tp_ni->ni_vap, tp->tp_ni,
-		    status->ack ?
-		      IEEE80211_RATECTL_TX_SUCCESS :
-		      IEEE80211_RATECTL_TX_FAILURE,
-		    &retrycnt, 0);
-
+		bwn_ratectl_tx_complete(tp->tp_ni, status);
 		if (tp->tp_m->m_flags & M_TXCB)
 			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
 		ieee80211_free_node(tp->tp_ni);

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/iwm/if_iwm.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -3027,10 +3027,9 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_soft
 	struct iwm_node *in)
 {
 	struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct ieee80211_node *ni = &in->in_ni;
-	struct ieee80211vap *vap = ni->ni_vap;
 	int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
-	int failack = tx_resp->failure_frame;
 
 	KASSERT(tx_resp->frame_count == 1, ("too many frames"));
 
@@ -3046,16 +3045,32 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_soft
 	    le32toh(tx_resp->initial_rate),
 	    (int) le16toh(tx_resp->wireless_media_time));
 
+	txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
+		     IEEE80211_RATECTL_STATUS_LONG_RETRY;
+	txs->short_retries = tx_resp->failure_rts;
+	txs->long_retries = tx_resp->failure_frame;
 	if (status != IWM_TX_STATUS_SUCCESS &&
 	    status != IWM_TX_STATUS_DIRECT_DONE) {
-		ieee80211_ratectl_tx_complete(vap, ni,
-		    IEEE80211_RATECTL_TX_FAILURE, &failack, NULL);
-		return (1);
+		switch (status) {
+		case IWM_TX_STATUS_FAIL_SHORT_LIMIT:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_SHORT;
+			break;
+		case IWM_TX_STATUS_FAIL_LONG_LIMIT:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_LONG;
+			break;
+		case IWM_TX_STATUS_FAIL_LIFE_EXPIRE:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+			break;
+		default:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+			break;
+		}
 	} else {
-		ieee80211_ratectl_tx_complete(vap, ni,
-		    IEEE80211_RATECTL_TX_SUCCESS, &failack, NULL);
-		return (0);
+		txs->status = IEEE80211_RATECTL_TX_SUCCESS;
 	}
+	ieee80211_ratectl_tx_complete(ni, txs);
+
+	return (txs->status != IEEE80211_RATECTL_TX_SUCCESS);
 }
 
 static void

Modified: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/iwm/if_iwmvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -392,6 +392,7 @@ struct iwm_softc {
 	struct mtx		sc_mtx;
 	struct mbufq		sc_snd;
 	struct ieee80211com	sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 
 	int			sc_flags;
 #define IWM_FLAG_USE_ICT	(1 << 0)

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/iwn/if_iwn.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -210,9 +210,10 @@ static void	iwn4965_tx_done(struct iwn_s
 		    struct iwn_rx_data *);
 static void	iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
 		    struct iwn_rx_data *);
-static void	iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
+static void	iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, int,
 		    uint8_t);
-static void	iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, void *);
+static void	iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, int,
+		    void *);
 static void	iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 static void	iwn_notif_intr(struct iwn_softc *);
 static void	iwn_wakeup_intr(struct iwn_softc *);
@@ -3147,6 +3148,7 @@ static void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
     struct iwn_rx_data *data)
 {
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct iwn_ops *ops = &sc->ops;
 	struct iwn_node *wn;
 	struct ieee80211_node *ni;
@@ -3158,7 +3160,7 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 	uint64_t bitmap;
 	uint16_t ssn;
 	uint8_t tid;
-	int ackfailcnt = 0, i, lastidx, qid, *res, shift;
+	int i, lastidx, qid, *res, shift;
 	int tx_ok = 0, tx_err = 0;
 
 	DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__);
@@ -3227,15 +3229,15 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 	ni = tap->txa_ni;
 	bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap;
 	for (i = 0; bitmap; i++) {
+		txs->flags = 0;		/* XXX TODO */
 		if ((bitmap & 1) == 0) {
 			tx_err ++;
-			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
-			    IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL);
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
 		} else {
 			tx_ok ++;
-			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
-			    IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL);
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
 		}
+		ieee80211_ratectl_tx_complete(ni, txs);
 		bitmap >>= 1;
 	}
 
@@ -3501,9 +3503,9 @@ iwn4965_tx_done(struct iwn_softc *sc, st
 	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 	if (qid >= sc->firstaggqueue) {
 		iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
-		    stat->ackfailcnt, &stat->status);
+		    stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
 	} else {
-		iwn_tx_done(sc, desc, stat->ackfailcnt,
+		iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
 		    le32toh(stat->status) & 0xff);
 	}
 }
@@ -3536,9 +3538,9 @@ iwn5000_tx_done(struct iwn_softc *sc, st
 	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 	if (qid >= sc->firstaggqueue) {
 		iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
-		    stat->ackfailcnt, &stat->status);
+		    stat->rtsfailcnt, stat->ackfailcnt, &stat->status);
 	} else {
-		iwn_tx_done(sc, desc, stat->ackfailcnt,
+		iwn_tx_done(sc, desc, stat->rtsfailcnt, stat->ackfailcnt,
 		    le16toh(stat->status) & 0xff);
 	}
 }
@@ -3547,14 +3549,14 @@ iwn5000_tx_done(struct iwn_softc *sc, st
  * Adapter-independent backend for TX_DONE firmware notifications.
  */
 static void
-iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt,
-    uint8_t status)
+iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int rtsfailcnt,
+    int ackfailcnt, uint8_t status)
 {
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
 	struct iwn_tx_data *data = &ring->data[desc->idx];
 	struct mbuf *m;
 	struct ieee80211_node *ni;
-	struct ieee80211vap *vap;
 
 	KASSERT(data->ni != NULL, ("no node"));
 
@@ -3565,17 +3567,33 @@ iwn_tx_done(struct iwn_softc *sc, struct
 	bus_dmamap_unload(ring->data_dmat, data->map);
 	m = data->m, data->m = NULL;
 	ni = data->ni, data->ni = NULL;
-	vap = ni->ni_vap;
 
 	/*
 	 * Update rate control statistics for the node.
 	 */
-	if (status & IWN_TX_FAIL)
-		ieee80211_ratectl_tx_complete(vap, ni,
-		    IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL);
-	else
-		ieee80211_ratectl_tx_complete(vap, ni,
-		    IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL);
+	txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
+		     IEEE80211_RATECTL_STATUS_LONG_RETRY;
+	txs->short_retries = rtsfailcnt;
+	txs->long_retries = ackfailcnt;
+	if (!(status & IWN_TX_FAIL))
+		txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+	else {
+		switch (status) {
+		case IWN_TX_FAIL_SHORT_LIMIT:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_SHORT;
+			break;
+		case IWN_TX_FAIL_LONG_LIMIT:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_LONG;
+			break;
+		case IWN_TX_STATUS_FAIL_LIFE_EXPIRE:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+			break;
+		default:
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+			break;
+		}
+	}
+	ieee80211_ratectl_tx_complete(ni, txs);
 
 	/*
 	 * Channels marked for "radar" require traffic to be received
@@ -3640,10 +3658,11 @@ iwn_cmd_done(struct iwn_softc *sc, struc
 
 static void
 iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
-    int ackfailcnt, void *stat)
+    int rtsfailcnt, int ackfailcnt, void *stat)
 {
 	struct iwn_ops *ops = &sc->ops;
 	struct iwn_tx_ring *ring = &sc->txq[qid];
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct iwn_tx_data *data;
 	struct mbuf *m;
 	struct iwn_node *wn;
@@ -3682,6 +3701,10 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 	 * handled differently.
 	 */
 	if (nframes == 1) {
+		txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
+			     IEEE80211_RATECTL_STATUS_LONG_RETRY;
+		txs->short_retries = rtsfailcnt;
+		txs->long_retries = ackfailcnt;
 		if ((*status & 0xff) != 1 && (*status & 0xff) != 2) {
 #ifdef	NOT_YET
 			printf("ieee80211_send_bar()\n");
@@ -3691,11 +3714,8 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 			 * notification is pushed up to the rate control
 			 * layer.
 			 */
-			ieee80211_ratectl_tx_complete(ni->ni_vap,
-			    ni,
-			    IEEE80211_RATECTL_TX_FAILURE,
-			    &ackfailcnt,
-			    NULL);
+			/* XXX */
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
 		} else {
 			/*
 			 * If nframes=1, then we won't be getting a BA for
@@ -3703,12 +3723,9 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 			 * rate control code with how many retries were
 			 * needed to send it.
 			 */
-			ieee80211_ratectl_tx_complete(ni->ni_vap,
-			    ni,
-			    IEEE80211_RATECTL_TX_SUCCESS,
-			    &ackfailcnt,
-			    NULL);
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
 		}
+		ieee80211_ratectl_tx_complete(ni, txs);
 	}
 
 	bitmap = 0;

Modified: head/sys/dev/iwn/if_iwnvar.h
==============================================================================
--- head/sys/dev/iwn/if_iwnvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/iwn/if_iwnvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -238,6 +238,7 @@ struct iwn_softc {
 	struct cdev		*sc_cdev;
 	struct mtx		sc_mtx;
 	struct ieee80211com	sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 
 	u_int			sc_flags;
 #define IWN_FLAG_HAS_OTPROM	(1 << 1)

Modified: head/sys/dev/otus/if_otus.c
==============================================================================
--- head/sys/dev/otus/if_otus.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/otus/if_otus.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -2148,14 +2148,18 @@ otus_hw_rate_is_ofdm(struct otus_softc *
 static void
 otus_tx_update_ratectl(struct otus_softc *sc, struct ieee80211_node *ni)
 {
-	int tx, tx_success, tx_retry;
+	struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs;
+	struct otus_node *on = OTUS_NODE(ni);
 
-	tx = OTUS_NODE(ni)->tx_done;
-	tx_success = OTUS_NODE(ni)->tx_done - OTUS_NODE(ni)->tx_err;
-	tx_retry = OTUS_NODE(ni)->tx_retries;
+	txs->flags = IEEE80211_RATECTL_TX_STATS_NODE |
+		     IEEE80211_RATECTL_TX_STATS_RETRIES;
+	txs->ni = ni;
+	txs->nframes = on->tx_done;
+	txs->nsuccess = on->tx_done - on->tx_err;
+	txs->nretries = on->tx_retries;
 
-	ieee80211_ratectl_tx_update(ni->ni_vap, ni, &tx, &tx_success,
-	    &tx_retry);
+	ieee80211_ratectl_tx_update(ni->ni_vap, txs);
+	on->tx_done = on->tx_err = on->tx_retries = 0;
 }
 
 /*

Modified: head/sys/dev/otus/if_otusreg.h
==============================================================================
--- head/sys/dev/otus/if_otusreg.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/otus/if_otusreg.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -997,6 +997,7 @@ struct otus_vap {
 
 struct otus_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_stats sc_txs;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;
 	struct usb_device		*sc_udev;

Modified: head/sys/dev/ral/if_ral_pci.c
==============================================================================
--- head/sys/dev/ral/if_ral_pci.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/if_ral_pci.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>

Modified: head/sys/dev/ral/rt2560.c
==============================================================================
--- head/sys/dev/ral/rt2560.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2560.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -911,17 +911,18 @@ rt2560_encryption_intr(struct rt2560_sof
 static void
 rt2560_tx_intr(struct rt2560_softc *sc)
 {
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct rt2560_tx_desc *desc;
 	struct rt2560_tx_data *data;
 	struct mbuf *m;
-	struct ieee80211vap *vap;
 	struct ieee80211_node *ni;
 	uint32_t flags;
-	int retrycnt, status;
+	int status;
 
 	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
 	    BUS_DMASYNC_POSTREAD);
 
+	txs->flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
 	for (;;) {
 		desc = &sc->txq.desc[sc->txq.next];
 		data = &sc->txq.data[sc->txq.next];
@@ -934,41 +935,37 @@ rt2560_tx_intr(struct rt2560_softc *sc)
 
 		m = data->m;
 		ni = data->ni;
-		vap = ni->ni_vap;
 
 		switch (flags & RT2560_TX_RESULT_MASK) {
 		case RT2560_TX_SUCCESS:
-			retrycnt = 0;
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+			txs->long_retries = 0;
 
 			DPRINTFN(sc, 10, "%s\n", "data frame sent successfully");
 			if (data->rix != IEEE80211_FIXED_RATE_NONE)
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_SUCCESS,
-				    &retrycnt, NULL);
+				ieee80211_ratectl_tx_complete(ni, txs);
 			status = 0;
 			break;
 
 		case RT2560_TX_SUCCESS_RETRY:
-			retrycnt = RT2560_TX_RETRYCNT(flags);
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+			txs->long_retries = RT2560_TX_RETRYCNT(flags);
 
 			DPRINTFN(sc, 9, "data frame sent after %u retries\n",
-			    retrycnt);
+			    txs->long_retries);
 			if (data->rix != IEEE80211_FIXED_RATE_NONE)
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_SUCCESS,
-				    &retrycnt, NULL);
+				ieee80211_ratectl_tx_complete(ni, txs);
 			status = 0;
 			break;
 
 		case RT2560_TX_FAIL_RETRY:
-			retrycnt = RT2560_TX_RETRYCNT(flags);
+			txs->status = IEEE80211_RATECTL_TX_FAIL_LONG;
+			txs->long_retries = RT2560_TX_RETRYCNT(flags);
 
 			DPRINTFN(sc, 9, "data frame failed after %d retries\n",
-			    retrycnt);
+			    txs->long_retries);
 			if (data->rix != IEEE80211_FIXED_RATE_NONE)
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_FAILURE,
-				    &retrycnt, NULL);
+				ieee80211_ratectl_tx_complete(ni, txs);
 			status = 1;
 			break;
 

Modified: head/sys/dev/ral/rt2560var.h
==============================================================================
--- head/sys/dev/ral/rt2560var.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2560var.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -105,6 +105,7 @@ struct rt2560_vap {
 
 struct rt2560_softc {
 	struct ieee80211com	sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 	struct mtx		sc_mtx;
 	struct mbufq		sc_snd;
 	device_t		sc_dev;

Modified: head/sys/dev/ral/rt2661.c
==============================================================================
--- head/sys/dev/ral/rt2661.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2661.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -851,12 +851,13 @@ rt2661_eeprom_read(struct rt2661_softc *
 static void
 rt2661_tx_intr(struct rt2661_softc *sc)
 {
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct rt2661_tx_ring *txq;
 	struct rt2661_tx_data *data;
 	uint32_t val;
-	int error, qid, retrycnt;
-	struct ieee80211vap *vap;
+	int error, qid;
 
+	txs->flags = IEEE80211_RATECTL_TX_FAIL_LONG;
 	for (;;) {
 		struct ieee80211_node *ni;
 		struct mbuf *m;
@@ -879,31 +880,27 @@ rt2661_tx_intr(struct rt2661_softc *sc)
 		/* if no frame has been sent, ignore */
 		if (ni == NULL)
 			continue;
-		else
-			vap = ni->ni_vap;
 
 		switch (RT2661_TX_RESULT(val)) {
 		case RT2661_TX_SUCCESS:
-			retrycnt = RT2661_TX_RETRYCNT(val);
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+			txs->long_retries = RT2661_TX_RETRYCNT(val);
 
 			DPRINTFN(sc, 10, "data frame sent successfully after "
-			    "%d retries\n", retrycnt);
+			    "%d retries\n", txs->long_retries);
 			if (data->rix != IEEE80211_FIXED_RATE_NONE)
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_SUCCESS,
-				    &retrycnt, NULL);
+				ieee80211_ratectl_tx_complete(ni, txs);
 			error = 0;
 			break;
 
 		case RT2661_TX_RETRY_FAIL:
-			retrycnt = RT2661_TX_RETRYCNT(val);
+			txs->status = IEEE80211_RATECTL_TX_FAIL_LONG;
+			txs->long_retries = RT2661_TX_RETRYCNT(val);
 
 			DPRINTFN(sc, 9, "%s\n",
 			    "sending data frame failed (too much retries)");
 			if (data->rix != IEEE80211_FIXED_RATE_NONE)
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_FAILURE,
-				    &retrycnt, NULL);
+				ieee80211_ratectl_tx_complete(ni, txs);
 			error = 1;
 			break;
 

Modified: head/sys/dev/ral/rt2661var.h
==============================================================================
--- head/sys/dev/ral/rt2661var.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2661var.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -98,6 +98,7 @@ struct rt2661_vap {
 
 struct rt2661_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 	struct mtx			sc_mtx;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;

Modified: head/sys/dev/ral/rt2860.c
==============================================================================
--- head/sys/dev/ral/rt2860.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2860.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1083,12 +1083,13 @@ rt2860_intr_coherent(struct rt2860_softc
 static void
 rt2860_drain_stats_fifo(struct rt2860_softc *sc)
 {
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct ieee80211_node *ni;
 	uint32_t stat;
-	int retrycnt;
 	uint8_t wcid, mcs, pid;
 
 	/* drain Tx status FIFO (maxsize = 16) */
+	txs->flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
 	while ((stat = RAL_READ(sc, RT2860_TX_STAT_FIFO)) & RT2860_TXQ_VLD) {
 		DPRINTFN(4, ("tx stat 0x%08x\n", stat));
 
@@ -1110,14 +1111,15 @@ rt2860_drain_stats_fifo(struct rt2860_so
 			mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
 			pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
 			if (mcs + 1 != pid)
-				retrycnt = 1;
+				txs->long_retries = 1;
 			else
-				retrycnt = 0;
-			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
-			    IEEE80211_RATECTL_TX_SUCCESS, &retrycnt, NULL);
+				txs->long_retries = 0;
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+			ieee80211_ratectl_tx_complete(ni, txs);
 		} else {
-			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
-			    IEEE80211_RATECTL_TX_FAILURE, &retrycnt, NULL);
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+			txs->long_retries = 1;	/* XXX */
+			ieee80211_ratectl_tx_complete(ni, txs);
 			if_inc_counter(ni->ni_vap->iv_ifp,
 			    IFCOUNTER_OERRORS, 1);
 		}

Modified: head/sys/dev/ral/rt2860var.h
==============================================================================
--- head/sys/dev/ral/rt2860var.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/ral/rt2860var.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -116,6 +116,7 @@ struct rt2860_vap {
 
 struct rt2860_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 	struct mbufq			sc_snd;
 	struct mtx			sc_mtx;
 	device_t			sc_dev;

Modified: head/sys/dev/urtwn/if_urtwn.c
==============================================================================
--- head/sys/dev/urtwn/if_urtwn.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/urtwn/if_urtwn.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1016,7 +1016,7 @@ static void
 urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *sc, void *arg)
 {
 	struct r88e_tx_rpt_ccx *rpt = arg;
-	struct ieee80211vap *vap;
+	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct ieee80211_node *ni;
 	uint8_t macid;
 	int ntries;
@@ -1027,19 +1027,28 @@ urtwn_r88e_ratectl_tx_complete(struct ur
 	URTWN_NT_LOCK(sc);
 	ni = sc->node_list[macid];
 	if (ni != NULL) {
-		vap = ni->ni_vap;
 		URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: frame for macid %d was"
 		    "%s sent (%d retries)\n", __func__, macid,
 		    (rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not",
 		    ntries);
 
-		if (rpt->rptb1 & R88E_RPTB1_PKT_OK) {
-			ieee80211_ratectl_tx_complete(vap, ni,
-			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
-		} else {
-			ieee80211_ratectl_tx_complete(vap, ni,
-			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
-		}
+		txs->flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | 
+			     IEEE80211_RATECTL_STATUS_FINAL_RATE;
+		txs->long_retries = ntries;
+		if (rpt->final_rate > URTWN_RIDX_OFDM54) {	/* MCS */
+			txs->final_rate =
+			    (rpt->final_rate - 12) | IEEE80211_RATE_MCS;
+		} else
+			txs->final_rate = ridx2rate[rpt->final_rate];
+		if (rpt->rptb1 & R88E_RPTB1_PKT_OK)
+			txs->status = IEEE80211_RATECTL_TX_SUCCESS;
+		else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER)
+			txs->status = IEEE80211_RATECTL_TX_FAIL_LONG;
+		else if (rpt->rptb2 & R88E_RPTB2_LIFE_EXPIRE)
+			txs->status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
+		else
+			txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
+		ieee80211_ratectl_tx_complete(ni, txs);
 	} else {
 		URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: macid %d, ni is NULL\n",
 		    __func__, macid);

Modified: head/sys/dev/urtwn/if_urtwnreg.h
==============================================================================
--- head/sys/dev/urtwn/if_urtwnreg.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/urtwn/if_urtwnreg.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1227,9 +1227,8 @@ struct r88e_tx_rpt_ccx {
 #define R88E_RPTB2_LIFE_EXPIRE	0x40
 #define R88E_RPTB2_RETRY_OVER	0x80
 
-	uint8_t		rptb3;
-	uint8_t		rptb4;
-	uint8_t		rptb5;
+	uint16_t	ccx_qtime;
+	uint8_t		final_rate;
 	uint8_t		rptb6;
 #define R88E_RPTB6_QSEL_M	0xf0
 #define R88E_RPTB6_QSEL_S	4

Modified: head/sys/dev/urtwn/if_urtwnvar.h
==============================================================================
--- head/sys/dev/urtwn/if_urtwnvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/urtwn/if_urtwnvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -136,6 +136,7 @@ union urtwn_rom {
 
 struct urtwn_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;
 	struct usb_device		*sc_udev;

Modified: head/sys/dev/usb/wlan/if_rum.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rum.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_rum.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1668,8 +1668,10 @@ rum_tx_data(struct rum_softc *sc, struct
 		rate = tp->ucastrate;
 	else if (m0->m_flags & M_EAPOL)
 		rate = tp->mgmtrate;
-	else
+	else {
+		(void) ieee80211_ratectl_rate(ni, NULL, 0);
 		rate = ni->ni_txrate;
+	}
 
 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
 		k = ieee80211_crypto_get_txkey(ni, m0);
@@ -3154,9 +3156,8 @@ rum_ratectl_task(void *arg, int pending)
 	struct rum_vap *rvp = arg;
 	struct ieee80211vap *vap = &rvp->vap;
 	struct rum_softc *sc = vap->iv_ic->ic_softc;
-	struct ieee80211_node *ni;
+	struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs;
 	int ok[3], fail;
-	int sum, success, retrycnt;
 
 	RUM_LOCK(sc);
 	/* read and clear statistic registers (STA_CSR0 to STA_CSR5) */
@@ -3167,17 +3168,14 @@ rum_ratectl_task(void *arg, int pending)
 	ok[2] = (le32toh(sc->sta[5]) & 0xffff);	/* TX ok w/ multiple retries */
 	fail =  (le32toh(sc->sta[5]) >> 16);	/* TX retry-fail count */
 
-	success = ok[0] + ok[1] + ok[2];
-	sum = success + fail;
+	txs->flags = IEEE80211_RATECTL_TX_STATS_RETRIES;
+	txs->nframes = ok[0] + ok[1] + ok[2] + fail;
+	txs->nsuccess = txs->nframes - fail;
 	/* XXX at least */
-	retrycnt = ok[1] + ok[2] * 2 + fail * (rvp->maxretry + 1);
+	txs->nretries = ok[1] + ok[2] * 2 + fail * (rvp->maxretry + 1);
 
-	if (sum != 0) {
-		ni = ieee80211_ref_node(vap->iv_bss);
-		ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt);
-		(void) ieee80211_ratectl_rate(ni, NULL, 0);
-		ieee80211_free_node(ni);
-	}
+	if (txs->nframes != 0)
+		ieee80211_ratectl_tx_update(vap, txs);
 
 	/* count TX retry-fail as Tx errors */
 	if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, fail);

Modified: head/sys/dev/usb/wlan/if_rumvar.h
==============================================================================
--- head/sys/dev/usb/wlan/if_rumvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_rumvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -110,6 +110,7 @@ enum {
 
 struct rum_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_stats sc_txs;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;
 	struct usb_device		*sc_udev;

Modified: head/sys/dev/usb/wlan/if_run.c
==============================================================================
--- head/sys/dev/usb/wlan/if_run.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_run.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -2552,11 +2552,12 @@ static void
 run_iter_func(void *arg, struct ieee80211_node *ni)
 {
 	struct run_softc *sc = arg;
+	struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs;
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct run_node *rn = RUN_NODE(ni);
 	union run_stats sta[2];
 	uint16_t (*wstat)[3];
-	int txcnt, success, retrycnt, error;
+	int error;
 
 	RUN_LOCK(sc);
 
@@ -2565,6 +2566,9 @@ run_iter_func(void *arg, struct ieee8021
 	    ni != vap->iv_bss)
 		goto fail;
 
+	txs->flags = IEEE80211_RATECTL_TX_STATS_NODE |
+		     IEEE80211_RATECTL_TX_STATS_RETRIES;
+	txs->ni = ni;
 	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
 	    vap->iv_opmode == IEEE80211_M_STA)) {
 		/* read statistic counters (clear on read) and update AMRR state */
@@ -2577,12 +2581,15 @@ run_iter_func(void *arg, struct ieee8021
 		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
 		    le16toh(sta[0].error.fail));
 
-		retrycnt = le16toh(sta[1].tx.retry);
-		success = le16toh(sta[1].tx.success);
-		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
+		txs->nretries = le16toh(sta[1].tx.retry);
+		txs->nsuccess = le16toh(sta[1].tx.success);
+		/* nretries??? */
+		txs->nframes = txs->nretries + txs->nsuccess +
+		    le16toh(sta[0].error.fail);
 
 		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
-			retrycnt, success, le16toh(sta[0].error.fail));
+			txs->nretries, txs->nsuccess,
+			le16toh(sta[0].error.fail));
 	} else {
 		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
 
@@ -2590,16 +2597,16 @@ run_iter_func(void *arg, struct ieee8021
 		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
 			goto fail;
 
-		txcnt = (*wstat)[RUN_TXCNT];
-		success = (*wstat)[RUN_SUCCESS];
-		retrycnt = (*wstat)[RUN_RETRY];
+		txs->nretries = (*wstat)[RUN_RETRY];
+		txs->nsuccess = (*wstat)[RUN_SUCCESS];
+		txs->nframes = (*wstat)[RUN_TXCNT];
 		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
-		    retrycnt, txcnt, success);
+		    txs->nretries, txs->nframes, txs->nsuccess);
 
 		memset(wstat, 0, sizeof(*wstat));
 	}
 
-	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
+	ieee80211_ratectl_tx_update(vap, txs);
 	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
 
 fail:

Modified: head/sys/dev/usb/wlan/if_runvar.h
==============================================================================
--- head/sys/dev/usb/wlan/if_runvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_runvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -159,6 +159,7 @@ struct run_endpoint_queue {
 struct run_softc {
 	struct mtx			sc_mtx;
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_stats sc_txs;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;
 	struct usb_device		*sc_udev;

Modified: head/sys/dev/usb/wlan/if_ural.c
==============================================================================
--- head/sys/dev/usb/wlan/if_ural.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_ural.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1254,8 +1254,10 @@ ural_tx_data(struct ural_softc *sc, stru
 		rate = tp->mcastrate;
 	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
 		rate = tp->ucastrate;
-	else
+	else {
+		(void) ieee80211_ratectl_rate(ni, NULL, 0);
 		rate = ni->ni_txrate;
+	}
 
 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
 		k = ieee80211_crypto_encap(ni, m0);
@@ -2208,32 +2210,29 @@ ural_ratectl_task(void *arg, int pending
 {
 	struct ural_vap *uvp = arg;
 	struct ieee80211vap *vap = &uvp->vap;
-	struct ieee80211com *ic = vap->iv_ic;
-	struct ural_softc *sc = ic->ic_softc;
-	struct ieee80211_node *ni;
-	int ok, fail;
-	int sum, retrycnt;
+	struct ural_softc *sc = vap->iv_ic->ic_softc;
+	struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs;
+	int fail;
 
-	ni = ieee80211_ref_node(vap->iv_bss);
 	RAL_LOCK(sc);
 	/* read and clear statistic registers (STA_CSR0 to STA_CSR10) */
 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof(sc->sta));
 
-	ok = sc->sta[7] +		/* TX ok w/o retry */
-	     sc->sta[8];		/* TX ok w/ retry */
+	txs->flags = IEEE80211_RATECTL_TX_STATS_RETRIES;
+	txs->nsuccess = sc->sta[7] +	/* TX ok w/o retry */
+			sc->sta[8];	/* TX ok w/ retry */
 	fail = sc->sta[9];		/* TX retry-fail count */
-	sum = ok+fail;
-	retrycnt = sc->sta[8] + fail;
+	txs->nframes = txs->nsuccess + fail;
+	/* XXX fail * maxretry */
+	txs->nretries = sc->sta[8] + fail;
 
-	ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt);
-	(void) ieee80211_ratectl_rate(ni, NULL, 0);
+	ieee80211_ratectl_tx_update(vap, txs);
 
 	/* count TX retry-fail as Tx errors */
-	if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, fail);
+	if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, fail);
 
 	usb_callout_reset(&uvp->ratectl_ch, hz, ural_ratectl_timeout, uvp);
 	RAL_UNLOCK(sc);
-	ieee80211_free_node(ni);
 }
 
 static int

Modified: head/sys/dev/usb/wlan/if_uralvar.h
==============================================================================
--- head/sys/dev/usb/wlan/if_uralvar.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_uralvar.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -90,6 +90,7 @@ enum {
 
 struct ural_softc {
 	struct ieee80211com		sc_ic;
+	struct ieee80211_ratectl_tx_stats sc_txs;
 	struct mbufq			sc_snd;
 	device_t			sc_dev;
 	struct usb_device		*sc_udev;

Modified: head/sys/dev/usb/wlan/if_zyd.c
==============================================================================
--- head/sys/dev/usb/wlan/if_zyd.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_zyd.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -662,12 +662,24 @@ zyd_intr_read_callback(struct usb_xfer *
 			 */
 			ni = ieee80211_find_txnode(vap, retry->macaddr);
 			if (ni != NULL) {
+				struct ieee80211_ratectl_tx_status *txs =
+				    &sc->sc_txs;
 				int retrycnt =
 				    (int)(le16toh(retry->count) & 0xff);
-				
-				ieee80211_ratectl_tx_complete(vap, ni,
-				    IEEE80211_RATECTL_TX_FAILURE,
-				    &retrycnt, NULL);
+
+				txs->flags =
+				    IEEE80211_RATECTL_STATUS_LONG_RETRY;
+				txs->long_retries = retrycnt;
+				if (le16toh(retry->count) & 0x100) {
+					txs->status =
+					    IEEE80211_RATECTL_TX_FAIL_LONG;
+				} else {
+					txs->status =
+					    IEEE80211_RATECTL_TX_SUCCESS;
+				}
+
+
+				ieee80211_ratectl_tx_complete(ni, txs);
 				ieee80211_free_node(ni);
 			}
 			if (le16toh(retry->count) & 0x100)

Modified: head/sys/dev/usb/wlan/if_zydreg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_zydreg.h	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/usb/wlan/if_zydreg.h	Sun Oct  2 20:35:55 2016	(r306591)
@@ -1254,6 +1254,7 @@ enum {
 
 struct zyd_softc {
 	struct ieee80211com	sc_ic;
+	struct ieee80211_ratectl_tx_status sc_txs;
 	struct mbufq		sc_snd;
 	device_t		sc_dev;
 	struct usb_device	*sc_udev;

Modified: head/sys/dev/wpi/if_wpi.c
==============================================================================
--- head/sys/dev/wpi/if_wpi.c	Sun Oct  2 19:39:23 2016	(r306590)
+++ head/sys/dev/wpi/if_wpi.c	Sun Oct  2 20:35:55 2016	(r306591)
@@ -526,6 +526,10 @@ wpi_attach(device_t dev)
 
 	wpi_radiotap_attach(sc);
 
+	/* Setup Tx status flags (constant). */
+	sc->sc_txs.flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
+	    IEEE80211_RATECTL_STATUS_LONG_RETRY;
+
 	callout_init_mtx(&sc->calib_to, &sc->rxon_mtx, 0);
 	callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0);
 	callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list