diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2010-10-29 17:41:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-15 13:25:33 -0500 |
commit | 2a6cef513fab525399e484edc9bfb39b6d462f76 (patch) | |
tree | 3397cf07534825de557e53630eafda5ebc2193b8 /drivers/net/wireless/ath/carl9170 | |
parent | e4a668c59080f862af3ecc28b359533027cbe434 (diff) |
carl9170: stop stale uplink BA sessions
This patch fixes a possible lengthy stall if the device
is operating as an experimental 11n AP and an STA
[during heavy txrx action] suddenly signalized to go
off-channel (old NetworkManager), or (sleep - which is
unlikely, because then it wouldn't be *active* at all!?).
Because the driver has to manage the BA Window, the
sudden PSM transition can leave active uplink BA
sessions to the STA in a bad state and a proper
cleanup is needed.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/carl9170')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/tx.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index b575c865142d..b27969c41812 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c | |||
@@ -524,6 +524,59 @@ next: | |||
524 | } | 524 | } |
525 | } | 525 | } |
526 | 526 | ||
527 | static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) | ||
528 | { | ||
529 | struct carl9170_sta_tid *iter; | ||
530 | struct sk_buff *skb; | ||
531 | struct ieee80211_tx_info *txinfo; | ||
532 | struct carl9170_tx_info *arinfo; | ||
533 | struct _carl9170_tx_superframe *super; | ||
534 | struct ieee80211_sta *sta; | ||
535 | struct ieee80211_vif *vif; | ||
536 | struct ieee80211_hdr *hdr; | ||
537 | unsigned int vif_id; | ||
538 | |||
539 | rcu_read_lock(); | ||
540 | list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { | ||
541 | if (iter->state < CARL9170_TID_STATE_IDLE) | ||
542 | continue; | ||
543 | |||
544 | spin_lock_bh(&iter->lock); | ||
545 | skb = skb_peek(&iter->queue); | ||
546 | if (!skb) | ||
547 | goto unlock; | ||
548 | |||
549 | txinfo = IEEE80211_SKB_CB(skb); | ||
550 | arinfo = (void *)txinfo->rate_driver_data; | ||
551 | if (time_is_after_jiffies(arinfo->timeout + | ||
552 | msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) | ||
553 | goto unlock; | ||
554 | |||
555 | super = (void *) skb->data; | ||
556 | hdr = (void *) super->frame_data; | ||
557 | |||
558 | vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> | ||
559 | CARL9170_TX_SUPER_MISC_VIF_ID_S; | ||
560 | |||
561 | if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) | ||
562 | goto unlock; | ||
563 | |||
564 | vif = rcu_dereference(ar->vif_priv[vif_id].vif); | ||
565 | if (WARN_ON(!vif)) | ||
566 | goto unlock; | ||
567 | |||
568 | sta = ieee80211_find_sta(vif, hdr->addr1); | ||
569 | if (WARN_ON(!sta)) | ||
570 | goto unlock; | ||
571 | |||
572 | ieee80211_stop_tx_ba_session(sta, iter->tid); | ||
573 | unlock: | ||
574 | spin_unlock_bh(&iter->lock); | ||
575 | |||
576 | } | ||
577 | rcu_read_unlock(); | ||
578 | } | ||
579 | |||
527 | void carl9170_tx_janitor(struct work_struct *work) | 580 | void carl9170_tx_janitor(struct work_struct *work) |
528 | { | 581 | { |
529 | struct ar9170 *ar = container_of(work, struct ar9170, | 582 | struct ar9170 *ar = container_of(work, struct ar9170, |
@@ -534,6 +587,7 @@ void carl9170_tx_janitor(struct work_struct *work) | |||
534 | ar->tx_janitor_last_run = jiffies; | 587 | ar->tx_janitor_last_run = jiffies; |
535 | 588 | ||
536 | carl9170_check_queue_stop_timeout(ar); | 589 | carl9170_check_queue_stop_timeout(ar); |
590 | carl9170_tx_ampdu_timeout(ar); | ||
537 | 591 | ||
538 | if (!atomic_read(&ar->tx_total_queued)) | 592 | if (!atomic_read(&ar->tx_total_queued)) |
539 | return; | 593 | return; |