aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/agg-rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-06-10 04:21:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:39:27 -0400
commita87f736d942c86255e3088c606f0e3eab6bbf784 (patch)
tree74d3d63dca9fc982fcb7c165247d6924c021b4ef /net/mac80211/agg-rx.c
parentc1475ca99edcc7216ddc45838ab2c3281c14ba22 (diff)
mac80211: use RCU for RX aggregation
Currently we allocate some memory for each RX aggregation session and additionally keep a flag indicating whether or not it is valid. By using RCU to protect the pointer and making sure that the memory is fully set up before it becomes visible to the RX path, we can remove the need for the bool that indicates validity, as well as for locking on the RX path since it is always synchronised against itself, and we can guarantee that all other modifications are done when the structure is not visible to the RX path. The net result is that since we remove locking requirements from the RX path, we can in the future use any kind of lock for the setup and teardown code paths. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/agg-rx.c')
-rw-r--r--net/mac80211/agg-rx.c70
1 files changed, 32 insertions, 38 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 6bb9a9a94960..bbf36d980232 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -19,25 +19,36 @@
19#include "ieee80211_i.h" 19#include "ieee80211_i.h"
20#include "driver-ops.h" 20#include "driver-ops.h"
21 21
22static void ieee80211_free_tid_rx(struct rcu_head *h)
23{
24 struct tid_ampdu_rx *tid_rx =
25 container_of(h, struct tid_ampdu_rx, rcu_head);
26 int i;
27
28 for (i = 0; i < tid_rx->buf_size; i++)
29 dev_kfree_skb(tid_rx->reorder_buf[i]);
30 kfree(tid_rx->reorder_buf);
31 kfree(tid_rx->reorder_time);
32 kfree(tid_rx);
33}
34
22static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 35static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
23 u16 initiator, u16 reason, 36 u16 initiator, u16 reason,
24 bool from_timer) 37 bool from_timer)
25{ 38{
26 struct ieee80211_local *local = sta->local; 39 struct ieee80211_local *local = sta->local;
27 struct tid_ampdu_rx *tid_rx; 40 struct tid_ampdu_rx *tid_rx;
28 int i;
29 41
30 spin_lock_bh(&sta->lock); 42 spin_lock_bh(&sta->lock);
31 43
32 /* check if TID is in operational state */ 44 tid_rx = sta->ampdu_mlme.tid_rx[tid];
33 if (!sta->ampdu_mlme.tid_active_rx[tid]) { 45
46 if (!tid_rx) {
34 spin_unlock_bh(&sta->lock); 47 spin_unlock_bh(&sta->lock);
35 return; 48 return;
36 } 49 }
37 50
38 sta->ampdu_mlme.tid_active_rx[tid] = false; 51 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
39
40 tid_rx = sta->ampdu_mlme.tid_rx[tid];
41 52
42#ifdef CONFIG_MAC80211_HT_DEBUG 53#ifdef CONFIG_MAC80211_HT_DEBUG
43 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", 54 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
@@ -54,26 +65,12 @@ static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
54 ieee80211_send_delba(sta->sdata, sta->sta.addr, 65 ieee80211_send_delba(sta->sdata, sta->sta.addr,
55 tid, 0, reason); 66 tid, 0, reason);
56 67
57 /* free the reordering buffer */
58 for (i = 0; i < tid_rx->buf_size; i++) {
59 if (tid_rx->reorder_buf[i]) {
60 /* release the reordered frames */
61 dev_kfree_skb(tid_rx->reorder_buf[i]);
62 tid_rx->stored_mpdu_num--;
63 tid_rx->reorder_buf[i] = NULL;
64 }
65 }
66
67 /* free resources */
68 kfree(tid_rx->reorder_buf);
69 kfree(tid_rx->reorder_time);
70 sta->ampdu_mlme.tid_rx[tid] = NULL;
71
72 spin_unlock_bh(&sta->lock); 68 spin_unlock_bh(&sta->lock);
73 69
74 if (!from_timer) 70 if (!from_timer)
75 del_timer_sync(&tid_rx->session_timer); 71 del_timer_sync(&tid_rx->session_timer);
76 kfree(tid_rx); 72
73 call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
77} 74}
78 75
79void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 76void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
@@ -214,7 +211,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
214 /* examine state machine */ 211 /* examine state machine */
215 spin_lock_bh(&sta->lock); 212 spin_lock_bh(&sta->lock);
216 213
217 if (sta->ampdu_mlme.tid_active_rx[tid]) { 214 if (sta->ampdu_mlme.tid_rx[tid]) {
218#ifdef CONFIG_MAC80211_HT_DEBUG 215#ifdef CONFIG_MAC80211_HT_DEBUG
219 if (net_ratelimit()) 216 if (net_ratelimit())
220 printk(KERN_DEBUG "unexpected AddBA Req from " 217 printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -225,9 +222,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
225 } 222 }
226 223
227 /* prepare A-MPDU MLME for Rx aggregation */ 224 /* prepare A-MPDU MLME for Rx aggregation */
228 sta->ampdu_mlme.tid_rx[tid] = 225 tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
229 kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); 226 if (!tid_agg_rx) {
230 if (!sta->ampdu_mlme.tid_rx[tid]) {
231#ifdef CONFIG_MAC80211_HT_DEBUG 227#ifdef CONFIG_MAC80211_HT_DEBUG
232 if (net_ratelimit()) 228 if (net_ratelimit())
233 printk(KERN_ERR "allocate rx mlme to tid %d failed\n", 229 printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
@@ -235,14 +231,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
235#endif 231#endif
236 goto end; 232 goto end;
237 } 233 }
238 /* rx timer */
239 sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
240 sta_rx_agg_session_timer_expired;
241 sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
242 (unsigned long)&sta->timer_to_tid[tid];
243 init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
244 234
245 tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; 235 /* rx timer */
236 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
237 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
238 init_timer(&tid_agg_rx->session_timer);
246 239
247 /* prepare reordering buffer */ 240 /* prepare reordering buffer */
248 tid_agg_rx->reorder_buf = 241 tid_agg_rx->reorder_buf =
@@ -257,8 +250,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
257#endif 250#endif
258 kfree(tid_agg_rx->reorder_buf); 251 kfree(tid_agg_rx->reorder_buf);
259 kfree(tid_agg_rx->reorder_time); 252 kfree(tid_agg_rx->reorder_time);
260 kfree(sta->ampdu_mlme.tid_rx[tid]); 253 kfree(tid_agg_rx);
261 sta->ampdu_mlme.tid_rx[tid] = NULL;
262 goto end; 254 goto end;
263 } 255 }
264 256
@@ -270,13 +262,12 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
270 262
271 if (ret) { 263 if (ret) {
272 kfree(tid_agg_rx->reorder_buf); 264 kfree(tid_agg_rx->reorder_buf);
265 kfree(tid_agg_rx->reorder_time);
273 kfree(tid_agg_rx); 266 kfree(tid_agg_rx);
274 sta->ampdu_mlme.tid_rx[tid] = NULL;
275 goto end; 267 goto end;
276 } 268 }
277 269
278 /* change state and send addba resp */ 270 /* update data */
279 sta->ampdu_mlme.tid_active_rx[tid] = true;
280 tid_agg_rx->dialog_token = dialog_token; 271 tid_agg_rx->dialog_token = dialog_token;
281 tid_agg_rx->ssn = start_seq_num; 272 tid_agg_rx->ssn = start_seq_num;
282 tid_agg_rx->head_seq_num = start_seq_num; 273 tid_agg_rx->head_seq_num = start_seq_num;
@@ -284,6 +275,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
284 tid_agg_rx->timeout = timeout; 275 tid_agg_rx->timeout = timeout;
285 tid_agg_rx->stored_mpdu_num = 0; 276 tid_agg_rx->stored_mpdu_num = 0;
286 status = WLAN_STATUS_SUCCESS; 277 status = WLAN_STATUS_SUCCESS;
278
279 /* activate it for RX */
280 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
287end: 281end:
288 spin_unlock_bh(&sta->lock); 282 spin_unlock_bh(&sta->lock);
289 283