From owner-svn-src-user@FreeBSD.ORG Mon Aug 22 06:25:10 2011 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 25F931065673; Mon, 22 Aug 2011 06:25:10 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 433428FC1F; Mon, 22 Aug 2011 06:25:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p7M6P2oF037059; Mon, 22 Aug 2011 06:25:02 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p7M6P2Mm037053; Mon, 22 Aug 2011 06:25:02 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201108220625.p7M6P2Mm037053@svn.freebsd.org> From: Adrian Chadd Date: Mon, 22 Aug 2011 06:25:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r225072 - in user/adrian/if_ath_tx/sys/dev/ath: . ath_rate/sample X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Aug 2011 06:25:10 -0000 Author: adrian Date: Mon Aug 22 06:25:01 2011 New Revision: 225072 URL: http://svn.freebsd.org/changeset/base/225072 Log: Do some reasonably major surgery to the way TX rates are calculated and completed, as part of providing the rate control code with accurate information about aggregate packet completions. Since the aggregate completion function has no idea how many frames have succeeded or failed until -after- the ath_buf list has been walked, compared against the Blockack bitmap (and buffers have been completed), we need to keep a variety of the state somewhere. So we can't just pass in an ath_buf into the completion code - it has likely already been freed before the rate update call is made. Also, the framelength for an aggregate is the aggregate itself, not the length of the first frame. The specifics: * add a 'ratecode' field to ath_rc_series, storing the ratecode decision; * update ratecode in ath_tx_rate_fill_rcflags(), also taking into account whether the ath_buf has the short preamble bit set; * modify the sample ath_tx_rate_complete() function to take a copy of the ath_rc_series, along with a framelength * if a buffer doesn't have a completion handler, manually call the rate control code * if a buffer -does- have a completion handler, leave calling the rate control code up to that. The things to do: * Actually teach ath_rate_sample about the packet error rate when TX'ing aggregates. That's next. * Becuase the rate lookup is done before the aggregate is formed, we can't query the rate control code with the length of the aggregate. It's a chicken and egg problem - we can't form aggregates until we know what the rate selection is (as that's used to enforce the 4ms frame max duration) and delimiter density. So for now, it'll just use the size of the first frame in the list when making a rate decision, and I'll worry about delaying the rate control lookup later. Modified: user/adrian/if_ath_tx/sys/dev/ath/ath_rate/sample/sample.c user/adrian/if_ath_tx/sys/dev/ath/if_ath.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_misc.h user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.c user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Modified: user/adrian/if_ath_tx/sys/dev/ath/ath_rate/sample/sample.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/ath_rate/sample/sample.c Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/ath_rate/sample/sample.c Mon Aug 22 06:25:01 2011 (r225072) @@ -594,21 +594,20 @@ badrate(struct ifnet *ifp, int series, i void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, - const struct ath_buf *bf) + const struct ath_rc_series *rc, const struct ath_tx_status *ts, + int frame_size, int nframes, int nbad) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct sample_node *sn = ATH_NODE_SAMPLE(an); - const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; - const struct ath_desc *ds0 = &bf->bf_desc[0]; - int final_rix, short_tries, long_tries, frame_size; + int final_rix, short_tries, long_tries; const HAL_RATE_TABLE *rt = sc->sc_currates; int mrr; final_rix = rt->rateCodeToIndex[ts->ts_rate]; short_tries = ts->ts_shortretry; long_tries = ts->ts_longretry + 1; - frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ + if (frame_size == 0) /* NB: should not happen */ frame_size = 1500; @@ -645,18 +644,12 @@ ath_rate_tx_complete(struct ath_softc *s 0, 0, short_tries, long_tries, ts->ts_status); } else { - int hwrates[4], tries[4], rix[4]; int finalTSIdx = ts->ts_finaltsi; int i; /* * Process intermediate rates that failed. */ - ath_hal_gettxcompletionrates(sc->sc_ah, ds0, hwrates, tries); - - for (i = 0; i < 4; i++) { - rix[i] = rt->rateCodeToIndex[hwrates[i]]; - } IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, @@ -665,16 +658,21 @@ ath_rate_tx_complete(struct ath_softc *s bin_to_size(size_to_bin(frame_size)), frame_size, finalTSIdx, - long_tries, + long_tries, ts->ts_status ? "FAIL" : "OK", - dot11rate(rt, rix[0]), dot11rate_label(rt, rix[0]), tries[0], - dot11rate(rt, rix[1]), dot11rate_label(rt, rix[1]), tries[1], - dot11rate(rt, rix[2]), dot11rate_label(rt, rix[2]), tries[2], - dot11rate(rt, rix[3]), dot11rate_label(rt, rix[3]), tries[3]); + dot11rate(rt, rc[0].rix), + dot11rate_label(rt, rc[0].rix), rc[0].tries, + dot11rate(rt, rc[1].rix), + dot11rate_label(rt, rc[1].rix), rc[1].tries, + dot11rate(rt, rc[2].rix), + dot11rate_label(rt, rc[2].rix), rc[2].tries, + dot11rate(rt, rc[3].rix), + dot11rate_label(rt, rc[3].rix), rc[3].tries); for (i = 0; i < 4; i++) { - if (tries[i] && !IS_RATE_DEFINED(sn, rix[i])) - badrate(ifp, 0, hwrates[i], tries[i], ts->ts_status); + if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) + badrate(ifp, 0, rc[i].ratecode, rc[i].tries, + ts->ts_status); } /* @@ -684,46 +682,46 @@ ath_rate_tx_complete(struct ath_softc *s * sample higher rates 1 try at a time doing so * may unfairly penalize them. */ - if (tries[0]) { - update_stats(sc, an, frame_size, - rix[0], tries[0], - rix[1], tries[1], - rix[2], tries[2], - rix[3], tries[3], - short_tries, long_tries, - long_tries > tries[0]); - long_tries -= tries[0]; + if (rc[0].tries) { + update_stats(sc, an, frame_size, + rc[0].rix, rc[0].tries, + rc[1].rix, rc[1].tries, + rc[2].rix, rc[2].tries, + rc[3].rix, rc[3].tries, + short_tries, long_tries, + long_tries > rc[0].tries); + long_tries -= rc[0].tries; } - if (tries[1] && finalTSIdx > 0) { - update_stats(sc, an, frame_size, - rix[1], tries[1], - rix[2], tries[2], - rix[3], tries[3], - 0, 0, - short_tries, long_tries, + if (rc[1].tries && finalTSIdx > 0) { + update_stats(sc, an, frame_size, + rc[1].rix, rc[1].tries, + rc[2].rix, rc[2].tries, + rc[3].rix, rc[3].tries, + 0, 0, + short_tries, long_tries, ts->ts_status); - long_tries -= tries[1]; + long_tries -= rc[1].tries; } - if (tries[2] && finalTSIdx > 1) { - update_stats(sc, an, frame_size, - rix[2], tries[2], - rix[3], tries[3], + if (rc[2].tries && finalTSIdx > 1) { + update_stats(sc, an, frame_size, + rc[2].rix, rc[2].tries, + rc[3].rix, rc[3].tries, 0, 0, 0, 0, - short_tries, long_tries, + short_tries, long_tries, ts->ts_status); - long_tries -= tries[2]; + long_tries -= rc[2].tries; } - if (tries[3] && finalTSIdx > 2) { - update_stats(sc, an, frame_size, - rix[3], tries[3], + if (rc[3].tries && finalTSIdx > 2) { + update_stats(sc, an, frame_size, + rc[3].rix, rc[3].tries, 0, 0, 0, 0, 0, 0, - short_tries, long_tries, + short_tries, long_tries, ts->ts_status); } } Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Mon Aug 22 06:25:01 2011 (r225072) @@ -4206,6 +4206,29 @@ ath_tx_default_comp(struct ath_softc *sc } /* + * Update rate control with the given completion status. + */ +void +ath_tx_update_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni, + struct ath_rc_series *rc, struct ath_tx_status *ts, int frmlen, + int nframes, int nbad) +{ + struct ath_node *an; + + /* Only for unicast frames */ + if (ni == NULL) + return; + + an = ATH_NODE(ni); + + if ((ts->ts_status & HAL_TXERR_FILT) == 0) { + ATH_NODE_LOCK(an); + ath_rate_tx_complete(sc, an, rc, ts, frmlen, nframes, nbad); + ATH_NODE_UNLOCK(an); + } +} + +/* * Process completed xmit descriptors from the specified queue. * Kick the packet scheduler if needed. This can occur from this * particular task. @@ -4283,21 +4306,31 @@ ath_tx_processq(struct ath_softc *sc, st an = ATH_NODE(ni); /* update statistics */ ath_tx_update_stats(sc, ts, bf); + } - /* - * Hand the descriptor to the rate control algorithm. - */ + + /* + * Call the completion handler. + * The completion handler is responsible for + * calling the rate control code. + * + * Frames with no completion handler get the + * rate control code called here. + */ + if (bf->bf_comp == NULL) { if ((ts->ts_status & HAL_TXERR_FILT) == 0 && (bf->bf_txflags & HAL_TXDESC_NOACK) == 0) { - ATH_NODE_LOCK(an); - ath_rate_tx_complete(sc, an, bf); - ATH_NODE_UNLOCK(an); - } - } - - if (bf->bf_comp == NULL) + /* + * XXX assume this isn't an aggregate + * frame. + */ + ath_tx_update_ratectrl(sc, ni, + bf->bf_state.bfs_rc, ts, + bf->bf_state.bfs_pktlen, 1, + (ts->ts_status == 0 ? 0 : 1)); ath_tx_default_comp(sc, bf, 0); - else + } + } else bf->bf_comp(sc, bf, 0); } #ifdef IEEE80211_SUPPORT_SUPERG Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_misc.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_misc.h Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_misc.h Mon Aug 22 06:25:01 2011 (r225072) @@ -57,6 +57,10 @@ extern int ath_reset(struct ifnet *); extern void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq); extern void ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf, int fail); +extern void ath_tx_update_ratectrl(struct ath_softc *sc, + struct ieee80211_node *ni, struct ath_rc_series *rc, + struct ath_tx_status *ts, int frmlen, int nframes, int nbad); + extern void ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf, int status); extern void ath_tx_sched_proc_sched(struct ath_softc *sc, struct ath_txq *txq); Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Mon Aug 22 06:25:01 2011 (r225072) @@ -760,26 +760,17 @@ static void ath_tx_set_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf) { - const HAL_RATE_TABLE *rt = sc->sc_currates; struct ath_rc_series *rc = bf->bf_state.bfs_rc; - uint8_t rate[4]; - int i; if (ath_tx_is_11n(sc)) { /* Always setup rate series */ ath_buf_set_rate(sc, ni, bf); } else if (bf->bf_state.bfs_ismrr) { /* Only call for legacy NICs if MRR */ - for (i = 0; i < 4; i++) { - rate[i] = rt->info[rc[i].rix].rateCode; - if (bf->bf_state.bfs_shpream) { - rate[i] |= rt->info[rc[i].rix].shortPreamble; - } - } ath_hal_setupxtxdesc(sc->sc_ah, bf->bf_desc - , rate[1], rc[1].tries - , rate[2], rc[2].tries - , rate[3], rc[3].tries + , rc[1].ratecode, rc[1].tries + , rc[2].ratecode, rc[2].tries + , rc[3].ratecode, rc[3].tries ); } } @@ -1129,6 +1120,7 @@ ath_tx_normal_setup(struct ath_softc *sc */ bf->bf_state.bfs_rc[0].rix = rix; bf->bf_state.bfs_rc[0].tries = try0; + bf->bf_state.bfs_rc[0].ratecode = txrate; /* Store the decided rate index values away */ bf->bf_state.bfs_pktlen = pktlen; @@ -1498,17 +1490,21 @@ ath_tx_raw_start(struct ath_softc *sc, s bf->bf_state.bfs_rc[0].rix = ath_tx_findrix(sc, params->ibp_rate0); bf->bf_state.bfs_rc[0].tries = try0; + bf->bf_state.bfs_rc[0].ratecode = txrate; if (ismrr) { - bf->bf_state.bfs_rc[1].rix = - ath_tx_findrix(sc, params->ibp_rate1); - bf->bf_state.bfs_rc[2].rix = - ath_tx_findrix(sc, params->ibp_rate2); - bf->bf_state.bfs_rc[3].rix = - ath_tx_findrix(sc, params->ibp_rate3); + int rix; + rix = ath_tx_findrix(sc, params->ibp_rate1); + bf->bf_state.bfs_rc[1].rix = rix; bf->bf_state.bfs_rc[1].tries = params->ibp_try1; + + rix = ath_tx_findrix(sc, params->ibp_rate2); + bf->bf_state.bfs_rc[2].rix = rix; bf->bf_state.bfs_rc[2].tries = params->ibp_try2; + + rix = ath_tx_findrix(sc, params->ibp_rate3); + bf->bf_state.bfs_rc[3].rix = rix; bf->bf_state.bfs_rc[3].tries = params->ibp_try3; } /* @@ -2179,6 +2175,7 @@ ath_tx_normal_comp(struct ath_softc *sc, struct ath_node *an = ATH_NODE(ni); int tid = bf->bf_state.bfs_tid; struct ath_tid *atid = &an->an_tid[tid]; + struct ath_tx_status *ts = &bf->bf_status.ds_txstat; DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: fail=%d, hwq_depth now %d\n", __func__, bf, fail, atid->hwq_depth - 1); @@ -2190,6 +2187,15 @@ ath_tx_normal_comp(struct ath_softc *sc, __func__, atid->hwq_depth); ATH_TXQ_UNLOCK(atid); + /* + * punt to rate control if we're not being cleaned up + * during a hw queue drain. + */ + if (fail == 0) + ath_tx_update_ratectrl(sc, ni, bf->bf_state.bfs_rc, + ts, bf->bf_state.bfs_pktlen, + 1, (ts->ts_status == 0) ? 0 : 1); + ath_tx_default_comp(sc, bf, fail); } @@ -2514,6 +2520,14 @@ ath_tx_comp_aggr_error(struct ath_softc TAILQ_INIT(&bf_q); + /* + * Update rate control - all frames have failed. + */ + ath_tx_update_ratectrl(sc, ni, bf_first->bf_state.bfs_rc, + &bf_first->bf_status.ds_txstat, + bf_first->bf_state.bfs_al, + bf_first->bf_state.bfs_nframes, bf_first->bf_state.bfs_nframes); + /* Retry all subframes */ bf = bf_first; while (bf) { @@ -2523,9 +2537,6 @@ ath_tx_comp_aggr_error(struct ath_softc bf = bf_next; } - /* Update rate control module about aggregation */ - /* XXX todo */ - #if 0 /* * send bar if we dropped any frames @@ -2579,7 +2590,7 @@ ath_tx_comp_cleanup_aggr(struct ath_soft atid->incomp--; bf_next = bf->bf_next; bf->bf_next = NULL; /* Remove it from the aggr list */ - ath_tx_default_comp(sc, bf, -1); + ath_tx_default_comp(sc, bf, 1); bf = bf_next; } @@ -2609,7 +2620,7 @@ ath_tx_aggr_comp_aggr(struct ath_softc * struct ath_node *an = ATH_NODE(ni); int tid = bf_first->bf_state.bfs_tid; struct ath_tid *atid = &an->an_tid[tid]; - struct ath_tx_status *ts = &bf_first->bf_status.ds_txstat; + struct ath_tx_status ts; struct ieee80211_tx_ampdu *tap; ath_bufhead bf_q; int seq_st, tx_ok; @@ -2619,7 +2630,10 @@ ath_tx_aggr_comp_aggr(struct ath_softc * int ba_index; int drops = 0; struct ath_txq *txq = sc->sc_ac2q[atid->ac]; - int np = 0; + int nframes = 0, nbad = 0; + int pktlen; + /* XXX there's too much on the stack? */ + struct ath_rc_series rc[4]; DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: called; hwq_depth=%d\n", __func__, atid->hwq_depth); @@ -2640,9 +2654,16 @@ ath_tx_aggr_comp_aggr(struct ath_softc * } /* + * Take a copy; this may be needed -after- bf_first + * has been completed and freed. + */ + ts = bf_first->bf_status.ds_txstat; + pktlen = bf_first->bf_state.bfs_al; + + /* * handle errors first */ - if (ts->ts_status & HAL_TXERR_XRETRY) { + if (ts.ts_status & HAL_TXERR_XRETRY) { ath_tx_comp_aggr_error(sc, bf_first, atid); return; } @@ -2654,22 +2675,30 @@ ath_tx_aggr_comp_aggr(struct ath_softc * * extract starting sequence and block-ack bitmap */ /* XXX endian-ness of seq_st, ba? */ - seq_st = ts->ts_seqnum; - hasba = !! (ts->ts_flags & HAL_TX_BA); - tx_ok = (ts->ts_status == 0); + seq_st = ts.ts_seqnum; + hasba = !! (ts.ts_flags & HAL_TX_BA); + tx_ok = (ts.ts_status == 0); isaggr = bf_first->bf_state.bfs_aggr; - ba[0] = ts->ts_ba_low; - ba[1] = ts->ts_ba_high; + ba[0] = ts.ts_ba_low; + ba[1] = ts.ts_ba_high; + + /* + * Copy the TX completion status and the rate control + * series from the first descriptor, as it may be freed + * before the rate control code can get its grubby fingers + * into things. + */ + memcpy(rc, bf_first->bf_state.bfs_rc, sizeof(rc)); DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: txa_start=%d, tx_ok=%d, status=%.8x, flags=%.8x, isaggr=%d, seq_st=%d, hasba=%d, ba=%.8x, %.8x\n", - __func__, tap->txa_start, tx_ok, ts->ts_status, ts->ts_flags, + __func__, tap->txa_start, tx_ok, ts.ts_status, ts.ts_flags, isaggr, seq_st, hasba, ba[0], ba[1]); /* Occasionally, the MAC sends a tx status for the wrong TID. */ - if (tid != ts->ts_tid) { + if (tid != ts.ts_tid) { device_printf(sc->sc_dev, "%s: tid %d != hw tid %d\n", - __func__, tid, ts->ts_tid); + __func__, tid, ts.ts_tid); tx_ok = 0; } @@ -2683,7 +2712,7 @@ ath_tx_aggr_comp_aggr(struct ath_softc * bf = bf_first; while (bf) { - np++; + nframes++; ba_index = ATH_BA_INDEX(seq_st, SEQNO(bf->bf_state.bfs_seqno)); bf_next = bf->bf_next; bf->bf_next = NULL; /* Remove it from the aggr list */ @@ -2706,16 +2735,21 @@ ath_tx_aggr_comp_aggr(struct ath_softc * ath_tx_default_comp(sc, bf, 0); } else { drops += ath_tx_retry_subframe(sc, bf, &bf_q); + nbad++; } bf = bf_next; } - if (np != bf_first->bf_state.bfs_nframes) + if (nframes != bf_first->bf_state.bfs_nframes) device_printf(sc->sc_dev, "%s: np=%d; nframes=%d\n", - __func__, np, bf_first->bf_state.bfs_nframes); + __func__, nframes, bf_first->bf_state.bfs_nframes); - /* update rate control module about aggregate status */ - /* XXX TODO */ + /* + * Now we know how many frames were bad, call the rate + * control code. + */ + if (fail == 0) + ath_tx_update_ratectrl(sc, ni, rc, &ts, pktlen, nframes, nbad); #if 0 /* @@ -2783,6 +2817,16 @@ ath_tx_aggr_comp_unaggr(struct ath_softc __func__, atid->hwq_depth); ATH_TXQ_UNLOCK(atid); + /* + * Update rate control status here, before we possibly + * punt to retry or cleanup. + */ + if (fail == 0) + ath_tx_update_ratectrl(sc, ni, bf->bf_state.bfs_rc, + &bf->bf_status.ds_txstat, + bf->bf_state.bfs_pktlen, + 1, (ts->ts_status == 0) ? 0 : 1); + ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]); ath_tx_tid_sched(sc, an, atid->tid); ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]); @@ -2791,7 +2835,7 @@ ath_tx_aggr_comp_unaggr(struct ath_softc * If a cleanup is in progress, punt to comp_cleanup; * rather than handling it here. It's thus their * responsibility to clean up, call the completion - * function in net80211, update rate control, etc. + * function in net80211, etc. */ if (atid->cleanup_inprogress) { ath_tx_comp_cleanup_unaggr(sc, bf); @@ -2955,6 +2999,11 @@ ath_tx_tid_hw_queue_aggr(struct ath_soft bf->bf_state.bfs_rc[1].rix = bf->bf_state.bfs_rc[2].rix = bf->bf_state.bfs_rc[3].rix = 0; + + bf->bf_state.bfs_rc[1].ratecode = + bf->bf_state.bfs_rc[2].ratecode = + bf->bf_state.bfs_rc[3].ratecode = 0; + bf->bf_state.bfs_rc[1].tries = bf->bf_state.bfs_rc[2].tries = bf->bf_state.bfs_rc[3].tries = 0; Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.c Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.c Mon Aug 22 06:25:01 2011 (r225072) @@ -234,6 +234,17 @@ ath_tx_rate_fill_rcflags(struct ath_soft rate = rt->info[rc[i].rix].rateCode; + /* + * XXX only do this for legacy rates? + */ + if (bf->bf_state.bfs_shpream) + rate |= rt->info[rc[i].rix].shortPreamble; + + /* + * Save this, used by the TX and completion code + */ + rc[i].ratecode = rate; + if (bf->bf_state.bfs_flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) rc[i].flags |= ATH_RC_RTSCTS_FLAG; Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Mon Aug 22 05:03:43 2011 (r225071) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Mon Aug 22 06:25:01 2011 (r225072) @@ -87,6 +87,7 @@ void ath_rate_detach(struct ath_ratectrl struct ath_rc_series { uint8_t rix; /* ratetable index, not rate code */ + uint8_t ratecode; /* hardware rate code */ uint8_t tries; uint8_t flags; uint32_t max4msframelen; @@ -141,8 +142,12 @@ void ath_rate_setupxtxdesc(struct ath_so * supplied transmit descriptor. The routine is invoked both * for packets that were successfully sent and for those that * failed (consult the descriptor for details). + * + * For A-MPDU frames, nframes and nbad indicate how many frames + * were in the aggregate, and how many failed. */ struct ath_buf; void ath_rate_tx_complete(struct ath_softc *, struct ath_node *, - const struct ath_buf *); + const struct ath_rc_series *, const struct ath_tx_status *, + int pktlen, int nframes, int nbad); #endif /* _ATH_RATECTRL_H_ */