aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2013-11-24 14:30:13 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-09 15:29:48 -0500
commitb3b06a32547fd2b0ba0f3f95ff37fbf94ad997dd (patch)
tree21d1cbbf6ff4d941d659bd1aae6c82ffaced047c
parenta56db7d100dc9695dad262e0c7f2ec3d6f6f186b (diff)
iwlwifi: mvm: rs: overhaul search cycle state machine
Rewrite the search cycle state machine to use a more data oriented approach where the different Tx columns (configs) limitations and next columns to search are reprsented in tables which are easy to change. This overhaul also includes several major fixes: 1. Prevent going back to a specific Tx column in a search cycle if it was already explored. 2. Avoid switching to a Tx column that doesn't have any chance if it performs perfectly to beat the current throughput we're getting. These issues were degrading throughput as they were causing switching to "bad" Tx columns. Signed-off-by: Eyal Shapira <eyal@wizery.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c921
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h64
2 files changed, 458 insertions, 527 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 1bfdde52db5c..1bb6581f3b25 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -123,6 +123,190 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
123 IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ 123 IWL_DECLARE_MCS_RATE(9), /* MCS 9 */
124}; 124};
125 125
126enum rs_column_mode {
127 RS_INVALID = 0,
128 RS_LEGACY,
129 RS_SISO,
130 RS_MIMO2,
131};
132
133#define MAX_NEXT_COLUMNS 5
134#define MAX_COLUMN_CHECKS 3
135
136typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
137 struct ieee80211_sta *sta,
138 struct iwl_scale_tbl_info *tbl);
139
140struct rs_tx_column {
141 enum rs_column_mode mode;
142 u8 ant;
143 bool sgi;
144 enum rs_column next_columns[MAX_NEXT_COLUMNS];
145 allow_column_func_t checks[MAX_COLUMN_CHECKS];
146};
147
148static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
149 struct iwl_scale_tbl_info *tbl)
150{
151 if (!sta->ht_cap.ht_supported)
152 return false;
153
154 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
155 return false;
156
157 if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
158 return false;
159
160 if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
161 return false;
162
163 return true;
164}
165
166static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
167 struct iwl_scale_tbl_info *tbl)
168{
169 if (!sta->ht_cap.ht_supported)
170 return false;
171
172 return true;
173}
174
175static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
176 struct iwl_scale_tbl_info *tbl)
177{
178 struct rs_rate *rate = &tbl->rate;
179 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
180 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
181
182 if (is_ht20(rate) && (ht_cap->cap &
183 IEEE80211_HT_CAP_SGI_20))
184 return true;
185 if (is_ht40(rate) && (ht_cap->cap &
186 IEEE80211_HT_CAP_SGI_40))
187 return true;
188 if (is_ht80(rate) && (vht_cap->cap &
189 IEEE80211_VHT_CAP_SHORT_GI_80))
190 return true;
191
192 return false;
193}
194
195static const struct rs_tx_column rs_tx_columns[] = {
196 [RS_COLUMN_LEGACY_ANT_A] = {
197 .mode = RS_LEGACY,
198 .ant = ANT_A,
199 .next_columns = {
200 RS_COLUMN_LEGACY_ANT_B,
201 RS_COLUMN_SISO_ANT_A,
202 RS_COLUMN_MIMO2,
203 RS_COLUMN_INVALID,
204 RS_COLUMN_INVALID,
205 },
206 },
207 [RS_COLUMN_LEGACY_ANT_B] = {
208 .mode = RS_LEGACY,
209 .ant = ANT_B,
210 .next_columns = {
211 RS_COLUMN_LEGACY_ANT_A,
212 RS_COLUMN_SISO_ANT_B,
213 RS_COLUMN_MIMO2,
214 RS_COLUMN_INVALID,
215 RS_COLUMN_INVALID,
216 },
217 },
218 [RS_COLUMN_SISO_ANT_A] = {
219 .mode = RS_SISO,
220 .ant = ANT_A,
221 .next_columns = {
222 RS_COLUMN_SISO_ANT_B,
223 RS_COLUMN_MIMO2,
224 RS_COLUMN_SISO_ANT_A_SGI,
225 RS_COLUMN_INVALID,
226 RS_COLUMN_INVALID,
227 },
228 .checks = {
229 rs_siso_allow,
230 },
231 },
232 [RS_COLUMN_SISO_ANT_B] = {
233 .mode = RS_SISO,
234 .ant = ANT_B,
235 .next_columns = {
236 RS_COLUMN_SISO_ANT_A,
237 RS_COLUMN_MIMO2,
238 RS_COLUMN_SISO_ANT_B_SGI,
239 RS_COLUMN_INVALID,
240 RS_COLUMN_INVALID,
241 },
242 .checks = {
243 rs_siso_allow,
244 },
245 },
246 [RS_COLUMN_SISO_ANT_A_SGI] = {
247 .mode = RS_SISO,
248 .ant = ANT_A,
249 .sgi = true,
250 .next_columns = {
251 RS_COLUMN_SISO_ANT_B_SGI,
252 RS_COLUMN_MIMO2_SGI,
253 RS_COLUMN_SISO_ANT_A,
254 RS_COLUMN_INVALID,
255 RS_COLUMN_INVALID,
256 },
257 .checks = {
258 rs_siso_allow,
259 rs_sgi_allow,
260 },
261 },
262 [RS_COLUMN_SISO_ANT_B_SGI] = {
263 .mode = RS_SISO,
264 .ant = ANT_B,
265 .sgi = true,
266 .next_columns = {
267 RS_COLUMN_SISO_ANT_A_SGI,
268 RS_COLUMN_MIMO2_SGI,
269 RS_COLUMN_SISO_ANT_B,
270 RS_COLUMN_INVALID,
271 RS_COLUMN_INVALID,
272 },
273 .checks = {
274 rs_siso_allow,
275 rs_sgi_allow,
276 },
277 },
278 [RS_COLUMN_MIMO2] = {
279 .mode = RS_MIMO2,
280 .ant = ANT_AB,
281 .next_columns = {
282 RS_COLUMN_SISO_ANT_A,
283 RS_COLUMN_MIMO2_SGI,
284 RS_COLUMN_INVALID,
285 RS_COLUMN_INVALID,
286 RS_COLUMN_INVALID,
287 },
288 .checks = {
289 rs_mimo_allow,
290 },
291 },
292 [RS_COLUMN_MIMO2_SGI] = {
293 .mode = RS_MIMO2,
294 .ant = ANT_AB,
295 .sgi = true,
296 .next_columns = {
297 RS_COLUMN_SISO_ANT_A_SGI,
298 RS_COLUMN_MIMO2,
299 RS_COLUMN_INVALID,
300 RS_COLUMN_INVALID,
301 RS_COLUMN_INVALID,
302 },
303 .checks = {
304 rs_mimo_allow,
305 rs_sgi_allow,
306 },
307 },
308};
309
126static inline u8 rs_extract_rate(u32 rate_n_flags) 310static inline u8 rs_extract_rate(u32 rate_n_flags)
127{ 311{
128 /* also works for HT because bits 7:6 are zero there */ 312 /* also works for HT because bits 7:6 are zero there */
@@ -839,6 +1023,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
839 lq_sta->missed_rate_counter++; 1023 lq_sta->missed_rate_counter++;
840 if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { 1024 if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
841 lq_sta->missed_rate_counter = 0; 1025 lq_sta->missed_rate_counter = 0;
1026 IWL_DEBUG_RATE(mvm,
1027 "Too many rates mismatch. Send sync LQ. rs_state %d\n",
1028 lq_sta->rs_state);
842 iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); 1029 iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
843 } 1030 }
844 /* Regardless, ignore this status info for outdated rate */ 1031 /* Regardless, ignore this status info for outdated rate */
@@ -888,7 +1075,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
888 info->status.ampdu_ack_len); 1075 info->status.ampdu_ack_len);
889 1076
890 /* Update success/fail counts if not searching for new mode */ 1077 /* Update success/fail counts if not searching for new mode */
891 if (lq_sta->stay_in_tbl) { 1078 if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
892 lq_sta->total_success += info->status.ampdu_ack_len; 1079 lq_sta->total_success += info->status.ampdu_ack_len;
893 lq_sta->total_failed += (info->status.ampdu_len - 1080 lq_sta->total_failed += (info->status.ampdu_len -
894 info->status.ampdu_ack_len); 1081 info->status.ampdu_ack_len);
@@ -915,14 +1102,20 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
915 tmp_tbl = curr_tbl; 1102 tmp_tbl = curr_tbl;
916 else if (rs_rate_match(&rate, &other_tbl->rate)) 1103 else if (rs_rate_match(&rate, &other_tbl->rate))
917 tmp_tbl = other_tbl; 1104 tmp_tbl = other_tbl;
918 else 1105 else {
1106 IWL_DEBUG_RATE(mvm,
1107 "Tx packet rate doesn't match ACTIVE or SEARCH tables\n");
1108 rs_dump_rate(mvm, &rate, "Tx PACKET:");
1109 rs_dump_rate(mvm, &curr_tbl->rate, "CURRENT:");
1110 rs_dump_rate(mvm, &other_tbl->rate, "OTHER:");
919 continue; 1111 continue;
1112 }
920 rs_collect_tx_data(tmp_tbl, rate.index, 1, 1113 rs_collect_tx_data(tmp_tbl, rate.index, 1,
921 i < retries ? 0 : legacy_success); 1114 i < retries ? 0 : legacy_success);
922 } 1115 }
923 1116
924 /* Update success/fail counts if not searching for new mode */ 1117 /* Update success/fail counts if not searching for new mode */
925 if (lq_sta->stay_in_tbl) { 1118 if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
926 lq_sta->total_success += legacy_success; 1119 lq_sta->total_success += legacy_success;
927 lq_sta->total_failed += retries + (1 - legacy_success); 1120 lq_sta->total_failed += retries + (1 - legacy_success);
928 } 1121 }
@@ -946,8 +1139,8 @@ done:
946static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, 1139static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
947 struct iwl_lq_sta *lq_sta) 1140 struct iwl_lq_sta *lq_sta)
948{ 1141{
949 IWL_DEBUG_RATE(mvm, "we are staying in the same table\n"); 1142 IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n");
950 lq_sta->stay_in_tbl = 1; /* only place this gets set */ 1143 lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN;
951 if (is_legacy) { 1144 if (is_legacy) {
952 lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; 1145 lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
953 lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; 1146 lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
@@ -961,38 +1154,31 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
961 lq_sta->total_failed = 0; 1154 lq_sta->total_failed = 0;
962 lq_sta->total_success = 0; 1155 lq_sta->total_success = 0;
963 lq_sta->flush_timer = jiffies; 1156 lq_sta->flush_timer = jiffies;
964 lq_sta->action_counter = 0; 1157 lq_sta->visited_columns = 0;
965} 1158}
966 1159
967/* 1160static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
968 * Find correct throughput table for given mode of modulation 1161 const struct rs_tx_column *column,
969 */ 1162 u32 bw)
970static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
971 struct iwl_scale_tbl_info *tbl)
972{ 1163{
973 /* Used to choose among HT tables */ 1164 /* Used to choose among HT tables */
974 s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; 1165 s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
975 struct rs_rate *rate = &tbl->rate;
976 1166
977 /* Check for invalid LQ type */ 1167 if (WARN_ON_ONCE(column->mode != RS_LEGACY &&
978 if (WARN_ON_ONCE(!is_legacy(rate) && !is_ht(rate) && 1168 column->mode != RS_SISO &&
979 !(is_vht(rate)))) { 1169 column->mode != RS_MIMO2))
980 tbl->expected_tpt = expected_tpt_legacy; 1170 return expected_tpt_legacy;
981 return;
982 }
983 1171
984 /* Legacy rates have only one table */ 1172 /* Legacy rates have only one table */
985 if (is_legacy(rate)) { 1173 if (column->mode == RS_LEGACY)
986 tbl->expected_tpt = expected_tpt_legacy; 1174 return expected_tpt_legacy;
987 return;
988 }
989 1175
990 ht_tbl_pointer = expected_tpt_mimo2_20MHz; 1176 ht_tbl_pointer = expected_tpt_mimo2_20MHz;
991 /* Choose among many HT tables depending on number of streams 1177 /* Choose among many HT tables depending on number of streams
992 * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation 1178 * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation
993 * status */ 1179 * status */
994 if (is_siso(rate)) { 1180 if (column->mode == RS_SISO) {
995 switch (rate->bw) { 1181 switch (bw) {
996 case RATE_MCS_CHAN_WIDTH_20: 1182 case RATE_MCS_CHAN_WIDTH_20:
997 ht_tbl_pointer = expected_tpt_siso_20MHz; 1183 ht_tbl_pointer = expected_tpt_siso_20MHz;
998 break; 1184 break;
@@ -1005,8 +1191,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
1005 default: 1191 default:
1006 WARN_ON_ONCE(1); 1192 WARN_ON_ONCE(1);
1007 } 1193 }
1008 } else if (is_mimo2(rate)) { 1194 } else if (column->mode == RS_MIMO2) {
1009 switch (rate->bw) { 1195 switch (bw) {
1010 case RATE_MCS_CHAN_WIDTH_20: 1196 case RATE_MCS_CHAN_WIDTH_20:
1011 ht_tbl_pointer = expected_tpt_mimo2_20MHz; 1197 ht_tbl_pointer = expected_tpt_mimo2_20MHz;
1012 break; 1198 break;
@@ -1023,14 +1209,23 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
1023 WARN_ON_ONCE(1); 1209 WARN_ON_ONCE(1);
1024 } 1210 }
1025 1211
1026 if (!rate->sgi && !lq_sta->is_agg) /* Normal */ 1212 if (!column->sgi && !lq_sta->is_agg) /* Normal */
1027 tbl->expected_tpt = ht_tbl_pointer[0]; 1213 return ht_tbl_pointer[0];
1028 else if (rate->sgi && !lq_sta->is_agg) /* SGI */ 1214 else if (column->sgi && !lq_sta->is_agg) /* SGI */
1029 tbl->expected_tpt = ht_tbl_pointer[1]; 1215 return ht_tbl_pointer[1];
1030 else if (!rate->sgi && lq_sta->is_agg) /* AGG */ 1216 else if (!column->sgi && lq_sta->is_agg) /* AGG */
1031 tbl->expected_tpt = ht_tbl_pointer[2]; 1217 return ht_tbl_pointer[2];
1032 else /* AGG+SGI */ 1218 else /* AGG+SGI */
1033 tbl->expected_tpt = ht_tbl_pointer[3]; 1219 return ht_tbl_pointer[3];
1220}
1221
1222static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
1223 struct iwl_scale_tbl_info *tbl)
1224{
1225 struct rs_rate *rate = &tbl->rate;
1226 const struct rs_tx_column *column = &rs_tx_columns[tbl->column];
1227
1228 tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw);
1034} 1229}
1035 1230
1036/* 1231/*
@@ -1135,19 +1330,6 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
1135 return new_rate; 1330 return new_rate;
1136} 1331}
1137 1332
1138/* Move to the next action and wrap around to the first action in case
1139 * we're at the last action. Assumes actions start at 0.
1140 */
1141static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl,
1142 u8 last_action)
1143{
1144 BUILD_BUG_ON(IWL_LEGACY_FIRST_ACTION != 0);
1145 BUILD_BUG_ON(IWL_SISO_FIRST_ACTION != 0);
1146 BUILD_BUG_ON(IWL_MIMO2_FIRST_ACTION != 0);
1147
1148 tbl->action = (tbl->action + 1) % (last_action + 1);
1149}
1150
1151static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) 1333static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
1152{ 1334{
1153 if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) 1335 if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
@@ -1158,409 +1340,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
1158 return RATE_MCS_CHAN_WIDTH_20; 1340 return RATE_MCS_CHAN_WIDTH_20;
1159} 1341}
1160 1342
1161static bool rs_sgi_allowed(struct rs_rate *rate,
1162 struct ieee80211_sta *sta)
1163{
1164 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
1165 struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
1166
1167 if (is_ht20(rate) && (ht_cap->cap &
1168 IEEE80211_HT_CAP_SGI_20))
1169 return true;
1170 if (is_ht40(rate) && (ht_cap->cap &
1171 IEEE80211_HT_CAP_SGI_40))
1172 return true;
1173 if (is_ht80(rate) && (vht_cap->cap &
1174 IEEE80211_VHT_CAP_SHORT_GI_80))
1175 return true;
1176
1177 return false;
1178}
1179
1180/*
1181 * Set up search table for MIMO2
1182 */
1183static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
1184 struct iwl_lq_sta *lq_sta,
1185 struct ieee80211_sta *sta,
1186 struct iwl_scale_tbl_info *tbl, int index)
1187{
1188 u16 rate_mask;
1189 s32 rate_idx;
1190
1191 if (!sta->ht_cap.ht_supported)
1192 return -1;
1193
1194 if (sta->smps_mode == IEEE80211_SMPS_STATIC)
1195 return -1;
1196
1197 /* Need both Tx chains/antennas to support MIMO */
1198 if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
1199 return -1;
1200
1201 IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
1202
1203 tbl->rate.type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
1204 tbl->action = 0;
1205 tbl->max_search = IWL_MAX_SEARCH;
1206 rate_mask = lq_sta->active_mimo2_rate;
1207
1208 tbl->rate.bw = rs_bw_from_sta_bw(sta);
1209 rs_set_expected_tpt_table(lq_sta, tbl);
1210
1211 rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
1212
1213 IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n",
1214 rate_idx, rate_mask);
1215 if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
1216 IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
1217 rate_idx, rate_mask);
1218 return -1;
1219 }
1220
1221 tbl->rate.index = rate_idx;
1222 tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
1223
1224 IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
1225 tbl->current_rate);
1226 return 0;
1227}
1228
1229/*
1230 * Set up search table for SISO
1231 */
1232static int rs_switch_to_siso(struct iwl_mvm *mvm,
1233 struct iwl_lq_sta *lq_sta,
1234 struct ieee80211_sta *sta,
1235 struct iwl_scale_tbl_info *tbl, int index)
1236{
1237 u16 rate_mask;
1238 s32 rate_idx;
1239
1240 if (!sta->ht_cap.ht_supported)
1241 return -1;
1242
1243 IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");
1244
1245 tbl->rate.type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
1246 tbl->action = 0;
1247 tbl->max_search = IWL_MAX_SEARCH;
1248 rate_mask = lq_sta->active_siso_rate;
1249
1250 tbl->rate.bw = rs_bw_from_sta_bw(sta);
1251 rs_set_expected_tpt_table(lq_sta, tbl);
1252 rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
1253
1254 IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n",
1255 rate_idx, rate_mask);
1256 if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
1257 IWL_DEBUG_RATE(mvm,
1258 "can not switch with index %d rate mask %x\n",
1259 rate_idx, rate_mask);
1260 return -1;
1261 }
1262
1263 tbl->rate.index = rate_idx;
1264 tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
1265
1266 IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
1267 tbl->current_rate);
1268 return 0;
1269}
1270
1271/*
1272 * Try to switch to new modulation mode from legacy
1273 */
1274static int rs_move_legacy_other(struct iwl_mvm *mvm,
1275 struct iwl_lq_sta *lq_sta,
1276 struct ieee80211_sta *sta,
1277 int index)
1278{
1279 struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
1280 struct iwl_scale_tbl_info *search_tbl =
1281 &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
1282 struct rs_rate *rate = &search_tbl->rate;
1283 struct iwl_rate_scale_data *window = &(tbl->win[index]);
1284 u32 sz = (sizeof(struct iwl_scale_tbl_info) -
1285 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
1286 u8 start_action;
1287 u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
1288 u8 tx_chains_num = num_of_ant(valid_tx_ant);
1289 int ret;
1290 u8 update_search_tbl_counter = 0;
1291
1292 start_action = tbl->action;
1293 while (1) {
1294 lq_sta->action_counter++;
1295 switch (tbl->action) {
1296 case IWL_LEGACY_SWITCH_ANTENNA:
1297 IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n");
1298
1299 if (tx_chains_num <= 1)
1300 break;
1301
1302 /* Don't change antenna if success has been great */
1303 if (window->success_ratio >= IWL_RS_GOOD_RATIO)
1304 break;
1305
1306 /* Set up search table to try other antenna */
1307 memcpy(search_tbl, tbl, sz);
1308
1309 if (rs_toggle_antenna(valid_tx_ant,
1310 &search_tbl->current_rate,
1311 &search_tbl->rate)) {
1312 update_search_tbl_counter = 1;
1313 rs_set_expected_tpt_table(lq_sta, search_tbl);
1314 goto out;
1315 }
1316 break;
1317 case IWL_LEGACY_SWITCH_SISO:
1318 IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n");
1319
1320 /* Set up search table to try SISO */
1321 memcpy(search_tbl, tbl, sz);
1322 rate->sgi = false;
1323 ret = rs_switch_to_siso(mvm, lq_sta, sta,
1324 search_tbl, index);
1325 if (!ret) {
1326 lq_sta->action_counter = 0;
1327 goto out;
1328 }
1329
1330 break;
1331 case IWL_LEGACY_SWITCH_MIMO2:
1332 IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n");
1333
1334 /* Set up search table to try MIMO */
1335 memcpy(search_tbl, tbl, sz);
1336 rate->sgi = false;
1337 rate->ant = ANT_AB;
1338
1339 if (!rs_is_valid_ant(valid_tx_ant,
1340 rate->ant))
1341 break;
1342
1343 ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
1344 search_tbl, index);
1345 if (!ret) {
1346 lq_sta->action_counter = 0;
1347 goto out;
1348 }
1349 break;
1350 default:
1351 WARN_ON_ONCE(1);
1352 }
1353 rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION);
1354
1355 if (tbl->action == start_action)
1356 break;
1357 }
1358 rate->type = LQ_NONE;
1359 return 0;
1360
1361out:
1362 lq_sta->search_better_tbl = 1;
1363 rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION);
1364 if (update_search_tbl_counter)
1365 search_tbl->action = tbl->action;
1366 return 0;
1367}
1368
1369/*
1370 * Try to switch to new modulation mode from SISO
1371 */
1372static int rs_move_siso_to_other(struct iwl_mvm *mvm,
1373 struct iwl_lq_sta *lq_sta,
1374 struct ieee80211_sta *sta, int index)
1375{
1376 struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
1377 struct iwl_scale_tbl_info *search_tbl =
1378 &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
1379 struct rs_rate *rate = &search_tbl->rate;
1380 struct iwl_rate_scale_data *window = &(tbl->win[index]);
1381 u32 sz = (sizeof(struct iwl_scale_tbl_info) -
1382 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
1383 u8 start_action;
1384 u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
1385 u8 tx_chains_num = num_of_ant(valid_tx_ant);
1386 u8 update_search_tbl_counter = 0;
1387 int ret;
1388
1389 if (tbl->action == IWL_SISO_SWITCH_MIMO2 &&
1390 !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
1391 tbl->action = IWL_SISO_SWITCH_ANTENNA;
1392
1393 start_action = tbl->action;
1394 while (1) {
1395 lq_sta->action_counter++;
1396 switch (tbl->action) {
1397 case IWL_SISO_SWITCH_ANTENNA:
1398 IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n");
1399 if (tx_chains_num <= 1)
1400 break;
1401
1402 if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
1403 BT_MBOX_MSG(&mvm->last_bt_notif, 3,
1404 TRAFFIC_LOAD) == 0)
1405 break;
1406
1407 memcpy(search_tbl, tbl, sz);
1408 if (rs_toggle_antenna(valid_tx_ant,
1409 &search_tbl->current_rate,
1410 rate)) {
1411 update_search_tbl_counter = 1;
1412 goto out;
1413 }
1414 break;
1415 case IWL_SISO_SWITCH_MIMO2:
1416 IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
1417 memcpy(search_tbl, tbl, sz);
1418 rate->sgi = false;
1419 rate->ant = ANT_AB;
1420
1421 if (!rs_is_valid_ant(valid_tx_ant,
1422 rate->ant))
1423 break;
1424
1425 ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
1426 search_tbl, index);
1427 if (!ret)
1428 goto out;
1429 break;
1430 case IWL_SISO_SWITCH_GI:
1431 if (!rs_sgi_allowed(rate, sta))
1432 break;
1433
1434 IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");
1435
1436 memcpy(search_tbl, tbl, sz);
1437 rate->sgi = !tbl->rate.sgi;
1438 rs_set_expected_tpt_table(lq_sta, search_tbl);
1439 if (tbl->rate.sgi) {
1440 s32 tpt = lq_sta->last_tpt / 100;
1441 if (tpt >= search_tbl->expected_tpt[index])
1442 break;
1443 }
1444 rate->index = index;
1445 search_tbl->current_rate =
1446 ucode_rate_from_rs_rate(mvm, rate);
1447 update_search_tbl_counter = 1;
1448 goto out;
1449 default:
1450 WARN_ON_ONCE(1);
1451 }
1452 rs_move_next_action(tbl, IWL_SISO_LAST_ACTION);
1453
1454 if (tbl->action == start_action)
1455 break;
1456 }
1457 rate->type = LQ_NONE;
1458 return 0;
1459
1460 out:
1461 lq_sta->search_better_tbl = 1;
1462 rs_move_next_action(tbl, IWL_SISO_LAST_ACTION);
1463 if (update_search_tbl_counter)
1464 search_tbl->action = tbl->action;
1465
1466 return 0;
1467}
1468
1469/*
1470 * Try to switch to new modulation mode from MIMO2
1471 */
1472static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
1473 struct iwl_lq_sta *lq_sta,
1474 struct ieee80211_sta *sta, int index)
1475{
1476 struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
1477 struct iwl_scale_tbl_info *search_tbl =
1478 &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
1479 struct rs_rate *rate = &search_tbl->rate;
1480 u32 sz = (sizeof(struct iwl_scale_tbl_info) -
1481 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
1482 u8 start_action;
1483 u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
1484 u8 update_search_tbl_counter = 0;
1485 int ret;
1486
1487 if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) {
1488 IWL_DEBUG_RATE(mvm, "BT COEX force switch to SISO A\n");
1489 tbl->action = IWL_MIMO2_SWITCH_SISO_A;
1490 }
1491
1492 start_action = tbl->action;
1493 while (1) {
1494 lq_sta->action_counter++;
1495 switch (tbl->action) {
1496 case IWL_MIMO2_SWITCH_SISO_A:
1497 case IWL_MIMO2_SWITCH_SISO_B:
1498 IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n");
1499
1500 /* Set up new search table for SISO */
1501 memcpy(search_tbl, tbl, sz);
1502
1503 if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
1504 rate->ant = ANT_A;
1505 else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */
1506 rate->ant = ANT_B;
1507
1508 if (!rs_is_valid_ant(valid_tx_ant,
1509 rate->ant))
1510 break;
1511
1512 ret = rs_switch_to_siso(mvm, lq_sta, sta,
1513 search_tbl, index);
1514 if (!ret)
1515 goto out;
1516
1517 break;
1518
1519 case IWL_MIMO2_SWITCH_GI:
1520 if (!rs_sgi_allowed(rate, sta))
1521 break;
1522
1523 IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");
1524
1525 /* Set up new search table for MIMO2 */
1526 memcpy(search_tbl, tbl, sz);
1527 rate->sgi = !tbl->rate.sgi;
1528 rs_set_expected_tpt_table(lq_sta, search_tbl);
1529 /*
1530 * If active table already uses the fastest possible
1531 * modulation (dual stream with short guard interval),
1532 * and it's working well, there's no need to look
1533 * for a better type of modulation!
1534 */
1535 if (tbl->rate.sgi) {
1536 s32 tpt = lq_sta->last_tpt / 100;
1537 if (tpt >= search_tbl->expected_tpt[index])
1538 break;
1539 }
1540 rate->index = index;
1541 search_tbl->current_rate =
1542 ucode_rate_from_rs_rate(mvm, rate);
1543 update_search_tbl_counter = 1;
1544 goto out;
1545 default:
1546 WARN_ON_ONCE(1);
1547 }
1548 rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION);
1549
1550 if (tbl->action == start_action)
1551 break;
1552 }
1553 rate->type = LQ_NONE;
1554 return 0;
1555 out:
1556 lq_sta->search_better_tbl = 1;
1557 rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION);
1558 if (update_search_tbl_counter)
1559 search_tbl->action = tbl->action;
1560
1561 return 0;
1562}
1563
1564/* 1343/*
1565 * Check whether we should continue using same modulation mode, or 1344 * Check whether we should continue using same modulation mode, or
1566 * begin search for a new mode, based on: 1345 * begin search for a new mode, based on:
@@ -1582,7 +1361,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
1582 tbl = &(lq_sta->lq_info[active_tbl]); 1361 tbl = &(lq_sta->lq_info[active_tbl]);
1583 1362
1584 /* If we've been disallowing search, see if we should now allow it */ 1363 /* If we've been disallowing search, see if we should now allow it */
1585 if (lq_sta->stay_in_tbl) { 1364 if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
1586 /* Elapsed time using current modulation mode */ 1365 /* Elapsed time using current modulation mode */
1587 if (lq_sta->flush_timer) 1366 if (lq_sta->flush_timer)
1588 flush_interval_passed = 1367 flush_interval_passed =
@@ -1610,10 +1389,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
1610 flush_interval_passed); 1389 flush_interval_passed);
1611 1390
1612 /* Allow search for new mode */ 1391 /* Allow search for new mode */
1613 lq_sta->stay_in_tbl = 0; /* only place reset */ 1392 lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_STARTED;
1393 IWL_DEBUG_RATE(mvm,
1394 "Moving to RS_STATE_SEARCH_CYCLE_STARTED\n");
1614 lq_sta->total_failed = 0; 1395 lq_sta->total_failed = 0;
1615 lq_sta->total_success = 0; 1396 lq_sta->total_success = 0;
1616 lq_sta->flush_timer = 0; 1397 lq_sta->flush_timer = 0;
1398 /* mark the current column as visited */
1399 lq_sta->visited_columns = BIT(tbl->column);
1617 /* 1400 /*
1618 * Else if we've used this modulation mode enough repetitions 1401 * Else if we've used this modulation mode enough repetitions
1619 * (regardless of elapsed time or success/failure), reset 1402 * (regardless of elapsed time or success/failure), reset
@@ -1637,7 +1420,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
1637 /* If transitioning to allow "search", reset all history 1420 /* If transitioning to allow "search", reset all history
1638 * bitmaps and stats in active table (this will become the new 1421 * bitmaps and stats in active table (this will become the new
1639 * "search" table). */ 1422 * "search" table). */
1640 if (!lq_sta->stay_in_tbl) { 1423 if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) {
1424 IWL_DEBUG_RATE(mvm, "Clearing up window stats\n");
1641 for (i = 0; i < IWL_RATE_COUNT; i++) 1425 for (i = 0; i < IWL_RATE_COUNT; i++)
1642 rs_rate_scale_clear_window(&(tbl->win[i])); 1426 rs_rate_scale_clear_window(&(tbl->win[i]));
1643 } 1427 }
@@ -1675,6 +1459,162 @@ static u8 rs_get_tid(struct iwl_lq_sta *lq_data,
1675 return tid; 1459 return tid;
1676} 1460}
1677 1461
1462static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
1463 struct iwl_lq_sta *lq_sta,
1464 struct ieee80211_sta *sta,
1465 struct iwl_scale_tbl_info *tbl)
1466{
1467 int i, j, n;
1468 enum rs_column next_col_id;
1469 const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
1470 const struct rs_tx_column *next_col;
1471 allow_column_func_t allow_func;
1472 u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw);
1473 s32 *expected_tpt_tbl;
1474 s32 tpt, max_expected_tpt;
1475
1476 for (i = 0; i < MAX_NEXT_COLUMNS; i++) {
1477 next_col_id = curr_col->next_columns[i];
1478
1479 if (next_col_id == RS_COLUMN_INVALID)
1480 continue;
1481
1482 if (lq_sta->visited_columns & BIT(next_col_id)) {
1483 IWL_DEBUG_RATE(mvm, "Skip already visited column %d\n",
1484 next_col_id);
1485 continue;
1486 }
1487
1488 next_col = &rs_tx_columns[next_col_id];
1489
1490 if (!rs_is_valid_ant(valid_ants, next_col->ant)) {
1491 IWL_DEBUG_RATE(mvm,
1492 "Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x\n",
1493 next_col_id, valid_ants, next_col->ant);
1494 continue;
1495 }
1496
1497 for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
1498 allow_func = next_col->checks[j];
1499 if (allow_func && !allow_func(mvm, sta, tbl))
1500 break;
1501 }
1502
1503 if (j != MAX_COLUMN_CHECKS) {
1504 IWL_DEBUG_RATE(mvm,
1505 "Skip column %d: not allowed (check %d failed)\n",
1506 next_col_id, j);
1507
1508 continue;
1509 }
1510
1511 tpt = lq_sta->last_tpt / 100;
1512 expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col,
1513 tbl->rate.bw);
1514 if (WARN_ON_ONCE(!expected_tpt_tbl))
1515 continue;
1516
1517 max_expected_tpt = 0;
1518 for (n = 0; n < IWL_RATE_COUNT; n++)
1519 if (expected_tpt_tbl[n] > max_expected_tpt)
1520 max_expected_tpt = expected_tpt_tbl[n];
1521
1522 if (tpt >= max_expected_tpt) {
1523 IWL_DEBUG_RATE(mvm,
1524 "Skip column %d: can't beat current TPT. Max expected %d current %d\n",
1525 next_col_id, max_expected_tpt, tpt);
1526 continue;
1527 }
1528
1529 break;
1530 }
1531
1532 if (i == MAX_NEXT_COLUMNS)
1533 return RS_COLUMN_INVALID;
1534
1535 IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id);
1536
1537 return next_col_id;
1538}
1539
1540static int rs_switch_to_column(struct iwl_mvm *mvm,
1541 struct iwl_lq_sta *lq_sta,
1542 struct ieee80211_sta *sta,
1543 enum rs_column col_id)
1544{
1545 struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
1546 struct iwl_scale_tbl_info *search_tbl =
1547 &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
1548 struct rs_rate *rate = &search_tbl->rate;
1549 const struct rs_tx_column *column = &rs_tx_columns[col_id];
1550 const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column];
1551 u32 sz = (sizeof(struct iwl_scale_tbl_info) -
1552 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
1553 u16 rate_mask = 0;
1554 u32 rate_idx = 0;
1555
1556 memcpy(search_tbl, tbl, sz);
1557
1558 rate->sgi = column->sgi;
1559 rate->ant = column->ant;
1560
1561 if (column->mode == RS_LEGACY) {
1562 if (lq_sta->band == IEEE80211_BAND_5GHZ)
1563 rate->type = LQ_LEGACY_A;
1564 else
1565 rate->type = LQ_LEGACY_G;
1566
1567 rate_mask = lq_sta->active_legacy_rate;
1568 } else if (column->mode == RS_SISO) {
1569 rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
1570 rate_mask = lq_sta->active_siso_rate;
1571 } else if (column->mode == RS_MIMO2) {
1572 rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
1573 rate_mask = lq_sta->active_mimo2_rate;
1574 } else {
1575 WARN_ON_ONCE("Bad column mode");
1576 }
1577
1578 rate->bw = rs_bw_from_sta_bw(sta);
1579 search_tbl->column = col_id;
1580 rs_set_expected_tpt_table(lq_sta, search_tbl);
1581
1582 /* Get the best matching rate if we're changing modes. e.g.
1583 * SISO->MIMO, LEGACY->SISO, MIMO->SISO
1584 */
1585 if (curr_column->mode != column->mode) {
1586 rate_idx = rs_get_best_rate(mvm, lq_sta, search_tbl,
1587 rate_mask, rate->index);
1588
1589 if ((rate_idx == IWL_RATE_INVALID) ||
1590 !(BIT(rate_idx) & rate_mask)) {
1591 IWL_DEBUG_RATE(mvm,
1592 "can not switch with index %d"
1593 " rate mask %x\n",
1594 rate_idx, rate_mask);
1595
1596 goto err;
1597 }
1598
1599 rate->index = rate_idx;
1600 }
1601
1602 /* TODO: remove current_rate and keep using rs_rate all the way until
1603 * we need to fill in the rs_table in the LQ command
1604 */
1605 search_tbl->current_rate = ucode_rate_from_rs_rate(mvm, rate);
1606 IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n",
1607 col_id, rate->index);
1608
1609 lq_sta->visited_columns |= BIT(col_id);
1610 return 0;
1611
1612err:
1613 rate->type = LQ_NONE;
1614 return -1;
1615}
1616
1617
1678/* 1618/*
1679 * Do rate scaling and search for new modulation mode. 1619 * Do rate scaling and search for new modulation mode.
1680 */ 1620 */
@@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
1772 if (!rate_scale_index_msk) 1712 if (!rate_scale_index_msk)
1773 rate_scale_index_msk = rate_mask; 1713 rate_scale_index_msk = rate_mask;
1774 1714
1775 if (!((1 << index) & rate_scale_index_msk)) { 1715 if (!((BIT(index) & rate_scale_index_msk))) {
1776 IWL_ERR(mvm, "Current Rate is not valid\n"); 1716 IWL_ERR(mvm, "Current Rate is not valid\n");
1777 if (lq_sta->search_better_tbl) { 1717 if (lq_sta->search_better_tbl) {
1778 /* revert to active table if search table is not valid*/ 1718 /* revert to active table if search table is not valid*/
@@ -1852,9 +1792,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
1852 window->average_tpt, 1792 window->average_tpt,
1853 lq_sta->last_tpt); 1793 lq_sta->last_tpt);
1854 1794
1855 if (!is_legacy(rate))
1856 lq_sta->enable_counter = 1;
1857
1858 /* Swap tables; "search" becomes "active" */ 1795 /* Swap tables; "search" becomes "active" */
1859 lq_sta->active_tbl = active_tbl; 1796 lq_sta->active_tbl = active_tbl;
1860 current_tpt = window->average_tpt; 1797 current_tpt = window->average_tpt;
@@ -2049,24 +1986,29 @@ lq_update:
2049 * 3) Allowing a new search 1986 * 3) Allowing a new search
2050 */ 1987 */
2051 if (!update_lq && !done_search && 1988 if (!update_lq && !done_search &&
2052 !lq_sta->stay_in_tbl && window->counter) { 1989 lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED
1990 && window->counter) {
1991 enum rs_column next_column;
1992
2053 /* Save current throughput to compare with "search" throughput*/ 1993 /* Save current throughput to compare with "search" throughput*/
2054 lq_sta->last_tpt = current_tpt; 1994 lq_sta->last_tpt = current_tpt;
2055 1995
2056 IWL_DEBUG_RATE(mvm, 1996 IWL_DEBUG_RATE(mvm,
2057 "Start Search: update_lq %d done_search %d stay_in_tbl %d win->counter %d\n", 1997 "Start Search: update_lq %d done_search %d rs_state %d win->counter %d\n",
2058 update_lq, done_search, lq_sta->stay_in_tbl, 1998 update_lq, done_search, lq_sta->rs_state,
2059 window->counter); 1999 window->counter);
2060 /* Select a new "search" modulation mode to try. 2000
2061 * If one is found, set up the new "search" table. */ 2001 next_column = rs_get_next_column(mvm, lq_sta, sta, tbl);
2062 if (is_legacy(&tbl->rate)) 2002 if (next_column != RS_COLUMN_INVALID) {
2063 rs_move_legacy_other(mvm, lq_sta, sta, index); 2003 int ret = rs_switch_to_column(mvm, lq_sta, sta,
2064 else if (is_siso(&tbl->rate)) 2004 next_column);
2065 rs_move_siso_to_other(mvm, lq_sta, sta, index); 2005 if (!ret)
2066 else if (is_mimo2(&tbl->rate)) 2006 lq_sta->search_better_tbl = 1;
2067 rs_move_mimo2_to_other(mvm, lq_sta, sta, index); 2007 } else {
2068 else 2008 IWL_DEBUG_RATE(mvm,
2069 WARN_ON_ONCE(1); 2009 "No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED\n");
2010 lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_ENDED;
2011 }
2070 2012
2071 /* If new "search" mode was selected, set up in uCode table */ 2013 /* If new "search" mode was selected, set up in uCode table */
2072 if (lq_sta->search_better_tbl) { 2014 if (lq_sta->search_better_tbl) {
@@ -2078,12 +2020,8 @@ lq_update:
2078 /* Use new "search" start rate */ 2020 /* Use new "search" start rate */
2079 index = iwl_hwrate_to_plcp_idx(tbl->current_rate); 2021 index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
2080 2022
2081 IWL_DEBUG_RATE(mvm, 2023 rs_dump_rate(mvm, &tbl->rate,
2082 "Switch to SEARCH TABLE: " 2024 "Switch to SEARCH TABLE:");
2083 "mcs %X (%s: %d)\n",
2084 tbl->current_rate,
2085 rs_pretty_lq_type(tbl->rate.type),
2086 index);
2087 rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); 2025 rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
2088 iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); 2026 iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
2089 } else { 2027 } else {
@@ -2091,24 +2029,20 @@ lq_update:
2091 } 2029 }
2092 } 2030 }
2093 2031
2094 if (done_search && !lq_sta->stay_in_tbl) { 2032 if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
2095 /* If the "active" (non-search) mode was legacy, 2033 /* If the "active" (non-search) mode was legacy,
2096 * and we've tried switching antennas, 2034 * and we've tried switching antennas,
2097 * but we haven't been able to try HT modes (not available), 2035 * but we haven't been able to try HT modes (not available),
2098 * stay with best antenna legacy modulation for a while 2036 * stay with best antenna legacy modulation for a while
2099 * before next round of mode comparisons. */ 2037 * before next round of mode comparisons. */
2100 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); 2038 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
2101 if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported && 2039 if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) {
2102 lq_sta->action_counter > tbl1->max_search) {
2103 IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); 2040 IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
2104 rs_set_stay_in_table(mvm, 1, lq_sta); 2041 rs_set_stay_in_table(mvm, 1, lq_sta);
2105 } 2042 } else {
2106
2107 /* If we're in an HT mode, and all 3 mode switch actions 2043 /* If we're in an HT mode, and all 3 mode switch actions
2108 * have been tried and compared, stay in this best modulation 2044 * have been tried and compared, stay in this best modulation
2109 * mode for a while before next round of mode comparisons. */ 2045 * mode for a while before next round of mode comparisons. */
2110 if (lq_sta->enable_counter &&
2111 (lq_sta->action_counter >= tbl1->max_search)) {
2112 if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && 2046 if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
2113 (lq_sta->tx_agg_tid_en & (1 << tid)) && 2047 (lq_sta->tx_agg_tid_en & (1 << tid)) &&
2114 (tid != IWL_MAX_TID_COUNT)) { 2048 (tid != IWL_MAX_TID_COUNT)) {
@@ -2176,19 +2110,24 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
2176 if ((i < 0) || (i >= IWL_RATE_COUNT)) 2110 if ((i < 0) || (i >= IWL_RATE_COUNT))
2177 i = 0; 2111 i = 0;
2178 2112
2179 ucode_rate = iwl_rates[i].plcp; 2113 rate->index = i;
2180 rate->ant = first_antenna(valid_tx_ant); 2114 rate->ant = first_antenna(valid_tx_ant);
2181 ucode_rate |= rate->ant << RATE_MCS_ANT_POS; 2115 rate->sgi = false;
2182 2116 rate->bw = RATE_MCS_CHAN_WIDTH_20;
2183 if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) 2117 if (band == IEEE80211_BAND_5GHZ)
2184 ucode_rate |= RATE_MCS_CCK_MSK; 2118 rate->type = LQ_LEGACY_A;
2185 2119 else
2186 rs_rate_from_ucode_rate(ucode_rate, band, rate); 2120 rate->type = LQ_LEGACY_G;
2187 if (!rs_is_valid_ant(valid_tx_ant, rate->ant))
2188 rs_toggle_antenna(valid_tx_ant, &ucode_rate, rate);
2189 2121
2190 ucode_rate = ucode_rate_from_rs_rate(mvm, rate); 2122 ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
2191 tbl->current_rate = ucode_rate; 2123 tbl->current_rate = ucode_rate;
2124
2125 WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
2126 if (rate->ant == ANT_A)
2127 tbl->column = RS_COLUMN_LEGACY_ANT_A;
2128 else
2129 tbl->column = RS_COLUMN_LEGACY_ANT_B;
2130
2192 rs_set_expected_tpt_table(lq_sta, tbl); 2131 rs_set_expected_tpt_table(lq_sta, tbl);
2193 rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate); 2132 rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate);
2194 /* TODO restore station should remember the lq cmd */ 2133 /* TODO restore station should remember the lq cmd */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 8fa26aff1339..b32960796384 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -157,37 +157,6 @@ enum {
157#define IWL_RATE_INCREASE_TH 6400 /* 50% */ 157#define IWL_RATE_INCREASE_TH 6400 /* 50% */
158#define RS_SR_FORCE_DECREASE 1920 /* 15% */ 158#define RS_SR_FORCE_DECREASE 1920 /* 15% */
159 159
160/* possible actions when in legacy mode */
161enum {
162 IWL_LEGACY_SWITCH_ANTENNA,
163 IWL_LEGACY_SWITCH_SISO,
164 IWL_LEGACY_SWITCH_MIMO2,
165 IWL_LEGACY_FIRST_ACTION = IWL_LEGACY_SWITCH_ANTENNA,
166 IWL_LEGACY_LAST_ACTION = IWL_LEGACY_SWITCH_MIMO2,
167};
168
169/* possible actions when in siso mode */
170enum {
171 IWL_SISO_SWITCH_ANTENNA,
172 IWL_SISO_SWITCH_MIMO2,
173 IWL_SISO_SWITCH_GI,
174 IWL_SISO_FIRST_ACTION = IWL_SISO_SWITCH_ANTENNA,
175 IWL_SISO_LAST_ACTION = IWL_SISO_SWITCH_GI,
176};
177
178/* possible actions when in mimo mode */
179enum {
180 IWL_MIMO2_SWITCH_SISO_A,
181 IWL_MIMO2_SWITCH_SISO_B,
182 IWL_MIMO2_SWITCH_GI,
183 IWL_MIMO2_FIRST_ACTION = IWL_MIMO2_SWITCH_SISO_A,
184 IWL_MIMO2_LAST_ACTION = IWL_MIMO2_SWITCH_GI,
185};
186
187#define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION
188
189#define IWL_ACTION_LIMIT 3 /* # possible actions */
190
191#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ 160#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
192#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) 161#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
193#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) 162#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
@@ -282,6 +251,23 @@ struct iwl_rate_scale_data {
282 s32 average_tpt; /* success ratio * expected throughput */ 251 s32 average_tpt; /* success ratio * expected throughput */
283}; 252};
284 253
254/* Possible Tx columns
255 * Tx Column = a combo of legacy/siso/mimo x antenna x SGI
256 */
257enum rs_column {
258 RS_COLUMN_LEGACY_ANT_A = 0,
259 RS_COLUMN_LEGACY_ANT_B,
260 RS_COLUMN_SISO_ANT_A,
261 RS_COLUMN_SISO_ANT_B,
262 RS_COLUMN_SISO_ANT_A_SGI,
263 RS_COLUMN_SISO_ANT_B_SGI,
264 RS_COLUMN_MIMO2,
265 RS_COLUMN_MIMO2_SGI,
266
267 RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI,
268 RS_COLUMN_INVALID,
269};
270
285/** 271/**
286 * struct iwl_scale_tbl_info -- tx params and success history for all rates 272 * struct iwl_scale_tbl_info -- tx params and success history for all rates
287 * 273 *
@@ -290,13 +276,18 @@ struct iwl_rate_scale_data {
290 */ 276 */
291struct iwl_scale_tbl_info { 277struct iwl_scale_tbl_info {
292 struct rs_rate rate; 278 struct rs_rate rate;
293 u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ 279 enum rs_column column;
294 u8 max_search; /* maximun number of tables we can search */
295 s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ 280 s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
296 u32 current_rate; /* rate_n_flags, uCode API format */ 281 u32 current_rate; /* rate_n_flags, uCode API format */
297 struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ 282 struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
298}; 283};
299 284
285enum {
286 RS_STATE_SEARCH_CYCLE_STARTED,
287 RS_STATE_SEARCH_CYCLE_ENDED,
288 RS_STATE_STAY_IN_COLUMN,
289};
290
300/** 291/**
301 * struct iwl_lq_sta -- driver's rate scaling private structure 292 * struct iwl_lq_sta -- driver's rate scaling private structure
302 * 293 *
@@ -304,8 +295,7 @@ struct iwl_scale_tbl_info {
304 */ 295 */
305struct iwl_lq_sta { 296struct iwl_lq_sta {
306 u8 active_tbl; /* index of active table, range 0-1 */ 297 u8 active_tbl; /* index of active table, range 0-1 */
307 u8 enable_counter; /* indicates HT mode */ 298 u8 rs_state; /* RS_STATE_* */
308 u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
309 u8 search_better_tbl; /* 1: currently trying alternate mode */ 299 u8 search_better_tbl; /* 1: currently trying alternate mode */
310 s32 last_tpt; 300 s32 last_tpt;
311 301
@@ -318,7 +308,9 @@ struct iwl_lq_sta {
318 u32 total_success; /* total successful frames, any/all rates */ 308 u32 total_success; /* total successful frames, any/all rates */
319 u64 flush_timer; /* time staying in mode before new search */ 309 u64 flush_timer; /* time staying in mode before new search */
320 310
321 u8 action_counter; /* # mode-switch actions tried */ 311 u32 visited_columns; /* Bitmask marking which Tx columns were
312 * explored during a search cycle
313 */
322 bool is_vht; 314 bool is_vht;
323 enum ieee80211_band band; 315 enum ieee80211_band band;
324 316