Example #1
0
/*
 * 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;

		/*
		 * 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_txflags &
		    (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;
		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);
	}
}
Example #2
0
/*
 * 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)
{
	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);

	/*
	 * If encryption is enabled, add extra delimiters to let the
	 * crypto hardware catch up. This could be tuned per-MAC and
	 * per-rate, but for now we'll simply assume encryption is
	 * always enabled.
	 */
	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.
	 */
	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;
}
Example #3
0
/*
 * 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 ieee80211vap *vap = ni->ni_vap;
	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;
	int do_ldpc;
	int do_stbc;

	/*
	 * We only do LDPC if the rate is 11n, both we and the
	 * receiver support LDPC and it's enabled.
	 *
	 * It's a global flag, not a per-try flag, so we clear
	 * it if any of the rate entries aren't 11n.
	 */
	do_ldpc = 0;
	if ((ni->ni_vap->iv_htcaps & IEEE80211_HTCAP_LDPC) &&
	    (ni->ni_htcap & IEEE80211_HTCAP_LDPC))
		do_ldpc = 1;
	do_stbc = 0;

	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;

		/*
		 * Only enable short preamble for legacy rates
		 */
		if ((! IS_HT_RATE(rate)) && 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_txflags &
		    (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
			rc[i].flags |= ATH_RC_RTSCTS_FLAG;

		/*
		 * If we can't do LDPC, don't.
		 */
		if (! IS_HT_RATE(rate))
			do_ldpc = 0;

		/* 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 &&
			    vap->iv_flags_ht & IEEE80211_FHT_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 &&
			    vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
				rc[i].flags |= ATH_RC_SGI_FLAG;

			/*
			 * If we have STBC TX enabled and the receiver
			 * can receive (at least) 1 stream STBC, AND it's
			 * MCS 0-7, AND we have at least two chains enabled,
			 * enable STBC.
			 *
			 * XXX TODO: .. and the rate is an 11n rate?
			 */
			if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC &&
			    ni->ni_vap->iv_flags_ht & IEEE80211_FHT_STBC_TX &&
			    ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM &&
			    (sc->sc_cur_txchainmask > 1) &&
			    HT_RC_2_STREAMS(rate) == 1) {
				rc[i].flags |= ATH_RC_STBC_FLAG;
				do_stbc = 1;
			}

			/*
			 * Dual / Triple stream rate?
			 */
			if (HT_RC_2_STREAMS(rate) == 2)
				rc[i].flags |= ATH_RC_DS_FLAG;
			else if (HT_RC_2_STREAMS(rate) == 3)
				rc[i].flags |= ATH_RC_TS_FLAG;
		}

		/*
		 * Calculate the maximum TX power cap for the current
		 * node.
		 */
		rc[i].tx_power_cap = ieee80211_get_node_txpower(ni);

		/*
		 * 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;
		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);
	}

	/*
	 * LDPC is a global flag, so ...
	 */
	if (do_ldpc) {
		bf->bf_state.bfs_txflags |= HAL_TXDESC_LDPC;
		sc->sc_stats.ast_tx_ldpc++;
	}

	if (do_stbc) {
		sc->sc_stats.ast_tx_stbc++;
	}
}