diff options
author | Ben Cahill <ben.m.cahill@intel.com> | 2007-11-28 22:09:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:05:15 -0500 |
commit | 7762635547ad31ecb045e7073989e76ae13e6c54 (patch) | |
tree | 041e42e31702b2a0e9934baf7c395aa0c314fb63 /drivers/net/wireless/iwlwifi/iwl-4965-rs.c | |
parent | f58177b9c3f377eee31bac719bda87e1aab415ab (diff) |
iwl4965: add comments to rate scaling code
Add comments to rate scaling code.
Signed-off-by: Ben Cahill <ben.m.cahill@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@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.c | 467 |
1 files changed, 409 insertions, 58 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 8d3d9f72a8ce..218c5a355ddb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c | |||
@@ -47,13 +47,12 @@ | |||
47 | #define IWL_NUMBER_TRY 1 | 47 | #define IWL_NUMBER_TRY 1 |
48 | #define IWL_HT_NUMBER_TRY 3 | 48 | #define IWL_HT_NUMBER_TRY 3 |
49 | 49 | ||
50 | #define IWL_RATE_MAX_WINDOW 62 | 50 | #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ |
51 | #define IWL_RATE_HIGH_TH 10880 | 51 | #define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ |
52 | #define IWL_RATE_MIN_FAILURE_TH 6 | 52 | #define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ |
53 | #define IWL_RATE_MIN_SUCCESS_TH 8 | 53 | |
54 | #define IWL_RATE_DECREASE_TH 1920 | 54 | /* max time to accum history 2 seconds */ |
55 | #define IWL_RATE_INCREASE_TH 8960 | 55 | #define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) |
56 | #define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */ | ||
57 | 56 | ||
58 | static u8 rs_ht_to_legacy[] = { | 57 | static u8 rs_ht_to_legacy[] = { |
59 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, | 58 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, |
@@ -69,54 +68,74 @@ struct iwl4965_rate { | |||
69 | u32 rate_n_flags; | 68 | u32 rate_n_flags; |
70 | } __attribute__ ((packed)); | 69 | } __attribute__ ((packed)); |
71 | 70 | ||
71 | /** | ||
72 | * struct iwl4965_rate_scale_data -- tx success history for one rate | ||
73 | */ | ||
72 | struct iwl4965_rate_scale_data { | 74 | struct iwl4965_rate_scale_data { |
73 | u64 data; | 75 | u64 data; /* bitmap of successful frames */ |
74 | s32 success_counter; | 76 | s32 success_counter; /* number of frames successful */ |
75 | s32 success_ratio; | 77 | s32 success_ratio; /* per-cent * 128 */ |
76 | s32 counter; | 78 | s32 counter; /* number of frames attempted */ |
77 | s32 average_tpt; | 79 | s32 average_tpt; /* success ratio * expected throughput */ |
78 | unsigned long stamp; | 80 | unsigned long stamp; |
79 | }; | 81 | }; |
80 | 82 | ||
83 | /** | ||
84 | * struct iwl4965_scale_tbl_info -- tx params and success history for all rates | ||
85 | * | ||
86 | * There are two of these in struct iwl_rate_scale_priv, | ||
87 | * one for "active", and one for "search". | ||
88 | */ | ||
81 | struct iwl4965_scale_tbl_info { | 89 | struct iwl4965_scale_tbl_info { |
82 | enum iwl4965_table_type lq_type; | 90 | enum iwl4965_table_type lq_type; |
83 | enum iwl4965_antenna_type antenna_type; | 91 | enum iwl4965_antenna_type antenna_type; |
84 | u8 is_SGI; | 92 | u8 is_SGI; /* 1 = short guard interval */ |
85 | u8 is_fat; | 93 | u8 is_fat; /* 1 = 40 MHz channel width */ |
86 | u8 is_dup; | 94 | u8 is_dup; /* 1 = duplicated data streams */ |
87 | u8 action; | 95 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ |
88 | s32 *expected_tpt; | 96 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ |
89 | struct iwl4965_rate current_rate; | 97 | struct iwl4965_rate current_rate; /* rate_n_flags, uCode API format */ |
90 | struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; | 98 | struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ |
91 | }; | 99 | }; |
92 | 100 | ||
101 | /** | ||
102 | * struct iwl_rate_scale_priv -- driver's rate scaling private structure | ||
103 | * | ||
104 | * Pointer to this gets passed back and forth between driver and mac80211. | ||
105 | */ | ||
93 | struct iwl4965_rate_scale_priv { | 106 | struct iwl4965_rate_scale_priv { |
94 | u8 active_tbl; | 107 | u8 active_tbl; /* index of active table, range 0-1 */ |
95 | u8 enable_counter; | 108 | u8 enable_counter; /* indicates HT mode */ |
96 | u8 stay_in_tbl; | 109 | u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ |
97 | u8 search_better_tbl; | 110 | u8 search_better_tbl; /* 1: currently trying alternate mode */ |
98 | s32 last_tpt; | 111 | s32 last_tpt; |
112 | |||
113 | /* The following determine when to search for a new mode */ | ||
99 | u32 table_count_limit; | 114 | u32 table_count_limit; |
100 | u32 max_failure_limit; | 115 | u32 max_failure_limit; /* # failed frames before new search */ |
101 | u32 max_success_limit; | 116 | u32 max_success_limit; /* # successful frames before new search */ |
102 | u32 table_count; | 117 | u32 table_count; |
103 | u32 total_failed; | 118 | u32 total_failed; /* total failed frames, any/all rates */ |
104 | u32 total_success; | 119 | u32 total_success; /* total successful frames, any/all rates */ |
105 | u32 flush_timer; | 120 | u32 flush_timer; /* time staying in mode before new search */ |
106 | u8 action_counter; | 121 | |
122 | u8 action_counter; /* # mode-switch actions tried */ | ||
107 | u8 antenna; | 123 | u8 antenna; |
108 | u8 valid_antenna; | 124 | u8 valid_antenna; |
109 | u8 is_green; | 125 | u8 is_green; |
110 | u8 is_dup; | 126 | u8 is_dup; |
111 | u8 phymode; | 127 | u8 phymode; |
112 | u8 ibss_sta_added; | 128 | u8 ibss_sta_added; |
129 | |||
130 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | ||
113 | u32 supp_rates; | 131 | u32 supp_rates; |
114 | u16 active_rate; | 132 | u16 active_rate; |
115 | u16 active_siso_rate; | 133 | u16 active_siso_rate; |
116 | u16 active_mimo_rate; | 134 | u16 active_mimo_rate; |
117 | u16 active_rate_basic; | 135 | u16 active_rate_basic; |
136 | |||
118 | struct iwl4965_link_quality_cmd lq; | 137 | struct iwl4965_link_quality_cmd lq; |
119 | struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; | 138 | struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ |
120 | #ifdef CONFIG_MAC80211_DEBUGFS | 139 | #ifdef CONFIG_MAC80211_DEBUGFS |
121 | struct dentry *rs_sta_dbgfs_scale_table_file; | 140 | struct dentry *rs_sta_dbgfs_scale_table_file; |
122 | struct dentry *rs_sta_dbgfs_stats_table_file; | 141 | struct dentry *rs_sta_dbgfs_stats_table_file; |
@@ -142,6 +161,12 @@ static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv, | |||
142 | struct iwl4965_rate *mcs, int index) | 161 | struct iwl4965_rate *mcs, int index) |
143 | {} | 162 | {} |
144 | #endif | 163 | #endif |
164 | |||
165 | /* | ||
166 | * Expected throughput metrics for following rates: | ||
167 | * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits | ||
168 | * "G" is the only table that supports CCK (the first 4 rates). | ||
169 | */ | ||
145 | static s32 expected_tpt_A[IWL_RATE_COUNT] = { | 170 | static s32 expected_tpt_A[IWL_RATE_COUNT] = { |
146 | 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 | 171 | 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 |
147 | }; | 172 | }; |
@@ -244,6 +269,13 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) | |||
244 | window->stamp = 0; | 269 | window->stamp = 0; |
245 | } | 270 | } |
246 | 271 | ||
272 | /** | ||
273 | * rs_collect_tx_data - Update the success/failure sliding window | ||
274 | * | ||
275 | * We keep a sliding window of the last 62 packets transmitted | ||
276 | * at this rate. window->data contains the bitmask of successful | ||
277 | * packets. | ||
278 | */ | ||
247 | static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, | 279 | static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, |
248 | int scale_index, s32 tpt, u32 status) | 280 | int scale_index, s32 tpt, u32 status) |
249 | { | 281 | { |
@@ -255,10 +287,18 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, | |||
255 | if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) | 287 | if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) |
256 | return -EINVAL; | 288 | return -EINVAL; |
257 | 289 | ||
290 | /* Select data for current tx bit rate */ | ||
258 | window = &(windows[scale_index]); | 291 | window = &(windows[scale_index]); |
259 | 292 | ||
293 | /* | ||
294 | * Keep track of only the latest 62 tx frame attempts in this rate's | ||
295 | * history window; anything older isn't really relevant any more. | ||
296 | * If we have filled up the sliding window, drop the oldest attempt; | ||
297 | * if the oldest attempt (highest bit in bitmap) shows "success", | ||
298 | * subtract "1" from the success counter (this is the main reason | ||
299 | * we keep these bitmaps!). | ||
300 | */ | ||
260 | if (window->counter >= win_size) { | 301 | if (window->counter >= win_size) { |
261 | |||
262 | window->counter = win_size - 1; | 302 | window->counter = win_size - 1; |
263 | mask = 1; | 303 | mask = 1; |
264 | mask = (mask << (win_size - 1)); | 304 | mask = (mask << (win_size - 1)); |
@@ -268,7 +308,11 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, | |||
268 | } | 308 | } |
269 | } | 309 | } |
270 | 310 | ||
311 | /* Increment frames-attempted counter */ | ||
271 | window->counter = window->counter + 1; | 312 | window->counter = window->counter + 1; |
313 | |||
314 | /* Shift bitmap by one frame (throw away oldest history), | ||
315 | * OR in "1", and increment "success" if this frame was successful. */ | ||
272 | mask = window->data; | 316 | mask = window->data; |
273 | window->data = (mask << 1); | 317 | window->data = (mask << 1); |
274 | if (status != 0) { | 318 | if (status != 0) { |
@@ -276,6 +320,7 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, | |||
276 | window->data |= 0x1; | 320 | window->data |= 0x1; |
277 | } | 321 | } |
278 | 322 | ||
323 | /* Calculate current success ratio, avoid divide-by-0! */ | ||
279 | if (window->counter > 0) | 324 | if (window->counter > 0) |
280 | window->success_ratio = 128 * (100 * window->success_counter) | 325 | window->success_ratio = 128 * (100 * window->success_counter) |
281 | / window->counter; | 326 | / window->counter; |
@@ -284,17 +329,22 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, | |||
284 | 329 | ||
285 | fail_count = window->counter - window->success_counter; | 330 | fail_count = window->counter - window->success_counter; |
286 | 331 | ||
332 | /* Calculate average throughput, if we have enough history. */ | ||
287 | if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || | 333 | if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || |
288 | (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) | 334 | (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) |
289 | window->average_tpt = (window->success_ratio * tpt + 64) / 128; | 335 | window->average_tpt = (window->success_ratio * tpt + 64) / 128; |
290 | else | 336 | else |
291 | window->average_tpt = IWL_INVALID_VALUE; | 337 | window->average_tpt = IWL_INVALID_VALUE; |
292 | 338 | ||
339 | /* Tag this window as having been updated */ | ||
293 | window->stamp = jiffies; | 340 | window->stamp = jiffies; |
294 | 341 | ||
295 | return 0; | 342 | return 0; |
296 | } | 343 | } |
297 | 344 | ||
345 | /* | ||
346 | * Fill uCode API rate_n_flags field, based on "search" or "active" table. | ||
347 | */ | ||
298 | static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, | 348 | static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, |
299 | struct iwl4965_scale_tbl_info *tbl, | 349 | struct iwl4965_scale_tbl_info *tbl, |
300 | int index, u8 use_green) | 350 | int index, u8 use_green) |
@@ -349,6 +399,10 @@ static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, | |||
349 | } | 399 | } |
350 | } | 400 | } |
351 | 401 | ||
402 | /* | ||
403 | * Interpret uCode API's rate_n_flags format, | ||
404 | * fill "search" or "active" tx mode table. | ||
405 | */ | ||
352 | static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, | 406 | static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, |
353 | int phymode, struct iwl4965_scale_tbl_info *tbl, | 407 | int phymode, struct iwl4965_scale_tbl_info *tbl, |
354 | int *rate_idx) | 408 | int *rate_idx) |
@@ -362,11 +416,12 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, | |||
362 | *rate_idx = -1; | 416 | *rate_idx = -1; |
363 | return -EINVAL; | 417 | return -EINVAL; |
364 | } | 418 | } |
365 | tbl->is_SGI = 0; | 419 | tbl->is_SGI = 0; /* default legacy setup */ |
366 | tbl->is_fat = 0; | 420 | tbl->is_fat = 0; |
367 | tbl->is_dup = 0; | 421 | tbl->is_dup = 0; |
368 | tbl->antenna_type = ANT_BOTH; | 422 | tbl->antenna_type = ANT_BOTH; /* default MIMO setup */ |
369 | 423 | ||
424 | /* legacy rate format */ | ||
370 | if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { | 425 | if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { |
371 | ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); | 426 | ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); |
372 | 427 | ||
@@ -386,6 +441,7 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, | |||
386 | } | 441 | } |
387 | *rate_idx = index; | 442 | *rate_idx = index; |
388 | 443 | ||
444 | /* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */ | ||
389 | } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) | 445 | } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) |
390 | <= IWL_RATE_SISO_60M_PLCP) { | 446 | <= IWL_RATE_SISO_60M_PLCP) { |
391 | tbl->lq_type = LQ_SISO; | 447 | tbl->lq_type = LQ_SISO; |
@@ -410,6 +466,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, | |||
410 | tbl->is_dup = 1; | 466 | tbl->is_dup = 1; |
411 | 467 | ||
412 | *rate_idx = index; | 468 | *rate_idx = index; |
469 | |||
470 | /* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */ | ||
413 | } else { | 471 | } else { |
414 | tbl->lq_type = LQ_MIMO; | 472 | tbl->lq_type = LQ_MIMO; |
415 | if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) | 473 | if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) |
@@ -564,8 +622,9 @@ static void rs_get_lower_rate(struct iwl4965_rate_scale_priv *lq_data, | |||
564 | 622 | ||
565 | rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); | 623 | rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); |
566 | 624 | ||
567 | /* mask with station rate restriction */ | 625 | /* Mask with station rate restriction */ |
568 | if (is_legacy(tbl->lq_type)) { | 626 | if (is_legacy(tbl->lq_type)) { |
627 | /* supp_rates has no CCK bits in A mode */ | ||
569 | if (lq_data->phymode == (u8) MODE_IEEE80211A) | 628 | if (lq_data->phymode == (u8) MODE_IEEE80211A) |
570 | rate_mask = (u16)(rate_mask & | 629 | rate_mask = (u16)(rate_mask & |
571 | (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); | 630 | (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); |
@@ -573,7 +632,7 @@ static void rs_get_lower_rate(struct iwl4965_rate_scale_priv *lq_data, | |||
573 | rate_mask = (u16)(rate_mask & lq_data->supp_rates); | 632 | rate_mask = (u16)(rate_mask & lq_data->supp_rates); |
574 | } | 633 | } |
575 | 634 | ||
576 | /* if we did switched from HT to legacy check current rate */ | 635 | /* If we switched from HT to legacy, check current rate */ |
577 | if (switch_to_legacy && (rate_mask & (1 << scale_index))) { | 636 | if (switch_to_legacy && (rate_mask & (1 << scale_index))) { |
578 | rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); | 637 | rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); |
579 | return; | 638 | return; |
@@ -588,6 +647,9 @@ static void rs_get_lower_rate(struct iwl4965_rate_scale_priv *lq_data, | |||
588 | rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); | 647 | rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); |
589 | } | 648 | } |
590 | 649 | ||
650 | /* | ||
651 | * mac80211 sends us Tx status | ||
652 | */ | ||
591 | static void rs_tx_status(void *priv_rate, | 653 | static void rs_tx_status(void *priv_rate, |
592 | struct net_device *dev, | 654 | struct net_device *dev, |
593 | struct sk_buff *skb, | 655 | struct sk_buff *skb, |
@@ -641,11 +703,14 @@ static void rs_tx_status(void *priv_rate, | |||
641 | table = &lq->lq; | 703 | table = &lq->lq; |
642 | active_index = lq->active_tbl; | 704 | active_index = lq->active_tbl; |
643 | 705 | ||
706 | /* Get mac80211 antenna info */ | ||
644 | lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); | 707 | lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); |
645 | if (!lq->antenna) | 708 | if (!lq->antenna) |
646 | lq->antenna = lq->valid_antenna; | 709 | lq->antenna = lq->valid_antenna; |
647 | 710 | ||
711 | /* Ignore mac80211 antenna info for now */ | ||
648 | lq->antenna = lq->valid_antenna; | 712 | lq->antenna = lq->valid_antenna; |
713 | |||
649 | curr_tbl = &(lq->lq_info[active_index]); | 714 | curr_tbl = &(lq->lq_info[active_index]); |
650 | search_tbl = &(lq->lq_info[(1 - active_index)]); | 715 | search_tbl = &(lq->lq_info[(1 - active_index)]); |
651 | window = (struct iwl4965_rate_scale_data *) | 716 | window = (struct iwl4965_rate_scale_data *) |
@@ -664,6 +729,14 @@ static void rs_tx_status(void *priv_rate, | |||
664 | return; | 729 | return; |
665 | } | 730 | } |
666 | 731 | ||
732 | /* | ||
733 | * Ignore this Tx frame response if its initial rate doesn't match | ||
734 | * that of latest Link Quality command. There may be stragglers | ||
735 | * from a previous Link Quality command, but we're no longer interested | ||
736 | * in those; they're either from the "active" mode while we're trying | ||
737 | * to check "search" mode, or a prior "search" mode after we've moved | ||
738 | * to a new "search" mode (which might become the new "active" mode). | ||
739 | */ | ||
667 | if (retries && | 740 | if (retries && |
668 | (tx_mcs.rate_n_flags != | 741 | (tx_mcs.rate_n_flags != |
669 | le32_to_cpu(table->rs_table[0].rate_n_flags))) { | 742 | le32_to_cpu(table->rs_table[0].rate_n_flags))) { |
@@ -674,12 +747,17 @@ static void rs_tx_status(void *priv_rate, | |||
674 | return; | 747 | return; |
675 | } | 748 | } |
676 | 749 | ||
750 | /* Update frame history window with "failure" for each Tx retry. */ | ||
677 | while (retries) { | 751 | while (retries) { |
752 | /* Look up the rate and other info used for each tx attempt. | ||
753 | * Each tx attempt steps one entry deeper in the rate table. */ | ||
678 | tx_mcs.rate_n_flags = | 754 | tx_mcs.rate_n_flags = |
679 | le32_to_cpu(table->rs_table[index].rate_n_flags); | 755 | le32_to_cpu(table->rs_table[index].rate_n_flags); |
680 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, | 756 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, |
681 | &tbl_type, &rs_index); | 757 | &tbl_type, &rs_index); |
682 | 758 | ||
759 | /* If type matches "search" table, | ||
760 | * add failure to "search" history */ | ||
683 | if ((tbl_type.lq_type == search_tbl->lq_type) && | 761 | if ((tbl_type.lq_type == search_tbl->lq_type) && |
684 | (tbl_type.antenna_type == search_tbl->antenna_type) && | 762 | (tbl_type.antenna_type == search_tbl->antenna_type) && |
685 | (tbl_type.is_SGI == search_tbl->is_SGI)) { | 763 | (tbl_type.is_SGI == search_tbl->is_SGI)) { |
@@ -687,8 +765,10 @@ static void rs_tx_status(void *priv_rate, | |||
687 | tpt = search_tbl->expected_tpt[rs_index]; | 765 | tpt = search_tbl->expected_tpt[rs_index]; |
688 | else | 766 | else |
689 | tpt = 0; | 767 | tpt = 0; |
690 | rs_collect_tx_data(search_win, | 768 | rs_collect_tx_data(search_win, rs_index, tpt, 0); |
691 | rs_index, tpt, 0); | 769 | |
770 | /* Else if type matches "current/active" table, | ||
771 | * add failure to "current/active" history */ | ||
692 | } else if ((tbl_type.lq_type == curr_tbl->lq_type) && | 772 | } else if ((tbl_type.lq_type == curr_tbl->lq_type) && |
693 | (tbl_type.antenna_type == curr_tbl->antenna_type) && | 773 | (tbl_type.antenna_type == curr_tbl->antenna_type) && |
694 | (tbl_type.is_SGI == curr_tbl->is_SGI)) { | 774 | (tbl_type.is_SGI == curr_tbl->is_SGI)) { |
@@ -698,6 +778,9 @@ static void rs_tx_status(void *priv_rate, | |||
698 | tpt = 0; | 778 | tpt = 0; |
699 | rs_collect_tx_data(window, rs_index, tpt, 0); | 779 | rs_collect_tx_data(window, rs_index, tpt, 0); |
700 | } | 780 | } |
781 | |||
782 | /* If not searching for a new mode, increment failed counter | ||
783 | * ... this helps determine when to start searching again */ | ||
701 | if (lq->stay_in_tbl) | 784 | if (lq->stay_in_tbl) |
702 | lq->total_failed++; | 785 | lq->total_failed++; |
703 | --retries; | 786 | --retries; |
@@ -705,6 +788,11 @@ static void rs_tx_status(void *priv_rate, | |||
705 | 788 | ||
706 | } | 789 | } |
707 | 790 | ||
791 | /* | ||
792 | * Find (by rate) the history window to update with final Tx attempt; | ||
793 | * if Tx was successful first try, use original rate, | ||
794 | * else look up the rate that was, finally, successful. | ||
795 | */ | ||
708 | if (!tx_resp->retry_count) | 796 | if (!tx_resp->retry_count) |
709 | tx_mcs.rate_n_flags = tx_resp->control.tx_rate; | 797 | tx_mcs.rate_n_flags = tx_resp->control.tx_rate; |
710 | else | 798 | else |
@@ -714,11 +802,14 @@ static void rs_tx_status(void *priv_rate, | |||
714 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, | 802 | rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, |
715 | &tbl_type, &rs_index); | 803 | &tbl_type, &rs_index); |
716 | 804 | ||
805 | /* Update frame history window with "success" if Tx got ACKed ... */ | ||
717 | if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) | 806 | if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) |
718 | status = 1; | 807 | status = 1; |
719 | else | 808 | else |
720 | status = 0; | 809 | status = 0; |
721 | 810 | ||
811 | /* If type matches "search" table, | ||
812 | * add final tx status to "search" history */ | ||
722 | if ((tbl_type.lq_type == search_tbl->lq_type) && | 813 | if ((tbl_type.lq_type == search_tbl->lq_type) && |
723 | (tbl_type.antenna_type == search_tbl->antenna_type) && | 814 | (tbl_type.antenna_type == search_tbl->antenna_type) && |
724 | (tbl_type.is_SGI == search_tbl->is_SGI)) { | 815 | (tbl_type.is_SGI == search_tbl->is_SGI)) { |
@@ -728,6 +819,9 @@ static void rs_tx_status(void *priv_rate, | |||
728 | tpt = 0; | 819 | tpt = 0; |
729 | rs_collect_tx_data(search_win, | 820 | rs_collect_tx_data(search_win, |
730 | rs_index, tpt, status); | 821 | rs_index, tpt, status); |
822 | |||
823 | /* Else if type matches "current/active" table, | ||
824 | * add final tx status to "current/active" history */ | ||
731 | } else if ((tbl_type.lq_type == curr_tbl->lq_type) && | 825 | } else if ((tbl_type.lq_type == curr_tbl->lq_type) && |
732 | (tbl_type.antenna_type == curr_tbl->antenna_type) && | 826 | (tbl_type.antenna_type == curr_tbl->antenna_type) && |
733 | (tbl_type.is_SGI == curr_tbl->is_SGI)) { | 827 | (tbl_type.is_SGI == curr_tbl->is_SGI)) { |
@@ -738,6 +832,8 @@ static void rs_tx_status(void *priv_rate, | |||
738 | rs_collect_tx_data(window, rs_index, tpt, status); | 832 | rs_collect_tx_data(window, rs_index, tpt, status); |
739 | } | 833 | } |
740 | 834 | ||
835 | /* If not searching for new mode, increment success/failed counter | ||
836 | * ... these help determine when to start searching again */ | ||
741 | if (lq->stay_in_tbl) { | 837 | if (lq->stay_in_tbl) { |
742 | if (status) | 838 | if (status) |
743 | lq->total_success++; | 839 | lq->total_success++; |
@@ -745,6 +841,7 @@ static void rs_tx_status(void *priv_rate, | |||
745 | lq->total_failed++; | 841 | lq->total_failed++; |
746 | } | 842 | } |
747 | 843 | ||
844 | /* See if there's a better rate or modulation mode to try. */ | ||
748 | rs_rate_scale_perform(priv, dev, hdr, sta); | 845 | rs_rate_scale_perform(priv, dev, hdr, sta); |
749 | sta_info_put(sta); | 846 | sta_info_put(sta); |
750 | return; | 847 | return; |
@@ -774,11 +871,19 @@ static u8 rs_is_other_ant_connected(u8 valid_antenna, | |||
774 | return 0; | 871 | return 0; |
775 | } | 872 | } |
776 | 873 | ||
874 | /* | ||
875 | * Begin a period of staying with a selected modulation mode. | ||
876 | * Set "stay_in_tbl" flag to prevent any mode switches. | ||
877 | * Set frame tx success limits according to legacy vs. high-throughput, | ||
878 | * and reset overall (spanning all rates) tx success history statistics. | ||
879 | * These control how long we stay using same modulation mode before | ||
880 | * searching for a new mode. | ||
881 | */ | ||
777 | static void rs_set_stay_in_table(u8 is_legacy, | 882 | static void rs_set_stay_in_table(u8 is_legacy, |
778 | struct iwl4965_rate_scale_priv *lq_data) | 883 | struct iwl4965_rate_scale_priv *lq_data) |
779 | { | 884 | { |
780 | IWL_DEBUG_HT("we are staying in the same table\n"); | 885 | IWL_DEBUG_HT("we are staying in the same table\n"); |
781 | lq_data->stay_in_tbl = 1; | 886 | lq_data->stay_in_tbl = 1; /* only place this gets set */ |
782 | if (is_legacy) { | 887 | if (is_legacy) { |
783 | lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; | 888 | lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; |
784 | lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; | 889 | lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; |
@@ -793,6 +898,9 @@ static void rs_set_stay_in_table(u8 is_legacy, | |||
793 | lq_data->total_success = 0; | 898 | lq_data->total_success = 0; |
794 | } | 899 | } |
795 | 900 | ||
901 | /* | ||
902 | * Find correct throughput table for given mode of modulation | ||
903 | */ | ||
796 | static void rs_get_expected_tpt_table(struct iwl4965_rate_scale_priv *lq_data, | 904 | static void rs_get_expected_tpt_table(struct iwl4965_rate_scale_priv *lq_data, |
797 | struct iwl4965_scale_tbl_info *tbl) | 905 | struct iwl4965_scale_tbl_info *tbl) |
798 | { | 906 | { |
@@ -827,17 +935,33 @@ static void rs_get_expected_tpt_table(struct iwl4965_rate_scale_priv *lq_data, | |||
827 | } | 935 | } |
828 | 936 | ||
829 | #ifdef CONFIG_IWL4965_HT | 937 | #ifdef CONFIG_IWL4965_HT |
938 | /* | ||
939 | * Find starting rate for new "search" high-throughput mode of modulation. | ||
940 | * Goal is to find lowest expected rate (under perfect conditions) that is | ||
941 | * above the current measured throughput of "active" mode, to give new mode | ||
942 | * a fair chance to prove itself without too many challenges. | ||
943 | * | ||
944 | * This gets called when transitioning to more aggressive modulation | ||
945 | * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive | ||
946 | * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need | ||
947 | * to decrease to match "active" throughput. When moving from MIMO to SISO, | ||
948 | * bit rate will typically need to increase, but not if performance was bad. | ||
949 | */ | ||
830 | static s32 rs_get_best_rate(struct iwl4965_priv *priv, | 950 | static s32 rs_get_best_rate(struct iwl4965_priv *priv, |
831 | struct iwl4965_rate_scale_priv *lq_data, | 951 | struct iwl4965_rate_scale_priv *lq_data, |
832 | struct iwl4965_scale_tbl_info *tbl, | 952 | struct iwl4965_scale_tbl_info *tbl, /* "search" */ |
833 | u16 rate_mask, s8 index, s8 rate) | 953 | u16 rate_mask, s8 index, s8 rate) |
834 | { | 954 | { |
955 | /* "active" values */ | ||
835 | struct iwl4965_scale_tbl_info *active_tbl = | 956 | struct iwl4965_scale_tbl_info *active_tbl = |
836 | &(lq_data->lq_info[lq_data->active_tbl]); | 957 | &(lq_data->lq_info[lq_data->active_tbl]); |
837 | s32 new_rate, high, low, start_hi; | ||
838 | s32 active_sr = active_tbl->win[index].success_ratio; | 958 | s32 active_sr = active_tbl->win[index].success_ratio; |
839 | s32 *tpt_tbl = tbl->expected_tpt; | ||
840 | s32 active_tpt = active_tbl->expected_tpt[index]; | 959 | s32 active_tpt = active_tbl->expected_tpt[index]; |
960 | |||
961 | /* expected "search" throughput */ | ||
962 | s32 *tpt_tbl = tbl->expected_tpt; | ||
963 | |||
964 | s32 new_rate, high, low, start_hi; | ||
841 | u16 high_low; | 965 | u16 high_low; |
842 | 966 | ||
843 | new_rate = high = low = start_hi = IWL_RATE_INVALID; | 967 | new_rate = high = low = start_hi = IWL_RATE_INVALID; |
@@ -848,6 +972,21 @@ static s32 rs_get_best_rate(struct iwl4965_priv *priv, | |||
848 | low = high_low & 0xff; | 972 | low = high_low & 0xff; |
849 | high = (high_low >> 8) & 0xff; | 973 | high = (high_low >> 8) & 0xff; |
850 | 974 | ||
975 | /* | ||
976 | * Lower the "search" bit rate, to give new "search" mode | ||
977 | * approximately the same throughput as "active" if: | ||
978 | * | ||
979 | * 1) "Active" mode has been working modestly well (but not | ||
980 | * great), and expected "search" throughput (under perfect | ||
981 | * conditions) at candidate rate is above the actual | ||
982 | * measured "active" throughput (but less than expected | ||
983 | * "active" throughput under perfect conditions). | ||
984 | * OR | ||
985 | * 2) "Active" mode has been working perfectly or very well | ||
986 | * and expected "search" throughput (under perfect | ||
987 | * conditions) at candidate rate is above expected | ||
988 | * "active" throughput (under perfect conditions). | ||
989 | */ | ||
851 | if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && | 990 | if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && |
852 | ((active_sr > IWL_RATE_DECREASE_TH) && | 991 | ((active_sr > IWL_RATE_DECREASE_TH) && |
853 | (active_sr <= IWL_RATE_HIGH_TH) && | 992 | (active_sr <= IWL_RATE_HIGH_TH) && |
@@ -855,21 +994,38 @@ static s32 rs_get_best_rate(struct iwl4965_priv *priv, | |||
855 | ((active_sr >= IWL_RATE_SCALE_SWITCH) && | 994 | ((active_sr >= IWL_RATE_SCALE_SWITCH) && |
856 | (tpt_tbl[rate] > active_tpt))) { | 995 | (tpt_tbl[rate] > active_tpt))) { |
857 | 996 | ||
997 | /* (2nd or later pass) | ||
998 | * If we've already tried to raise the rate, and are | ||
999 | * now trying to lower it, use the higher rate. */ | ||
858 | if (start_hi != IWL_RATE_INVALID) { | 1000 | if (start_hi != IWL_RATE_INVALID) { |
859 | new_rate = start_hi; | 1001 | new_rate = start_hi; |
860 | break; | 1002 | break; |
861 | } | 1003 | } |
1004 | |||
862 | new_rate = rate; | 1005 | new_rate = rate; |
1006 | |||
1007 | /* Loop again with lower rate */ | ||
863 | if (low != IWL_RATE_INVALID) | 1008 | if (low != IWL_RATE_INVALID) |
864 | rate = low; | 1009 | rate = low; |
1010 | |||
1011 | /* Lower rate not available, use the original */ | ||
865 | else | 1012 | else |
866 | break; | 1013 | break; |
1014 | |||
1015 | /* Else try to raise the "search" rate to match "active" */ | ||
867 | } else { | 1016 | } else { |
1017 | /* (2nd or later pass) | ||
1018 | * If we've already tried to lower the rate, and are | ||
1019 | * now trying to raise it, use the lower rate. */ | ||
868 | if (new_rate != IWL_RATE_INVALID) | 1020 | if (new_rate != IWL_RATE_INVALID) |
869 | break; | 1021 | break; |
1022 | |||
1023 | /* Loop again with higher rate */ | ||
870 | else if (high != IWL_RATE_INVALID) { | 1024 | else if (high != IWL_RATE_INVALID) { |
871 | start_hi = high; | 1025 | start_hi = high; |
872 | rate = high; | 1026 | rate = high; |
1027 | |||
1028 | /* Higher rate not available, use the original */ | ||
873 | } else { | 1029 | } else { |
874 | new_rate = rate; | 1030 | new_rate = rate; |
875 | break; | 1031 | break; |
@@ -886,6 +1042,9 @@ static inline u8 rs_is_both_ant_supp(u8 valid_antenna) | |||
886 | return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); | 1042 | return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); |
887 | } | 1043 | } |
888 | 1044 | ||
1045 | /* | ||
1046 | * Set up search table for MIMO | ||
1047 | */ | ||
889 | static int rs_switch_to_mimo(struct iwl4965_priv *priv, | 1048 | static int rs_switch_to_mimo(struct iwl4965_priv *priv, |
890 | struct iwl4965_rate_scale_priv *lq_data, | 1049 | struct iwl4965_rate_scale_priv *lq_data, |
891 | struct iwl4965_scale_tbl_info *tbl, int index) | 1050 | struct iwl4965_scale_tbl_info *tbl, int index) |
@@ -906,6 +1065,7 @@ static int rs_switch_to_mimo(struct iwl4965_priv *priv, | |||
906 | if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) | 1065 | if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) |
907 | return -1; | 1066 | return -1; |
908 | 1067 | ||
1068 | /* Need both Tx chains/antennas to support MIMO */ | ||
909 | if (!rs_is_both_ant_supp(lq_data->antenna)) | 1069 | if (!rs_is_both_ant_supp(lq_data->antenna)) |
910 | return -1; | 1070 | return -1; |
911 | 1071 | ||
@@ -943,6 +1103,9 @@ static int rs_switch_to_mimo(struct iwl4965_priv *priv, | |||
943 | #endif /*CONFIG_IWL4965_HT */ | 1103 | #endif /*CONFIG_IWL4965_HT */ |
944 | } | 1104 | } |
945 | 1105 | ||
1106 | /* | ||
1107 | * Set up search table for SISO | ||
1108 | */ | ||
946 | static int rs_switch_to_siso(struct iwl4965_priv *priv, | 1109 | static int rs_switch_to_siso(struct iwl4965_priv *priv, |
947 | struct iwl4965_rate_scale_priv *lq_data, | 1110 | struct iwl4965_rate_scale_priv *lq_data, |
948 | struct iwl4965_scale_tbl_info *tbl, int index) | 1111 | struct iwl4965_scale_tbl_info *tbl, int index) |
@@ -999,6 +1162,9 @@ static int rs_switch_to_siso(struct iwl4965_priv *priv, | |||
999 | #endif /*CONFIG_IWL4965_HT */ | 1162 | #endif /*CONFIG_IWL4965_HT */ |
1000 | } | 1163 | } |
1001 | 1164 | ||
1165 | /* | ||
1166 | * Try to switch to new modulation mode from legacy | ||
1167 | */ | ||
1002 | static int rs_move_legacy_other(struct iwl4965_priv *priv, | 1168 | static int rs_move_legacy_other(struct iwl4965_priv *priv, |
1003 | struct iwl4965_rate_scale_priv *lq_data, | 1169 | struct iwl4965_rate_scale_priv *lq_data, |
1004 | int index) | 1170 | int index) |
@@ -1020,12 +1186,17 @@ static int rs_move_legacy_other(struct iwl4965_priv *priv, | |||
1020 | 1186 | ||
1021 | search_tbl->lq_type = LQ_NONE; | 1187 | search_tbl->lq_type = LQ_NONE; |
1022 | lq_data->action_counter++; | 1188 | lq_data->action_counter++; |
1189 | |||
1190 | /* Don't change antenna if success has been great */ | ||
1023 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | 1191 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) |
1024 | break; | 1192 | break; |
1193 | |||
1194 | /* Don't change antenna if other one is not connected */ | ||
1025 | if (!rs_is_other_ant_connected(lq_data->antenna, | 1195 | if (!rs_is_other_ant_connected(lq_data->antenna, |
1026 | tbl->antenna_type)) | 1196 | tbl->antenna_type)) |
1027 | break; | 1197 | break; |
1028 | 1198 | ||
1199 | /* Set up search table to try other antenna */ | ||
1029 | memcpy(search_tbl, tbl, sz); | 1200 | memcpy(search_tbl, tbl, sz); |
1030 | 1201 | ||
1031 | rs_toggle_antenna(&(search_tbl->current_rate), | 1202 | rs_toggle_antenna(&(search_tbl->current_rate), |
@@ -1036,6 +1207,8 @@ static int rs_move_legacy_other(struct iwl4965_priv *priv, | |||
1036 | 1207 | ||
1037 | case IWL_LEGACY_SWITCH_SISO: | 1208 | case IWL_LEGACY_SWITCH_SISO: |
1038 | IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); | 1209 | IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); |
1210 | |||
1211 | /* Set up search table to try SISO */ | ||
1039 | memcpy(search_tbl, tbl, sz); | 1212 | memcpy(search_tbl, tbl, sz); |
1040 | search_tbl->lq_type = LQ_SISO; | 1213 | search_tbl->lq_type = LQ_SISO; |
1041 | search_tbl->is_SGI = 0; | 1214 | search_tbl->is_SGI = 0; |
@@ -1051,6 +1224,8 @@ static int rs_move_legacy_other(struct iwl4965_priv *priv, | |||
1051 | break; | 1224 | break; |
1052 | case IWL_LEGACY_SWITCH_MIMO: | 1225 | case IWL_LEGACY_SWITCH_MIMO: |
1053 | IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); | 1226 | IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); |
1227 | |||
1228 | /* Set up search table to try MIMO */ | ||
1054 | memcpy(search_tbl, tbl, sz); | 1229 | memcpy(search_tbl, tbl, sz); |
1055 | search_tbl->lq_type = LQ_MIMO; | 1230 | search_tbl->lq_type = LQ_MIMO; |
1056 | search_tbl->is_SGI = 0; | 1231 | search_tbl->is_SGI = 0; |
@@ -1083,6 +1258,9 @@ static int rs_move_legacy_other(struct iwl4965_priv *priv, | |||
1083 | 1258 | ||
1084 | } | 1259 | } |
1085 | 1260 | ||
1261 | /* | ||
1262 | * Try to switch to new modulation mode from SISO | ||
1263 | */ | ||
1086 | static int rs_move_siso_to_other(struct iwl4965_priv *priv, | 1264 | static int rs_move_siso_to_other(struct iwl4965_priv *priv, |
1087 | struct iwl4965_rate_scale_priv *lq_data, | 1265 | struct iwl4965_rate_scale_priv *lq_data, |
1088 | int index) | 1266 | int index) |
@@ -1173,6 +1351,9 @@ static int rs_move_siso_to_other(struct iwl4965_priv *priv, | |||
1173 | return 0; | 1351 | return 0; |
1174 | } | 1352 | } |
1175 | 1353 | ||
1354 | /* | ||
1355 | * Try to switch to new modulation mode from MIMO | ||
1356 | */ | ||
1176 | static int rs_move_mimo_to_other(struct iwl4965_priv *priv, | 1357 | static int rs_move_mimo_to_other(struct iwl4965_priv *priv, |
1177 | struct iwl4965_rate_scale_priv *lq_data, | 1358 | struct iwl4965_rate_scale_priv *lq_data, |
1178 | int index) | 1359 | int index) |
@@ -1193,6 +1374,8 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv, | |||
1193 | case IWL_MIMO_SWITCH_ANTENNA_A: | 1374 | case IWL_MIMO_SWITCH_ANTENNA_A: |
1194 | case IWL_MIMO_SWITCH_ANTENNA_B: | 1375 | case IWL_MIMO_SWITCH_ANTENNA_B: |
1195 | IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); | 1376 | IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); |
1377 | |||
1378 | /* Set up new search table for SISO */ | ||
1196 | memcpy(search_tbl, tbl, sz); | 1379 | memcpy(search_tbl, tbl, sz); |
1197 | search_tbl->lq_type = LQ_SISO; | 1380 | search_tbl->lq_type = LQ_SISO; |
1198 | search_tbl->is_SGI = 0; | 1381 | search_tbl->is_SGI = 0; |
@@ -1212,6 +1395,8 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv, | |||
1212 | 1395 | ||
1213 | case IWL_MIMO_SWITCH_GI: | 1396 | case IWL_MIMO_SWITCH_GI: |
1214 | IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); | 1397 | IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); |
1398 | |||
1399 | /* Set up new search table for MIMO */ | ||
1215 | memcpy(search_tbl, tbl, sz); | 1400 | memcpy(search_tbl, tbl, sz); |
1216 | search_tbl->lq_type = LQ_MIMO; | 1401 | search_tbl->lq_type = LQ_MIMO; |
1217 | search_tbl->antenna_type = ANT_BOTH; | 1402 | search_tbl->antenna_type = ANT_BOTH; |
@@ -1221,6 +1406,13 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv, | |||
1221 | else | 1406 | else |
1222 | search_tbl->is_SGI = 1; | 1407 | search_tbl->is_SGI = 1; |
1223 | lq_data->search_better_tbl = 1; | 1408 | lq_data->search_better_tbl = 1; |
1409 | |||
1410 | /* | ||
1411 | * If active table already uses the fastest possible | ||
1412 | * modulation (dual stream with short guard interval), | ||
1413 | * and it's working well, there's no need to look | ||
1414 | * for a better type of modulation! | ||
1415 | */ | ||
1224 | if ((tbl->lq_type == LQ_MIMO) && | 1416 | if ((tbl->lq_type == LQ_MIMO) && |
1225 | (tbl->is_SGI)) { | 1417 | (tbl->is_SGI)) { |
1226 | s32 tpt = lq_data->last_tpt / 100; | 1418 | s32 tpt = lq_data->last_tpt / 100; |
@@ -1253,6 +1445,13 @@ static int rs_move_mimo_to_other(struct iwl4965_priv *priv, | |||
1253 | 1445 | ||
1254 | } | 1446 | } |
1255 | 1447 | ||
1448 | /* | ||
1449 | * Check whether we should continue using same modulation mode, or | ||
1450 | * begin search for a new mode, based on: | ||
1451 | * 1) # tx successes or failures while using this mode | ||
1452 | * 2) # times calling this function | ||
1453 | * 3) elapsed time in this mode (not used, for now) | ||
1454 | */ | ||
1256 | static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) | 1455 | static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) |
1257 | { | 1456 | { |
1258 | struct iwl4965_scale_tbl_info *tbl; | 1457 | struct iwl4965_scale_tbl_info *tbl; |
@@ -1264,15 +1463,27 @@ static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) | |||
1264 | 1463 | ||
1265 | tbl = &(lq_data->lq_info[active_tbl]); | 1464 | tbl = &(lq_data->lq_info[active_tbl]); |
1266 | 1465 | ||
1466 | /* If we've been disallowing search, see if we should now allow it */ | ||
1267 | if (lq_data->stay_in_tbl) { | 1467 | if (lq_data->stay_in_tbl) { |
1268 | 1468 | ||
1469 | /* Elapsed time using current modulation mode */ | ||
1269 | if (lq_data->flush_timer) | 1470 | if (lq_data->flush_timer) |
1270 | flush_interval_passed = | 1471 | flush_interval_passed = |
1271 | time_after(jiffies, | 1472 | time_after(jiffies, |
1272 | (unsigned long)(lq_data->flush_timer + | 1473 | (unsigned long)(lq_data->flush_timer + |
1273 | IWL_RATE_SCALE_FLUSH_INTVL)); | 1474 | IWL_RATE_SCALE_FLUSH_INTVL)); |
1274 | 1475 | ||
1476 | /* For now, disable the elapsed time criterion */ | ||
1275 | flush_interval_passed = 0; | 1477 | flush_interval_passed = 0; |
1478 | |||
1479 | /* | ||
1480 | * Check if we should allow search for new modulation mode. | ||
1481 | * If many frames have failed or succeeded, or we've used | ||
1482 | * this same modulation for a long time, allow search, and | ||
1483 | * reset history stats that keep track of whether we should | ||
1484 | * allow a new search. Also (below) reset all bitmaps and | ||
1485 | * stats in active history. | ||
1486 | */ | ||
1276 | if ((lq_data->total_failed > lq_data->max_failure_limit) || | 1487 | if ((lq_data->total_failed > lq_data->max_failure_limit) || |
1277 | (lq_data->total_success > lq_data->max_success_limit) || | 1488 | (lq_data->total_success > lq_data->max_success_limit) || |
1278 | ((!lq_data->search_better_tbl) && (lq_data->flush_timer) | 1489 | ((!lq_data->search_better_tbl) && (lq_data->flush_timer) |
@@ -1281,10 +1492,19 @@ static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) | |||
1281 | lq_data->total_failed, | 1492 | lq_data->total_failed, |
1282 | lq_data->total_success, | 1493 | lq_data->total_success, |
1283 | flush_interval_passed); | 1494 | flush_interval_passed); |
1284 | lq_data->stay_in_tbl = 0; | 1495 | |
1496 | /* Allow search for new mode */ | ||
1497 | lq_data->stay_in_tbl = 0; /* only place reset */ | ||
1285 | lq_data->total_failed = 0; | 1498 | lq_data->total_failed = 0; |
1286 | lq_data->total_success = 0; | 1499 | lq_data->total_success = 0; |
1287 | lq_data->flush_timer = 0; | 1500 | lq_data->flush_timer = 0; |
1501 | |||
1502 | /* | ||
1503 | * Else if we've used this modulation mode enough repetitions | ||
1504 | * (regardless of elapsed time or success/failure), reset | ||
1505 | * history bitmaps and rate-specific stats for all rates in | ||
1506 | * active table. | ||
1507 | */ | ||
1288 | } else { | 1508 | } else { |
1289 | lq_data->table_count++; | 1509 | lq_data->table_count++; |
1290 | if (lq_data->table_count >= | 1510 | if (lq_data->table_count >= |
@@ -1298,6 +1518,9 @@ static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) | |||
1298 | } | 1518 | } |
1299 | } | 1519 | } |
1300 | 1520 | ||
1521 | /* If transitioning to allow "search", reset all history | ||
1522 | * bitmaps and stats in active table (this will become the new | ||
1523 | * "search" table). */ | ||
1301 | if (!lq_data->stay_in_tbl) { | 1524 | if (!lq_data->stay_in_tbl) { |
1302 | for (i = 0; i < IWL_RATE_COUNT; i++) | 1525 | for (i = 0; i < IWL_RATE_COUNT; i++) |
1303 | rs_rate_scale_clear_window(&(tbl->win[i])); | 1526 | rs_rate_scale_clear_window(&(tbl->win[i])); |
@@ -1305,6 +1528,9 @@ static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data) | |||
1305 | } | 1528 | } |
1306 | } | 1529 | } |
1307 | 1530 | ||
1531 | /* | ||
1532 | * Do rate scaling and search for new modulation mode. | ||
1533 | */ | ||
1308 | static void rs_rate_scale_perform(struct iwl4965_priv *priv, | 1534 | static void rs_rate_scale_perform(struct iwl4965_priv *priv, |
1309 | struct net_device *dev, | 1535 | struct net_device *dev, |
1310 | struct ieee80211_hdr *hdr, | 1536 | struct ieee80211_hdr *hdr, |
@@ -1350,6 +1576,11 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1350 | } | 1576 | } |
1351 | lq_data = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv; | 1577 | lq_data = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv; |
1352 | 1578 | ||
1579 | /* | ||
1580 | * Select rate-scale / modulation-mode table to work with in | ||
1581 | * the rest of this function: "search" if searching for better | ||
1582 | * modulation mode, or "active" if doing rate scaling within a mode. | ||
1583 | */ | ||
1353 | if (!lq_data->search_better_tbl) | 1584 | if (!lq_data->search_better_tbl) |
1354 | active_tbl = lq_data->active_tbl; | 1585 | active_tbl = lq_data->active_tbl; |
1355 | else | 1586 | else |
@@ -1358,11 +1589,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1358 | tbl = &(lq_data->lq_info[active_tbl]); | 1589 | tbl = &(lq_data->lq_info[active_tbl]); |
1359 | is_green = lq_data->is_green; | 1590 | is_green = lq_data->is_green; |
1360 | 1591 | ||
1592 | /* current tx rate */ | ||
1361 | index = sta->last_txrate; | 1593 | index = sta->last_txrate; |
1362 | 1594 | ||
1363 | IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, | 1595 | IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, |
1364 | tbl->lq_type); | 1596 | tbl->lq_type); |
1365 | 1597 | ||
1598 | /* rates available for this association, and for modulation mode */ | ||
1366 | rs_get_supported_rates(lq_data, hdr, tbl->lq_type, | 1599 | rs_get_supported_rates(lq_data, hdr, tbl->lq_type, |
1367 | &rate_mask); | 1600 | &rate_mask); |
1368 | 1601 | ||
@@ -1371,6 +1604,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1371 | /* mask with station rate restriction */ | 1604 | /* mask with station rate restriction */ |
1372 | if (is_legacy(tbl->lq_type)) { | 1605 | if (is_legacy(tbl->lq_type)) { |
1373 | if (lq_data->phymode == (u8) MODE_IEEE80211A) | 1606 | if (lq_data->phymode == (u8) MODE_IEEE80211A) |
1607 | /* supp_rates has no CCK bits in A mode */ | ||
1374 | rate_scale_index_msk = (u16) (rate_mask & | 1608 | rate_scale_index_msk = (u16) (rate_mask & |
1375 | (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); | 1609 | (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); |
1376 | else | 1610 | else |
@@ -1383,11 +1617,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1383 | if (!rate_scale_index_msk) | 1617 | if (!rate_scale_index_msk) |
1384 | rate_scale_index_msk = rate_mask; | 1618 | rate_scale_index_msk = rate_mask; |
1385 | 1619 | ||
1620 | /* If current rate is no longer supported on current association, | ||
1621 | * or user changed preferences for rates, find a new supported rate. */ | ||
1386 | if (index < 0 || !((1 << index) & rate_scale_index_msk)) { | 1622 | if (index < 0 || !((1 << index) & rate_scale_index_msk)) { |
1387 | index = IWL_INVALID_VALUE; | 1623 | index = IWL_INVALID_VALUE; |
1388 | update_lq = 1; | 1624 | update_lq = 1; |
1389 | 1625 | ||
1390 | /* get the lowest available rate */ | 1626 | /* get the highest available rate */ |
1391 | for (i = 0; i <= IWL_RATE_COUNT; i++) { | 1627 | for (i = 0; i <= IWL_RATE_COUNT; i++) { |
1392 | if ((1 << i) & rate_scale_index_msk) | 1628 | if ((1 << i) & rate_scale_index_msk) |
1393 | index = i; | 1629 | index = i; |
@@ -1399,11 +1635,19 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1399 | } | 1635 | } |
1400 | } | 1636 | } |
1401 | 1637 | ||
1638 | /* Get expected throughput table and history window for current rate */ | ||
1402 | if (!tbl->expected_tpt) | 1639 | if (!tbl->expected_tpt) |
1403 | rs_get_expected_tpt_table(lq_data, tbl); | 1640 | rs_get_expected_tpt_table(lq_data, tbl); |
1404 | 1641 | ||
1405 | window = &(tbl->win[index]); | 1642 | window = &(tbl->win[index]); |
1406 | 1643 | ||
1644 | /* | ||
1645 | * If there is not enough history to calculate actual average | ||
1646 | * throughput, keep analyzing results of more tx frames, without | ||
1647 | * changing rate or mode (bypass most of the rest of this function). | ||
1648 | * Set up new rate table in uCode only if old rate is not supported | ||
1649 | * in current association (use new rate found above). | ||
1650 | */ | ||
1407 | fail_count = window->counter - window->success_counter; | 1651 | fail_count = window->counter - window->success_counter; |
1408 | if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && | 1652 | if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && |
1409 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) | 1653 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) |
@@ -1411,8 +1655,15 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1411 | IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " | 1655 | IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " |
1412 | "for index %d\n", | 1656 | "for index %d\n", |
1413 | window->success_counter, window->counter, index); | 1657 | window->success_counter, window->counter, index); |
1658 | |||
1659 | /* Can't calculate this yet; not enough history */ | ||
1414 | window->average_tpt = IWL_INVALID_VALUE; | 1660 | window->average_tpt = IWL_INVALID_VALUE; |
1661 | |||
1662 | /* Should we stay with this modulation mode, | ||
1663 | * or search for a new one? */ | ||
1415 | rs_stay_in_table(lq_data); | 1664 | rs_stay_in_table(lq_data); |
1665 | |||
1666 | /* Set up new rate table in uCode, if needed */ | ||
1416 | if (update_lq) { | 1667 | if (update_lq) { |
1417 | rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); | 1668 | rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); |
1418 | rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); | 1669 | rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); |
@@ -1420,13 +1671,19 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1420 | } | 1671 | } |
1421 | goto out; | 1672 | goto out; |
1422 | 1673 | ||
1674 | /* Else we have enough samples; calculate estimate of | ||
1675 | * actual average throughput */ | ||
1423 | } else | 1676 | } else |
1424 | window->average_tpt = ((window->success_ratio * | 1677 | window->average_tpt = ((window->success_ratio * |
1425 | tbl->expected_tpt[index] + 64) / 128); | 1678 | tbl->expected_tpt[index] + 64) / 128); |
1426 | 1679 | ||
1680 | /* If we are searching for better modulation mode, check success. */ | ||
1427 | if (lq_data->search_better_tbl) { | 1681 | if (lq_data->search_better_tbl) { |
1428 | int success_limit = IWL_RATE_SCALE_SWITCH; | 1682 | int success_limit = IWL_RATE_SCALE_SWITCH; |
1429 | 1683 | ||
1684 | /* If good success, continue using the "search" mode; | ||
1685 | * no need to send new link quality command, since we're | ||
1686 | * continuing to use the setup that we've been trying. */ | ||
1430 | if ((window->success_ratio > success_limit) || | 1687 | if ((window->success_ratio > success_limit) || |
1431 | (window->average_tpt > lq_data->last_tpt)) { | 1688 | (window->average_tpt > lq_data->last_tpt)) { |
1432 | if (!is_legacy(tbl->lq_type)) { | 1689 | if (!is_legacy(tbl->lq_type)) { |
@@ -1438,55 +1695,78 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1438 | lq_data->last_tpt); | 1695 | lq_data->last_tpt); |
1439 | lq_data->enable_counter = 1; | 1696 | lq_data->enable_counter = 1; |
1440 | } | 1697 | } |
1698 | /* Swap tables; "search" becomes "active" */ | ||
1441 | lq_data->active_tbl = active_tbl; | 1699 | lq_data->active_tbl = active_tbl; |
1442 | current_tpt = window->average_tpt; | 1700 | current_tpt = window->average_tpt; |
1701 | |||
1702 | /* Else poor success; go back to mode in "active" table */ | ||
1443 | } else { | 1703 | } else { |
1704 | /* Nullify "search" table */ | ||
1444 | tbl->lq_type = LQ_NONE; | 1705 | tbl->lq_type = LQ_NONE; |
1706 | |||
1707 | /* Revert to "active" table */ | ||
1445 | active_tbl = lq_data->active_tbl; | 1708 | active_tbl = lq_data->active_tbl; |
1446 | tbl = &(lq_data->lq_info[active_tbl]); | 1709 | tbl = &(lq_data->lq_info[active_tbl]); |
1447 | 1710 | ||
1711 | /* Revert to "active" rate and throughput info */ | ||
1448 | index = iwl4965_rate_index_from_plcp( | 1712 | index = iwl4965_rate_index_from_plcp( |
1449 | tbl->current_rate.rate_n_flags); | 1713 | tbl->current_rate.rate_n_flags); |
1714 | current_tpt = lq_data->last_tpt; | ||
1450 | 1715 | ||
1716 | /* Need to set up a new rate table in uCode */ | ||
1451 | update_lq = 1; | 1717 | update_lq = 1; |
1452 | current_tpt = lq_data->last_tpt; | ||
1453 | IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); | 1718 | IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); |
1454 | } | 1719 | } |
1720 | |||
1721 | /* Either way, we've made a decision; modulation mode | ||
1722 | * search is done, allow rate adjustment next time. */ | ||
1455 | lq_data->search_better_tbl = 0; | 1723 | lq_data->search_better_tbl = 0; |
1456 | done_search = 1; | 1724 | done_search = 1; /* Don't switch modes below! */ |
1457 | goto lq_update; | 1725 | goto lq_update; |
1458 | } | 1726 | } |
1459 | 1727 | ||
1728 | /* (Else) not in search of better modulation mode, try for better | ||
1729 | * starting rate, while staying in this mode. */ | ||
1460 | high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, | 1730 | high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, |
1461 | tbl->lq_type); | 1731 | tbl->lq_type); |
1462 | low = high_low & 0xff; | 1732 | low = high_low & 0xff; |
1463 | high = (high_low >> 8) & 0xff; | 1733 | high = (high_low >> 8) & 0xff; |
1464 | 1734 | ||
1735 | /* Collect measured throughputs for current and adjacent rates */ | ||
1465 | current_tpt = window->average_tpt; | 1736 | current_tpt = window->average_tpt; |
1466 | |||
1467 | if (low != IWL_RATE_INVALID) | 1737 | if (low != IWL_RATE_INVALID) |
1468 | low_tpt = tbl->win[low].average_tpt; | 1738 | low_tpt = tbl->win[low].average_tpt; |
1469 | |||
1470 | if (high != IWL_RATE_INVALID) | 1739 | if (high != IWL_RATE_INVALID) |
1471 | high_tpt = tbl->win[high].average_tpt; | 1740 | high_tpt = tbl->win[high].average_tpt; |
1472 | 1741 | ||
1473 | 1742 | /* Assume rate increase */ | |
1474 | scale_action = 1; | 1743 | scale_action = 1; |
1475 | 1744 | ||
1745 | /* Too many failures, decrease rate */ | ||
1476 | if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || | 1746 | if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || |
1477 | (current_tpt == 0)) { | 1747 | (current_tpt == 0)) { |
1478 | IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); | 1748 | IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); |
1479 | scale_action = -1; | 1749 | scale_action = -1; |
1750 | |||
1751 | /* No throughput measured yet for adjacent rates; try increase. */ | ||
1480 | } else if ((low_tpt == IWL_INVALID_VALUE) && | 1752 | } else if ((low_tpt == IWL_INVALID_VALUE) && |
1481 | (high_tpt == IWL_INVALID_VALUE)) | 1753 | (high_tpt == IWL_INVALID_VALUE)) |
1482 | scale_action = 1; | 1754 | scale_action = 1; |
1755 | |||
1756 | /* Both adjacent throughputs are measured, but neither one has better | ||
1757 | * throughput; we're using the best rate, don't change it! */ | ||
1483 | else if ((low_tpt != IWL_INVALID_VALUE) && | 1758 | else if ((low_tpt != IWL_INVALID_VALUE) && |
1484 | (high_tpt != IWL_INVALID_VALUE) && | 1759 | (high_tpt != IWL_INVALID_VALUE) && |
1485 | (low_tpt < current_tpt) && | 1760 | (low_tpt < current_tpt) && |
1486 | (high_tpt < current_tpt)) | 1761 | (high_tpt < current_tpt)) |
1487 | scale_action = 0; | 1762 | scale_action = 0; |
1763 | |||
1764 | /* At least one adjacent rate's throughput is measured, | ||
1765 | * and may have better performance. */ | ||
1488 | else { | 1766 | else { |
1767 | /* Higher adjacent rate's throughput is measured */ | ||
1489 | if (high_tpt != IWL_INVALID_VALUE) { | 1768 | if (high_tpt != IWL_INVALID_VALUE) { |
1769 | /* Higher rate has better throughput */ | ||
1490 | if (high_tpt > current_tpt) | 1770 | if (high_tpt > current_tpt) |
1491 | scale_action = 1; | 1771 | scale_action = 1; |
1492 | else { | 1772 | else { |
@@ -1494,7 +1774,10 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1494 | ("decrease rate because of high tpt\n"); | 1774 | ("decrease rate because of high tpt\n"); |
1495 | scale_action = -1; | 1775 | scale_action = -1; |
1496 | } | 1776 | } |
1777 | |||
1778 | /* Lower adjacent rate's throughput is measured */ | ||
1497 | } else if (low_tpt != IWL_INVALID_VALUE) { | 1779 | } else if (low_tpt != IWL_INVALID_VALUE) { |
1780 | /* Lower rate has better throughput */ | ||
1498 | if (low_tpt > current_tpt) { | 1781 | if (low_tpt > current_tpt) { |
1499 | IWL_DEBUG_RATE | 1782 | IWL_DEBUG_RATE |
1500 | ("decrease rate because of low tpt\n"); | 1783 | ("decrease rate because of low tpt\n"); |
@@ -1504,23 +1787,30 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1504 | } | 1787 | } |
1505 | } | 1788 | } |
1506 | 1789 | ||
1790 | /* Sanity check; asked for decrease, but success rate or throughput | ||
1791 | * has been good at old rate. Don't change it. */ | ||
1507 | if (scale_action == -1) { | 1792 | if (scale_action == -1) { |
1508 | if ((low != IWL_RATE_INVALID) && | 1793 | if ((low != IWL_RATE_INVALID) && |
1509 | ((window->success_ratio > IWL_RATE_HIGH_TH) || | 1794 | ((window->success_ratio > IWL_RATE_HIGH_TH) || |
1510 | (current_tpt > (100 * tbl->expected_tpt[low])))) | 1795 | (current_tpt > (100 * tbl->expected_tpt[low])))) |
1511 | scale_action = 0; | 1796 | scale_action = 0; |
1797 | |||
1798 | /* Sanity check; asked for increase, but success rate has not been great | ||
1799 | * even at old rate, higher rate will be worse. Don't change it. */ | ||
1512 | } else if ((scale_action == 1) && | 1800 | } else if ((scale_action == 1) && |
1513 | (window->success_ratio < IWL_RATE_INCREASE_TH)) | 1801 | (window->success_ratio < IWL_RATE_INCREASE_TH)) |
1514 | scale_action = 0; | 1802 | scale_action = 0; |
1515 | 1803 | ||
1516 | switch (scale_action) { | 1804 | switch (scale_action) { |
1517 | case -1: | 1805 | case -1: |
1806 | /* Decrease starting rate, update uCode's rate table */ | ||
1518 | if (low != IWL_RATE_INVALID) { | 1807 | if (low != IWL_RATE_INVALID) { |
1519 | update_lq = 1; | 1808 | update_lq = 1; |
1520 | index = low; | 1809 | index = low; |
1521 | } | 1810 | } |
1522 | break; | 1811 | break; |
1523 | case 1: | 1812 | case 1: |
1813 | /* Increase starting rate, update uCode's rate table */ | ||
1524 | if (high != IWL_RATE_INVALID) { | 1814 | if (high != IWL_RATE_INVALID) { |
1525 | update_lq = 1; | 1815 | update_lq = 1; |
1526 | index = high; | 1816 | index = high; |
@@ -1528,6 +1818,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1528 | 1818 | ||
1529 | break; | 1819 | break; |
1530 | case 0: | 1820 | case 0: |
1821 | /* No change */ | ||
1531 | default: | 1822 | default: |
1532 | break; | 1823 | break; |
1533 | } | 1824 | } |
@@ -1537,16 +1828,28 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1537 | index, scale_action, low, high, tbl->lq_type); | 1828 | index, scale_action, low, high, tbl->lq_type); |
1538 | 1829 | ||
1539 | lq_update: | 1830 | lq_update: |
1831 | /* Replace uCode's rate table for the destination station. */ | ||
1540 | if (update_lq) { | 1832 | if (update_lq) { |
1541 | rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); | 1833 | rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); |
1542 | rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); | 1834 | rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); |
1543 | rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); | 1835 | rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); |
1544 | } | 1836 | } |
1837 | |||
1838 | /* Should we stay with this modulation mode, or search for a new one? */ | ||
1545 | rs_stay_in_table(lq_data); | 1839 | rs_stay_in_table(lq_data); |
1546 | 1840 | ||
1841 | /* | ||
1842 | * Search for new modulation mode if we're: | ||
1843 | * 1) Not changing rates right now | ||
1844 | * 2) Not just finishing up a search | ||
1845 | * 3) Allowing a new search | ||
1846 | */ | ||
1547 | if (!update_lq && !done_search && !lq_data->stay_in_tbl) { | 1847 | if (!update_lq && !done_search && !lq_data->stay_in_tbl) { |
1848 | /* Save current throughput to compare with "search" throughput*/ | ||
1548 | lq_data->last_tpt = current_tpt; | 1849 | lq_data->last_tpt = current_tpt; |
1549 | 1850 | ||
1851 | /* Select a new "search" modulation mode to try. | ||
1852 | * If one is found, set up the new "search" table. */ | ||
1550 | if (is_legacy(tbl->lq_type)) | 1853 | if (is_legacy(tbl->lq_type)) |
1551 | rs_move_legacy_other(priv, lq_data, index); | 1854 | rs_move_legacy_other(priv, lq_data, index); |
1552 | else if (is_siso(tbl->lq_type)) | 1855 | else if (is_siso(tbl->lq_type)) |
@@ -1554,11 +1857,14 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1554 | else | 1857 | else |
1555 | rs_move_mimo_to_other(priv, lq_data, index); | 1858 | rs_move_mimo_to_other(priv, lq_data, index); |
1556 | 1859 | ||
1860 | /* If new "search" mode was selected, set up in uCode table */ | ||
1557 | if (lq_data->search_better_tbl) { | 1861 | if (lq_data->search_better_tbl) { |
1862 | /* Access the "search" table, clear its history. */ | ||
1558 | tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]); | 1863 | tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]); |
1559 | for (i = 0; i < IWL_RATE_COUNT; i++) | 1864 | for (i = 0; i < IWL_RATE_COUNT; i++) |
1560 | rs_rate_scale_clear_window(&(tbl->win[i])); | 1865 | rs_rate_scale_clear_window(&(tbl->win[i])); |
1561 | 1866 | ||
1867 | /* Use new "search" start rate */ | ||
1562 | index = iwl4965_rate_index_from_plcp( | 1868 | index = iwl4965_rate_index_from_plcp( |
1563 | tbl->current_rate.rate_n_flags); | 1869 | tbl->current_rate.rate_n_flags); |
1564 | 1870 | ||
@@ -1568,8 +1874,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1568 | &lq_data->lq); | 1874 | &lq_data->lq); |
1569 | rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); | 1875 | rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); |
1570 | } | 1876 | } |
1571 | tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); | ||
1572 | 1877 | ||
1878 | /* If the "active" (non-search) mode was legacy, | ||
1879 | * and we've tried switching antennas, | ||
1880 | * but we haven't been able to try HT modes (not available), | ||
1881 | * stay with best antenna legacy modulation for a while | ||
1882 | * before next round of mode comparisons. */ | ||
1883 | tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); | ||
1573 | if (is_legacy(tbl1->lq_type) && | 1884 | if (is_legacy(tbl1->lq_type) && |
1574 | #ifdef CONFIG_IWL4965_HT | 1885 | #ifdef CONFIG_IWL4965_HT |
1575 | !priv->current_assoc_ht.is_ht && | 1886 | !priv->current_assoc_ht.is_ht && |
@@ -1580,9 +1891,13 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1580 | rs_set_stay_in_table(1, lq_data); | 1891 | rs_set_stay_in_table(1, lq_data); |
1581 | } | 1892 | } |
1582 | 1893 | ||
1894 | /* If we're in an HT mode, and all 3 mode switch actions | ||
1895 | * have been tried and compared, stay in this best modulation | ||
1896 | * mode for a while before next round of mode comparisons. */ | ||
1583 | if (lq_data->enable_counter && | 1897 | if (lq_data->enable_counter && |
1584 | (lq_data->action_counter >= IWL_ACTION_LIMIT)) { | 1898 | (lq_data->action_counter >= IWL_ACTION_LIMIT)) { |
1585 | #ifdef CONFIG_IWL4965_HT_AGG | 1899 | #ifdef CONFIG_IWL4965_HT_AGG |
1900 | /* If appropriate, set up aggregation! */ | ||
1586 | if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) && | 1901 | if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) && |
1587 | (priv->lq_mngr.agg_ctrl.auto_agg)) { | 1902 | (priv->lq_mngr.agg_ctrl.auto_agg)) { |
1588 | priv->lq_mngr.agg_ctrl.tid_retry = | 1903 | priv->lq_mngr.agg_ctrl.tid_retry = |
@@ -1593,6 +1908,14 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, | |||
1593 | lq_data->action_counter = 0; | 1908 | lq_data->action_counter = 0; |
1594 | rs_set_stay_in_table(0, lq_data); | 1909 | rs_set_stay_in_table(0, lq_data); |
1595 | } | 1910 | } |
1911 | |||
1912 | /* | ||
1913 | * Else, don't search for a new modulation mode. | ||
1914 | * Put new timestamp in stay-in-modulation-mode flush timer if: | ||
1915 | * 1) Not changing rates right now | ||
1916 | * 2) Not just finishing up a search | ||
1917 | * 3) flush timer is empty | ||
1918 | */ | ||
1596 | } else { | 1919 | } else { |
1597 | if ((!update_lq) && (!done_search) && (!lq_data->flush_timer)) | 1920 | if ((!update_lq) && (!done_search) && (!lq_data->flush_timer)) |
1598 | lq_data->flush_timer = jiffies; | 1921 | lq_data->flush_timer = jiffies; |
@@ -1789,15 +2112,14 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, | |||
1789 | priv->assoc_station_added = 1; | 2112 | priv->assoc_station_added = 1; |
1790 | } | 2113 | } |
1791 | 2114 | ||
2115 | /* Find highest tx rate supported by hardware and destination station */ | ||
1792 | for (i = 0; i < mode->num_rates; i++) { | 2116 | for (i = 0; i < mode->num_rates; i++) { |
1793 | if ((sta->supp_rates & BIT(i)) && | 2117 | if ((sta->supp_rates & BIT(i)) && |
1794 | (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) | 2118 | (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) |
1795 | sta->txrate = i; | 2119 | sta->txrate = i; |
1796 | } | 2120 | } |
1797 | sta->last_txrate = sta->txrate; | 2121 | sta->last_txrate = sta->txrate; |
1798 | /* For MODE_IEEE80211A mode cck rate are at end | 2122 | /* For MODE_IEEE80211A, cck rates are at end of rate table */ |
1799 | * rate table | ||
1800 | */ | ||
1801 | if (local->hw.conf.phymode == MODE_IEEE80211A) | 2123 | if (local->hw.conf.phymode == MODE_IEEE80211A) |
1802 | sta->last_txrate += IWL_FIRST_OFDM_RATE; | 2124 | sta->last_txrate += IWL_FIRST_OFDM_RATE; |
1803 | 2125 | ||
@@ -1810,11 +2132,16 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, | |||
1810 | crl->active_rate_basic = priv->active_rate_basic; | 2132 | crl->active_rate_basic = priv->active_rate_basic; |
1811 | crl->phymode = priv->phymode; | 2133 | crl->phymode = priv->phymode; |
1812 | #ifdef CONFIG_IWL4965_HT | 2134 | #ifdef CONFIG_IWL4965_HT |
2135 | /* | ||
2136 | * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), | ||
2137 | * supp_rates[] does not; shift to convert format, force 9 MBits off. | ||
2138 | */ | ||
1813 | crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1); | 2139 | crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1); |
1814 | crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1); | 2140 | crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1); |
1815 | crl->active_siso_rate &= ~((u16)0x2); | 2141 | crl->active_siso_rate &= ~((u16)0x2); |
1816 | crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE; | 2142 | crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE; |
1817 | 2143 | ||
2144 | /* Same here */ | ||
1818 | crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1); | 2145 | crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1); |
1819 | crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1); | 2146 | crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1); |
1820 | crl->active_mimo_rate &= ~((u16)0x2); | 2147 | crl->active_mimo_rate &= ~((u16)0x2); |
@@ -1844,11 +2171,14 @@ static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data, | |||
1844 | struct iwl4965_rate new_rate; | 2171 | struct iwl4965_rate new_rate; |
1845 | struct iwl4965_scale_tbl_info tbl_type = { 0 }; | 2172 | struct iwl4965_scale_tbl_info tbl_type = { 0 }; |
1846 | 2173 | ||
2174 | /* Override starting rate (index 0) if needed for debug purposes */ | ||
1847 | rs_dbgfs_set_mcs(lq_data, tx_mcs, index); | 2175 | rs_dbgfs_set_mcs(lq_data, tx_mcs, index); |
1848 | 2176 | ||
2177 | /* Interpret rate_n_flags */ | ||
1849 | rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, | 2178 | rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, |
1850 | &tbl_type, &rate_idx); | 2179 | &tbl_type, &rate_idx); |
1851 | 2180 | ||
2181 | /* How many times should we repeat the initial rate? */ | ||
1852 | if (is_legacy(tbl_type.lq_type)) { | 2182 | if (is_legacy(tbl_type.lq_type)) { |
1853 | ant_toggle_count = 1; | 2183 | ant_toggle_count = 1; |
1854 | repeat_rate = IWL_NUMBER_TRY; | 2184 | repeat_rate = IWL_NUMBER_TRY; |
@@ -1857,19 +2187,27 @@ static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data, | |||
1857 | 2187 | ||
1858 | lq_cmd->general_params.mimo_delimiter = | 2188 | lq_cmd->general_params.mimo_delimiter = |
1859 | is_mimo(tbl_type.lq_type) ? 1 : 0; | 2189 | is_mimo(tbl_type.lq_type) ? 1 : 0; |
2190 | |||
2191 | /* Fill 1st table entry (index 0) */ | ||
1860 | lq_cmd->rs_table[index].rate_n_flags = | 2192 | lq_cmd->rs_table[index].rate_n_flags = |
1861 | cpu_to_le32(tx_mcs->rate_n_flags); | 2193 | cpu_to_le32(tx_mcs->rate_n_flags); |
1862 | new_rate.rate_n_flags = tx_mcs->rate_n_flags; | 2194 | new_rate.rate_n_flags = tx_mcs->rate_n_flags; |
1863 | 2195 | ||
1864 | if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) | 2196 | if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) |
1865 | lq_cmd->general_params.single_stream_ant_msk = 1; | 2197 | lq_cmd->general_params.single_stream_ant_msk |
2198 | = LINK_QUAL_ANT_A_MSK; | ||
1866 | else | 2199 | else |
1867 | lq_cmd->general_params.single_stream_ant_msk = 2; | 2200 | lq_cmd->general_params.single_stream_ant_msk |
2201 | = LINK_QUAL_ANT_B_MSK; | ||
1868 | 2202 | ||
1869 | index++; | 2203 | index++; |
1870 | repeat_rate--; | 2204 | repeat_rate--; |
1871 | 2205 | ||
2206 | /* Fill rest of rate table */ | ||
1872 | while (index < LINK_QUAL_MAX_RETRY_NUM) { | 2207 | while (index < LINK_QUAL_MAX_RETRY_NUM) { |
2208 | /* Repeat initial/next rate. | ||
2209 | * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. | ||
2210 | * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ | ||
1873 | while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { | 2211 | while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { |
1874 | if (is_legacy(tbl_type.lq_type)) { | 2212 | if (is_legacy(tbl_type.lq_type)) { |
1875 | if (ant_toggle_count < | 2213 | if (ant_toggle_count < |
@@ -1881,7 +2219,10 @@ static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data, | |||
1881 | } | 2219 | } |
1882 | } | 2220 | } |
1883 | 2221 | ||
2222 | /* Override next rate if needed for debug purposes */ | ||
1884 | rs_dbgfs_set_mcs(lq_data, &new_rate, index); | 2223 | rs_dbgfs_set_mcs(lq_data, &new_rate, index); |
2224 | |||
2225 | /* Fill next table entry */ | ||
1885 | lq_cmd->rs_table[index].rate_n_flags = | 2226 | lq_cmd->rs_table[index].rate_n_flags = |
1886 | cpu_to_le32(new_rate.rate_n_flags); | 2227 | cpu_to_le32(new_rate.rate_n_flags); |
1887 | repeat_rate--; | 2228 | repeat_rate--; |
@@ -1891,12 +2232,17 @@ static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data, | |||
1891 | rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type, | 2232 | rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type, |
1892 | &rate_idx); | 2233 | &rate_idx); |
1893 | 2234 | ||
2235 | /* Indicate to uCode which entries might be MIMO. | ||
2236 | * If initial rate was MIMO, this will finally end up | ||
2237 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ | ||
1894 | if (is_mimo(tbl_type.lq_type)) | 2238 | if (is_mimo(tbl_type.lq_type)) |
1895 | lq_cmd->general_params.mimo_delimiter = index; | 2239 | lq_cmd->general_params.mimo_delimiter = index; |
1896 | 2240 | ||
2241 | /* Get next rate */ | ||
1897 | rs_get_lower_rate(lq_data, &tbl_type, rate_idx, | 2242 | rs_get_lower_rate(lq_data, &tbl_type, rate_idx, |
1898 | use_ht_possible, &new_rate); | 2243 | use_ht_possible, &new_rate); |
1899 | 2244 | ||
2245 | /* How many times should we repeat the next rate? */ | ||
1900 | if (is_legacy(tbl_type.lq_type)) { | 2246 | if (is_legacy(tbl_type.lq_type)) { |
1901 | if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) | 2247 | if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) |
1902 | ant_toggle_count++; | 2248 | ant_toggle_count++; |
@@ -1908,9 +2254,14 @@ static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data, | |||
1908 | } else | 2254 | } else |
1909 | repeat_rate = IWL_HT_NUMBER_TRY; | 2255 | repeat_rate = IWL_HT_NUMBER_TRY; |
1910 | 2256 | ||
2257 | /* Don't allow HT rates after next pass. | ||
2258 | * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ | ||
1911 | use_ht_possible = 0; | 2259 | use_ht_possible = 0; |
1912 | 2260 | ||
2261 | /* Override next rate if needed for debug purposes */ | ||
1913 | rs_dbgfs_set_mcs(lq_data, &new_rate, index); | 2262 | rs_dbgfs_set_mcs(lq_data, &new_rate, index); |
2263 | |||
2264 | /* Fill next table entry */ | ||
1914 | lq_cmd->rs_table[index].rate_n_flags = | 2265 | lq_cmd->rs_table[index].rate_n_flags = |
1915 | cpu_to_le32(new_rate.rate_n_flags); | 2266 | cpu_to_le32(new_rate.rate_n_flags); |
1916 | 2267 | ||
@@ -2006,9 +2357,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, | |||
2006 | else | 2357 | else |
2007 | rs_priv->dbg_fixed.rate_n_flags = 0; | 2358 | rs_priv->dbg_fixed.rate_n_flags = 0; |
2008 | 2359 | ||
2009 | rs_priv->active_rate = 0x0FFF; | 2360 | rs_priv->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ |
2010 | rs_priv->active_siso_rate = 0x1FD0; | 2361 | rs_priv->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ |
2011 | rs_priv->active_mimo_rate = 0x1FD0; | 2362 | rs_priv->active_mimo_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ |
2012 | 2363 | ||
2013 | IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", | 2364 | IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", |
2014 | rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags); | 2365 | rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags); |
@@ -2209,7 +2560,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) | |||
2209 | 2560 | ||
2210 | /* Display the average rate of all samples taken. | 2561 | /* Display the average rate of all samples taken. |
2211 | * | 2562 | * |
2212 | * NOTE: We multiple # of samples by 2 since the IEEE measurement | 2563 | * NOTE: We multiply # of samples by 2 since the IEEE measurement |
2213 | * added from iwl4965_rates is actually 2X the rate */ | 2564 | * added from iwl4965_rates is actually 2X the rate */ |
2214 | if (samples) | 2565 | if (samples) |
2215 | count += sprintf(&buf[count], | 2566 | count += sprintf(&buf[count], |