diff options
author | Felix Fietkau <nbd@openwrt.org> | 2012-03-18 17:58:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-09 16:09:36 -0400 |
commit | 12d3952fc4a1cd96234bc7023bf7eefeb0bb6355 (patch) | |
tree | 5c3437e1f996a5c772b286530a3fce547a7d40f2 /net/mac80211 | |
parent | fcb2c9e1025cd529890303ffbde813a98cdffed4 (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>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/agg-rx.c | 18 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 18 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 3 |
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 | ||
341 | end: | 355 | end: |
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 | } |