Commit a93e3644 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: change RX aggregation locking

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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f955ebb4
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * 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 * 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 * 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, ...@@ -38,7 +38,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
struct ieee80211_local *local = sta->local; struct ieee80211_local *local = sta->local;
struct tid_ampdu_rx *tid_rx; 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]; tid_rx = sta->ampdu_mlme.tid_rx[tid];
...@@ -70,9 +70,9 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 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, void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason) u16 initiator, u16 reason)
{ {
spin_lock_bh(&sta->lock); mutex_lock(&sta->ampdu_mlme.mtx);
___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason); ___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, ...@@ -205,7 +205,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* examine state machine */ /* examine state machine */
spin_lock_bh(&sta->lock); mutex_lock(&sta->ampdu_mlme.mtx);
if (sta->ampdu_mlme.tid_rx[tid]) { if (sta->ampdu_mlme.tid_rx[tid]) {
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
...@@ -279,7 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, ...@@ -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)); mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
end: end:
spin_unlock_bh(&sta->lock); mutex_unlock(&sta->ampdu_mlme.mtx);
end_no_lock: end_no_lock:
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
......
...@@ -349,9 +349,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, ...@@ -349,9 +349,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
u16 *ssn) u16 *ssn)
{ {
int ret = -EOPNOTSUPP; int ret = -EOPNOTSUPP;
local_bh_disable();
if (local->ops->ampdu_action) if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
sta, tid, ssn); sta, tid, ssn);
local_bh_enable();
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret); trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
return ret; return ret;
} }
......
...@@ -130,13 +130,17 @@ void ieee80211_ba_session_work(struct work_struct *work) ...@@ -130,13 +130,17 @@ void ieee80211_ba_session_work(struct work_struct *work)
if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
return; return;
spin_lock_bh(&sta->lock); mutex_lock(&sta->ampdu_mlme.mtx);
for (tid = 0; tid < STA_TID_NUM; tid++) { for (tid = 0; tid < STA_TID_NUM; tid++) {
if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
___ieee80211_stop_rx_ba_session( ___ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT, sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_TIMEOUT); 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]; tid_tx = sta->ampdu_mlme.tid_tx[tid];
if (!tid_tx) if (!tid_tx)
continue; continue;
......
...@@ -740,7 +740,7 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -740,7 +740,7 @@ static void ieee80211_iface_work(struct work_struct *work)
mgmt->u.action.category == WLAN_CATEGORY_BACK) { mgmt->u.action.category == WLAN_CATEGORY_BACK) {
int len = skb->len; int len = skb->len;
rcu_read_lock(); mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, mgmt->sa); sta = sta_info_get(sdata, mgmt->sa);
if (sta) { if (sta) {
switch (mgmt->u.action.u.addba_req.action_code) { switch (mgmt->u.action.u.addba_req.action_code) {
...@@ -761,7 +761,7 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -761,7 +761,7 @@ static void ieee80211_iface_work(struct work_struct *work)
break; break;
} }
} }
rcu_read_unlock(); mutex_unlock(&local->sta_mtx);
} else if (ieee80211_is_data_qos(mgmt->frame_control)) { } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *)mgmt; struct ieee80211_hdr *hdr = (void *)mgmt;
/* /*
...@@ -781,7 +781,7 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -781,7 +781,7 @@ static void ieee80211_iface_work(struct work_struct *work)
* a block-ack session was active. That cannot be * a block-ack session was active. That cannot be
* right, so terminate the session. * right, so terminate the session.
*/ */
rcu_read_lock(); mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, mgmt->sa); sta = sta_info_get(sdata, mgmt->sa);
if (sta) { if (sta) {
u16 tid = *ieee80211_get_qos_ctl(hdr) & u16 tid = *ieee80211_get_qos_ctl(hdr) &
...@@ -791,7 +791,7 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -791,7 +791,7 @@ static void ieee80211_iface_work(struct work_struct *work)
sta, tid, WLAN_BACK_RECIPIENT, sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_REQUIRE_SETUP); WLAN_REASON_QSTA_REQUIRE_SETUP);
} }
rcu_read_unlock(); mutex_unlock(&local->sta_mtx);
} else switch (sdata->vif.type) { } else switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
ieee80211_sta_rx_queued_mgmt(sdata, skb); ieee80211_sta_rx_queued_mgmt(sdata, skb);
......
...@@ -236,6 +236,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -236,6 +236,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
spin_lock_init(&sta->flaglock); spin_lock_init(&sta->flaglock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
memcpy(sta->sta.addr, addr, ETH_ALEN); memcpy(sta->sta.addr, addr, ETH_ALEN);
sta->local = local; sta->local = local;
......
...@@ -142,8 +142,11 @@ struct tid_ampdu_rx { ...@@ -142,8 +142,11 @@ struct tid_ampdu_rx {
* @work: work struct for starting/stopping aggregation * @work: work struct for starting/stopping aggregation
* @tid_rx_timer_expired: bitmap indicating on which TIDs the * @tid_rx_timer_expired: bitmap indicating on which TIDs the
* RX timer expired until the work for it runs * 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 sta_ampdu_mlme {
struct mutex mtx;
/* rx */ /* rx */
struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment