diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-06-10 04:21:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-14 15:39:27 -0400 |
commit | a87f736d942c86255e3088c606f0e3eab6bbf784 (patch) | |
tree | 74d3d63dca9fc982fcb7c165247d6924c021b4ef /net/mac80211/agg-rx.c | |
parent | c1475ca99edcc7216ddc45838ab2c3281c14ba22 (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.c | 70 |
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 | ||
22 | static 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 | |||
22 | static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 35 | static 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 | ||
79 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 76 | void __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); | ||
287 | end: | 281 | end: |
288 | spin_unlock_bh(&sta->lock); | 282 | spin_unlock_bh(&sta->lock); |
289 | 283 | ||