iwlwifi: mvm: change open and close criteria of a BA session
authorGregory Greenman <gregory.greenman@intel.com>
Tue, 15 Aug 2017 09:27:01 +0000 (12:27 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 18 Aug 2017 14:24:04 +0000 (17:24 +0300)
Tx BA session should be started according to the current throughput
without any dependence on the internal rate scaling state. The criteria
for opening a BA session will be 10 frames per second.

Sending frequent del BAs can cause inter-op issues with some APs. We'll
not close a BA session until we receive an explicit del BA from the
peer.

Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/constants.h
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h

index 753d413..976640f 100644 (file)
 #define IWL_MVM_RS_SR_NO_DECREASE              85      /* percent */
 #define IWL_MVM_RS_AGG_TIME_LIMIT              4000    /* 4 msecs. valid 100-8000 */
 #define IWL_MVM_RS_AGG_DISABLE_START           3
+#define IWL_MVM_RS_AGG_START_THRESHOLD         10      /* num frames per second */
 #define IWL_MVM_RS_TPC_SR_FORCE_INCREASE       75      /* percent */
 #define IWL_MVM_RS_TPC_SR_NO_INCREASE          85      /* percent */
 #define IWL_MVM_RS_TPC_TX_POWER_STEP           3
index cdf10ce..44c8730 100644 (file)
@@ -622,7 +622,9 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
 
        IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n",
                     sta->addr, tid);
-       ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
+
+       /* start BA session until the peer sends del BA */
+       ret = ieee80211_start_tx_ba_session(sta, tid, 0);
        if (ret == -EAGAIN) {
                /*
                 * driver and mac80211 is out of sync
@@ -636,15 +638,31 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
        return ret;
 }
 
-static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid,
-                             struct iwl_lq_sta *lq_data,
+static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
+                             u8 tid, struct iwl_lq_sta *lq_sta,
                              struct ieee80211_sta *sta)
 {
-       if (tid < IWL_MAX_TID_COUNT)
-               rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta);
-       else
+       struct iwl_mvm_tid_data *tid_data;
+
+       /*
+        * In AP mode, tid can be equal to IWL_MAX_TID_COUNT
+        * when the frame is not QoS
+        */
+       if (WARN_ON_ONCE(tid > IWL_MAX_TID_COUNT)) {
                IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n",
                        tid, IWL_MAX_TID_COUNT);
+               return;
+       } else if (tid == IWL_MAX_TID_COUNT) {
+               return;
+       }
+
+       tid_data = &mvmsta->tid_data[tid];
+       if ((tid_data->state == IWL_AGG_OFF) &&
+           (lq_sta->tx_agg_tid_en & BIT(tid)) &&
+           (tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD)) {
+               IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid);
+               rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta);
+       }
 }
 
 static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
@@ -753,8 +771,38 @@ static int rs_collect_tpc_data(struct iwl_mvm *mvm,
                                    window);
 }
 
+static void rs_update_tid_tpt_stats(struct iwl_mvm *mvm,
+                                   struct iwl_mvm_sta *mvmsta,
+                                   u8 tid, int successes)
+{
+       struct iwl_mvm_tid_data *tid_data;
+
+       if (tid >= IWL_MAX_TID_COUNT)
+               return;
+
+       tid_data = &mvmsta->tid_data[tid];
+
+       /*
+        * Measure if there're enough successful transmits per second.
+        * These statistics are used only to decide if we can start a
+        * BA session, so it should be updated only when A-MPDU is
+        * off.
+        */
+       if (tid_data->state != IWL_AGG_OFF)
+               return;
+
+       if (time_is_before_jiffies(tid_data->tpt_meas_start + HZ) ||
+           (tid_data->tx_count >= IWL_MVM_RS_AGG_START_THRESHOLD)) {
+               tid_data->tx_count_last = tid_data->tx_count;
+               tid_data->tx_count = 0;
+               tid_data->tpt_meas_start = jiffies;
+       } else {
+               tid_data->tx_count += successes;
+       }
+}
+
 static int rs_collect_tlc_data(struct iwl_mvm *mvm,
-                              struct iwl_lq_sta *lq_sta,
+                              struct iwl_mvm_sta *mvmsta, u8 tid,
                               struct iwl_scale_tbl_info *tbl,
                               int scale_index, int attempts, int successes)
 {
@@ -764,12 +812,14 @@ static int rs_collect_tlc_data(struct iwl_mvm *mvm,
                return -EINVAL;
 
        if (tbl->column != RS_COLUMN_INVALID) {
-               struct lq_sta_pers *pers = &lq_sta->pers;
+               struct lq_sta_pers *pers = &mvmsta->lq_sta.pers;
 
                pers->tx_stats[tbl->column][scale_index].total += attempts;
                pers->tx_stats[tbl->column][scale_index].success += successes;
        }
 
+       rs_update_tid_tpt_stats(mvm, mvmsta, tid, successes);
+
        /* Select window for current tx bit rate */
        window = &(tbl->win[scale_index]);
        return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
@@ -1211,12 +1261,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (time_after(jiffies,
                       (unsigned long)(lq_sta->last_tx +
                                       (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
-               int t;
-
                IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
-               for (t = 0; t < IWL_MAX_TID_COUNT; t++)
-                       ieee80211_stop_tx_ba_session(sta, t);
-
                iwl_mvm_rs_rate_init(mvm, sta, info->band, false);
                return;
        }
@@ -1312,7 +1357,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                if (info->status.ampdu_ack_len == 0)
                        info->status.ampdu_len = 1;
 
-               rs_collect_tlc_data(mvm, lq_sta, curr_tbl, lq_rate.index,
+               rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl,
+                                   lq_rate.index,
                                    info->status.ampdu_len,
                                    info->status.ampdu_ack_len);
 
@@ -1351,7 +1397,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                            lq_rate.index, 1,
                                            i < retries ? 0 : legacy_success,
                                            reduced_txp);
-                       rs_collect_tlc_data(mvm, lq_sta, tmp_tbl,
+                       rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl,
                                            lq_rate.index, 1,
                                            i < retries ? 0 : legacy_success);
                }
@@ -2229,7 +2275,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        s32 sr;
        u8 prev_agg = lq_sta->is_agg;
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-       struct iwl_mvm_tid_data *tid_data;
        struct rs_rate *rate;
 
        lq_sta->is_agg = !!mvmsta->agg_tids;
@@ -2480,44 +2525,12 @@ lq_update:
                }
        }
 
+       if (!ndp)
+               rs_tl_turn_on_agg(mvm, mvmsta, tid, lq_sta, sta);
+
        if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
-               /* If the "active" (non-search) mode was legacy,
-                * and we've tried switching antennas,
-                * but we haven't been able to try HT modes (not available),
-                * stay with best antenna legacy modulation for a while
-                * before next round of mode comparisons. */
                tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               if (is_legacy(&tbl1->rate)) {
-                       IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
-
-                       if (tid != IWL_MAX_TID_COUNT) {
-                               tid_data = &mvmsta->tid_data[tid];
-                               if (tid_data->state != IWL_AGG_OFF) {
-                                       IWL_DEBUG_RATE(mvm,
-                                                      "Stop aggregation on tid %d\n",
-                                                      tid);
-                                       ieee80211_stop_tx_ba_session(sta, tid);
-                               }
-                       }
-                       rs_set_stay_in_table(mvm, 1, lq_sta);
-               } else {
-               /* If we're in an HT mode, and all 3 mode switch actions
-                * have been tried and compared, stay in this best modulation
-                * mode for a while before next round of mode comparisons. */
-                       if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
-                           (lq_sta->tx_agg_tid_en & (1 << tid)) &&
-                           (tid != IWL_MAX_TID_COUNT)) {
-                               tid_data = &mvmsta->tid_data[tid];
-                               if (tid_data->state == IWL_AGG_OFF && !ndp) {
-                                       IWL_DEBUG_RATE(mvm,
-                                                      "try to aggregate tid %d\n",
-                                                      tid);
-                                       rs_tl_turn_on_agg(mvm, tid,
-                                                         lq_sta, sta);
-                               }
-                       }
-                       rs_set_stay_in_table(mvm, 0, lq_sta);
-               }
+               rs_set_stay_in_table(mvm, is_legacy(&tbl1->rate), lq_sta);
        }
 }
 
index 005037a..d138938 100644 (file)
@@ -316,6 +316,10 @@ enum iwl_mvm_agg_state {
  * @is_tid_active: has this TID sent traffic in the last
  *     %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this
  *     field should be ignored.
+ * @tpt_meas_start: time of the throughput measurements start, is reset every HZ
+ * @tx_count_last: number of frames transmitted during the last second
+ * @tx_count: counts the number of frames transmitted since the last reset of
+ *      tpt_meas_start
  */
 struct iwl_mvm_tid_data {
        struct sk_buff_head deferred_tx_frames;
@@ -330,6 +334,9 @@ struct iwl_mvm_tid_data {
        u16 ssn;
        u16 tx_time;
        bool is_tid_active;
+       unsigned long tpt_meas_start;
+       u32 tx_count_last;
+       u32 tx_count;
 };
 
 struct iwl_mvm_key_pn {