aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c204
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c396
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h54
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c20
5 files changed, 199 insertions, 487 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index 55f707382787..13b6c72eeb73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -212,6 +212,18 @@ enum {
212 212
213#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ 213#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */
214 214
215/* load per tid defines for A-MPDU activation */
216#define IWL_AGG_TPT_THREHOLD 0
217#define IWL_AGG_LOAD_THRESHOLD 10
218#define IWL_AGG_ALL_TID 0xff
219#define TID_QUEUE_CELL_SPACING 50 /*mS */
220#define TID_QUEUE_MAX_SIZE 20
221#define TID_ROUND_VALUE 5 /* mS */
222#define TID_MAX_LOAD_COUNT 8
223
224#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
225#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
226
215extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; 227extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
216 228
217enum iwl4965_table_type { 229enum iwl4965_table_type {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 89aff4aae45f..e81120cc45f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2946,378 +2946,6 @@ void iwl4965_set_rxon_chain(struct iwl4965_priv *priv)
2946 IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); 2946 IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
2947} 2947}
2948 2948
2949#ifdef CONFIG_IWL4965_HT
2950#ifdef CONFIG_IWL4965_HT_AGG
2951/*
2952 get the traffic load value for tid
2953*/
2954static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid)
2955{
2956 u32 load = 0;
2957 u32 current_time = jiffies_to_msecs(jiffies);
2958 u32 time_diff;
2959 s32 index;
2960 unsigned long flags;
2961 struct iwl4965_traffic_load *tid_ptr = NULL;
2962
2963 if (tid >= TID_MAX_LOAD_COUNT)
2964 return 0;
2965
2966 tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
2967
2968 current_time -= current_time % TID_ROUND_VALUE;
2969
2970 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
2971 if (!(tid_ptr->queue_count))
2972 goto out;
2973
2974 time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
2975 index = time_diff / TID_QUEUE_CELL_SPACING;
2976
2977 if (index >= TID_QUEUE_MAX_SIZE) {
2978 u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
2979
2980 while (tid_ptr->queue_count &&
2981 (tid_ptr->time_stamp < oldest_time)) {
2982 tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
2983 tid_ptr->packet_count[tid_ptr->head] = 0;
2984 tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
2985 tid_ptr->queue_count--;
2986 tid_ptr->head++;
2987 if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
2988 tid_ptr->head = 0;
2989 }
2990 }
2991 load = tid_ptr->total;
2992
2993 out:
2994 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
2995 return load;
2996}
2997
2998/*
2999 increment traffic load value for tid and also remove
3000 any old values if passed the certian time period
3001*/
3002static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid)
3003{
3004 u32 current_time = jiffies_to_msecs(jiffies);
3005 u32 time_diff;
3006 s32 index;
3007 unsigned long flags;
3008 struct iwl4965_traffic_load *tid_ptr = NULL;
3009
3010 if (tid >= TID_MAX_LOAD_COUNT)
3011 return;
3012
3013 tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
3014
3015 current_time -= current_time % TID_ROUND_VALUE;
3016
3017 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3018 if (!(tid_ptr->queue_count)) {
3019 tid_ptr->total = 1;
3020 tid_ptr->time_stamp = current_time;
3021 tid_ptr->queue_count = 1;
3022 tid_ptr->head = 0;
3023 tid_ptr->packet_count[0] = 1;
3024 goto out;
3025 }
3026
3027 time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
3028 index = time_diff / TID_QUEUE_CELL_SPACING;
3029
3030 if (index >= TID_QUEUE_MAX_SIZE) {
3031 u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
3032
3033 while (tid_ptr->queue_count &&
3034 (tid_ptr->time_stamp < oldest_time)) {
3035 tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
3036 tid_ptr->packet_count[tid_ptr->head] = 0;
3037 tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
3038 tid_ptr->queue_count--;
3039 tid_ptr->head++;
3040 if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
3041 tid_ptr->head = 0;
3042 }
3043 }
3044
3045 index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
3046 tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
3047 tid_ptr->total = tid_ptr->total + 1;
3048
3049 if ((index + 1) > tid_ptr->queue_count)
3050 tid_ptr->queue_count = index + 1;
3051 out:
3052 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3053
3054}
3055
3056#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7
3057enum HT_STATUS {
3058 BA_STATUS_FAILURE = 0,
3059 BA_STATUS_INITIATOR_DELBA,
3060 BA_STATUS_RECIPIENT_DELBA,
3061 BA_STATUS_RENEW_ADDBA_REQUEST,
3062 BA_STATUS_ACTIVE,
3063};
3064
3065/**
3066 * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available
3067 */
3068static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv)
3069{
3070 int i;
3071 struct iwl4965_lq_mngr *lq;
3072 u8 count = 0;
3073 u16 msk;
3074
3075 lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
3076
3077 /* Find out how many agg queues are in use */
3078 for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
3079 msk = 1 << i;
3080 if ((lq->agg_ctrl.granted_ba & msk) ||
3081 (lq->agg_ctrl.wait_for_agg_status & msk))
3082 count++;
3083 }
3084
3085 if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
3086 return 1;
3087
3088 return 0;
3089}
3090
3091static void iwl4965_ba_status(struct iwl4965_priv *priv,
3092 u8 tid, enum HT_STATUS status);
3093
3094static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length,
3095 u32 ba_timeout)
3096{
3097 int rc;
3098
3099 rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
3100 if (rc)
3101 iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
3102
3103 return rc;
3104}
3105
3106static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid)
3107{
3108 int rc;
3109
3110 rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
3111 if (rc)
3112 iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
3113
3114 return rc;
3115}
3116
3117static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv,
3118 struct iwl4965_lq_mngr *lq,
3119 u8 auto_agg, u8 tid)
3120{
3121 u32 tid_msk = (1 << tid);
3122 unsigned long flags;
3123
3124 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3125/*
3126 if ((auto_agg) && (!lq->enable_counter)){
3127 lq->agg_ctrl.next_retry = 0;
3128 lq->agg_ctrl.tid_retry = 0;
3129 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3130 return;
3131 }
3132*/
3133 if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
3134 (lq->agg_ctrl.requested_ba & tid_msk)) {
3135 u8 available_queues;
3136 u32 load;
3137
3138 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3139 available_queues = iwl4964_tl_ba_avail(priv);
3140 load = iwl4965_tl_get_load(priv, tid);
3141
3142 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3143 if (!available_queues) {
3144 if (auto_agg)
3145 lq->agg_ctrl.tid_retry |= tid_msk;
3146 else {
3147 lq->agg_ctrl.requested_ba &= ~tid_msk;
3148 lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
3149 }
3150 } else if ((auto_agg) &&
3151 ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
3152 ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
3153 lq->agg_ctrl.tid_retry |= tid_msk;
3154 else {
3155 lq->agg_ctrl.wait_for_agg_status |= tid_msk;
3156 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3157 iwl4965_perform_addba(priv, tid, 0x40,
3158 lq->agg_ctrl.ba_timeout);
3159 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3160 }
3161 }
3162 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3163}
3164
3165static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid)
3166{
3167 struct iwl4965_lq_mngr *lq;
3168 unsigned long flags;
3169
3170 lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
3171
3172 if ((tid < TID_MAX_LOAD_COUNT))
3173 iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
3174 tid);
3175 else if (tid == TID_ALL_SPECIFIED) {
3176 if (lq->agg_ctrl.requested_ba) {
3177 for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
3178 iwl4965_turn_on_agg_for_tid(priv, lq,
3179 lq->agg_ctrl.auto_agg, tid);
3180 } else {
3181 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3182 lq->agg_ctrl.tid_retry = 0;
3183 lq->agg_ctrl.next_retry = 0;
3184 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3185 }
3186 }
3187
3188}
3189
3190void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid)
3191{
3192 u32 tid_msk;
3193 struct iwl4965_lq_mngr *lq;
3194 unsigned long flags;
3195
3196 lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
3197
3198 if ((tid < TID_MAX_LOAD_COUNT)) {
3199 tid_msk = 1 << tid;
3200 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3201 lq->agg_ctrl.wait_for_agg_status |= tid_msk;
3202 lq->agg_ctrl.requested_ba &= ~tid_msk;
3203 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3204 iwl4965_perform_delba(priv, tid);
3205 } else if (tid == TID_ALL_SPECIFIED) {
3206 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3207 for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
3208 tid_msk = 1 << tid;
3209 lq->agg_ctrl.wait_for_agg_status |= tid_msk;
3210 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3211 iwl4965_perform_delba(priv, tid);
3212 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3213 }
3214 lq->agg_ctrl.requested_ba = 0;
3215 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3216 }
3217}
3218
3219/**
3220 * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status
3221 */
3222static void iwl4965_ba_status(struct iwl4965_priv *priv,
3223 u8 tid, enum HT_STATUS status)
3224{
3225 struct iwl4965_lq_mngr *lq;
3226 u32 tid_msk = (1 << tid);
3227 unsigned long flags;
3228
3229 lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
3230
3231 if ((tid >= TID_MAX_LOAD_COUNT))
3232 goto out;
3233
3234 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3235 switch (status) {
3236 case BA_STATUS_ACTIVE:
3237 if (!(lq->agg_ctrl.granted_ba & tid_msk))
3238 lq->agg_ctrl.granted_ba |= tid_msk;
3239 break;
3240 default:
3241 if ((lq->agg_ctrl.granted_ba & tid_msk))
3242 lq->agg_ctrl.granted_ba &= ~tid_msk;
3243 break;
3244 }
3245
3246 lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
3247 if (status != BA_STATUS_ACTIVE) {
3248 if (lq->agg_ctrl.auto_agg) {
3249 lq->agg_ctrl.tid_retry |= tid_msk;
3250 lq->agg_ctrl.next_retry =
3251 jiffies + msecs_to_jiffies(500);
3252 } else
3253 lq->agg_ctrl.requested_ba &= ~tid_msk;
3254 }
3255 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3256 out:
3257 return;
3258}
3259
3260static void iwl4965_bg_agg_work(struct work_struct *work)
3261{
3262 struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
3263 agg_work);
3264
3265 u32 tid;
3266 u32 retry_tid;
3267 u32 tid_msk;
3268 unsigned long flags;
3269 struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
3270
3271 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3272 retry_tid = lq->agg_ctrl.tid_retry;
3273 lq->agg_ctrl.tid_retry = 0;
3274 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3275
3276 if (retry_tid == TID_ALL_SPECIFIED)
3277 iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
3278 else {
3279 for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
3280 tid_msk = (1 << tid);
3281 if (retry_tid & tid_msk)
3282 iwl4965_turn_on_agg(priv, tid);
3283 }
3284 }
3285
3286 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3287 if (lq->agg_ctrl.tid_retry)
3288 lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
3289 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3290 return;
3291}
3292
3293/* TODO: move this functionality to rate scaling */
3294void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
3295 struct ieee80211_hdr *hdr)
3296{
3297 __le16 *qc = ieee80211_get_qos_ctrl(hdr);
3298
3299 if (qc &&
3300 (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
3301 u8 tid = 0;
3302 tid = (u8) (le16_to_cpu(*qc) & 0xF);
3303 if (tid < TID_MAX_LOAD_COUNT)
3304 iwl4965_tl_add_packet(priv, tid);
3305 }
3306
3307 if (priv->lq_mngr.agg_ctrl.next_retry &&
3308 (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
3309 unsigned long flags;
3310
3311 spin_lock_irqsave(&priv->lq_mngr.lock, flags);
3312 priv->lq_mngr.agg_ctrl.next_retry = 0;
3313 spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
3314 schedule_work(&priv->agg_work);
3315 }
3316}
3317
3318#endif /*CONFIG_IWL4965_HT_AGG */
3319#endif /* CONFIG_IWL4965_HT */
3320
3321/** 2949/**
3322 * sign_extend - Sign extend a value using specified bit as sign-bit 2950 * sign_extend - Sign extend a value using specified bit as sign-bit
3323 * 2951 *
@@ -4191,25 +3819,6 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv,
4191} 3819}
4192 3820
4193#ifdef CONFIG_IWL4965_HT 3821#ifdef CONFIG_IWL4965_HT
4194#ifdef CONFIG_IWL4965_HT_AGG
4195
4196/**
4197 * iwl4965_set_tx_status - Update driver's record of one Tx frame's status
4198 *
4199 * This will get sent to mac80211.
4200 */
4201static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx,
4202 u32 status, u32 retry_count, u32 rate)
4203{
4204 struct ieee80211_tx_status *tx_status =
4205 &(priv->txq[txq_id].txb[idx].status);
4206
4207 tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
4208 tx_status->retry_count += retry_count;
4209 tx_status->control.tx_rate = rate;
4210}
4211
4212#endif/* CONFIG_IWL4965_HT_AGG */
4213 3822
4214/** 3823/**
4215 * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table 3824 * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
@@ -4984,11 +4593,6 @@ void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv)
4984#ifdef CONFIG_IWL4965_SENSITIVITY 4593#ifdef CONFIG_IWL4965_SENSITIVITY
4985 INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); 4594 INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
4986#endif 4595#endif
4987#ifdef CONFIG_IWL4965_HT
4988#ifdef CONFIG_IWL4965_HT_AGG
4989 INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
4990#endif /* CONFIG_IWL4965_HT_AGG */
4991#endif /* CONFIG_IWL4965_HT */
4992 init_timer(&priv->statistics_periodic); 4596 init_timer(&priv->statistics_periodic);
4993 priv->statistics_periodic.data = (unsigned long)priv; 4597 priv->statistics_periodic.data = (unsigned long)priv;
4994 priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; 4598 priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 47c7f3ffe369..de5c1bf8fc42 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -782,11 +782,6 @@ extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
782 const u8 *addr, u16 tid, u16 *ssn); 782 const u8 *addr, u16 tid, u16 *ssn);
783extern int iwl4965_check_empty_hw_queue(struct iwl4965_priv *priv, int sta_id, 783extern int iwl4965_check_empty_hw_queue(struct iwl4965_priv *priv, int sta_id,
784 u8 tid, int txq_id); 784 u8 tid, int txq_id);
785#ifdef CONFIG_IWL4965_HT_AGG
786extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid);
787extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
788 struct ieee80211_hdr *hdr);
789#endif /* CONFIG_IWL4965_HT_AGG */
790#endif /*CONFIG_IWL4965_HT */ 785#endif /*CONFIG_IWL4965_HT */
791/* Structures, enum, and defines specific to the 4965 */ 786/* Structures, enum, and defines specific to the 4965 */
792 787
@@ -798,18 +793,6 @@ struct iwl4965_kw {
798 size_t size; 793 size_t size;
799}; 794};
800 795
801#define TID_QUEUE_CELL_SPACING 50 /*mS */
802#define TID_QUEUE_MAX_SIZE 20
803#define TID_ROUND_VALUE 5 /* mS */
804#define TID_MAX_LOAD_COUNT 8
805
806#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
807#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
808
809#define TID_ALL_ENABLED 0x7f
810#define TID_ALL_SPECIFIED 0xff
811#define TID_AGG_TPT_THREHOLD 0x0
812
813#define IWL_CHANNEL_WIDTH_20MHZ 0 796#define IWL_CHANNEL_WIDTH_20MHZ 0
814#define IWL_CHANNEL_WIDTH_40MHZ 1 797#define IWL_CHANNEL_WIDTH_40MHZ 1
815 798
@@ -834,37 +817,7 @@ struct iwl4965_kw {
834 817
835#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 818#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
836 819
837struct iwl4965_traffic_load {
838 unsigned long time_stamp;
839 u32 packet_count[TID_QUEUE_MAX_SIZE];
840 u8 queue_count;
841 u8 head;
842 u32 total;
843};
844
845#ifdef CONFIG_IWL4965_HT_AGG
846/**
847 * struct iwl4965_agg_control
848 * @requested_ba: bit map of tids requesting aggregation/block-ack
849 * @granted_ba: bit map of tids granted aggregation/block-ack
850 */
851struct iwl4965_agg_control {
852 unsigned long next_retry;
853 u32 wait_for_agg_status;
854 u32 tid_retry;
855 u32 requested_ba;
856 u32 granted_ba;
857 u8 auto_agg;
858 u32 tid_traffic_load_threshold;
859 u32 ba_timeout;
860 struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
861};
862#endif /*CONFIG_IWL4965_HT_AGG */
863
864struct iwl4965_lq_mngr { 820struct iwl4965_lq_mngr {
865#ifdef CONFIG_IWL4965_HT_AGG
866 struct iwl4965_agg_control agg_ctrl;
867#endif
868 spinlock_t lock; 821 spinlock_t lock;
869 s32 max_window_size; 822 s32 max_window_size;
870 s32 *expected_tpt; 823 s32 *expected_tpt;
@@ -877,7 +830,6 @@ struct iwl4965_lq_mngr {
877 u8 lq_ready; 830 u8 lq_ready;
878}; 831};
879 832
880
881/* Sensitivity and chain noise calibration */ 833/* Sensitivity and chain noise calibration */
882#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) 834#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
883#define INITIALIZATION_VALUE 0xFFFF 835#define INITIALIZATION_VALUE 0xFFFF
@@ -1265,11 +1217,7 @@ struct iwl4965_priv {
1265#endif 1217#endif
1266 struct work_struct statistics_work; 1218 struct work_struct statistics_work;
1267 struct timer_list statistics_periodic; 1219 struct timer_list statistics_periodic;
1268 1220}; /*iwl4965_priv */
1269#ifdef CONFIG_IWL4965_HT_AGG
1270 struct work_struct agg_work;
1271#endif
1272}; /*iwl4965_priv */
1273 1221
1274static inline int iwl4965_is_associated(struct iwl4965_priv *priv) 1222static inline int iwl4965_is_associated(struct iwl4965_priv *priv)
1275{ 1223{
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 16cb990e06fa..5f38fc585eda 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -3075,14 +3075,6 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
3075 out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); 3075 out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
3076 out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); 3076 out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
3077 3077
3078#ifdef CONFIG_IWL4965_HT_AGG
3079#ifdef CONFIG_IWL4965_HT
3080 /* TODO: move this functionality to rate scaling */
3081 iwl4965_tl_get_stats(priv, hdr);
3082#endif /* CONFIG_IWL4965_HT_AGG */
3083#endif /*CONFIG_IWL4965_HT */
3084
3085
3086 if (!ieee80211_get_morefrag(hdr)) { 3078 if (!ieee80211_get_morefrag(hdr)) {
3087 txq->need_update = 1; 3079 txq->need_update = 1;
3088 if (qc) { 3080 if (qc) {
@@ -8102,18 +8094,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
8102 spin_lock_irqsave(&priv->lock, flags); 8094 spin_lock_irqsave(&priv->lock, flags);
8103 memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); 8095 memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
8104 spin_unlock_irqrestore(&priv->lock, flags); 8096 spin_unlock_irqrestore(&priv->lock, flags);
8105#ifdef CONFIG_IWL4965_HT_AGG
8106/* if (priv->lq_mngr.agg_ctrl.granted_ba)
8107 iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
8108
8109 memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control));
8110 priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
8111 priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
8112 priv->lq_mngr.agg_ctrl.auto_agg = 1;
8113
8114 if (priv->lq_mngr.agg_ctrl.auto_agg)
8115 priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
8116#endif /*CONFIG_IWL4965_HT_AGG */
8117#endif /* CONFIG_IWL4965_HT */ 8097#endif /* CONFIG_IWL4965_HT */
8118 8098
8119#ifdef CONFIG_IWL4965_QOS 8099#ifdef CONFIG_IWL4965_QOS