diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c index 8f8f6da45119..9ffa3d12d446 100644 --- a/sys/net80211/ieee80211_amrr.c +++ b/sys/net80211/ieee80211_amrr.c @@ -59,6 +59,30 @@ #define is_enough(amn) \ ((amn)->amn_txcnt > 10) +/* + * A table of MCS rates in a progression order + * by MCS/streams. + * + * This is to avoid the problem with MCS streams + * not necessarily being "higher is faster". + * + * This table maps each MCS rate (0..7) for each stream + * (1..4). It's not entirely by bitrate throughput, + * but it will be better than trying MCS 0..31 on + * a 4x4 device, and getting stuck at lower MCS rates + * at 1 stream before trying 2 and more streams. + */ +static int amrr_mcs_progression_list[] = { + 0x00, 0x08, 0x10, 0x18, + 0x01, 0x09, 0x11, 0x19, + 0x02, 0x0a, 0x12, 0x1a, + 0x03, 0x0b, 0x13, 0x1b, + 0x04, 0x0c, 0x14, 0x1c, + 0x05, 0x0d, 0x15, 0x1d, + 0x06, 0x0e, 0x16, 0x1e, + 0x07, 0x0f, 0x17, 0x1f, +}; + static void amrr_setinterval(const struct ieee80211vap *, int); static void amrr_init(struct ieee80211vap *); static void amrr_deinit(struct ieee80211vap *); @@ -225,6 +249,147 @@ amrr_node_deinit(struct ieee80211_node *ni) IEEE80211_FREE(ni->ni_rctls, M_80211_RATECTL); } +static int +amrr_map_rix_to_mcs(struct ieee80211_amrr *amrr, + struct ieee80211_node *ni, + int rix) +{ + const struct ieee80211_rateset *rs; + + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + return rs->rs_rates[rix] & IEEE80211_RATE_VAL; +} + +static int +amrr_map_mcs_to_nstreams(int mcs) +{ + return (mcs / 8); +} + +static int +amrr_map_mcs_to_base_mcs(int mcs) +{ + return (mcs % 8); +} + +static int +amrr_map_mcs_to_rix(struct ieee80211_amrr *amrr, + struct ieee80211_node *ni, + int mcs) +{ + const struct ieee80211_rateset *rs; + mcs &= IEEE80211_RATE_VAL; + + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + for (int i = 0; i < rs->rs_nrates; i++) { + if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == mcs) + return i; + } + + return -1; +} + +static int +amrr_find_ht_progression_idx(int mcs) +{ + mcs &= IEEE80211_RATE_VAL; + + for (int i = 0; i < nitems(amrr_mcs_progression_list); i++) { + if (amrr_mcs_progression_list[i] == mcs) + return i; + } + + return -1; +} + +/* + * Choose the next best rix given the current rix. + * + * The progression should go through each stream at + * a given base MCS rate before trying the next one up. + */ +static int +amrr_get_best_incr_rix(struct ieee80211_amrr *amrr, + struct ieee80211_amrr_node *amn, + struct ieee80211_node *ni, + int rix) +{ + const struct ieee80211_rateset *rs; + int mcs, idx; + + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + + mcs = amrr_map_rix_to_mcs(amrr, ni, rix) & IEEE80211_RATE_VAL; + idx = amrr_find_ht_progression_idx(mcs); + + if (idx == -1) + goto invalid_idx; + + /* Iterate idx forward until we find a valid rate */ + idx++; + while (idx < nitems(amrr_mcs_progression_list)) { + int r_mcs, r_rix; + /* See if the rate is in our rate table */ + r_mcs = amrr_mcs_progression_list[idx]; + + r_rix = amrr_map_mcs_to_rix(amrr, ni, r_mcs); + + if (r_rix != -1) + return r_rix; + + idx++; + } + + /* Default to just trying the next rix */ +invalid_idx: + if (rix + 1 >= rs->rs_nrates) + return rix; + + return rix + 1; +} + +/* + * Choose the previous best rix given the current rix. + */ +static int +amrr_get_best_decr_rix(struct ieee80211_amrr *amrr, + struct ieee80211_amrr_node *amn, + struct ieee80211_node *ni, + int rix) +{ + int mcs, idx; + + mcs = amrr_map_rix_to_mcs(amrr, ni, rix) & IEEE80211_RATE_VAL; + idx = amrr_find_ht_progression_idx(mcs); + + if (idx == -1 || idx == 0) + goto invalid_idx; + + /* Iterate idx backward until we find a valid rate */ + idx--; + while (idx >= 0) { + int r_mcs, r_rix; + + /* See if the rate is in our rate table */ + r_mcs = amrr_mcs_progression_list[idx]; + + r_rix = amrr_map_mcs_to_rix(amrr, ni, r_mcs); + + if (r_rix != -1) + return r_rix; + + idx--; + } + + /* Default to just trying the previous rix */ +invalid_idx: + if (rix == 0) + return 0; + + return rix - 1; +} + + static int amrr_update_ht(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, struct ieee80211_node *ni) @@ -255,7 +420,7 @@ amrr_update_ht(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, rix + 1 < rs->rs_nrates) { amn->amn_recovery = 1; amn->amn_success = 0; - rix++; + rix = amrr_get_best_incr_rix(amrr, amn, ni, rix); /* XXX TODO: we really need a rate-to-string method */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR increasing rate MCS %d " @@ -278,7 +443,7 @@ amrr_update_ht(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, amn->amn_success_threshold = amrr->amrr_min_success_threshold; } - rix--; + rix = amrr_get_best_decr_rix(amrr, amn, ni, rix); /* XXX TODO: we really need a rate-to-string method */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR decreasing rate MCS %d "