mac80211: defer RX agg session teardown to work
authorJohannes Berg <johannes.berg@intel.com>
Thu, 10 Jun 2010 08:21:44 +0000 (10:21 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 14 Jun 2010 19:39:28 +0000 (15:39 -0400)
Since we want the code to be able to sleep
in the future, it must not be called from
the timer directly. To prepare, move it out
into the aggregation work.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/agg-rx.c
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/sta_info.h

index bbf36d98023238b0d14977059b0dca63ce447032..1c4320b01e3cd3715bc958b1ea0be35504eedcf4 100644 (file)
@@ -32,21 +32,18 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
        kfree(tid_rx);
 }
 
-static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                           u16 initiator, u16 reason,
-                                           bool from_timer)
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+                                    u16 initiator, u16 reason)
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_rx *tid_rx;
 
-       spin_lock_bh(&sta->lock);
+       lockdep_assert_held(&sta->lock);
 
        tid_rx = sta->ampdu_mlme.tid_rx[tid];
 
-       if (!tid_rx) {
-               spin_unlock_bh(&sta->lock);
+       if (!tid_rx)
                return;
-       }
 
        rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
 
@@ -65,10 +62,7 @@ static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, 0, reason);
 
-       spin_unlock_bh(&sta->lock);
-
-       if (!from_timer)
-               del_timer_sync(&tid_rx->session_timer);
+       del_timer_sync(&tid_rx->session_timer);
 
        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
@@ -76,7 +70,9 @@ static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason)
 {
-       ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, false);
+       spin_lock_bh(&sta->lock);
+       ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+       spin_unlock_bh(&sta->lock);
 }
 
 /*
@@ -97,8 +93,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
 #endif
-       ___ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT,
-                                       WLAN_REASON_QSTA_TIMEOUT, true);
+       set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
+       ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
 
 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
index 531a19d358df4e8bf4e55e6fd8c25ea6c939f37f..730f8089678e6db158bad6e46281e05820a57e84 100644 (file)
@@ -132,6 +132,11 @@ void ieee80211_ba_session_work(struct work_struct *work)
 
        spin_lock_bh(&sta->lock);
        for (tid = 0; tid < STA_TID_NUM; tid++) {
+               if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
+                       ___ieee80211_stop_rx_ba_session(
+                               sta, tid, WLAN_BACK_RECIPIENT,
+                               WLAN_REASON_QSTA_TIMEOUT);
+
                tid_tx = sta->ampdu_mlme.tid_tx[tid];
                if (!tid_tx)
                        continue;
index 628a53db9f7e1a5eab4f01b3e261de9382ef33d6..9d753a02a2e4640790d282bf51e116fac0e26d87 100644 (file)
@@ -1096,6 +1096,8 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_smps_mode smps, const u8 *da,
                               const u8 *bssid);
 
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+                                    u16 initiator, u16 reason);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason);
 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
index 040cbb0ac3af5b5d524fe47b1e2c864dd063ab5a..500bafe0a0bb31fdc1f6bb2dd4029804648c3b74 100644 (file)
@@ -140,10 +140,13 @@ struct tid_ampdu_rx {
  * @addba_req_num: number of times addBA request has been sent.
  * @dialog_token_allocator: dialog token enumerator for each new session;
  * @work: work struct for starting/stopping aggregation
+ * @tid_rx_timer_expired: bitmap indicating on which TIDs the
+ *     RX timer expired until the work for it runs
  */
 struct sta_ampdu_mlme {
        /* rx */
        struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+       unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
        /* tx */
        struct work_struct work;
        struct tid_ampdu_tx *tid_tx[STA_TID_NUM];