iwlwifi: mvm: close the SP if we send fewer frames than expected in SP
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 5 Nov 2015 08:32:31 +0000 (10:32 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 13 Dec 2015 07:42:56 +0000 (09:42 +0200)
When we have holes in the BA window, there might be frames
that have been ACKed between the read and the right
pointers. This means that these frames won't be scheduled
again by the SCD and the firwmare won't see them.
This invalidates the number of frames we tell the firmware
to send. When we detect this case, tell mac80211 to close
the SP and to send an EOSP so that the firmware can be in
sync.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index 566b65944fb8a08f78d0d9fd9480537f392a715c..78ff21a88a8b83fb4e0b8125cba1b9775c1b51cd 100644 (file)
@@ -1664,6 +1664,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
         */
        if (agg) {
                int remaining = cnt;
+               int sleep_tx_count;
 
                spin_lock_bh(&mvmsta->lock);
                for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) {
@@ -1688,9 +1689,12 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                        }
                        remaining -= n_queued;
                }
+               sleep_tx_count = cnt - remaining;
+               if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
+                       mvmsta->sleep_tx_count = sleep_tx_count;
                spin_unlock_bh(&mvmsta->lock);
 
-               cmd.sleep_tx_count = cpu_to_le16(cnt - remaining);
+               cmd.sleep_tx_count = cpu_to_le16(sleep_tx_count);
                if (WARN_ON(cnt - remaining == 0)) {
                        ieee80211_sta_eosp(sta);
                        return;
index 0631cc0a6d3c908d71c93270a15679270272c6c7..ce1b16ac4c6632cf08f63a610b06a926e61fa50a 100644 (file)
@@ -303,6 +303,11 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
  * @tt_tx_protection: is thermal throttling enable Tx protection?
  * @disable_tx: is tx to this STA disabled?
  * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
+ * @sleep_tx_count: the number of frames that we told the firmware to let out
+ *     even when that station is asleep. This is useful in case the queue
+ *     gets empty before all the frames were sent, which can happen when
+ *     we are sending frames from an AMPDU queue and there was a hole in
+ *     the BA window. To be used for UAPSD only.
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is placed in that
@@ -329,6 +334,7 @@ struct iwl_mvm_sta {
 
        bool disable_tx;
        u8 agg_tids;
+       u8 sleep_tx_count;
 };
 
 static inline struct iwl_mvm_sta *
index aaebb5d4462ab046da0bcf886bc94f03b4c2766d..cc0cdce84954b9b8d3c00d454966246914511a56 100644 (file)
@@ -788,13 +788,43 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                if (tid != IWL_TID_NON_QOS) {
                        struct iwl_mvm_tid_data *tid_data =
                                &mvmsta->tid_data[tid];
+                       bool send_eosp_ndp = false;
 
                        spin_lock_bh(&mvmsta->lock);
                        tid_data->next_reclaimed = next_reclaimed;
                        IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
                                           next_reclaimed);
                        iwl_mvm_check_ratid_empty(mvm, sta, tid);
+
+                       if (mvmsta->sleep_tx_count) {
+                               mvmsta->sleep_tx_count--;
+                               if (mvmsta->sleep_tx_count &&
+                                   !iwl_mvm_tid_queued(tid_data)) {
+                                       /*
+                                        * The number of frames in the queue
+                                        * dropped to 0 even if we sent less
+                                        * frames than we thought we had on the
+                                        * Tx queue.
+                                        * This means we had holes in the BA
+                                        * window that we just filled, ask
+                                        * mac80211 to send EOSP since the
+                                        * firmware won't know how to do that.
+                                        * Send NDP and the firmware will send
+                                        * EOSP notification that will trigger
+                                        * a call to ieee80211_sta_eosp().
+                                        */
+                                       send_eosp_ndp = true;
+                               }
+                       }
+
                        spin_unlock_bh(&mvmsta->lock);
+                       if (send_eosp_ndp) {
+                               iwl_mvm_sta_modify_sleep_tx_count(mvm, sta,
+                                       IEEE80211_FRAME_RELEASE_UAPSD,
+                                       1, tid, false, false);
+                               mvmsta->sleep_tx_count = 0;
+                               ieee80211_send_eosp_nullfunc(sta, tid);
+                       }
                }
 
                if (mvmsta->next_status_eosp) {