diff options
-rw-r--r-- | net/mac80211/agg-tx.c | 94 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 3 | ||||
-rw-r--r-- | net/mac80211/ht.c | 8 |
3 files changed, 58 insertions, 47 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 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e5e7ef175ca2..7e86c6f89be9 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -349,6 +349,9 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, | |||
349 | u16 *ssn) | 349 | u16 *ssn) |
350 | { | 350 | { |
351 | int ret = -EOPNOTSUPP; | 351 | int ret = -EOPNOTSUPP; |
352 | |||
353 | might_sleep(); | ||
354 | |||
352 | local_bh_disable(); | 355 | local_bh_disable(); |
353 | if (local->ops->ampdu_action) | 356 | if (local->ops->ampdu_action) |
354 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, | 357 | ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index e29be64083c3..be928ef7ef51 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.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-2008, 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 |
@@ -136,11 +136,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
136 | ___ieee80211_stop_rx_ba_session( | 136 | ___ieee80211_stop_rx_ba_session( |
137 | sta, tid, WLAN_BACK_RECIPIENT, | 137 | sta, tid, WLAN_BACK_RECIPIENT, |
138 | WLAN_REASON_QSTA_TIMEOUT); | 138 | WLAN_REASON_QSTA_TIMEOUT); |
139 | } | ||
140 | mutex_unlock(&sta->ampdu_mlme.mtx); | ||
141 | 139 | ||
142 | spin_lock_bh(&sta->lock); | ||
143 | for (tid = 0; tid < STA_TID_NUM; tid++) { | ||
144 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 140 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
145 | if (!tid_tx) | 141 | if (!tid_tx) |
146 | continue; | 142 | continue; |
@@ -152,7 +148,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
152 | ___ieee80211_stop_tx_ba_session(sta, tid, | 148 | ___ieee80211_stop_tx_ba_session(sta, tid, |
153 | WLAN_BACK_INITIATOR); | 149 | WLAN_BACK_INITIATOR); |
154 | } | 150 | } |
155 | spin_unlock_bh(&sta->lock); | 151 | mutex_unlock(&sta->ampdu_mlme.mtx); |
156 | } | 152 | } |
157 | 153 | ||
158 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 154 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |