aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2012-03-18 17:58:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-09 16:09:36 -0400
commit12d3952fc4a1cd96234bc7023bf7eefeb0bb6355 (patch)
tree5c3437e1f996a5c772b286530a3fce547a7d40f2
parentfcb2c9e1025cd529890303ffbde813a98cdffed4 (diff)
mac80211: optimize aggregation session timeout handling
Calling mod_timer from the rx/tx hotpath is somewhat expensive, and the timeout doesn't need to be so precise. Switch to a different strategy: Schedule the timer initially, store jiffies of all last rx/tx activity which would previously modify the timer, and let the timer re-arm itself after checking the last rx/tx timestamp. Make the session timers deferrable to avoid causing extra wakeups on systems running on battery. This visibly reduces CPU load under high network load on small embedded systems. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/agg-rx.c18
-rw-r--r--net/mac80211/agg-tx.c18
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/rx.c3
-rw-r--r--net/mac80211/sta_info.h4
-rw-r--r--net/mac80211/tx.c3
6 files changed, 40 insertions, 9 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 64d3ce5ea1a0..a070d4f460ea 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -142,6 +142,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
142 u8 *timer_to_id = ptid - *ptid; 142 u8 *timer_to_id = ptid - *ptid;
143 struct sta_info *sta = container_of(timer_to_id, struct sta_info, 143 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
144 timer_to_tid[0]); 144 timer_to_tid[0]);
145 struct tid_ampdu_rx *tid_rx;
146 unsigned long timeout;
147
148 tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
149 if (!tid_rx)
150 return;
151
152 timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
153 if (time_is_after_jiffies(timeout)) {
154 mod_timer(&tid_rx->session_timer, timeout);
155 return;
156 }
145 157
146#ifdef CONFIG_MAC80211_HT_DEBUG 158#ifdef CONFIG_MAC80211_HT_DEBUG
147 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); 159 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
@@ -291,7 +303,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
291 /* rx timer */ 303 /* rx timer */
292 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; 304 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
293 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; 305 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
294 init_timer(&tid_agg_rx->session_timer); 306 init_timer_deferrable(&tid_agg_rx->session_timer);
295 307
296 /* rx reorder timer */ 308 /* rx reorder timer */
297 tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired; 309 tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
@@ -335,8 +347,10 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
335 /* activate it for RX */ 347 /* activate it for RX */
336 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx); 348 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
337 349
338 if (timeout) 350 if (timeout) {
339 mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout)); 351 mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
352 tid_agg_rx->last_rx = jiffies;
353 }
340 354
341end: 355end:
342 mutex_unlock(&sta->ampdu_mlme.mtx); 356 mutex_unlock(&sta->ampdu_mlme.mtx);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 76be61744198..9628a1892441 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -417,6 +417,18 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
417 u8 *timer_to_id = ptid - *ptid; 417 u8 *timer_to_id = ptid - *ptid;
418 struct sta_info *sta = container_of(timer_to_id, struct sta_info, 418 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
419 timer_to_tid[0]); 419 timer_to_tid[0]);
420 struct tid_ampdu_tx *tid_tx;
421 unsigned long timeout;
422
423 tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid);
424 if (!tid_tx)
425 return;
426
427 timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
428 if (time_is_after_jiffies(timeout)) {
429 mod_timer(&tid_tx->session_timer, timeout);
430 return;
431 }
420 432
421#ifdef CONFIG_MAC80211_HT_DEBUG 433#ifdef CONFIG_MAC80211_HT_DEBUG
422 printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); 434 printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
@@ -542,7 +554,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
542 /* tx timer */ 554 /* tx timer */
543 tid_tx->session_timer.function = sta_tx_agg_session_timer_expired; 555 tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
544 tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; 556 tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
545 init_timer(&tid_tx->session_timer); 557 init_timer_deferrable(&tid_tx->session_timer);
546 558
547 /* assign a dialog token */ 559 /* assign a dialog token */
548 sta->ampdu_mlme.dialog_token_allocator++; 560 sta->ampdu_mlme.dialog_token_allocator++;
@@ -884,9 +896,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
884 896
885 sta->ampdu_mlme.addba_req_num[tid] = 0; 897 sta->ampdu_mlme.addba_req_num[tid] = 0;
886 898
887 if (tid_tx->timeout) 899 if (tid_tx->timeout) {
888 mod_timer(&tid_tx->session_timer, 900 mod_timer(&tid_tx->session_timer,
889 TU_TO_EXP_TIME(tid_tx->timeout)); 901 TU_TO_EXP_TIME(tid_tx->timeout));
902 tid_tx->last_tx = jiffies;
903 }
890 904
891 } else { 905 } else {
892 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 906 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0ae822c47930..23765e3ca7bc 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -52,7 +52,8 @@ struct ieee80211_local;
52 * increased memory use (about 2 kB of RAM per entry). */ 52 * increased memory use (about 2 kB of RAM per entry). */
53#define IEEE80211_FRAGMENT_MAX 4 53#define IEEE80211_FRAGMENT_MAX 4
54 54
55#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) 55#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
56#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
56 57
57#define IEEE80211_DEFAULT_UAPSD_QUEUES \ 58#define IEEE80211_DEFAULT_UAPSD_QUEUES \
58 (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ 59 (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index bcfe8c77c839..8da3b36c287a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -793,8 +793,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
793 793
794 /* reset session timer */ 794 /* reset session timer */
795 if (tid_agg_rx->timeout) 795 if (tid_agg_rx->timeout)
796 mod_timer(&tid_agg_rx->session_timer, 796 tid_agg_rx->last_rx = jiffies;
797 TU_TO_EXP_TIME(tid_agg_rx->timeout));
798 797
799 /* if this mpdu is fragmented - terminate rx aggregation session */ 798 /* if this mpdu is fragmented - terminate rx aggregation session */
800 sc = le16_to_cpu(hdr->seq_ctrl); 799 sc = le16_to_cpu(hdr->seq_ctrl);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ab0576827baf..e21652bccf7c 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -101,6 +101,7 @@ enum ieee80211_sta_info_flags {
101 * @dialog_token: dialog token for aggregation session 101 * @dialog_token: dialog token for aggregation session
102 * @timeout: session timeout value to be filled in ADDBA requests 102 * @timeout: session timeout value to be filled in ADDBA requests
103 * @state: session state (see above) 103 * @state: session state (see above)
104 * @last_tx: jiffies of last tx activity
104 * @stop_initiator: initiator of a session stop 105 * @stop_initiator: initiator of a session stop
105 * @tx_stop: TX DelBA frame when stopping 106 * @tx_stop: TX DelBA frame when stopping
106 * @buf_size: reorder buffer size at receiver 107 * @buf_size: reorder buffer size at receiver
@@ -122,6 +123,7 @@ struct tid_ampdu_tx {
122 struct timer_list addba_resp_timer; 123 struct timer_list addba_resp_timer;
123 struct sk_buff_head pending; 124 struct sk_buff_head pending;
124 unsigned long state; 125 unsigned long state;
126 unsigned long last_tx;
125 u16 timeout; 127 u16 timeout;
126 u8 dialog_token; 128 u8 dialog_token;
127 u8 stop_initiator; 129 u8 stop_initiator;
@@ -139,6 +141,7 @@ struct tid_ampdu_tx {
139 * @reorder_time: jiffies when skb was added 141 * @reorder_time: jiffies when skb was added
140 * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) 142 * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
141 * @reorder_timer: releases expired frames from the reorder buffer. 143 * @reorder_timer: releases expired frames from the reorder buffer.
144 * @last_rx: jiffies of last rx activity
142 * @head_seq_num: head sequence number in reordering buffer. 145 * @head_seq_num: head sequence number in reordering buffer.
143 * @stored_mpdu_num: number of MPDUs in reordering buffer 146 * @stored_mpdu_num: number of MPDUs in reordering buffer
144 * @ssn: Starting Sequence Number expected to be aggregated. 147 * @ssn: Starting Sequence Number expected to be aggregated.
@@ -163,6 +166,7 @@ struct tid_ampdu_rx {
163 unsigned long *reorder_time; 166 unsigned long *reorder_time;
164 struct timer_list session_timer; 167 struct timer_list session_timer;
165 struct timer_list reorder_timer; 168 struct timer_list reorder_timer;
169 unsigned long last_rx;
166 u16 head_seq_num; 170 u16 head_seq_num;
167 u16 stored_mpdu_num; 171 u16 stored_mpdu_num;
168 u16 ssn; 172 u16 ssn;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a9b27273320e..da2447a7bade 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1118,8 +1118,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1118 1118
1119 /* reset session timer */ 1119 /* reset session timer */
1120 if (reset_agg_timer && tid_tx->timeout) 1120 if (reset_agg_timer && tid_tx->timeout)
1121 mod_timer(&tid_tx->session_timer, 1121 tid_tx->last_tx = jiffies;
1122 TU_TO_EXP_TIME(tid_tx->timeout));
1123 1122
1124 return queued; 1123 return queued;
1125} 1124}