aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2008-01-28 07:07:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:19:19 -0500
commit0c11b4de5d81771ba0fdc8a5d13d59ed01d41252 (patch)
tree26bcbf8828bb0351a2939c7b07d113fb80ef3012 /drivers/net/wireless/iwlwifi/iwl-4965-rs.c
parent995564382f9d177214b6ec64db6b9109d4cd41dd (diff)
iwlwifi: A-MPDU Tx activation by load measures
This patch gives a heuristic for activation of the A-MPDU Tx. As the rate scaling is rate aware, it now also measures estimated load, and sends A-MPDU activation after a threshold has been met. Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-4965-rs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c204
1 files changed, 186 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index f4f2497646bd..660671f17a3b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -83,7 +83,7 @@ struct iwl4965_rate_scale_data {
83/** 83/**
84 * struct iwl4965_scale_tbl_info -- tx params and success history for all rates 84 * struct iwl4965_scale_tbl_info -- tx params and success history for all rates
85 * 85 *
86 * There are two of these in struct iwl_rate_scale_priv, 86 * There are two of these in struct iwl4965_lq_sta,
87 * one for "active", and one for "search". 87 * one for "active", and one for "search".
88 */ 88 */
89struct iwl4965_scale_tbl_info { 89struct iwl4965_scale_tbl_info {
@@ -98,8 +98,23 @@ struct iwl4965_scale_tbl_info {
98 struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ 98 struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
99}; 99};
100 100
101#ifdef CONFIG_IWL4965_HT
102
103struct iwl4965_traffic_load {
104 unsigned long time_stamp; /* age of the oldest statistics */
105 u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
106 * slice */
107 u32 total; /* total num of packets during the
108 * last TID_MAX_TIME_DIFF */
109 u8 queue_count; /* number of queues that has
110 * been used since the last cleanup */
111 u8 head; /* start of the circular buffer */
112};
113
114#endif /* CONFIG_IWL4965_HT */
115
101/** 116/**
102 * struct iwl_rate_scale_priv -- driver's rate scaling private structure 117 * struct iwl4965_lq_sta -- driver's rate scaling private structure
103 * 118 *
104 * Pointer to this gets passed back and forth between driver and mac80211. 119 * Pointer to this gets passed back and forth between driver and mac80211.
105 */ 120 */
@@ -136,9 +151,16 @@ struct iwl4965_lq_sta {
136 151
137 struct iwl4965_link_quality_cmd lq; 152 struct iwl4965_link_quality_cmd lq;
138 struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ 153 struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
154#ifdef CONFIG_IWL4965_HT
155 struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT];
156 u8 tx_agg_tid_en;
157#endif
139#ifdef CONFIG_MAC80211_DEBUGFS 158#ifdef CONFIG_MAC80211_DEBUGFS
140 struct dentry *rs_sta_dbgfs_scale_table_file; 159 struct dentry *rs_sta_dbgfs_scale_table_file;
141 struct dentry *rs_sta_dbgfs_stats_table_file; 160 struct dentry *rs_sta_dbgfs_stats_table_file;
161#ifdef CONFIG_IWL4965_HT
162 struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
163#endif
142 struct iwl4965_rate dbg_fixed; 164 struct iwl4965_rate dbg_fixed;
143 struct iwl4965_priv *drv; 165 struct iwl4965_priv *drv;
144#endif 166#endif
@@ -269,6 +291,135 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
269 window->stamp = 0; 291 window->stamp = 0;
270} 292}
271 293
294#ifdef CONFIG_IWL4965_HT
295/*
296 * removes the old data from the statistics. All data that is older than
297 * TID_MAX_TIME_DIFF, will be deleted.
298 */
299static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
300{
301 /* The oldest age we want to keep */
302 u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
303
304 while (tl->queue_count &&
305 (tl->time_stamp < oldest_time)) {
306 tl->total -= tl->packet_count[tl->head];
307 tl->packet_count[tl->head] = 0;
308 tl->time_stamp += TID_QUEUE_CELL_SPACING;
309 tl->queue_count--;
310 tl->head++;
311 if (tl->head >= TID_QUEUE_MAX_SIZE)
312 tl->head = 0;
313 }
314}
315
316/*
317 * increment traffic load value for tid and also remove
318 * any old values if passed the certain time period
319 */
320static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid)
321{
322 u32 curr_time = jiffies_to_msecs(jiffies);
323 u32 time_diff;
324 s32 index;
325 struct iwl4965_traffic_load *tl = NULL;
326
327 if (tid >= TID_MAX_LOAD_COUNT)
328 return;
329
330 tl = &lq_data->load[tid];
331
332 curr_time -= curr_time % TID_ROUND_VALUE;
333
334 /* Happens only for the first packet. Initialize the data */
335 if (!(tl->queue_count)) {
336 tl->total = 1;
337 tl->time_stamp = curr_time;
338 tl->queue_count = 1;
339 tl->head = 0;
340 tl->packet_count[0] = 1;
341 return;
342 }
343
344 time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
345 index = time_diff / TID_QUEUE_CELL_SPACING;
346
347 /* The history is too long: remove data that is older than */
348 /* TID_MAX_TIME_DIFF */
349 if (index >= TID_QUEUE_MAX_SIZE)
350 rs_tl_rm_old_stats(tl, curr_time);
351
352 index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
353 tl->packet_count[index] = tl->packet_count[index] + 1;
354 tl->total = tl->total + 1;
355
356 if ((index + 1) > tl->queue_count)
357 tl->queue_count = index + 1;
358}
359
360/*
361 get the traffic load value for tid
362*/
363static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid)
364{
365 u32 curr_time = jiffies_to_msecs(jiffies);
366 u32 time_diff;
367 s32 index;
368 struct iwl4965_traffic_load *tl = NULL;
369
370 if (tid >= TID_MAX_LOAD_COUNT)
371 return 0;
372
373 tl = &(lq_data->load[tid]);
374
375 curr_time -= curr_time % TID_ROUND_VALUE;
376
377 if (!(tl->queue_count))
378 return 0;
379
380 time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
381 index = time_diff / TID_QUEUE_CELL_SPACING;
382
383 /* The history is too long: remove data that is older than */
384 /* TID_MAX_TIME_DIFF */
385 if (index >= TID_QUEUE_MAX_SIZE)
386 rs_tl_rm_old_stats(tl, curr_time);
387
388 return tl->total;
389}
390
391static void rs_tl_turn_on_agg_for_tid(struct iwl4965_priv *priv,
392 struct iwl4965_lq_sta *lq_data, u8 tid,
393 struct sta_info *sta)
394{
395 unsigned long state;
396 DECLARE_MAC_BUF(mac);
397
398 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
399 state = sta->ampdu_mlme.tid_tx[tid].state;
400 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
401
402 if (state == HT_AGG_STATE_IDLE &&
403 rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
404 IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
405 print_mac(mac, sta->addr), tid);
406 ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
407 }
408}
409
410static void rs_tl_turn_on_agg(struct iwl4965_priv *priv, u8 tid,
411 struct iwl4965_lq_sta *lq_data,
412 struct sta_info *sta)
413{
414 if ((tid < TID_MAX_LOAD_COUNT))
415 rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
416 else if (tid == IWL_AGG_ALL_TID)
417 for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
418 rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
419}
420
421#endif /* CONFIG_IWLWIFI_HT */
422
272/** 423/**
273 * rs_collect_tx_data - Update the success/failure sliding window 424 * rs_collect_tx_data - Update the success/failure sliding window
274 * 425 *
@@ -1134,7 +1285,7 @@ static int rs_switch_to_mimo(struct iwl4965_priv *priv,
1134 return 0; 1285 return 0;
1135#else 1286#else
1136 return -1; 1287 return -1;
1137#endif /*CONFIG_IWL4965_HT */ 1288#endif /*CONFIG_IWL4965_HT */
1138} 1289}
1139 1290
1140/* 1291/*
@@ -1197,7 +1348,7 @@ static int rs_switch_to_siso(struct iwl4965_priv *priv,
1197#else 1348#else
1198 return -1; 1349 return -1;
1199 1350
1200#endif /*CONFIG_IWL4965_HT */ 1351#endif /*CONFIG_IWL4965_HT */
1201} 1352}
1202 1353
1203/* 1354/*
@@ -1354,6 +1505,7 @@ static int rs_move_siso_to_other(struct iwl4965_priv *priv,
1354 break; 1505 break;
1355 case IWL_SISO_SWITCH_GI: 1506 case IWL_SISO_SWITCH_GI:
1356 IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); 1507 IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
1508
1357 memcpy(search_tbl, tbl, sz); 1509 memcpy(search_tbl, tbl, sz);
1358 search_tbl->action = 0; 1510 search_tbl->action = 0;
1359 if (search_tbl->is_SGI) 1511 if (search_tbl->is_SGI)
@@ -1419,6 +1571,7 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv,
1419 case IWL_MIMO_SWITCH_ANTENNA_B: 1571 case IWL_MIMO_SWITCH_ANTENNA_B:
1420 IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); 1572 IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
1421 1573
1574
1422 /* Set up new search table for SISO */ 1575 /* Set up new search table for SISO */
1423 memcpy(search_tbl, tbl, sz); 1576 memcpy(search_tbl, tbl, sz);
1424 search_tbl->lq_type = LQ_SISO; 1577 search_tbl->lq_type = LQ_SISO;
@@ -1603,6 +1756,10 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv,
1603 u8 active_tbl = 0; 1756 u8 active_tbl = 0;
1604 u8 done_search = 0; 1757 u8 done_search = 0;
1605 u16 high_low; 1758 u16 high_low;
1759#ifdef CONFIG_IWL4965_HT
1760 u8 tid = MAX_TID_COUNT;
1761 __le16 *qc;
1762#endif
1606 1763
1607 IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); 1764 IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
1608 1765
@@ -1623,6 +1780,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv,
1623 } 1780 }
1624 lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; 1781 lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
1625 1782
1783#ifdef CONFIG_IWL4965_HT
1784 qc = ieee80211_get_qos_ctrl(hdr);
1785 if (qc) {
1786 tid = (u8)(le16_to_cpu(*qc) & 0xf);
1787 rs_tl_add_packet(lq_sta, tid);
1788 }
1789#endif
1626 /* 1790 /*
1627 * Select rate-scale / modulation-mode table to work with in 1791 * Select rate-scale / modulation-mode table to work with in
1628 * the rest of this function: "search" if searching for better 1792 * the rest of this function: "search" if searching for better
@@ -1943,15 +2107,14 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv,
1943 * mode for a while before next round of mode comparisons. */ 2107 * mode for a while before next round of mode comparisons. */
1944 if (lq_sta->enable_counter && 2108 if (lq_sta->enable_counter &&
1945 (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { 2109 (lq_sta->action_counter >= IWL_ACTION_LIMIT)) {
1946#ifdef CONFIG_IWL4965_HT_AGG 2110#ifdef CONFIG_IWL4965_HT
1947 /* If appropriate, set up aggregation! */ 2111 if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
1948 if ((lq_sta->last_tpt > TID_AGG_TPT_THREHOLD) && 2112 (lq_sta->tx_agg_tid_en & (1 << tid)) &&
1949 (priv->lq_mngr.agg_ctrl.auto_agg)) { 2113 (tid != MAX_TID_COUNT)) {
1950 priv->lq_mngr.agg_ctrl.tid_retry = 2114 IWL_DEBUG_HT("try to aggregate tid %d\n", tid);
1951 TID_ALL_SPECIFIED; 2115 rs_tl_turn_on_agg(priv, tid, lq_sta, sta);
1952 schedule_work(&priv->agg_work);
1953 } 2116 }
1954#endif /*CONFIG_IWL4965_HT_AGG */ 2117#endif /*CONFIG_IWL4965_HT */
1955 lq_sta->action_counter = 0; 2118 lq_sta->action_counter = 0;
1956 rs_set_stay_in_table(0, lq_sta); 2119 rs_set_stay_in_table(0, lq_sta);
1957 } 2120 }
@@ -2209,6 +2372,8 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
2209 IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n", 2372 IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n",
2210 lq_sta->active_siso_rate, 2373 lq_sta->active_siso_rate,
2211 lq_sta->active_mimo_rate); 2374 lq_sta->active_mimo_rate);
2375 /* as default allow aggregation for all tids */
2376 lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
2212#endif /*CONFIG_IWL4965_HT*/ 2377#endif /*CONFIG_IWL4965_HT*/
2213#ifdef CONFIG_MAC80211_DEBUGFS 2378#ifdef CONFIG_MAC80211_DEBUGFS
2214 lq_sta->drv = priv; 2379 lq_sta->drv = priv;
@@ -2352,12 +2517,6 @@ static void rs_clear(void *priv_rate)
2352 IWL_DEBUG_RATE("enter\n"); 2517 IWL_DEBUG_RATE("enter\n");
2353 2518
2354 priv->lq_mngr.lq_ready = 0; 2519 priv->lq_mngr.lq_ready = 0;
2355#ifdef CONFIG_IWL4965_HT
2356#ifdef CONFIG_IWL4965_HT_AGG
2357 if (priv->lq_mngr.agg_ctrl.granted_ba)
2358 iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
2359#endif /*CONFIG_IWL4965_HT_AGG */
2360#endif /* CONFIG_IWL4965_HT */
2361 2520
2362 IWL_DEBUG_RATE("leave\n"); 2521 IWL_DEBUG_RATE("leave\n");
2363} 2522}
@@ -2524,6 +2683,12 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
2524 lq_sta->rs_sta_dbgfs_stats_table_file = 2683 lq_sta->rs_sta_dbgfs_stats_table_file =
2525 debugfs_create_file("rate_stats_table", 0600, dir, 2684 debugfs_create_file("rate_stats_table", 0600, dir,
2526 lq_sta, &rs_sta_dbgfs_stats_table_ops); 2685 lq_sta, &rs_sta_dbgfs_stats_table_ops);
2686#ifdef CONFIG_IWL4965_HT
2687 lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
2688 debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
2689 &lq_sta->tx_agg_tid_en);
2690#endif
2691
2527} 2692}
2528 2693
2529static void rs_remove_debugfs(void *priv, void *priv_sta) 2694static void rs_remove_debugfs(void *priv, void *priv_sta)
@@ -2531,6 +2696,9 @@ static void rs_remove_debugfs(void *priv, void *priv_sta)
2531 struct iwl4965_lq_sta *lq_sta = priv_sta; 2696 struct iwl4965_lq_sta *lq_sta = priv_sta;
2532 debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); 2697 debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
2533 debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); 2698 debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
2699#ifdef CONFIG_IWL4965_HT
2700 debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
2701#endif
2534} 2702}
2535#endif 2703#endif
2536 2704