summaryrefslogtreecommitdiff
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-06-10 10:21:38 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:39:27 -0400
commita87f736d942c86255e3088c606f0e3eab6bbf784 (patch)
tree74d3d63dca9fc982fcb7c165247d6924c021b4ef /net/mac80211/rx.c
parentc1475ca99edcc7216ddc45838ab2c3281c14ba22 (diff)
downloadlinux-3.10-a87f736d942c86255e3088c606f0e3eab6bbf784.tar.gz
linux-3.10-a87f736d942c86255e3088c606f0e3eab6bbf784.tar.bz2
linux-3.10-a87f736d942c86255e3088c606f0e3eab6bbf784.zip
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/rx.c')
-rw-r--r--net/mac80211/rx.c34
1 files changed, 15 insertions, 19 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 84f11733b9f..ee01daccacb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -719,16 +719,13 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
- spin_lock(&sta->lock);
-
- if (!sta->ampdu_mlme.tid_active_rx[tid])
- goto dont_reorder_unlock;
-
- tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+ tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
+ goto dont_reorder;
/* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
- goto dont_reorder_unlock;
+ goto dont_reorder;
/* new, potentially un-ordered, ampdu frame - process it */
@@ -740,20 +737,22 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
- spin_unlock(&sta->lock);
skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
skb_queue_tail(&rx->sdata->skb_queue, skb);
ieee80211_queue_work(&local->hw, &rx->sdata->work);
return;
}
- if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) {
- spin_unlock(&sta->lock);
+ /*
+ * No locking needed -- we will only ever process one
+ * RX packet at a time, and thus own tid_agg_rx. All
+ * other code manipulating it needs to (and does) make
+ * sure that we cannot get to it any more before doing
+ * anything with it.
+ */
+ if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
return;
- }
- dont_reorder_unlock:
- spin_unlock(&sta->lock);
dont_reorder:
__skb_queue_tail(frames, skb);
}
@@ -1830,13 +1829,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
&bar_data, sizeof(bar_data)))
return RX_DROP_MONITOR;
- spin_lock(&rx->sta->lock);
tid = le16_to_cpu(bar_data.control) >> 12;
- if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
- spin_unlock(&rx->sta->lock);
+
+ tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
return RX_DROP_MONITOR;
- }
- tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
@@ -1849,7 +1846,6 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
frames);
kfree_skb(skb);
- spin_unlock(&rx->sta->lock);
return RX_QUEUED;
}