Ejemplo n.º 1
0
/*
 * Setup a 11n rate series structure
 *
 * This should be called for both legacy and MCS rates.
 *
 * It, along with ath_buf_set_rate, must be called -after- a burst
 * or aggregate is setup.
 */
static void
ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
    struct ath_buf *bf, HAL_11N_RATE_SERIES *series)
{
#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
	struct ieee80211com *ic = ni->ni_ic;
	struct ath_hal *ah = sc->sc_ah;
	HAL_BOOL shortPreamble = AH_FALSE;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	int i;
	int pktlen;
	int flags = bf->bf_state.bfs_txflags;
	struct ath_rc_series *rc = bf->bf_state.bfs_rc;

	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
		shortPreamble = AH_TRUE;

	/*
	 * If this is the first frame in an aggregate series,
	 * use the aggregate length.
	 */
	if (bf->bf_state.bfs_aggr)
		pktlen = bf->bf_state.bfs_al;
	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 */
		if (rc[i].tries == 0)
			continue;

		series[i].Tries = rc[i].tries;

		/*
		 * XXX this isn't strictly correct - sc_txchainmask
		 * XXX isn't the currently active chainmask;
		 * XXX it's the interface chainmask at startup.
		 * XXX It's overridden in the HAL rate scenario function
		 * XXX for now.
		 */
		series[i].ChSel = sc->sc_txchainmask;

		if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
			series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;

		/*
		 * Transmit 40MHz frames only if the node has negotiated
		 * it rather than whether the node is capable of it or not.
	 	 * It's subtly different in the hostap case.
	 	 */
		if (ni->ni_chw == 40)
			series[i].RateFlags |= HAL_RATESERIES_2040;

		/*
		 * Set short-GI only if the node has advertised it
		 * the channel width is suitable, and we support it.
		 * We don't currently have a "negotiated" set of bits -
		 * ni_htcap is what the remote end sends, not what this
		 * node is capable of.
		 */
		if (ni->ni_chw == 40 &&
		    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
		    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
			series[i].RateFlags |= HAL_RATESERIES_HALFGI;

		if (ni->ni_chw == 20 &&
		    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
		    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
			series[i].RateFlags |= HAL_RATESERIES_HALFGI;

		series[i].Rate = rt->info[rc[i].rix].rateCode;

		/* PktDuration doesn't include slot, ACK, RTS, etc timing - it's just the packet duration */
		if (series[i].Rate & IEEE80211_RATE_MCS) {
			series[i].PktDuration =
			    ath_computedur_ht(pktlen
				, series[i].Rate
				, HT_RC_2_STREAMS(series[i].Rate)
				, series[i].RateFlags & HAL_RATESERIES_2040
				, series[i].RateFlags & HAL_RATESERIES_HALFGI);
		} else {
			if (shortPreamble)
				series[i].Rate |=
				    rt->info[rc[i].rix].shortPreamble;
			series[i].PktDuration = ath_hal_computetxtime(ah,
			    rt, pktlen, rc[i].rix, shortPreamble);
		}
	}
#undef	HT_RC_2_STREAMS
}
Ejemplo n.º 2
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++;
	}
}
Ejemplo n.º 3
0
/*
 * Setup a 11n rate series structure
 *
 * This should be called for both legacy and MCS rates.
 *
 * This uses the rate series stuf from ath_tx_rate_fill_rcflags().
 *
 * It, along with ath_buf_set_rate, must be called -after- a burst
 * or aggregate is setup.
 */
static void
ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
    struct ath_buf *bf, HAL_11N_RATE_SERIES *series)
{
	struct ieee80211com *ic = ni->ni_ic;
	struct ath_hal *ah = sc->sc_ah;
	HAL_BOOL shortPreamble = AH_FALSE;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	int i;
	int pktlen;
	struct ath_rc_series *rc = bf->bf_state.bfs_rc;

	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
		shortPreamble = AH_TRUE;

	/*
	 * If this is the first frame in an aggregate series,
	 * use the aggregate length.
	 */
	if (bf->bf_state.bfs_aggr)
		pktlen = bf->bf_state.bfs_al;
	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 < ATH_RC_NUM;  i++) {
		/* Only set flags for actual TX attempts */
		if (rc[i].tries == 0)
			continue;

		series[i].Tries = rc[i].tries;

		/*
		 * XXX TODO: When the NIC is capable of three stream TX,
		 * transmit 1/2 stream rates on two streams.
		 *
		 * This reduces the power consumption of the NIC and
		 * keeps it within the PCIe slot power limits.
		 */
		series[i].ChSel = sc->sc_cur_txchainmask;

		/*
		 * Setup rate and TX power cap for this series.
		 */
		series[i].Rate = rt->info[rc[i].rix].rateCode;
		series[i].RateIndex = rc[i].rix;
		series[i].tx_power_cap = rc[i].tx_power_cap;

		/*
		 * Enable RTS/CTS as appropriate.
		 */
		if (rc[i].flags & ATH_RC_RTSCTS_FLAG)
			series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;

		/*
		 * 11n rate? Update 11n flags.
		 */
		if (rc[i].flags & ATH_RC_HT_FLAG) {
			if (rc[i].flags & ATH_RC_CW40_FLAG)
				series[i].RateFlags |= HAL_RATESERIES_2040;

			if (rc[i].flags & ATH_RC_SGI_FLAG)
				series[i].RateFlags |= HAL_RATESERIES_HALFGI;

			if (rc[i].flags & ATH_RC_STBC_FLAG)
				series[i].RateFlags |= HAL_RATESERIES_STBC;
		}

		/*
		 * TODO: If we're all doing 11n rates then we can set LDPC.
		 * If we've been asked to /do/ LDPC but we are handed a
		 * legacy rate, then we should complain.  Loudly.
		 */

		/*
		 * PktDuration doesn't include slot, ACK, RTS, etc timing -
		 * it's just the packet duration
		 */
		if (rc[i].flags & ATH_RC_HT_FLAG) {
			series[i].PktDuration =
			    ath_computedur_ht(pktlen
				, series[i].Rate
				, HT_RC_2_STREAMS(series[i].Rate)
				, series[i].RateFlags & HAL_RATESERIES_2040
				, series[i].RateFlags & HAL_RATESERIES_HALFGI);
		} else {
			if (shortPreamble)
				series[i].Rate |=
				    rt->info[rc[i].rix].shortPreamble;
			series[i].PktDuration = ath_hal_computetxtime(ah,
			    rt, pktlen, rc[i].rix, shortPreamble);
		}
	}
}
Ejemplo n.º 4
0
static u_int32_t
ol_ath_node_get_maxphyrate(struct ieee80211com *ic, struct ieee80211_node *ni)
{
    u_int8_t mcs;
    u_int8_t bw;
    struct ieee80211vap *vap = ni->ni_vap;
    u_int8_t curr_phy_mode = wlan_get_current_phymode(vap);
    enum ieee80211_fixed_rate_mode rate_mode = vap->iv_fixed_rate.mode;
    u_int8_t nss = 0;
    u_int8_t sgi = 0;

    bw = wlan_get_param(vap, IEEE80211_CHWIDTH);

    if (ieee80211_vap_get_opmode(vap) == IEEE80211_M_STA) {
        if (((ni->ni_htcap & IEEE80211_HTCAP_C_SHORTGI40) && (bw == IEEE80211_CWM_WIDTH40)) ||
            ((ni->ni_htcap & IEEE80211_HTCAP_C_SHORTGI20) && (bw == IEEE80211_CWM_WIDTH20)) ||
            ((ni->ni_vhtcap & IEEE80211_VHTCAP_SHORTGI_80) && (bw == IEEE80211_CWM_WIDTH80))) {
           sgi = 1;
        }
    } else {
           sgi = wlan_get_param(vap, IEEE80211_SHORT_GI);
    }

    if (rate_mode != IEEE80211_FIXED_RATE_NONE) {
        /* Get rates for fixed rate */
        u_int32_t nbps = 0; /*Number of bits per symbol*/
        u_int32_t rc; /* rate code*/
        u_int32_t i;

	/* For fixed rate ensure that SGI is enabled by user */
	sgi = vap->iv_data_sgi;

        switch (rate_mode)
        {
        case IEEE80211_FIXED_RATE_MCS:
            nss = HT_RC_2_STREAMS(vap->iv_fixed_rateset);
            rc = wlan_get_param(vap, IEEE80211_FIXED_RATE);
            mcs = (rc & 0x07);
            for (i = 0; i < NUM_VHT_HT_RATES; i++) {
                if (vht_ht_tbl[i][BW_COL] == bw &&
                    vht_ht_tbl[i][MCS_COL] == mcs) {
                    nbps = vht_ht_tbl[i][NBPS_COL];
                }
            }
            break;
        case IEEE80211_FIXED_RATE_VHT:
            nss = vap->iv_nss;
            mcs = wlan_get_param(vap, IEEE80211_FIXED_VHT_MCS);
            for (i = 0; i < NUM_VHT_HT_RATES; i++) {
                if (vht_ht_tbl[i][BW_COL] == bw &&
                    vht_ht_tbl[i][MCS_COL] == mcs) {
                    nbps = vht_ht_tbl[i][NBPS_COL];
                }
            }
            break;
        case IEEE80211_FIXED_RATE_LEGACY:
            rc = wlan_get_param(vap, IEEE80211_FIXED_RATE);
            for (i = 0; i < NUM_LEGACY_RATES; i++) {
                if (legacy_rate_idx[i][L_RC_COL] == (rc & 0xff)) {
                    return legacy_rate_idx[i][L_BPS_COL] * 1000;
                }
            }
            break;
        default:
            break;
        }

        if (sgi) {
            return (nbps * 5 * 1000 * nss / 18) ;
        } else {
            return (nbps * 1000 * nss / 4) ;
        }
    } else {
        /* Get rates for auto rate */
        nss = ni->ni_streams;
        if(ieee80211_vap_get_opmode(vap) == IEEE80211_M_HOSTAP) {
            nss = (vap->iv_nss >
                   ieee80211_getstreams(ic, ic->ic_tx_chainmask)) ?
                   ieee80211_getstreams(ic, ic->ic_tx_chainmask) :
                   vap->iv_nss;
        }
        if ((nss < 1) || (nss > 3)) {
            printk("%s : NSS greater than 3 or less than 1!(nss:%d)\n", __func__, nss);
            return 0;
        }

    }

    if(ieee80211_vap_256qam_is_set(ni->ni_vap) &&
        (((ieee80211_vap_get_opmode(vap) == IEEE80211_M_HOSTAP) && (ic->ic_vhtcap)) ||
        ((ieee80211_vap_get_opmode(vap) == IEEE80211_M_STA) && (ni->ni_vhtcap)))) {
       switch(curr_phy_mode) {
          case IEEE80211_MODE_11NG_HT20:
             if(((ieee80211_vap_get_opmode(vap) == IEEE80211_M_HOSTAP) &&
                                 !ieee80211_vap_ldpc_is_set(ni->ni_vap)) ||
                      ((ieee80211_vap_get_opmode(vap) == IEEE80211_M_STA) &&
                        !((ni->ni_htcap & IEEE80211_HTCAP_C_ADVCODING) &&
                          (ni->ni_vhtcap & IEEE80211_VHTCAP_RX_LDPC)))) {
                   /*256QAM 2G BCC rateset */
                 curr_phy_mode = IEEE80211_MODE_11AC_VHT80 + 1;
             } else {
                   /*256 QAM 2G LDPC rateset */
                 curr_phy_mode = IEEE80211_MODE_11AC_VHT80 + 2;
             }
          break;
          case IEEE80211_MODE_11NG_HT40PLUS:
          case IEEE80211_MODE_11NG_HT40MINUS:
          case IEEE80211_MODE_11NG_HT40:
                /*256 QAM 2G */
             curr_phy_mode = IEEE80211_MODE_11AC_VHT80 + 3;
          break;
          default:
          break;
       }
    }

    if (sgi) {
        return (max_rates[curr_phy_mode][(nss * 2) - 1] * 10);
    } else {
        return (max_rates[curr_phy_mode][(nss - 1) * 2] * 10);
    }
}