Commit 2fd647f8 authored by Eliad Peller's avatar Eliad Peller Committed by Emmanuel Grumbach

iwlwifi: mvm: add ATPC implementation

Implement Adaptive Tx Power Control algorithm.

ATPC basically tries to decrease the tx power
as much as possible while the throughput is
not being hurt.
Signed-off-by: default avatarEliad Peller <eliadx.peller@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 3a84b69e
......@@ -1215,6 +1215,17 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT;
}
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
enum ieee80211_band band)
{
u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
if (band != IEEE80211_BAND_2GHZ)
return false;
return bt_activity >= BT_LOW_TRAFFIC;
}
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_tx_info *info, u8 ac)
{
......
......@@ -936,6 +936,8 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
enum ieee80211_band band);
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_tx_info *info, u8 ac);
int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable);
......
......@@ -509,6 +509,9 @@ static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&tbl->win[i]);
for (i = 0; i < ARRAY_SIZE(tbl->tpc_win); i++)
rs_rate_scale_clear_window(&tbl->tpc_win[i]);
}
static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
......@@ -639,9 +642,11 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
}
static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
int scale_index, int attempts, int successes)
int scale_index, int attempts, int successes,
u8 reduced_txp)
{
struct iwl_rate_scale_data *window = NULL;
int ret;
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
return -EINVAL;
......@@ -649,6 +654,15 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
/* Select window for current tx bit rate */
window = &(tbl->win[scale_index]);
ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes,
window);
if (ret)
return ret;
if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION))
return -EINVAL;
window = &tbl->tpc_win[reduced_txp];
return _rs_collect_tx_data(tbl, scale_index, attempts, successes,
window);
}
......@@ -982,6 +996,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
u32 ucode_rate;
struct rs_rate rate;
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0];
/* Treat uninitialized rate scaling data same as non-existing. */
if (!lq_sta) {
......@@ -1106,7 +1121,8 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
rs_collect_tx_data(curr_tbl, rate.index,
info->status.ampdu_len,
info->status.ampdu_ack_len);
info->status.ampdu_ack_len,
reduced_txp);
/* Update success/fail counts if not searching for new mode */
if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
......@@ -1140,7 +1156,8 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
continue;
rs_collect_tx_data(tmp_tbl, rate.index, 1,
i < retries ? 0 : legacy_success);
i < retries ? 0 : legacy_success,
reduced_txp);
}
/* Update success/fail counts if not searching for new mode */
......@@ -1151,6 +1168,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
}
/* The last TX rate is cached in lq_sta; it's set in if/else above */
lq_sta->last_rate_n_flags = ucode_rate;
IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
done:
/* See if there's a better rate or modulation mode to try. */
if (sta && sta->supp_rates[sband->band])
......@@ -1724,6 +1742,189 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
return action;
}
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
int *weaker, int *stronger)
{
*weaker = index + TPC_TX_POWER_STEP;
if (*weaker > TPC_MAX_REDUCTION)
*weaker = TPC_INVALID;
*stronger = index - TPC_TX_POWER_STEP;
if (*stronger < 0)
*stronger = TPC_INVALID;
}
static bool rs_tpc_allowed(struct iwl_mvm *mvm, struct rs_rate *rate,
enum ieee80211_band band)
{
int index = rate->index;
/*
* allow tpc only if power management is enabled, or bt coex
* activity grade allows it and we are on 2.4Ghz.
*/
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM &&
!iwl_mvm_bt_coex_is_tpc_allowed(mvm, band))
return false;
IWL_DEBUG_RATE(mvm, "check rate, table type: %d\n", rate->type);
if (is_legacy(rate))
return index == IWL_RATE_54M_INDEX;
if (is_ht(rate))
return index == IWL_RATE_MCS_7_INDEX;
if (is_vht(rate))
return index == IWL_RATE_MCS_7_INDEX ||
index == IWL_RATE_MCS_8_INDEX ||
index == IWL_RATE_MCS_9_INDEX;
WARN_ON_ONCE(1);
return false;
}
enum tpc_action {
TPC_ACTION_STAY,
TPC_ACTION_DECREASE,
TPC_ACTION_INCREASE,
TPC_ACTION_NO_RESTIRCTION,
};
static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
s32 sr, int weak, int strong,
int current_tpt,
int weak_tpt, int strong_tpt)
{
/* stay until we have valid tpt */
if (current_tpt == IWL_INVALID_VALUE) {
IWL_DEBUG_RATE(mvm, "no current tpt. stay.\n");
return TPC_ACTION_STAY;
}
/* Too many failures, increase txp */
if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) {
IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n");
return TPC_ACTION_NO_RESTIRCTION;
}
/* try decreasing first if applicable */
if (weak != TPC_INVALID) {
if (weak_tpt == IWL_INVALID_VALUE &&
(strong_tpt == IWL_INVALID_VALUE ||
current_tpt >= strong_tpt)) {
IWL_DEBUG_RATE(mvm,
"no weak txp measurement. decrease txp\n");
return TPC_ACTION_DECREASE;
}
if (weak_tpt > current_tpt) {
IWL_DEBUG_RATE(mvm,
"lower txp has better tpt. decrease txp\n");
return TPC_ACTION_DECREASE;
}
}
/* next, increase if needed */
if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) {
if (weak_tpt == IWL_INVALID_VALUE &&
strong_tpt != IWL_INVALID_VALUE &&
current_tpt < strong_tpt) {
IWL_DEBUG_RATE(mvm,
"higher txp has better tpt. increase txp\n");
return TPC_ACTION_INCREASE;
}
if (weak_tpt < current_tpt &&
(strong_tpt == IWL_INVALID_VALUE ||
strong_tpt > current_tpt)) {
IWL_DEBUG_RATE(mvm,
"lower txp has worse tpt. increase txp\n");
return TPC_ACTION_INCREASE;
}
}
IWL_DEBUG_RATE(mvm, "no need to increase or decrease txp - stay\n");
return TPC_ACTION_STAY;
}
static bool rs_tpc_perform(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl)
{
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
struct ieee80211_vif *vif = mvm_sta->vif;
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_band band;
struct iwl_rate_scale_data *window;
struct rs_rate *rate = &tbl->rate;
enum tpc_action action;
s32 sr;
u8 cur = lq_sta->lq.reduced_tpc;
int current_tpt;
int weak, strong;
int weak_tpt = IWL_INVALID_VALUE, strong_tpt = IWL_INVALID_VALUE;
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (WARN_ON(!chanctx_conf))
band = IEEE80211_NUM_BANDS;
else
band = chanctx_conf->def.chan->band;
rcu_read_unlock();
if (!rs_tpc_allowed(mvm, rate, band)) {
IWL_DEBUG_RATE(mvm,
"tpc is not allowed. remove txp restrictions");
lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION;
return cur != TPC_NO_REDUCTION;
}
rs_get_adjacent_txp(mvm, cur, &weak, &strong);
/* Collect measured throughputs for current and adjacent rates */
window = tbl->tpc_win;
sr = window[cur].success_ratio;
current_tpt = window[cur].average_tpt;
if (weak != TPC_INVALID)
weak_tpt = window[weak].average_tpt;
if (strong != TPC_INVALID)
strong_tpt = window[strong].average_tpt;
IWL_DEBUG_RATE(mvm,
"(TPC: %d): cur_tpt %d SR %d weak %d strong %d weak_tpt %d strong_tpt %d\n",
cur, current_tpt, sr, weak, strong,
weak_tpt, strong_tpt);
action = rs_get_tpc_action(mvm, sr, weak, strong,
current_tpt, weak_tpt, strong_tpt);
/* override actions if we are on the edge */
if (weak == TPC_INVALID && action == TPC_ACTION_DECREASE) {
IWL_DEBUG_RATE(mvm, "already in lowest txp, stay");
action = TPC_ACTION_STAY;
} else if (strong == TPC_INVALID &&
(action == TPC_ACTION_INCREASE ||
action == TPC_ACTION_NO_RESTIRCTION)) {
IWL_DEBUG_RATE(mvm, "already in highest txp, stay");
action = TPC_ACTION_STAY;
}
switch (action) {
case TPC_ACTION_DECREASE:
lq_sta->lq.reduced_tpc = weak;
return true;
case TPC_ACTION_INCREASE:
lq_sta->lq.reduced_tpc = strong;
return true;
case TPC_ACTION_NO_RESTIRCTION:
lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION;
return true;
case TPC_ACTION_STAY:
/* do nothing */
break;
}
return false;
}
/*
* Do rate scaling and search for new modulation mode.
*/
......@@ -1973,6 +2174,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
break;
case RS_ACTION_STAY:
/* No change */
update_lq = rs_tpc_perform(mvm, sta, lq_sta, tbl);
break;
default:
break;
}
......@@ -2584,6 +2787,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
rs_build_rates_table_from_fixed(mvm, lq_cmd,
lq_sta->band,
lq_sta->dbg_fixed_rate);
lq_cmd->reduced_tpc = 0;
ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
RATE_MCS_ANT_POS;
} else
......@@ -2787,6 +2991,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->lq.agg_disable_start_th,
lq_sta->lq.agg_frame_cnt_limit);
desc += sprintf(buff+desc, "reduced tpc=%d\n", lq_sta->lq.reduced_tpc);
desc += sprintf(buff+desc,
"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
lq_sta->lq.initial_rate_index[0],
......
......@@ -157,6 +157,13 @@ enum {
#define IWL_RATE_INCREASE_TH 6400 /* 50% */
#define RS_SR_FORCE_DECREASE 1920 /* 15% */
#define TPC_SR_FORCE_INCREASE 9600 /* 75% */
#define TPC_SR_NO_INCREASE 10880 /* 85% */
#define TPC_TX_POWER_STEP 3
#define TPC_MAX_REDUCTION 15
#define TPC_NO_REDUCTION 0
#define TPC_INVALID 0xff
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
......@@ -279,6 +286,8 @@ struct iwl_scale_tbl_info {
enum rs_column column;
const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
/* per txpower-reduction history */
struct iwl_rate_scale_data tpc_win[TPC_MAX_REDUCTION + 1];
};
enum {
......@@ -337,6 +346,9 @@ struct iwl_lq_sta {
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
u8 is_agg;
/* tx power reduce for this sta */
int tpc_reduce;
};
/* Initialize station's rate scaling information after adding station */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment