diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-06-10 04:21:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-14 15:39:28 -0400 |
commit | cfcdbde35e2b621cf56bedc38a3a81e8c28addb9 (patch) | |
tree | cd0664681dc4629f7ce9a3319868eebb005060ff /net/mac80211/agg-tx.c | |
parent | 83a5cbf73a13d0c8be019b22afec4407e4285aed (diff) |
mac80211: change TX aggregation locking
To prepare for allowing drivers to sleep in
ampdu_action, change the locking in the TX
aggregation code to use the mutex the RX part
already uses. The spinlock is still necessary
around some code to avoid races with TX, but
now we can also synchronize_net() to avoid
getting an inconsistent sequence number.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r-- | net/mac80211/agg-tx.c | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 0026604cfe30..5dff73eebefb 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Copyright 2005-2006, Devicescape Software, Inc. | 6 | * Copyright 2005-2006, Devicescape Software, Inc. |
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | 8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
9 | * Copyright 2007-2009, Intel Corporation | 9 | * Copyright 2007-2010, Intel Corporation |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -140,18 +140,23 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
140 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 140 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
141 | int ret; | 141 | int ret; |
142 | 142 | ||
143 | lockdep_assert_held(&sta->lock); | 143 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
144 | 144 | ||
145 | if (WARN_ON(!tid_tx)) | 145 | if (!tid_tx) |
146 | return -ENOENT; | 146 | return -ENOENT; |
147 | 147 | ||
148 | spin_lock_bh(&sta->lock); | ||
149 | |||
148 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 150 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
149 | /* not even started yet! */ | 151 | /* not even started yet! */ |
150 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 152 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); |
153 | spin_unlock_bh(&sta->lock); | ||
151 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 154 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
152 | return 0; | 155 | return 0; |
153 | } | 156 | } |
154 | 157 | ||
158 | spin_unlock_bh(&sta->lock); | ||
159 | |||
155 | #ifdef CONFIG_MAC80211_HT_DEBUG | 160 | #ifdef CONFIG_MAC80211_HT_DEBUG |
156 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", | 161 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", |
157 | sta->sta.addr, tid); | 162 | sta->sta.addr, tid); |
@@ -269,6 +274,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
269 | u16 start_seq_num; | 274 | u16 start_seq_num; |
270 | int ret; | 275 | int ret; |
271 | 276 | ||
277 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | ||
278 | |||
272 | /* | 279 | /* |
273 | * While we're asking the driver about the aggregation, | 280 | * While we're asking the driver about the aggregation, |
274 | * stop the AC queue so that we don't have to worry | 281 | * stop the AC queue so that we don't have to worry |
@@ -281,10 +288,11 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
281 | clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); | 288 | clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); |
282 | 289 | ||
283 | /* | 290 | /* |
284 | * This might be off by one due to a race that we can't | 291 | * make sure no packets are being processed to get |
285 | * really prevent here without synchronize_net() which | 292 | * valid starting sequence number |
286 | * can't be called now. | ||
287 | */ | 293 | */ |
294 | synchronize_net(); | ||
295 | |||
288 | start_seq_num = sta->tid_seq[tid] >> 4; | 296 | start_seq_num = sta->tid_seq[tid] >> 4; |
289 | 297 | ||
290 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | 298 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, |
@@ -294,7 +302,10 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
294 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | 302 | printk(KERN_DEBUG "BA request denied - HW unavailable for" |
295 | " tid %d\n", tid); | 303 | " tid %d\n", tid); |
296 | #endif | 304 | #endif |
305 | spin_lock_bh(&sta->lock); | ||
297 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 306 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); |
307 | spin_unlock_bh(&sta->lock); | ||
308 | |||
298 | ieee80211_wake_queue_agg(local, tid); | 309 | ieee80211_wake_queue_agg(local, tid); |
299 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 310 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
300 | return; | 311 | return; |
@@ -309,7 +320,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
309 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | 320 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); |
310 | #endif | 321 | #endif |
311 | 322 | ||
323 | spin_lock_bh(&sta->lock); | ||
312 | sta->ampdu_mlme.addba_req_num[tid]++; | 324 | sta->ampdu_mlme.addba_req_num[tid]++; |
325 | spin_unlock_bh(&sta->lock); | ||
313 | 326 | ||
314 | /* send AddBA request */ | 327 | /* send AddBA request */ |
315 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, | 328 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, |
@@ -445,16 +458,25 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
445 | ieee80211_wake_queue_agg(local, tid); | 458 | ieee80211_wake_queue_agg(local, tid); |
446 | } | 459 | } |
447 | 460 | ||
448 | /* caller must hold sta->lock */ | ||
449 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 461 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
450 | struct sta_info *sta, u16 tid) | 462 | struct sta_info *sta, u16 tid) |
451 | { | 463 | { |
452 | lockdep_assert_held(&sta->lock); | 464 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
453 | 465 | ||
454 | #ifdef CONFIG_MAC80211_HT_DEBUG | 466 | #ifdef CONFIG_MAC80211_HT_DEBUG |
455 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 467 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
456 | #endif | 468 | #endif |
457 | 469 | ||
470 | drv_ampdu_action(local, sta->sdata, | ||
471 | IEEE80211_AMPDU_TX_OPERATIONAL, | ||
472 | &sta->sta, tid, NULL); | ||
473 | |||
474 | /* | ||
475 | * synchronize with TX path, while splicing the TX path | ||
476 | * should block so it won't put more packets onto pending. | ||
477 | */ | ||
478 | spin_lock_bh(&sta->lock); | ||
479 | |||
458 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 480 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); |
459 | /* | 481 | /* |
460 | * Now mark as operational. This will be visible | 482 | * Now mark as operational. This will be visible |
@@ -464,9 +486,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
464 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 486 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); |
465 | ieee80211_agg_splice_finish(local, tid); | 487 | ieee80211_agg_splice_finish(local, tid); |
466 | 488 | ||
467 | drv_ampdu_action(local, sta->sdata, | 489 | spin_unlock_bh(&sta->lock); |
468 | IEEE80211_AMPDU_TX_OPERATIONAL, | ||
469 | &sta->sta, tid, NULL); | ||
470 | } | 490 | } |
471 | 491 | ||
472 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | 492 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) |
@@ -486,37 +506,35 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
486 | return; | 506 | return; |
487 | } | 507 | } |
488 | 508 | ||
489 | rcu_read_lock(); | 509 | mutex_lock(&local->sta_mtx); |
490 | sta = sta_info_get(sdata, ra); | 510 | sta = sta_info_get(sdata, ra); |
491 | if (!sta) { | 511 | if (!sta) { |
492 | rcu_read_unlock(); | 512 | mutex_unlock(&local->sta_mtx); |
493 | #ifdef CONFIG_MAC80211_HT_DEBUG | 513 | #ifdef CONFIG_MAC80211_HT_DEBUG |
494 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | 514 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); |
495 | #endif | 515 | #endif |
496 | return; | 516 | return; |
497 | } | 517 | } |
498 | 518 | ||
499 | spin_lock_bh(&sta->lock); | 519 | mutex_lock(&sta->ampdu_mlme.mtx); |
500 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 520 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
501 | 521 | ||
502 | if (WARN_ON(!tid_tx)) { | 522 | if (WARN_ON(!tid_tx)) { |
503 | #ifdef CONFIG_MAC80211_HT_DEBUG | 523 | #ifdef CONFIG_MAC80211_HT_DEBUG |
504 | printk(KERN_DEBUG "addBA was not requested!\n"); | 524 | printk(KERN_DEBUG "addBA was not requested!\n"); |
505 | #endif | 525 | #endif |
506 | spin_unlock_bh(&sta->lock); | 526 | goto unlock; |
507 | rcu_read_unlock(); | ||
508 | return; | ||
509 | } | 527 | } |
510 | 528 | ||
511 | if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) | 529 | if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) |
512 | goto out; | 530 | goto unlock; |
513 | 531 | ||
514 | if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) | 532 | if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) |
515 | ieee80211_agg_tx_operational(local, sta, tid); | 533 | ieee80211_agg_tx_operational(local, sta, tid); |
516 | 534 | ||
517 | out: | 535 | unlock: |
518 | spin_unlock_bh(&sta->lock); | 536 | mutex_unlock(&sta->ampdu_mlme.mtx); |
519 | rcu_read_unlock(); | 537 | mutex_unlock(&local->sta_mtx); |
520 | } | 538 | } |
521 | 539 | ||
522 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, | 540 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, |
@@ -548,21 +566,14 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | |||
548 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 566 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
549 | enum ieee80211_back_parties initiator) | 567 | enum ieee80211_back_parties initiator) |
550 | { | 568 | { |
551 | struct tid_ampdu_tx *tid_tx; | ||
552 | int ret; | 569 | int ret; |
553 | 570 | ||
554 | spin_lock_bh(&sta->lock); | 571 | mutex_lock(&sta->ampdu_mlme.mtx); |
555 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | ||
556 | |||
557 | if (!tid_tx) { | ||
558 | ret = -ENOENT; | ||
559 | goto unlock; | ||
560 | } | ||
561 | 572 | ||
562 | ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); | 573 | ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); |
563 | 574 | ||
564 | unlock: | 575 | mutex_unlock(&sta->ampdu_mlme.mtx); |
565 | spin_unlock_bh(&sta->lock); | 576 | |
566 | return ret; | 577 | return ret; |
567 | } | 578 | } |
568 | 579 | ||
@@ -627,16 +638,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
627 | ra, tid); | 638 | ra, tid); |
628 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 639 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
629 | 640 | ||
630 | rcu_read_lock(); | 641 | mutex_lock(&local->sta_mtx); |
642 | |||
631 | sta = sta_info_get(sdata, ra); | 643 | sta = sta_info_get(sdata, ra); |
632 | if (!sta) { | 644 | if (!sta) { |
633 | #ifdef CONFIG_MAC80211_HT_DEBUG | 645 | #ifdef CONFIG_MAC80211_HT_DEBUG |
634 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | 646 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); |
635 | #endif | 647 | #endif |
636 | rcu_read_unlock(); | 648 | goto unlock; |
637 | return; | ||
638 | } | 649 | } |
639 | 650 | ||
651 | mutex_lock(&sta->ampdu_mlme.mtx); | ||
640 | spin_lock_bh(&sta->lock); | 652 | spin_lock_bh(&sta->lock); |
641 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 653 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
642 | 654 | ||
@@ -644,9 +656,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
644 | #ifdef CONFIG_MAC80211_HT_DEBUG | 656 | #ifdef CONFIG_MAC80211_HT_DEBUG |
645 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | 657 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); |
646 | #endif | 658 | #endif |
647 | spin_unlock_bh(&sta->lock); | 659 | goto unlock_sta; |
648 | rcu_read_unlock(); | ||
649 | return; | ||
650 | } | 660 | } |
651 | 661 | ||
652 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR) | 662 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR) |
@@ -672,8 +682,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
672 | 682 | ||
673 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 683 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
674 | 684 | ||
685 | unlock_sta: | ||
675 | spin_unlock_bh(&sta->lock); | 686 | spin_unlock_bh(&sta->lock); |
676 | rcu_read_unlock(); | 687 | mutex_unlock(&sta->ampdu_mlme.mtx); |
688 | unlock: | ||
689 | mutex_unlock(&local->sta_mtx); | ||
677 | } | 690 | } |
678 | 691 | ||
679 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, | 692 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, |
@@ -714,10 +727,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
714 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 727 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
715 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 728 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
716 | 729 | ||
717 | spin_lock_bh(&sta->lock); | 730 | mutex_lock(&sta->ampdu_mlme.mtx); |
718 | 731 | ||
719 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 732 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
720 | |||
721 | if (!tid_tx) | 733 | if (!tid_tx) |
722 | goto out; | 734 | goto out; |
723 | 735 | ||
@@ -751,5 +763,5 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
751 | } | 763 | } |
752 | 764 | ||
753 | out: | 765 | out: |
754 | spin_unlock_bh(&sta->lock); | 766 | mutex_unlock(&sta->ampdu_mlme.mtx); |
755 | } | 767 | } |