diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/rs.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 539 |
1 files changed, 289 insertions, 250 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 009e72abcd51..e4415e58fa78 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c | |||
@@ -1197,239 +1197,6 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr) | |||
1197 | return tid; | 1197 | return tid; |
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
1201 | int tid, struct ieee80211_tx_info *info, bool ndp) | ||
1202 | { | ||
1203 | int legacy_success; | ||
1204 | int retries; | ||
1205 | int i; | ||
1206 | struct iwl_lq_cmd *table; | ||
1207 | u32 lq_hwrate; | ||
1208 | struct rs_rate lq_rate, tx_resp_rate; | ||
1209 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; | ||
1210 | u32 tlc_info = (uintptr_t)info->status.status_driver_data[0]; | ||
1211 | u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK; | ||
1212 | u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info); | ||
1213 | u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1]; | ||
1214 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1215 | struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv; | ||
1216 | |||
1217 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
1218 | if (!lq_sta) { | ||
1219 | IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); | ||
1220 | return; | ||
1221 | } else if (!lq_sta->pers.drv) { | ||
1222 | IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); | ||
1223 | return; | ||
1224 | } | ||
1225 | |||
1226 | /* This packet was aggregated but doesn't carry status info */ | ||
1227 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
1228 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | ||
1229 | return; | ||
1230 | |||
1231 | if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, | ||
1232 | &tx_resp_rate)) { | ||
1233 | WARN_ON_ONCE(1); | ||
1234 | return; | ||
1235 | } | ||
1236 | |||
1237 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
1238 | /* Disable last tx check if we are debugging with fixed rate but | ||
1239 | * update tx stats */ | ||
1240 | if (lq_sta->pers.dbg_fixed_rate) { | ||
1241 | int index = tx_resp_rate.index; | ||
1242 | enum rs_column column; | ||
1243 | int attempts, success; | ||
1244 | |||
1245 | column = rs_get_column_from_rate(&tx_resp_rate); | ||
1246 | if (WARN_ONCE(column == RS_COLUMN_INVALID, | ||
1247 | "Can't map rate 0x%x to column", | ||
1248 | tx_resp_hwrate)) | ||
1249 | return; | ||
1250 | |||
1251 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
1252 | attempts = info->status.ampdu_len; | ||
1253 | success = info->status.ampdu_ack_len; | ||
1254 | } else { | ||
1255 | attempts = info->status.rates[0].count; | ||
1256 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
1257 | } | ||
1258 | |||
1259 | lq_sta->pers.tx_stats[column][index].total += attempts; | ||
1260 | lq_sta->pers.tx_stats[column][index].success += success; | ||
1261 | |||
1262 | IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", | ||
1263 | tx_resp_hwrate, success, attempts); | ||
1264 | return; | ||
1265 | } | ||
1266 | #endif | ||
1267 | |||
1268 | if (time_after(jiffies, | ||
1269 | (unsigned long)(lq_sta->last_tx + | ||
1270 | (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { | ||
1271 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); | ||
1272 | iwl_mvm_rs_rate_init(mvm, sta, info->band, true); | ||
1273 | return; | ||
1274 | } | ||
1275 | lq_sta->last_tx = jiffies; | ||
1276 | |||
1277 | /* Ignore this Tx frame response if its initial rate doesn't match | ||
1278 | * that of latest Link Quality command. There may be stragglers | ||
1279 | * from a previous Link Quality command, but we're no longer interested | ||
1280 | * in those; they're either from the "active" mode while we're trying | ||
1281 | * to check "search" mode, or a prior "search" mode after we've moved | ||
1282 | * to a new "search" mode (which might become the new "active" mode). | ||
1283 | */ | ||
1284 | table = &lq_sta->lq; | ||
1285 | lq_hwrate = le32_to_cpu(table->rs_table[0]); | ||
1286 | if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) { | ||
1287 | WARN_ON_ONCE(1); | ||
1288 | return; | ||
1289 | } | ||
1290 | |||
1291 | /* Here we actually compare this rate to the latest LQ command */ | ||
1292 | if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { | ||
1293 | IWL_DEBUG_RATE(mvm, | ||
1294 | "tx resp color 0x%x does not match 0x%x\n", | ||
1295 | lq_color, LQ_FLAG_COLOR_GET(table->flags)); | ||
1296 | |||
1297 | /* | ||
1298 | * Since rates mis-match, the last LQ command may have failed. | ||
1299 | * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with | ||
1300 | * ... driver. | ||
1301 | */ | ||
1302 | lq_sta->missed_rate_counter++; | ||
1303 | if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { | ||
1304 | lq_sta->missed_rate_counter = 0; | ||
1305 | IWL_DEBUG_RATE(mvm, | ||
1306 | "Too many rates mismatch. Send sync LQ. rs_state %d\n", | ||
1307 | lq_sta->rs_state); | ||
1308 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); | ||
1309 | } | ||
1310 | /* Regardless, ignore this status info for outdated rate */ | ||
1311 | return; | ||
1312 | } else | ||
1313 | /* Rate did match, so reset the missed_rate_counter */ | ||
1314 | lq_sta->missed_rate_counter = 0; | ||
1315 | |||
1316 | if (!lq_sta->search_better_tbl) { | ||
1317 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1318 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
1319 | } else { | ||
1320 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
1321 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1322 | } | ||
1323 | |||
1324 | if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) { | ||
1325 | IWL_DEBUG_RATE(mvm, | ||
1326 | "Neither active nor search matches tx rate\n"); | ||
1327 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1328 | rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); | ||
1329 | tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | ||
1330 | rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); | ||
1331 | rs_dump_rate(mvm, &lq_rate, "ACTUAL"); | ||
1332 | |||
1333 | /* | ||
1334 | * no matching table found, let's by-pass the data collection | ||
1335 | * and continue to perform rate scale to find the rate table | ||
1336 | */ | ||
1337 | rs_stay_in_table(lq_sta, true); | ||
1338 | goto done; | ||
1339 | } | ||
1340 | |||
1341 | /* | ||
1342 | * Updating the frame history depends on whether packets were | ||
1343 | * aggregated. | ||
1344 | * | ||
1345 | * For aggregation, all packets were transmitted at the same rate, the | ||
1346 | * first index into rate scale table. | ||
1347 | */ | ||
1348 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
1349 | rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, | ||
1350 | info->status.ampdu_len, | ||
1351 | info->status.ampdu_ack_len, | ||
1352 | reduced_txp); | ||
1353 | |||
1354 | /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat | ||
1355 | * it as a single frame loss as we don't want the success ratio | ||
1356 | * to dip too quickly because a BA wasn't received. | ||
1357 | * For TPC, there's no need for this optimisation since we want | ||
1358 | * to recover very quickly from a bad power reduction and, | ||
1359 | * therefore we'd like the success ratio to get an immediate hit | ||
1360 | * when failing to get a BA, so we'd switch back to a lower or | ||
1361 | * zero power reduction. When FW transmits agg with a rate | ||
1362 | * different from the initial rate, it will not use reduced txp | ||
1363 | * and will send BA notification twice (one empty with reduced | ||
1364 | * txp equal to the value from LQ and one with reduced txp 0). | ||
1365 | * We need to update counters for each txp level accordingly. | ||
1366 | */ | ||
1367 | if (info->status.ampdu_ack_len == 0) | ||
1368 | info->status.ampdu_len = 1; | ||
1369 | |||
1370 | rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, tx_resp_rate.index, | ||
1371 | info->status.ampdu_len, | ||
1372 | info->status.ampdu_ack_len); | ||
1373 | |||
1374 | /* Update success/fail counts if not searching for new mode */ | ||
1375 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { | ||
1376 | lq_sta->total_success += info->status.ampdu_ack_len; | ||
1377 | lq_sta->total_failed += (info->status.ampdu_len - | ||
1378 | info->status.ampdu_ack_len); | ||
1379 | } | ||
1380 | } else { | ||
1381 | /* For legacy, update frame history with for each Tx retry. */ | ||
1382 | retries = info->status.rates[0].count - 1; | ||
1383 | /* HW doesn't send more than 15 retries */ | ||
1384 | retries = min(retries, 15); | ||
1385 | |||
1386 | /* The last transmission may have been successful */ | ||
1387 | legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
1388 | /* Collect data for each rate used during failed TX attempts */ | ||
1389 | for (i = 0; i <= retries; ++i) { | ||
1390 | lq_hwrate = le32_to_cpu(table->rs_table[i]); | ||
1391 | if (rs_rate_from_ucode_rate(lq_hwrate, info->band, | ||
1392 | &lq_rate)) { | ||
1393 | WARN_ON_ONCE(1); | ||
1394 | return; | ||
1395 | } | ||
1396 | |||
1397 | /* | ||
1398 | * Only collect stats if retried rate is in the same RS | ||
1399 | * table as active/search. | ||
1400 | */ | ||
1401 | if (rs_rate_column_match(&lq_rate, &curr_tbl->rate)) | ||
1402 | tmp_tbl = curr_tbl; | ||
1403 | else if (rs_rate_column_match(&lq_rate, | ||
1404 | &other_tbl->rate)) | ||
1405 | tmp_tbl = other_tbl; | ||
1406 | else | ||
1407 | continue; | ||
1408 | |||
1409 | rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, | ||
1410 | tx_resp_rate.index, 1, | ||
1411 | i < retries ? 0 : legacy_success, | ||
1412 | reduced_txp); | ||
1413 | rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl, | ||
1414 | tx_resp_rate.index, 1, | ||
1415 | i < retries ? 0 : legacy_success); | ||
1416 | } | ||
1417 | |||
1418 | /* Update success/fail counts if not searching for new mode */ | ||
1419 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { | ||
1420 | lq_sta->total_success += legacy_success; | ||
1421 | lq_sta->total_failed += retries + (1 - legacy_success); | ||
1422 | } | ||
1423 | } | ||
1424 | /* The last TX rate is cached in lq_sta; it's set in if/else above */ | ||
1425 | lq_sta->last_rate_n_flags = lq_hwrate; | ||
1426 | IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); | ||
1427 | done: | ||
1428 | /* See if there's a better rate or modulation mode to try. */ | ||
1429 | if (sta->supp_rates[info->band]) | ||
1430 | rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); | ||
1431 | } | ||
1432 | |||
1433 | /* | 1200 | /* |
1434 | * mac80211 sends us Tx status | 1201 | * mac80211 sends us Tx status |
1435 | */ | 1202 | */ |
@@ -1442,8 +1209,9 @@ static void rs_drv_mac80211_tx_status(void *mvm_r, | |||
1442 | struct iwl_op_mode *op_mode = mvm_r; | 1209 | struct iwl_op_mode *op_mode = mvm_r; |
1443 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 1210 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
1444 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1211 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1212 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1445 | 1213 | ||
1446 | if (!iwl_mvm_sta_from_mac80211(sta)->vif) | 1214 | if (!mvmsta->vif) |
1447 | return; | 1215 | return; |
1448 | 1216 | ||
1449 | if (!ieee80211_is_data(hdr->frame_control) || | 1217 | if (!ieee80211_is_data(hdr->frame_control) || |
@@ -1584,6 +1352,18 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1584 | tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); | 1352 | tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); |
1585 | } | 1353 | } |
1586 | 1354 | ||
1355 | /* rs uses two tables, one is active and the second is for searching better | ||
1356 | * configuration. This function, according to the index of the currently | ||
1357 | * active table returns the search table, which is located at the | ||
1358 | * index complementary to 1 according to the active table (active = 1, | ||
1359 | * search = 0 or active = 0, search = 1). | ||
1360 | * Since lq_info is an arary of size 2, make sure index cannot be out of bounds. | ||
1361 | */ | ||
1362 | static inline u8 rs_search_tbl(u8 active_tbl) | ||
1363 | { | ||
1364 | return (active_tbl ^ 1) & 1; | ||
1365 | } | ||
1366 | |||
1587 | static s32 rs_get_best_rate(struct iwl_mvm *mvm, | 1367 | static s32 rs_get_best_rate(struct iwl_mvm *mvm, |
1588 | struct iwl_lq_sta *lq_sta, | 1368 | struct iwl_lq_sta *lq_sta, |
1589 | struct iwl_scale_tbl_info *tbl, /* "search" */ | 1369 | struct iwl_scale_tbl_info *tbl, /* "search" */ |
@@ -1794,7 +1574,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, | |||
1794 | struct iwl_scale_tbl_info *tbl) | 1574 | struct iwl_scale_tbl_info *tbl) |
1795 | { | 1575 | { |
1796 | rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate); | 1576 | rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate); |
1797 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); | 1577 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); |
1798 | } | 1578 | } |
1799 | 1579 | ||
1800 | static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm, | 1580 | static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm, |
@@ -1931,9 +1711,9 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, | |||
1931 | struct ieee80211_sta *sta, | 1711 | struct ieee80211_sta *sta, |
1932 | enum rs_column col_id) | 1712 | enum rs_column col_id) |
1933 | { | 1713 | { |
1934 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1714 | struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; |
1935 | struct iwl_scale_tbl_info *search_tbl = | 1715 | struct iwl_scale_tbl_info *search_tbl = |
1936 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 1716 | &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; |
1937 | struct rs_rate *rate = &search_tbl->rate; | 1717 | struct rs_rate *rate = &search_tbl->rate; |
1938 | const struct rs_tx_column *column = &rs_tx_columns[col_id]; | 1718 | const struct rs_tx_column *column = &rs_tx_columns[col_id]; |
1939 | const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; | 1719 | const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; |
@@ -2341,7 +2121,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2341 | if (!lq_sta->search_better_tbl) | 2121 | if (!lq_sta->search_better_tbl) |
2342 | active_tbl = lq_sta->active_tbl; | 2122 | active_tbl = lq_sta->active_tbl; |
2343 | else | 2123 | else |
2344 | active_tbl = 1 - lq_sta->active_tbl; | 2124 | active_tbl = rs_search_tbl(lq_sta->active_tbl); |
2345 | 2125 | ||
2346 | tbl = &(lq_sta->lq_info[active_tbl]); | 2126 | tbl = &(lq_sta->lq_info[active_tbl]); |
2347 | rate = &tbl->rate; | 2127 | rate = &tbl->rate; |
@@ -2565,7 +2345,7 @@ lq_update: | |||
2565 | /* If new "search" mode was selected, set up in uCode table */ | 2345 | /* If new "search" mode was selected, set up in uCode table */ |
2566 | if (lq_sta->search_better_tbl) { | 2346 | if (lq_sta->search_better_tbl) { |
2567 | /* Access the "search" table, clear its history. */ | 2347 | /* Access the "search" table, clear its history. */ |
2568 | tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 2348 | tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; |
2569 | rs_rate_scale_clear_tbl_windows(mvm, tbl); | 2349 | rs_rate_scale_clear_tbl_windows(mvm, tbl); |
2570 | 2350 | ||
2571 | /* Use new "search" start rate */ | 2351 | /* Use new "search" start rate */ |
@@ -2896,7 +2676,7 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, | |||
2896 | static void rs_initialize_lq(struct iwl_mvm *mvm, | 2676 | static void rs_initialize_lq(struct iwl_mvm *mvm, |
2897 | struct ieee80211_sta *sta, | 2677 | struct ieee80211_sta *sta, |
2898 | struct iwl_lq_sta *lq_sta, | 2678 | struct iwl_lq_sta *lq_sta, |
2899 | enum nl80211_band band, bool update) | 2679 | enum nl80211_band band) |
2900 | { | 2680 | { |
2901 | struct iwl_scale_tbl_info *tbl; | 2681 | struct iwl_scale_tbl_info *tbl; |
2902 | struct rs_rate *rate; | 2682 | struct rs_rate *rate; |
@@ -2908,7 +2688,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2908 | if (!lq_sta->search_better_tbl) | 2688 | if (!lq_sta->search_better_tbl) |
2909 | active_tbl = lq_sta->active_tbl; | 2689 | active_tbl = lq_sta->active_tbl; |
2910 | else | 2690 | else |
2911 | active_tbl = 1 - lq_sta->active_tbl; | 2691 | active_tbl = rs_search_tbl(lq_sta->active_tbl); |
2912 | 2692 | ||
2913 | tbl = &(lq_sta->lq_info[active_tbl]); | 2693 | tbl = &(lq_sta->lq_info[active_tbl]); |
2914 | rate = &tbl->rate; | 2694 | rate = &tbl->rate; |
@@ -2926,7 +2706,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2926 | rs_set_expected_tpt_table(lq_sta, tbl); | 2706 | rs_set_expected_tpt_table(lq_sta, tbl); |
2927 | rs_fill_lq_cmd(mvm, sta, lq_sta, rate); | 2707 | rs_fill_lq_cmd(mvm, sta, lq_sta, rate); |
2928 | /* TODO restore station should remember the lq cmd */ | 2708 | /* TODO restore station should remember the lq cmd */ |
2929 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update); | 2709 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); |
2930 | } | 2710 | } |
2931 | 2711 | ||
2932 | static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, | 2712 | static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, |
@@ -3175,7 +2955,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) | |||
3175 | * Called after adding a new station to initialize rate scaling | 2955 | * Called after adding a new station to initialize rate scaling |
3176 | */ | 2956 | */ |
3177 | static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 2957 | static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
3178 | enum nl80211_band band, bool update) | 2958 | enum nl80211_band band) |
3179 | { | 2959 | { |
3180 | int i, j; | 2960 | int i, j; |
3181 | struct ieee80211_hw *hw = mvm->hw; | 2961 | struct ieee80211_hw *hw = mvm->hw; |
@@ -3186,6 +2966,8 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
3186 | struct ieee80211_supported_band *sband; | 2966 | struct ieee80211_supported_band *sband; |
3187 | unsigned long supp; /* must be unsigned long for for_each_set_bit */ | 2967 | unsigned long supp; /* must be unsigned long for for_each_set_bit */ |
3188 | 2968 | ||
2969 | lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock); | ||
2970 | |||
3189 | /* clear all non-persistent lq data */ | 2971 | /* clear all non-persistent lq data */ |
3190 | memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); | 2972 | memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); |
3191 | 2973 | ||
@@ -3255,7 +3037,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
3255 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 3037 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
3256 | iwl_mvm_reset_frame_stats(mvm); | 3038 | iwl_mvm_reset_frame_stats(mvm); |
3257 | #endif | 3039 | #endif |
3258 | rs_initialize_lq(mvm, sta, lq_sta, band, update); | 3040 | rs_initialize_lq(mvm, sta, lq_sta, band); |
3259 | } | 3041 | } |
3260 | 3042 | ||
3261 | static void rs_drv_rate_update(void *mvm_r, | 3043 | static void rs_drv_rate_update(void *mvm_r, |
@@ -3278,6 +3060,258 @@ static void rs_drv_rate_update(void *mvm_r, | |||
3278 | iwl_mvm_rs_rate_init(mvm, sta, sband->band, true); | 3060 | iwl_mvm_rs_rate_init(mvm, sta, sband->band, true); |
3279 | } | 3061 | } |
3280 | 3062 | ||
3063 | static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, | ||
3064 | struct ieee80211_sta *sta, | ||
3065 | int tid, struct ieee80211_tx_info *info, | ||
3066 | bool ndp) | ||
3067 | { | ||
3068 | int legacy_success; | ||
3069 | int retries; | ||
3070 | int i; | ||
3071 | struct iwl_lq_cmd *table; | ||
3072 | u32 lq_hwrate; | ||
3073 | struct rs_rate lq_rate, tx_resp_rate; | ||
3074 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; | ||
3075 | u32 tlc_info = (uintptr_t)info->status.status_driver_data[0]; | ||
3076 | u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK; | ||
3077 | u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info); | ||
3078 | u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1]; | ||
3079 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
3080 | struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv; | ||
3081 | |||
3082 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
3083 | if (!lq_sta) { | ||
3084 | IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); | ||
3085 | return; | ||
3086 | } else if (!lq_sta->pers.drv) { | ||
3087 | IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); | ||
3088 | return; | ||
3089 | } | ||
3090 | |||
3091 | /* This packet was aggregated but doesn't carry status info */ | ||
3092 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
3093 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | ||
3094 | return; | ||
3095 | |||
3096 | if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, | ||
3097 | &tx_resp_rate)) { | ||
3098 | WARN_ON_ONCE(1); | ||
3099 | return; | ||
3100 | } | ||
3101 | |||
3102 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
3103 | /* Disable last tx check if we are debugging with fixed rate but | ||
3104 | * update tx stats | ||
3105 | */ | ||
3106 | if (lq_sta->pers.dbg_fixed_rate) { | ||
3107 | int index = tx_resp_rate.index; | ||
3108 | enum rs_column column; | ||
3109 | int attempts, success; | ||
3110 | |||
3111 | column = rs_get_column_from_rate(&tx_resp_rate); | ||
3112 | if (WARN_ONCE(column == RS_COLUMN_INVALID, | ||
3113 | "Can't map rate 0x%x to column", | ||
3114 | tx_resp_hwrate)) | ||
3115 | return; | ||
3116 | |||
3117 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
3118 | attempts = info->status.ampdu_len; | ||
3119 | success = info->status.ampdu_ack_len; | ||
3120 | } else { | ||
3121 | attempts = info->status.rates[0].count; | ||
3122 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
3123 | } | ||
3124 | |||
3125 | lq_sta->pers.tx_stats[column][index].total += attempts; | ||
3126 | lq_sta->pers.tx_stats[column][index].success += success; | ||
3127 | |||
3128 | IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", | ||
3129 | tx_resp_hwrate, success, attempts); | ||
3130 | return; | ||
3131 | } | ||
3132 | #endif | ||
3133 | |||
3134 | if (time_after(jiffies, | ||
3135 | (unsigned long)(lq_sta->last_tx + | ||
3136 | (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { | ||
3137 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); | ||
3138 | /* reach here only in case of driver RS, call directly | ||
3139 | * the unlocked version | ||
3140 | */ | ||
3141 | rs_drv_rate_init(mvm, sta, info->band); | ||
3142 | return; | ||
3143 | } | ||
3144 | lq_sta->last_tx = jiffies; | ||
3145 | |||
3146 | /* Ignore this Tx frame response if its initial rate doesn't match | ||
3147 | * that of latest Link Quality command. There may be stragglers | ||
3148 | * from a previous Link Quality command, but we're no longer interested | ||
3149 | * in those; they're either from the "active" mode while we're trying | ||
3150 | * to check "search" mode, or a prior "search" mode after we've moved | ||
3151 | * to a new "search" mode (which might become the new "active" mode). | ||
3152 | */ | ||
3153 | table = &lq_sta->lq; | ||
3154 | lq_hwrate = le32_to_cpu(table->rs_table[0]); | ||
3155 | if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) { | ||
3156 | WARN_ON_ONCE(1); | ||
3157 | return; | ||
3158 | } | ||
3159 | |||
3160 | /* Here we actually compare this rate to the latest LQ command */ | ||
3161 | if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { | ||
3162 | IWL_DEBUG_RATE(mvm, | ||
3163 | "tx resp color 0x%x does not match 0x%x\n", | ||
3164 | lq_color, LQ_FLAG_COLOR_GET(table->flags)); | ||
3165 | |||
3166 | /* Since rates mis-match, the last LQ command may have failed. | ||
3167 | * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with | ||
3168 | * ... driver. | ||
3169 | */ | ||
3170 | lq_sta->missed_rate_counter++; | ||
3171 | if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { | ||
3172 | lq_sta->missed_rate_counter = 0; | ||
3173 | IWL_DEBUG_RATE(mvm, | ||
3174 | "Too many rates mismatch. Send sync LQ. rs_state %d\n", | ||
3175 | lq_sta->rs_state); | ||
3176 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); | ||
3177 | } | ||
3178 | /* Regardless, ignore this status info for outdated rate */ | ||
3179 | return; | ||
3180 | } | ||
3181 | |||
3182 | /* Rate did match, so reset the missed_rate_counter */ | ||
3183 | lq_sta->missed_rate_counter = 0; | ||
3184 | |||
3185 | if (!lq_sta->search_better_tbl) { | ||
3186 | curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; | ||
3187 | other_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; | ||
3188 | } else { | ||
3189 | curr_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; | ||
3190 | other_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; | ||
3191 | } | ||
3192 | |||
3193 | if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) { | ||
3194 | IWL_DEBUG_RATE(mvm, | ||
3195 | "Neither active nor search matches tx rate\n"); | ||
3196 | tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; | ||
3197 | rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); | ||
3198 | tmp_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; | ||
3199 | rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); | ||
3200 | rs_dump_rate(mvm, &lq_rate, "ACTUAL"); | ||
3201 | |||
3202 | /* no matching table found, let's by-pass the data collection | ||
3203 | * and continue to perform rate scale to find the rate table | ||
3204 | */ | ||
3205 | rs_stay_in_table(lq_sta, true); | ||
3206 | goto done; | ||
3207 | } | ||
3208 | |||
3209 | /* Updating the frame history depends on whether packets were | ||
3210 | * aggregated. | ||
3211 | * | ||
3212 | * For aggregation, all packets were transmitted at the same rate, the | ||
3213 | * first index into rate scale table. | ||
3214 | */ | ||
3215 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
3216 | rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, | ||
3217 | info->status.ampdu_len, | ||
3218 | info->status.ampdu_ack_len, | ||
3219 | reduced_txp); | ||
3220 | |||
3221 | /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat | ||
3222 | * it as a single frame loss as we don't want the success ratio | ||
3223 | * to dip too quickly because a BA wasn't received. | ||
3224 | * For TPC, there's no need for this optimisation since we want | ||
3225 | * to recover very quickly from a bad power reduction and, | ||
3226 | * therefore we'd like the success ratio to get an immediate hit | ||
3227 | * when failing to get a BA, so we'd switch back to a lower or | ||
3228 | * zero power reduction. When FW transmits agg with a rate | ||
3229 | * different from the initial rate, it will not use reduced txp | ||
3230 | * and will send BA notification twice (one empty with reduced | ||
3231 | * txp equal to the value from LQ and one with reduced txp 0). | ||
3232 | * We need to update counters for each txp level accordingly. | ||
3233 | */ | ||
3234 | if (info->status.ampdu_ack_len == 0) | ||
3235 | info->status.ampdu_len = 1; | ||
3236 | |||
3237 | rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, | ||
3238 | tx_resp_rate.index, | ||
3239 | info->status.ampdu_len, | ||
3240 | info->status.ampdu_ack_len); | ||
3241 | |||
3242 | /* Update success/fail counts if not searching for new mode */ | ||
3243 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { | ||
3244 | lq_sta->total_success += info->status.ampdu_ack_len; | ||
3245 | lq_sta->total_failed += (info->status.ampdu_len - | ||
3246 | info->status.ampdu_ack_len); | ||
3247 | } | ||
3248 | } else { | ||
3249 | /* For legacy, update frame history with for each Tx retry. */ | ||
3250 | retries = info->status.rates[0].count - 1; | ||
3251 | /* HW doesn't send more than 15 retries */ | ||
3252 | retries = min(retries, 15); | ||
3253 | |||
3254 | /* The last transmission may have been successful */ | ||
3255 | legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
3256 | /* Collect data for each rate used during failed TX attempts */ | ||
3257 | for (i = 0; i <= retries; ++i) { | ||
3258 | lq_hwrate = le32_to_cpu(table->rs_table[i]); | ||
3259 | if (rs_rate_from_ucode_rate(lq_hwrate, info->band, | ||
3260 | &lq_rate)) { | ||
3261 | WARN_ON_ONCE(1); | ||
3262 | return; | ||
3263 | } | ||
3264 | |||
3265 | /* Only collect stats if retried rate is in the same RS | ||
3266 | * table as active/search. | ||
3267 | */ | ||
3268 | if (rs_rate_column_match(&lq_rate, &curr_tbl->rate)) | ||
3269 | tmp_tbl = curr_tbl; | ||
3270 | else if (rs_rate_column_match(&lq_rate, | ||
3271 | &other_tbl->rate)) | ||
3272 | tmp_tbl = other_tbl; | ||
3273 | else | ||
3274 | continue; | ||
3275 | |||
3276 | rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, | ||
3277 | tx_resp_rate.index, 1, | ||
3278 | i < retries ? 0 : legacy_success, | ||
3279 | reduced_txp); | ||
3280 | rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl, | ||
3281 | tx_resp_rate.index, 1, | ||
3282 | i < retries ? 0 : legacy_success); | ||
3283 | } | ||
3284 | |||
3285 | /* Update success/fail counts if not searching for new mode */ | ||
3286 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { | ||
3287 | lq_sta->total_success += legacy_success; | ||
3288 | lq_sta->total_failed += retries + (1 - legacy_success); | ||
3289 | } | ||
3290 | } | ||
3291 | /* The last TX rate is cached in lq_sta; it's set in if/else above */ | ||
3292 | lq_sta->last_rate_n_flags = lq_hwrate; | ||
3293 | IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); | ||
3294 | done: | ||
3295 | /* See if there's a better rate or modulation mode to try. */ | ||
3296 | if (sta->supp_rates[info->band]) | ||
3297 | rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); | ||
3298 | } | ||
3299 | |||
3300 | void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
3301 | int tid, struct ieee80211_tx_info *info, bool ndp) | ||
3302 | { | ||
3303 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
3304 | |||
3305 | /* If it's locked we are in middle of init flow | ||
3306 | * just wait for next tx status to update the lq_sta data | ||
3307 | */ | ||
3308 | if (!spin_trylock(&mvmsta->lq_sta.rs_drv.pers.lock)) | ||
3309 | return; | ||
3310 | |||
3311 | __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); | ||
3312 | spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock); | ||
3313 | } | ||
3314 | |||
3281 | #ifdef CONFIG_MAC80211_DEBUGFS | 3315 | #ifdef CONFIG_MAC80211_DEBUGFS |
3282 | static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, | 3316 | static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, |
3283 | struct iwl_lq_cmd *lq_cmd, | 3317 | struct iwl_lq_cmd *lq_cmd, |
@@ -3569,7 +3603,7 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm, | |||
3569 | 3603 | ||
3570 | bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; | 3604 | bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; |
3571 | bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); | 3605 | bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); |
3572 | iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false); | 3606 | iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd); |
3573 | 3607 | ||
3574 | ss_params |= LQ_SS_BFER_ALLOWED; | 3608 | ss_params |= LQ_SS_BFER_ALLOWED; |
3575 | IWL_DEBUG_RATE(mvm, | 3609 | IWL_DEBUG_RATE(mvm, |
@@ -3735,7 +3769,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
3735 | 3769 | ||
3736 | if (lq_sta->pers.dbg_fixed_rate) { | 3770 | if (lq_sta->pers.dbg_fixed_rate) { |
3737 | rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL); | 3771 | rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL); |
3738 | iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); | 3772 | iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq); |
3739 | } | 3773 | } |
3740 | } | 3774 | } |
3741 | 3775 | ||
@@ -4127,10 +4161,15 @@ static const struct rate_control_ops rs_mvm_ops_drv = { | |||
4127 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 4161 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
4128 | enum nl80211_band band, bool update) | 4162 | enum nl80211_band band, bool update) |
4129 | { | 4163 | { |
4130 | if (iwl_mvm_has_tlc_offload(mvm)) | 4164 | if (iwl_mvm_has_tlc_offload(mvm)) { |
4131 | rs_fw_rate_init(mvm, sta, band, update); | 4165 | rs_fw_rate_init(mvm, sta, band, update); |
4132 | else | 4166 | } else { |
4133 | rs_drv_rate_init(mvm, sta, band, update); | 4167 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
4168 | |||
4169 | spin_lock(&mvmsta->lq_sta.rs_drv.pers.lock); | ||
4170 | rs_drv_rate_init(mvm, sta, band); | ||
4171 | spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock); | ||
4172 | } | ||
4134 | } | 4173 | } |
4135 | 4174 | ||
4136 | int iwl_mvm_rate_control_register(void) | 4175 | int iwl_mvm_rate_control_register(void) |
@@ -4160,7 +4199,7 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | |||
4160 | lq->flags &= ~LQ_FLAG_USE_RTS_MSK; | 4199 | lq->flags &= ~LQ_FLAG_USE_RTS_MSK; |
4161 | } | 4200 | } |
4162 | 4201 | ||
4163 | return iwl_mvm_send_lq_cmd(mvm, lq, false); | 4202 | return iwl_mvm_send_lq_cmd(mvm, lq); |
4164 | } | 4203 | } |
4165 | 4204 | ||
4166 | /** | 4205 | /** |