Date: Sat, 20 Aug 2011 06:08:31 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r225021 - user/adrian/if_ath_tx/sys/dev/ath Message-ID: <201108200608.p7K68VhV036645@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Sat Aug 20 06:08:31 2011 New Revision: 225021 URL: http://svn.freebsd.org/changeset/base/225021 Log: Another combined diff - partly debugging, partly implementing more aggregation related stuff. Debugging/enforcing (which I'll likely remove at some point, or at least make optional): * Remove ath_buf's from the aggregate list - ie, blank bf->bf_next - when they've been handled and they're being requeued or completed. * Print out a message ath_tx_default_comp() if the ath_buf in question is still on an aggregation list. * Check whether the number of buffers handled in the aggregate frame completion or aggregate frame error functions match the number of frames -in- the aggregate buffer list. Print out an error if this isn't the case. Aggregation changes: * Fill out the rest of the ath_rc_series fields in the ath_buf - max4msframelen and the flags fields. This is done after the rate control decisions have been made in the (raw, normal) TX path. Later on, this will be pushed into the rate control module and then, much later on, it'll be pushed into net80211. * Implement the rest of the ampdu delimiter calculation code. The ampdu density figure, negotiated in STA mode and configured in hostap mode, is enforced when calculating delimiter counts. It uses the "fastest" rate (ie, the first one) to calculate how long a frame will be (in bytes) at the given rate/config, and then enforces that the configured delimiter count matches at least -that- length. If a sub-frame length is smaller than the configured mpdudensity, the delimiter count is the minimum density, rather than soley based on the frame count. * Implement a very simple function to return the maximum frame length for 4ms, based on the slowest rate. If the rate control returns a set of rate series rather than a single one, the aggregate may end up being transmitted at the slowest rather than the fastest. A lot of stuff that has been shoehorned into if_ath_tx_ht.c should likely live elsewhere, including the HAL and net80211. I'll worry about where to place all of this once the code is (more) stable. Obtained from: Atheros, Linux ath9k Modified: user/adrian/if_ath_tx/sys/dev/ath/README user/adrian/if_ath_tx/sys/dev/ath/if_ath.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h 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.h user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Modified: user/adrian/if_ath_tx/sys/dev/ath/README ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/README Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/README Sat Aug 20 06:08:31 2011 (r225021) @@ -1,3 +1,18 @@ +Things to debug! + +* Write something in ath_tx_default_comp() that ensures the buffer is unlinked + (ie, not part of an aggregate) + +* Write something in the aggr comp function which checks that the number of + frames in the aggregate list matches bf_stats.bfs_nframes + - Done + +* Am I losing an ath_buf in the hardware TX queue code? Ie, are they not + ever queued? + +* Is it some missing sequence numbers? ie, is addto_baw being called with + sequence numbers out of order, or "gaps" in the sequence numbers? + Things that need doing! * RIFS? Do I care about supporting RIFS? Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath.c ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c Sat Aug 20 06:08:31 2011 (r225021) @@ -4159,6 +4159,9 @@ ath_tx_default_comp(struct ath_softc *sc if (bf->bf_state.bfs_dobaw) device_printf(sc->sc_dev, "%s: dobaw should've been cleared!\n", __func__); + if (bf->bf_next != NULL) + device_printf(sc->sc_dev, + "%s: bf_next not NULL!\n", __func__); /* * Do any tx complete callback. Note this must 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 Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Sat Aug 20 06:08:31 2011 (r225021) @@ -1273,6 +1273,12 @@ ath_tx_start(struct ath_softc *sc, struc /* At this point m0 could have changed! */ m0 = bf->bf_m; + /* + * ath_tx_normal_setup() has done the single and multi-rate + * retry rate lookup for us. Fill in the rcflags based on + * that. + */ + ath_tx_rate_fill_rcflags(sc, bf); #if 1 /* * If it's a multicast frame, do a direct-dispatch to the @@ -1510,6 +1516,11 @@ ath_tx_raw_start(struct ath_softc *sc, s bf->bf_state.bfs_rc[2].tries = params->ibp_try2; bf->bf_state.bfs_rc[3].tries = params->ibp_try3; } + /* + * All the required rate control decisions have been made; + * fill in the rc flags. + */ + ath_tx_rate_fill_rcflags(sc, bf); /* NB: no buffered multicast in power save support */ @@ -2478,6 +2489,7 @@ ath_tx_comp_aggr_error(struct ath_softc bf = bf_first; while (bf) { bf_next = bf->bf_next; + bf->bf_next = NULL; /* Remove it from the aggr list */ drops += ath_tx_retry_subframe(sc, bf, &bf_q); bf = bf_next; } @@ -2540,6 +2552,7 @@ ath_tx_comp_cleanup_aggr(struct ath_soft while (bf) { atid->incomp--; bf_next = bf->bf_next; + bf->bf_next = NULL; /* Remove it from the aggr list */ ath_tx_default_comp(sc, bf, -1); bf = bf_next; } @@ -2580,6 +2593,7 @@ 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; DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: called\n", __func__); @@ -2635,8 +2649,10 @@ ath_tx_aggr_comp_aggr(struct ath_softc * bf = bf_first; while (bf) { + np++; 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 */ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: checking bf=%p seqno=%d; ack=%d\n", @@ -2656,6 +2672,10 @@ ath_tx_aggr_comp_aggr(struct ath_softc * bf = bf_next; } + if (np != 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); + /* update rate control module about aggregate status */ /* XXX TODO */ Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Sat Aug 20 06:08:31 2011 (r225021) @@ -44,6 +44,11 @@ #define WME_MAX_BA WME_BA_BMP_SIZE /* + * How 'busy' to try and keep the hardware txq + */ +#define ATH_AGGR_MIN_QDEPTH 2 + +/* * return whether a bit at index _n in bitmap _bm is set * _sz is the size of the bitmap */ 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 Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.c Sat Aug 20 06:08:31 2011 (r225021) @@ -88,6 +88,8 @@ __FBSDID("$FreeBSD$"); #include <dev/ath/if_ath_tx.h> /* XXX for some support functions */ #include <dev/ath/if_ath_tx_ht.h> +#include <dev/ath/if_athrate.h> +#include <dev/ath/if_ath_debug.h> /* * XXX net80211? @@ -135,19 +137,196 @@ int ath_max_4ms_framelen[4][32] = { }; /* + * XXX should be in net80211 + */ +static int ieee80211_mpdudensity_map[] = { + 0, /* IEEE80211_HTCAP_MPDUDENSITY_NA */ + 25, /* IEEE80211_HTCAP_MPDUDENSITY_025 */ + 50, /* IEEE80211_HTCAP_MPDUDENSITY_05 */ + 100, /* IEEE80211_HTCAP_MPDUDENSITY_1 */ + 200, /* IEEE80211_HTCAP_MPDUDENSITY_2 */ + 400, /* IEEE80211_HTCAP_MPDUDENSITY_4 */ + 800, /* IEEE80211_HTCAP_MPDUDENSITY_8 */ + 1600, /* IEEE80211_HTCAP_MPDUDENSITY_16 */ +}; + +/* + * XXX should be in the HAL/net80211 ? + */ +#define BITS_PER_BYTE 8 +#define OFDM_PLCP_BITS 22 +#define HT_RC_2_MCS(_rc) ((_rc) & 0x7f) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) +#define L_STF 8 +#define L_LTF 8 +#define L_SIG 4 +#define HT_SIG 8 +#define HT_STF 4 +#define HT_LTF(_ns) (4 * (_ns)) +#define SYMBOL_TIME(_ns) ((_ns) << 2) // ns * 4 us +#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) // ns * 3.6 us +#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) +#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) +#define IS_HT_RATE(_rate) ((_rate) & 0x80) + +const uint32_t bits_per_symbol[][2] = { + /* 20MHz 40MHz */ + { 26, 54 }, // 0: BPSK + { 52, 108 }, // 1: QPSK 1/2 + { 78, 162 }, // 2: QPSK 3/4 + { 104, 216 }, // 3: 16-QAM 1/2 + { 156, 324 }, // 4: 16-QAM 3/4 + { 208, 432 }, // 5: 64-QAM 2/3 + { 234, 486 }, // 6: 64-QAM 3/4 + { 260, 540 }, // 7: 64-QAM 5/6 + { 52, 108 }, // 8: BPSK + { 104, 216 }, // 9: QPSK 1/2 + { 156, 324 }, // 10: QPSK 3/4 + { 208, 432 }, // 11: 16-QAM 1/2 + { 312, 648 }, // 12: 16-QAM 3/4 + { 416, 864 }, // 13: 64-QAM 2/3 + { 468, 972 }, // 14: 64-QAM 3/4 + { 520, 1080 }, // 15: 64-QAM 5/6 + { 78, 162 }, // 16: BPSK + { 156, 324 }, // 17: QPSK 1/2 + { 234, 486 }, // 18: QPSK 3/4 + { 312, 648 }, // 19: 16-QAM 1/2 + { 468, 972 }, // 20: 16-QAM 3/4 + { 624, 1296 }, // 21: 64-QAM 2/3 + { 702, 1458 }, // 22: 64-QAM 3/4 + { 780, 1620 }, // 23: 64-QAM 5/6 + { 104, 216 }, // 24: BPSK + { 208, 432 }, // 25: QPSK 1/2 + { 312, 648 }, // 26: QPSK 3/4 + { 416, 864 }, // 27: 16-QAM 1/2 + { 624, 1296 }, // 28: 16-QAM 3/4 + { 832, 1728 }, // 29: 64-QAM 2/3 + { 936, 1944 }, // 30: 64-QAM 3/4 + { 1040, 2160 }, // 31: 64-QAM 5/6 +}; + +/* + * Fill in the rate array information based on the current + * node configuration and the choices made by the rate + * selection code and ath_buf setup code. + * + * Later on, this may end up also being made by the + * rate control code, but for now it can live here. + * + * This needs to be called just before the packet is + * queued to the software queue or hardware queue, + * so all of the needed fields in bf_state are setup. + */ +void +ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ieee80211_node *ni = bf->bf_node; + struct ieee80211com *ic = ni->ni_ic; + const HAL_RATE_TABLE *rt = sc->sc_currates; + struct ath_rc_series *rc = bf->bf_state.bfs_rc; + uint8_t rate; + int i; + + for (i = 0; i < ATH_RC_NUM; i++) { + rc[i].flags = 0; + if (rc[i].tries == 0) + continue; + + rate = rt->info[rc[i].rix].rateCode; + + if (bf->bf_state.bfs_flags & + (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) + rc[i].flags |= ATH_RC_RTSCTS_FLAG; + + /* Only enable shortgi, 2040, dual-stream if HT is set */ + if (IS_HT_RATE(rate)) { + rc[i].flags |= ATH_RC_HT_FLAG; + + if (ni->ni_chw == 40) + rc[i].flags |= ATH_RC_CW40_FLAG; + + if (ni->ni_chw == 40 && + ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 && + ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) + rc[i].flags |= ATH_RC_SGI_FLAG; + + if (ni->ni_chw == 20 && + ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 && + ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) + rc[i].flags |= ATH_RC_SGI_FLAG; + + /* XXX dual stream? and 3-stream? */ + } + + /* + * Calculate the maximum 4ms frame length based + * on the MCS rate, SGI and channel width flags. + */ + if ((rc[i].flags & ATH_RC_HT_FLAG) && + (HT_RC_2_MCS(rate) < 32)) { + int j; + if (rc[i].flags & ATH_RC_CW40_FLAG) { + if (rc[i].flags & ATH_RC_SGI_FLAG) + j = MCS_HT40_SGI; + else + j = MCS_HT40; + } else { + if (rc[i].flags & ATH_RC_SGI_FLAG) + j = MCS_HT20_SGI; + else + j = MCS_HT20; + } + rc[i].max4msframelen = + ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)]; + } else + rc[i].max4msframelen = 0; +#if 0 + DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, + "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n", + __func__, i, rate, rc[i].flags, rc[i].max4msframelen); +#endif + } +} + +/* * Return the number of delimiters to be added to * meet the minimum required mpdudensity. + * * Caller should make sure that the rate is HT. * * TODO: is this delimiter calculation supposed to be the * total frame length, the hdr length, the data length (including * delimiters, padding, CRC, etc) or ? + * + * TODO: this should ensure that the rate control information + * HAS been setup for the first rate. + * + * TODO: ensure this is only called for MCS rates. + * + * TODO: enforce MCS < 31 */ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf, uint16_t pktlen) { - int ndelim; + const HAL_RATE_TABLE *rt = sc->sc_currates; + struct ieee80211_node *ni = first_bf->bf_node; + struct ieee80211vap *vap = ni->ni_vap; + int ndelim, mindelim = 0; + int mpdudensity; /* in 1/100'th of a microsecond */ + uint8_t rc, rix, flags; + int width, half_gi; + uint32_t nsymbits, nsymbols; + uint16_t minlen; + + /* + * vap->iv_ampdu_density is a value, rather than the actual + * density. + */ + if (vap->iv_ampdu_density > IEEE80211_HTCAP_MPDUDENSITY_16) + mpdudensity = 1600; /* maximum density */ + else + mpdudensity = ieee80211_mpdudensity_map[vap->iv_ampdu_density]; /* Select standard number of delimiters based on frame length */ ndelim = ATH_AGGR_GET_NDELIM(pktlen); @@ -160,19 +339,85 @@ ath_compute_num_delims(struct ath_softc */ ndelim += ATH_AGGR_ENCRYPTDELIM; + DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, + "%s: pktlen=%d, ndelim=%d, mpdudensity=%d\n", + __func__, pktlen, ndelim, mpdudensity); + /* * If the MPDU density is 0, we can return here. * Otherwise, we need to convert the desired mpdudensity * into a byte length, based on the rate in the subframe. - * - * XXX TODO: since the rate scenario hasn't been configured - * XXX yet, this is likely not going to work. So, for now, - * XXX ignore it. */ + if (mpdudensity == 0) + return ndelim; + + /* + * Convert desired mpdu density from microeconds to bytes based + * on highest rate in rate series (i.e. first rate) to determine + * required minimum length for subframe. Take into account + * whether high rate is 20 or 40Mhz and half or full GI. + */ + rix = first_bf->bf_state.bfs_rc[0].rix; + rc = rt->info[rix].rateCode; + flags = first_bf->bf_state.bfs_rc[0].flags; + width = !! (flags & ATH_RC_CW40_FLAG); + half_gi = !! (flags & ATH_RC_SGI_FLAG); + + /* + * mpdudensity is in 1/100th of a usec, so divide by 100 + */ + if (half_gi) + nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); + else + nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); + nsymbols /= 100; + + if (nsymbols == 0) + nsymbols = 1; + + nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; + + /* + * Min length is the minimum frame length for the + * required MPDU density. + */ + if (pktlen < minlen) { + mindelim = (minlen - pktlen) / ATH_AGGR_DELIM_SZ; + ndelim = MAX(mindelim, ndelim); + } + + DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, + "%s: pktlen=%d, minlen=%d, rix=%x, rc=%x, width=%d, hgi=%d, ndelim=%d\n", + __func__, pktlen, minlen, rix, rc, width, half_gi, ndelim); + return ndelim; } /* + * Fetch the aggregation limit. + * + * It's the lowest of the four rate series 4ms frame length. + */ +static int +ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf) +{ + int amin = 65530; + int i; + + for (i = 0; i < 4; i++) { + if (bf->bf_state.bfs_rc[i].tries == 0) + continue; + amin = MIN(amin, bf->bf_state.bfs_rc[i].max4msframelen); + } + + DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: max frame len= %d\n", + __func__, amin); + + return amin; +} + +/* * Setup a 11n rate series structure * * This should be called for both legacy and MCS rates. @@ -207,6 +452,10 @@ ath_rateseries_setup(struct ath_softc *s else pktlen = bf->bf_state.bfs_pktlen; + /* + * XXX TODO: modify this routine to use the bfs_rc[x].flags + * XXX fields. + */ memset(series, 0, sizeof(HAL_11N_RATE_SERIES) * 4); for (i = 0; i < 4; i++) { /* Only set flags for actual TX attempts */ @@ -403,12 +652,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s h_baw = tap->txa_wnd / 2; - /* Calculate aggregation limit */ - /* - * XXX TODO: do not exceed 4ms packet length - */ - aggr_limit = 65530; /* XXX just for now, for testing */ - for (;;) { ATH_TXQ_LOCK(tid); bf = TAILQ_FIRST(&tid->axq_q); @@ -418,6 +661,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s ATH_TXQ_UNLOCK(tid); status = ATH_AGGR_DONE; break; + } else { + /* + * It's the first frame; + * set the aggregation limit based on the + * rate control decision that has been made. + */ + aggr_limit = ath_get_aggr_limit(sc, bf_first); } /* Set this early just so things don't get confused */ @@ -442,6 +692,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s } /* + * If any of the rates are non-HT, this packet + * can't be aggregated. + * XXX TODO: add a bf_state flag which gets marked + * if any active rate is non-HT. + */ + + /* * If the packet has a sequence number, do not * step outside of the block-ack window. */ @@ -481,7 +738,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s break; } - /* * this packet is part of an aggregate. */ Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.h Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx_ht.h Sat Aug 20 06:08:31 2011 (r225021) @@ -50,6 +50,8 @@ typedef enum { extern int ath_max_4ms_framelen[4][32]; +extern void ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf); + extern void ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf); Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h ============================================================================== --- user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Fri Aug 19 21:59:47 2011 (r225020) +++ user/adrian/if_ath_tx/sys/dev/ath/if_athrate.h Sat Aug 20 06:08:31 2011 (r225021) @@ -79,6 +79,12 @@ void ath_rate_detach(struct ath_ratectrl #define ATH_RC_NUM 4 +#define ATH_RC_DS_FLAG 0x01 /* dual-stream rate */ +#define ATH_RC_CW40_FLAG 0x02 /* use HT40 */ +#define ATH_RC_SGI_FLAG 0x04 /* use short-GI */ +#define ATH_RC_HT_FLAG 0x08 /* use HT */ +#define ATH_RC_RTSCTS_FLAG 0x10 /* enable RTS/CTS protection */ + struct ath_rc_series { uint8_t rix; /* ratetable index, not rate code */ uint8_t tries;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108200608.p7K68VhV036645>