ARM: tegra: dvfs: Add interface to set fmax at vmin
[linux-3.10.git] / net / mac80211 / agg-tx.c
index 7380287..13b7683 100644 (file)
@@ -55,6 +55,8 @@
  * @ampdu_action function will be called with the action
  * %IEEE80211_AMPDU_TX_STOP. In this case, the call must not fail,
  * and the driver must later call ieee80211_stop_tx_ba_cb_irqsafe().
+ * Note that the sta can get destroyed before the BA tear down is
+ * complete.
  */
 
 static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
@@ -105,7 +107,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.addba_req.start_seq_num =
                                        cpu_to_le16(start_seq_num << 4);
 
-       ieee80211_tx_skb(sdata, skb);
+       ieee80211_tx_skb_tid(sdata, skb, tid);
 }
 
 void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
@@ -133,8 +135,9 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
        bar->control = cpu_to_le16(bar_control);
        bar->start_seq_num = cpu_to_le16(ssn);
 
-       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-       ieee80211_tx_skb(sdata, skb);
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
+                                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+       ieee80211_tx_skb_tid(sdata, skb, tid);
 }
 EXPORT_SYMBOL(ieee80211_send_bar);
 
@@ -146,16 +149,133 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
        rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
 }
 
+static inline int ieee80211_ac_from_tid(int tid)
+{
+       return ieee802_1d_to_ac[tid & 7];
+}
+
+/*
+ * When multiple aggregation sessions on multiple stations
+ * are being created/destroyed simultaneously, we need to
+ * refcount the global queue stop caused by that in order
+ * to not get into a situation where one of the aggregation
+ * setup or teardown re-enables queues before the other is
+ * ready to handle that.
+ *
+ * These two functions take care of this issue by keeping
+ * a global "agg_queue_stop" refcount.
+ */
+static void __acquires(agg_queue)
+ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
+{
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+
+       if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
+               ieee80211_stop_queue_by_reason(
+                       &sdata->local->hw, queue,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+       __acquire(agg_queue);
+}
+
+static void __releases(agg_queue)
+ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
+{
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+
+       if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
+               ieee80211_wake_queue_by_reason(
+                       &sdata->local->hw, queue,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+       __release(agg_queue);
+}
+
+/*
+ * splice packets from the STA's pending to the local pending,
+ * requires a call to ieee80211_agg_splice_finish later
+ */
+static void __acquires(agg_queue)
+ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
+                            struct tid_ampdu_tx *tid_tx, u16 tid)
+{
+       struct ieee80211_local *local = sdata->local;
+       int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
+       unsigned long flags;
+
+       ieee80211_stop_queue_agg(sdata, tid);
+
+       if (WARN(!tid_tx,
+                "TID %d gone but expected when splicing aggregates from the pending queue\n",
+                tid))
+               return;
+
+       if (!skb_queue_empty(&tid_tx->pending)) {
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               /* copy over remaining packets */
+               skb_queue_splice_tail_init(&tid_tx->pending,
+                                          &local->pending[queue]);
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       }
+}
+
+static void __releases(agg_queue)
+ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
+{
+       ieee80211_wake_queue_agg(sdata, tid);
+}
+
+static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
+{
+       struct tid_ampdu_tx *tid_tx;
+
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       lockdep_assert_held(&sta->lock);
+
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+
+       /*
+        * When we get here, the TX path will not be lockless any more wrt.
+        * aggregation, since the OPERATIONAL bit has long been cleared.
+        * Thus it will block on getting the lock, if it occurs. So if we
+        * stop the queue now, we will not get any more packets, and any
+        * that might be being processed will wait for us here, thereby
+        * guaranteeing that no packets go to the tid_tx pending queue any
+        * more.
+        */
+
+       ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
+
+       /* future packets must not find the tid_tx struct any more */
+       ieee80211_assign_tid_tx(sta, tid, NULL);
+
+       ieee80211_agg_splice_finish(sta->sdata, tid);
+
+       kfree_rcu(tid_tx, rcu_head);
+}
+
 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                   enum ieee80211_back_parties initiator,
-                                   bool tx)
+                                   enum ieee80211_agg_stop_reason reason)
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_tx *tid_tx;
+       enum ieee80211_ampdu_mlme_action action;
        int ret;
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
+       switch (reason) {
+       case AGG_STOP_DECLINED:
+       case AGG_STOP_LOCAL_REQUEST:
+       case AGG_STOP_PEER_REQUEST:
+               action = IEEE80211_AMPDU_TX_STOP_CONT;
+               break;
+       case AGG_STOP_DESTROY_STA:
+               action = IEEE80211_AMPDU_TX_STOP_FLUSH;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+
        spin_lock_bh(&sta->lock);
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
@@ -164,10 +284,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                return -ENOENT;
        }
 
-       /* if we're already stopping ignore any new requests to stop */
+       /*
+        * if we're already stopping ignore any new requests to stop
+        * unless we're destroying it in which case notify the driver
+        */
        if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
                spin_unlock_bh(&sta->lock);
-               return -EALREADY;
+               if (reason != AGG_STOP_DESTROY_STA)
+                       return -EALREADY;
+               ret = drv_ampdu_action(local, sta->sdata,
+                                      IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
+                                      &sta->sta, tid, NULL, 0);
+               WARN_ON_ONCE(ret);
+               return 0;
        }
 
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
@@ -182,10 +311,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        spin_unlock_bh(&sta->lock);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+       ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n",
               sta->sta.addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
        del_timer_sync(&tid_tx->addba_resp_timer);
        del_timer_sync(&tid_tx->session_timer);
@@ -211,11 +338,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
         */
        synchronize_net();
 
-       tid_tx->stop_initiator = initiator;
-       tid_tx->tx_stop = tx;
+       tid_tx->stop_initiator = reason == AGG_STOP_PEER_REQUEST ?
+                                       WLAN_BACK_RECIPIENT :
+                                       WLAN_BACK_INITIATOR;
+       tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
 
-       ret = drv_ampdu_action(local, sta->sdata,
-                              IEEE80211_AMPDU_TX_STOP,
+       ret = drv_ampdu_action(local, sta->sdata, action,
                               &sta->sta, tid, NULL, 0);
 
        /* HW shall not deny going back to legacy */
@@ -226,7 +354,17 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                 */
        }
 
-       return ret;
+       /*
+        * In the case of AGG_STOP_DESTROY_STA, the driver won't
+        * necessarily call ieee80211_stop_tx_ba_cb(), so this may
+        * seem like we can leave the tid_tx data pending forever.
+        * This is true, in a way, but "forever" is only until the
+        * station struct is actually destroyed. In the meantime,
+        * leaving it around ensures that we don't transmit packets
+        * to the driver on this TID which might confuse it.
+        */
+
+       return 0;
 }
 
 /*
@@ -251,94 +389,19 @@ static void sta_addba_resp_timer_expired(unsigned long data)
        if (!tid_tx ||
            test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
                rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "timer expired on tid %d but we are not "
-                               "(or no longer) expecting addBA response there\n",
-                       tid);
-#endif
+               ht_dbg(sta->sdata,
+                      "timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n",
+                      sta->sta.addr, tid);
                return;
        }
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "addBA response timer expired on %pM tid %d\n",
+              sta->sta.addr, tid);
 
        ieee80211_stop_tx_ba_session(&sta->sta, tid);
        rcu_read_unlock();
 }
 
-static inline int ieee80211_ac_from_tid(int tid)
-{
-       return ieee802_1d_to_ac[tid & 7];
-}
-
-/*
- * When multiple aggregation sessions on multiple stations
- * are being created/destroyed simultaneously, we need to
- * refcount the global queue stop caused by that in order
- * to not get into a situation where one of the aggregation
- * setup or teardown re-enables queues before the other is
- * ready to handle that.
- *
- * These two functions take care of this issue by keeping
- * a global "agg_queue_stop" refcount.
- */
-static void __acquires(agg_queue)
-ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
-{
-       int queue = ieee80211_ac_from_tid(tid);
-
-       if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
-               ieee80211_stop_queue_by_reason(
-                       &local->hw, queue,
-                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-       __acquire(agg_queue);
-}
-
-static void __releases(agg_queue)
-ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
-{
-       int queue = ieee80211_ac_from_tid(tid);
-
-       if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
-               ieee80211_wake_queue_by_reason(
-                       &local->hw, queue,
-                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-       __release(agg_queue);
-}
-
-/*
- * splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish later
- */
-static void __acquires(agg_queue)
-ieee80211_agg_splice_packets(struct ieee80211_local *local,
-                            struct tid_ampdu_tx *tid_tx, u16 tid)
-{
-       int queue = ieee80211_ac_from_tid(tid);
-       unsigned long flags;
-
-       ieee80211_stop_queue_agg(local, tid);
-
-       if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
-                         " from the pending queue\n", tid))
-               return;
-
-       if (!skb_queue_empty(&tid_tx->pending)) {
-               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               /* copy over remaining packets */
-               skb_queue_splice_tail_init(&tid_tx->pending,
-                                          &local->pending[queue]);
-               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-       }
-}
-
-static void __releases(agg_queue)
-ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
-{
-       ieee80211_wake_queue_agg(local, tid);
-}
-
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
        struct tid_ampdu_tx *tid_tx;
@@ -369,14 +432,13 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
        ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
                               &sta->sta, tid, &start_seq_num, 0);
        if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - HW unavailable for"
-                                       " tid %d\n", tid);
-#endif
+               ht_dbg(sdata,
+                      "BA request denied - HW unavailable for %pM tid %d\n",
+                      sta->sta.addr, tid);
                spin_lock_bh(&sta->lock);
-               ieee80211_agg_splice_packets(local, tid_tx, tid);
+               ieee80211_agg_splice_packets(sdata, tid_tx, tid);
                ieee80211_assign_tid_tx(sta, tid, NULL);
-               ieee80211_agg_splice_finish(local, tid);
+               ieee80211_agg_splice_finish(sdata, tid);
                spin_unlock_bh(&sta->lock);
 
                kfree_rcu(tid_tx, rcu_head);
@@ -385,11 +447,11 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 
        /* activate the timer for the recipient's addBA response */
        mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
+       ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
+              sta->sta.addr, tid);
 
        spin_lock_bh(&sta->lock);
+       sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
        sta->ampdu_mlme.addba_req_num[tid]++;
        spin_unlock_bh(&sta->lock);
 
@@ -414,10 +476,27 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
        u8 *timer_to_id = ptid - *ptid;
        struct sta_info *sta = container_of(timer_to_id, struct sta_info,
                                         timer_to_tid[0]);
+       struct tid_ampdu_tx *tid_tx;
+       unsigned long timeout;
+
+       rcu_read_lock();
+       tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]);
+       if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+               rcu_read_unlock();
+               return;
+       }
+
+       timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
+       if (time_is_after_jiffies(timeout)) {
+               mod_timer(&tid_tx->session_timer, timeout);
+               rcu_read_unlock();
+               return;
+       }
+
+       rcu_read_unlock();
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+       ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
+              sta->sta.addr, (u16)*ptid);
 
        ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
 }
@@ -433,18 +512,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 
        trace_api_start_tx_ba_session(pubsta, tid);
 
-       if (WARN_ON(!local->ops->ampdu_action))
+       if (WARN_ON_ONCE(!local->ops->ampdu_action))
                return -EINVAL;
 
-       if ((tid >= STA_TID_NUM) ||
+       if ((tid >= IEEE80211_NUM_TIDS) ||
            !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) ||
            (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
                return -EINVAL;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+       ht_dbg(sdata, "Open BA session requested for %pM tid %u\n",
               pubsta->addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
            sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
@@ -454,10 +531,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                return -EINVAL;
 
        if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA sessions blocked. "
-                      "Denying BA session request\n");
-#endif
+               ht_dbg(sdata,
+                      "BA sessions blocked - Denying BA session request %pM tid %d\n",
+                      sta->sta.addr, tid);
                return -EINVAL;
        }
 
@@ -475,10 +551,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
         */
        if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
            !sta->sta.ht_cap.ht_supported) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
-                      "does not advertise HT support\n", pubsta->addr);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg(sdata,
+                      "BA request denied - IBSS STA %pM does not advertise HT support\n",
+                      pubsta->addr);
                return -EINVAL;
        }
 
@@ -490,13 +565,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                goto err_unlock_sta;
        }
 
+       /*
+        * if we have tried more than HT_AGG_BURST_RETRIES times we
+        * will spread our requests in time to avoid stalling connection
+        * for too long
+        */
+       if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
+           time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
+                       HT_AGG_RETRIES_PERIOD)) {
+               ht_dbg(sdata,
+                      "BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n",
+                      sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
+               ret = -EBUSY;
+               goto err_unlock_sta;
+       }
+
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        /* check if the TID is not in aggregation flow already */
        if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - session is not "
-                                "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg(sdata,
+                      "BA request denied - session is not idle on %pM tid %u\n",
+                      sta->sta.addr, tid);
                ret = -EAGAIN;
                goto err_unlock_sta;
        }
@@ -521,7 +610,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        /* tx timer */
        tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
        tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
-       init_timer(&tid_tx->session_timer);
+       init_timer_deferrable(&tid_tx->session_timer);
 
        /* assign a dialog token */
        sta->ampdu_mlme.dialog_token_allocator++;
@@ -551,9 +640,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
+              sta->sta.addr, tid);
 
        drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
@@ -565,14 +653,14 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
         */
        spin_lock_bh(&sta->lock);
 
-       ieee80211_agg_splice_packets(local, tid_tx, tid);
+       ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
        /*
         * Now mark as operational. This will be visible
         * in the TX path, and lets it go lock-free in
         * the common case.
         */
        set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
-       ieee80211_agg_splice_finish(local, tid);
+       ieee80211_agg_splice_finish(sta->sdata, tid);
 
        spin_unlock_bh(&sta->lock);
 }
@@ -586,11 +674,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 
        trace_api_start_tx_ba_cb(sdata, ra, tid);
 
-       if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-                               tid, STA_TID_NUM);
-#endif
+       if (tid >= IEEE80211_NUM_TIDS) {
+               ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+                      tid, IEEE80211_NUM_TIDS);
                return;
        }
 
@@ -598,9 +684,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
                mutex_unlock(&local->sta_mtx);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+               ht_dbg(sdata, "Could not find station: %pM\n", ra);
                return;
        }
 
@@ -608,9 +692,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (WARN_ON(!tid_tx)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "addBA was not requested!\n");
-#endif
+               ht_dbg(sdata, "addBA was not requested!\n");
                goto unlock;
        }
 
@@ -647,14 +729,13 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
 
 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
-                                  enum ieee80211_back_parties initiator,
-                                  bool tx)
+                                  enum ieee80211_agg_stop_reason reason)
 {
        int ret;
 
        mutex_lock(&sta->ampdu_mlme.mtx);
 
-       ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
+       ret = ___ieee80211_stop_tx_ba_session(sta, tid, reason);
 
        mutex_unlock(&sta->ampdu_mlme.mtx);
 
@@ -674,7 +755,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
        if (!local->ops->ampdu_action)
                return -EINVAL;
 
-       if (tid >= STA_TID_NUM)
+       if (tid >= IEEE80211_NUM_TIDS)
                return -EINVAL;
 
        spin_lock_bh(&sta->lock);
@@ -709,26 +790,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 
        trace_api_stop_tx_ba_cb(sdata, ra, tid);
 
-       if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-                               tid, STA_TID_NUM);
-#endif
+       if (tid >= IEEE80211_NUM_TIDS) {
+               ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+                      tid, IEEE80211_NUM_TIDS);
                return;
        }
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
-              ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+       ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid);
 
        mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+               ht_dbg(sdata, "Could not find station: %pM\n", ra);
                goto unlock;
        }
 
@@ -737,9 +811,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
+               ht_dbg(sdata,
+                      "unexpected callback to A-MPDU stop for %pM tid %d\n",
+                      sta->sta.addr, tid);
                goto unlock_sta;
        }
 
@@ -747,24 +821,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
                ieee80211_send_delba(sta->sdata, ra, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-       /*
-        * When we get here, the TX path will not be lockless any more wrt.
-        * aggregation, since the OPERATIONAL bit has long been cleared.
-        * Thus it will block on getting the lock, if it occurs. So if we
-        * stop the queue now, we will not get any more packets, and any
-        * that might be being processed will wait for us here, thereby
-        * guaranteeing that no packets go to the tid_tx pending queue any
-        * more.
-        */
-
-       ieee80211_agg_splice_packets(local, tid_tx, tid);
-
-       /* future packets must not find the tid_tx struct any more */
-       ieee80211_assign_tid_tx(sta, tid, NULL);
-
-       ieee80211_agg_splice_finish(local, tid);
-
-       kfree_rcu(tid_tx, rcu_head);
+       ieee80211_remove_tid_tx(sta, tid);
 
  unlock_sta:
        spin_unlock_bh(&sta->lock);
@@ -815,17 +872,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                goto out;
 
        if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif
+               ht_dbg(sta->sdata, "wrong addBA response token, %pM tid %d\n",
+                      sta->sta.addr, tid);
                goto out;
        }
 
        del_timer_sync(&tid_tx->addba_resp_timer);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "switched off addBA timer for %pM tid %d\n",
+              sta->sta.addr, tid);
 
        /*
         * addba_resp_timer may have fired before we got here, and
@@ -834,11 +889,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
         */
        if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
            test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG
-                      "got addBA resp for tid %d but we already gave up\n",
-                      tid);
-#endif
+               ht_dbg(sta->sdata,
+                      "got addBA resp for %pM tid %d but we already gave up\n",
+                      sta->sta.addr, tid);
                goto out;
        }
 
@@ -863,13 +916,14 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 
                sta->ampdu_mlme.addba_req_num[tid] = 0;
 
-               if (tid_tx->timeout)
+               if (tid_tx->timeout) {
                        mod_timer(&tid_tx->session_timer,
                                  TU_TO_EXP_TIME(tid_tx->timeout));
+                       tid_tx->last_tx = jiffies;
+               }
 
        } else {
-               ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
-                                               true);
+               ___ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_DECLINED);
        }
 
  out: