mac80211: change RX aggregation locking
authorJohannes Berg <johannes.berg@intel.com>
Thu, 10 Jun 2010 08:21:46 +0000 (10:21 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 14 Jun 2010 19:39:28 +0000 (15:39 -0400)
To prepare for allowing drivers to sleep in
ampdu_action, change the locking in the RX
aggregation code to use a mutex, so that it
would already allow drivers to sleep. But
explicitly disable BHs around the callback
for now since the TX part cannot yet sleep,
and drivers' locking might require it.

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/driver-ops.h
net/mac80211/ht.c
net/mac80211/iface.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h

index aa858a03951cb66efe920ec5d5c969507ac7210a..a843df26f384898146d257294be13ef571ee3199 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2008, Intel Corporation
+ * Copyright 2007-2010, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -38,7 +38,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_rx *tid_rx;
 
-       lockdep_assert_held(&sta->lock);
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
        tid_rx = sta->ampdu_mlme.tid_rx[tid];
 
@@ -70,9 +70,9 @@ 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)
 {
-       spin_lock_bh(&sta->lock);
+       mutex_lock(&sta->ampdu_mlme.mtx);
        ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
-       spin_unlock_bh(&sta->lock);
+       mutex_unlock(&sta->ampdu_mlme.mtx);
 }
 
 /*
@@ -205,7 +205,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
 
        /* examine state machine */
-       spin_lock_bh(&sta->lock);
+       mutex_lock(&sta->ampdu_mlme.mtx);
 
        if (sta->ampdu_mlme.tid_rx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -279,7 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
 
 end:
-       spin_unlock_bh(&sta->lock);
+       mutex_unlock(&sta->ampdu_mlme.mtx);
 
 end_no_lock:
        ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
index 7d18a3245e3d8475cb045d52977827d00649bc9a..e5e7ef175ca235efe069251e7d346df57a3b98ef 100644 (file)
@@ -349,9 +349,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
                                   u16 *ssn)
 {
        int ret = -EOPNOTSUPP;
+       local_bh_disable();
        if (local->ops->ampdu_action)
                ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
                                               sta, tid, ssn);
+       local_bh_enable();
        trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
        return ret;
 }
index 730f8089678e6db158bad6e46281e05820a57e84..e29be64083c3072bee3e897a89cb0fd3d581532d 100644 (file)
@@ -130,13 +130,17 @@ void ieee80211_ba_session_work(struct work_struct *work)
        if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
                return;
 
-       spin_lock_bh(&sta->lock);
+       mutex_lock(&sta->ampdu_mlme.mtx);
        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);
+       }
+       mutex_unlock(&sta->ampdu_mlme.mtx);
 
+       spin_lock_bh(&sta->lock);
+       for (tid = 0; tid < STA_TID_NUM; tid++) {
                tid_tx = sta->ampdu_mlme.tid_tx[tid];
                if (!tid_tx)
                        continue;
index 9f00d3f174e426d6178e6a5afa5c4aae56656cb6..490be2f3af27de722f3e3bc7e06a5f4135370678 100644 (file)
@@ -740,7 +740,7 @@ static void ieee80211_iface_work(struct work_struct *work)
                           mgmt->u.action.category == WLAN_CATEGORY_BACK) {
                        int len = skb->len;
 
-                       rcu_read_lock();
+                       mutex_lock(&local->sta_mtx);
                        sta = sta_info_get(sdata, mgmt->sa);
                        if (sta) {
                                switch (mgmt->u.action.u.addba_req.action_code) {
@@ -761,7 +761,7 @@ static void ieee80211_iface_work(struct work_struct *work)
                                        break;
                                }
                        }
-                       rcu_read_unlock();
+                       mutex_unlock(&local->sta_mtx);
                } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
                        struct ieee80211_hdr *hdr = (void *)mgmt;
                        /*
@@ -781,7 +781,7 @@ static void ieee80211_iface_work(struct work_struct *work)
                         * a block-ack session was active. That cannot be
                         * right, so terminate the session.
                         */
-                       rcu_read_lock();
+                       mutex_lock(&local->sta_mtx);
                        sta = sta_info_get(sdata, mgmt->sa);
                        if (sta) {
                                u16 tid = *ieee80211_get_qos_ctl(hdr) &
@@ -791,7 +791,7 @@ static void ieee80211_iface_work(struct work_struct *work)
                                        sta, tid, WLAN_BACK_RECIPIENT,
                                        WLAN_REASON_QSTA_REQUIRE_SETUP);
                        }
-                       rcu_read_unlock();
+                       mutex_unlock(&local->sta_mtx);
                } else switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        ieee80211_sta_rx_queued_mgmt(sdata, skb);
index bd726c6204df557e24719672c111de9675202a41..f54d8ba7d78844a3840ea9ae8e488a148ed42a7c 100644 (file)
@@ -236,6 +236,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        spin_lock_init(&sta->flaglock);
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+       mutex_init(&sta->ampdu_mlme.mtx);
 
        memcpy(sta->sta.addr, addr, ETH_ALEN);
        sta->local = local;
index 500bafe0a0bb31fdc1f6bb2dd4029804648c3b74..10d0fcb417ae07e4d0a99ee387f2859c796bad69 100644 (file)
@@ -142,8 +142,11 @@ struct tid_ampdu_rx {
  * @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
+ * @mtx: mutex to protect all TX data (except non-NULL assignments
+ *     to tid_tx[idx], which are protected by the sta spinlock)
  */
 struct sta_ampdu_mlme {
+       struct mutex mtx;
        /* rx */
        struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];