2012-06-03 20:29:09

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH] mac80211: don't call drv_ampdu_action() during reconfig

When tearing down BA sessions during HW reconfig, the low level driver
is not aware of them yet. Add a parameter to relevant Rx/Tx BA functions
to prevent calls to the driver, while removing all mac80211 related state.

Signed-off-by: Arik Nemtsov <[email protected]>
---
net/mac80211/agg-rx.c | 16 ++++++++++------
net/mac80211/agg-tx.c | 18 +++++++++++-------
net/mac80211/debugfs_sta.c | 2 +-
net/mac80211/ht.c | 19 +++++++++++--------
net/mac80211/ieee80211_i.h | 13 ++++++++-----
net/mac80211/iface.c | 2 +-
net/mac80211/mlme.c | 2 +-
net/mac80211/pm.c | 2 +-
net/mac80211/sta_info.c | 2 +-
net/mac80211/util.c | 3 ++-
10 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index a070d4f..d1afa99 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -59,7 +59,8 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
}

void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason, bool tx)
+ u16 initiator, u16 reason, bool tx,
+ bool call_drv)
{
struct ieee80211_local *local = sta->local;
struct tid_ampdu_rx *tid_rx;
@@ -82,8 +83,9 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
(int)reason);
#endif /* CONFIG_MAC80211_HT_DEBUG */

- if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
- &sta->sta, tid, NULL, 0))
+ if (call_drv && drv_ampdu_action(local, sta->sdata,
+ IEEE80211_AMPDU_RX_STOP,
+ &sta->sta, tid, NULL, 0))
printk(KERN_DEBUG "HW problem - can not stop rx "
"aggregation for tid %d\n", tid);

@@ -98,10 +100,12 @@ 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, bool tx)
+ u16 initiator, u16 reason, bool tx,
+ bool call_drv)
{
mutex_lock(&sta->ampdu_mlme.mtx);
- ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
+ ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx,
+ call_drv);
mutex_unlock(&sta->ampdu_mlme.mtx);
}

@@ -290,7 +294,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* delete existing Rx BA session on the same tid */
___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
WLAN_STATUS_UNSPECIFIED_QOS,
- false);
+ false, true);
}

/* prepare A-MPDU MLME for Rx aggregation */
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 7cf0715..daa1764 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -150,7 +150,7 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,

int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator,
- bool tx)
+ bool tx, bool call_drv)
{
struct ieee80211_local *local = sta->local;
struct tid_ampdu_tx *tid_tx;
@@ -216,9 +216,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
tid_tx->stop_initiator = initiator;
tid_tx->tx_stop = tx;

- ret = drv_ampdu_action(local, sta->sdata,
- IEEE80211_AMPDU_TX_STOP,
- &sta->sta, tid, NULL, 0);
+ if (call_drv)
+ ret = drv_ampdu_action(local, sta->sdata,
+ IEEE80211_AMPDU_TX_STOP,
+ &sta->sta, tid, NULL, 0);
+ else
+ ret = 0;

/* HW shall not deny going back to legacy */
if (WARN_ON(ret)) {
@@ -688,13 +691,14 @@ 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)
+ bool tx, bool call_drv)
{
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, initiator, tx,
+ call_drv);

mutex_unlock(&sta->ampdu_mlme.mtx);

@@ -911,7 +915,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,

} else {
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
- true);
+ true, true);
}

out:
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 5ccec2c..0127367 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -230,7 +230,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
} else {
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
- 3, true);
+ 3, true, true);
ret = 0;
}

diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 9b60336..a8125cb 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -179,16 +179,19 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
ieee80211_apply_htcap_overrides(sdata, ht_cap);
}

-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx,
+ bool call_drv)
{
int i;

cancel_work_sync(&sta->ampdu_mlme.work);

for (i = 0; i < STA_TID_NUM; i++) {
- __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
+ __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx,
+ call_drv);
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_LEAVE_QBSS, tx);
+ WLAN_REASON_QSTA_LEAVE_QBSS, tx,
+ call_drv);
}
}

@@ -213,13 +216,13 @@ void ieee80211_ba_session_work(struct work_struct *work)
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, true);
+ WLAN_REASON_QSTA_TIMEOUT, true, true);

if (test_and_clear_bit(tid,
sta->ampdu_mlme.tid_rx_stop_requested))
___ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT,
- WLAN_REASON_UNSPECIFIED, true);
+ WLAN_REASON_UNSPECIFIED, true, true);

tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
if (tid_tx) {
@@ -246,7 +249,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
&tid_tx->state))
___ieee80211_stop_tx_ba_session(sta, tid,
WLAN_BACK_INITIATOR,
- true);
+ true, true);
}
mutex_unlock(&sta->ampdu_mlme.mtx);
}
@@ -314,10 +317,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,

if (initiator == WLAN_BACK_INITIATOR)
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
- true);
+ true, true);
else
__ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
- true);
+ true, true);
}

int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ae046b5..1975f35 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1336,10 +1336,13 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
void ieee80211_request_smps_work(struct work_struct *work);

void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason, bool stop);
+ u16 initiator, u16 reason, bool stop,
+ bool call_drv);
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason, bool stop);
-void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
+ u16 initiator, u16 reason, bool stop,
+ bool call_drv);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx,
+ bool call_drv);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_mgmt *mgmt, size_t len);
@@ -1354,10 +1357,10 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,

int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator,
- bool tx);
+ bool tx, bool call_drv);
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator,
- bool tx);
+ bool tx, bool call_drv);
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
void ieee80211_ba_session_work(struct work_struct *work);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index c550945..859271d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -922,7 +922,7 @@ static void ieee80211_iface_work(struct work_struct *work)
__ieee80211_stop_rx_ba_session(
sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_REQUIRE_SETUP,
- true);
+ true, true);
}
mutex_unlock(&local->sta_mtx);
} else switch (sdata->vif.type) {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 40c933c..4ae9b23 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1363,7 +1363,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, bssid);
if (sta) {
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta, tx);
+ ieee80211_sta_tear_down_BA_sessions(sta, tx, true);
}
mutex_unlock(&local->sta_mtx);

diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index af1c4e2..52cb3d3 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -43,7 +43,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta, true);
+ ieee80211_sta_tear_down_BA_sessions(sta, true, true);
}
mutex_unlock(&local->sta_mtx);
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 97a9d66..f5c2b7e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -682,7 +682,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
* will be sufficient.
*/
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta, true);
+ ieee80211_sta_tear_down_BA_sessions(sta, true, true);

ret = sta_info_hash_del(local, sta);
if (ret)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index a44c680..7c7e571 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1391,7 +1391,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_lock(&local->sta_mtx);

list_for_each_entry(sta, &local->sta_list, list) {
- ieee80211_sta_tear_down_BA_sessions(sta, true);
+ /* don't call the driver when tearing down sessions */
+ ieee80211_sta_tear_down_BA_sessions(sta, true, false);
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
}

--
1.7.9.5



2012-06-04 06:13:40

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211: don't call drv_ampdu_action() during reconfig

On Sun, 2012-06-03 at 23:29 +0300, Arik Nemtsov wrote:
> When tearing down BA sessions during HW reconfig, the low level driver
> is not aware of them yet. Add a parameter to relevant Rx/Tx BA functions
> to prevent calls to the driver, while removing all mac80211 related state.

I think iwlwifi uses the callback, even during restart, to clean up
hardware state, so this might break it.

johannes