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