diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/rc.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/rc.c | 317 |
1 files changed, 186 insertions, 131 deletions
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e49be733d546..ba7f36ab0a74 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 Video54 Technologies, Inc. | 2 | * Copyright (c) 2004 Video54 Technologies, Inc. |
3 | * Copyright (c) 2004-2009 Atheros Communications, Inc. | 3 | * Copyright (c) 2004-2011 Atheros Communications, Inc. |
4 | * | 4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above |
@@ -302,7 +302,7 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { | |||
302 | [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, | 302 | [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, |
303 | 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */ | 303 | 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */ |
304 | [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, | 304 | [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, |
305 | 224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */ | 305 | 224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */ |
306 | [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, | 306 | [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, |
307 | 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */ | 307 | 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */ |
308 | [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, | 308 | [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, |
@@ -378,39 +378,9 @@ static const struct ath_rate_table ar5416_11g_ratetable = { | |||
378 | 0, /* Phy rates allowed initially */ | 378 | 0, /* Phy rates allowed initially */ |
379 | }; | 379 | }; |
380 | 380 | ||
381 | static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = { | ||
382 | [ATH9K_MODE_11A] = &ar5416_11a_ratetable, | ||
383 | [ATH9K_MODE_11G] = &ar5416_11g_ratetable, | ||
384 | [ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable, | ||
385 | [ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable, | ||
386 | [ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable, | ||
387 | [ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable, | ||
388 | [ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable, | ||
389 | [ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable, | ||
390 | }; | ||
391 | |||
392 | static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, | 381 | static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, |
393 | struct ieee80211_tx_rate *rate); | 382 | struct ieee80211_tx_rate *rate); |
394 | 383 | ||
395 | static inline int8_t median(int8_t a, int8_t b, int8_t c) | ||
396 | { | ||
397 | if (a >= b) { | ||
398 | if (b >= c) | ||
399 | return b; | ||
400 | else if (a > c) | ||
401 | return c; | ||
402 | else | ||
403 | return a; | ||
404 | } else { | ||
405 | if (a >= c) | ||
406 | return a; | ||
407 | else if (b >= c) | ||
408 | return c; | ||
409 | else | ||
410 | return b; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, | 384 | static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, |
415 | struct ath_rate_priv *ath_rc_priv) | 385 | struct ath_rate_priv *ath_rc_priv) |
416 | { | 386 | { |
@@ -430,7 +400,7 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, | |||
430 | } | 400 | } |
431 | } | 401 | } |
432 | 402 | ||
433 | static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) | 403 | static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv) |
434 | { | 404 | { |
435 | u8 i; | 405 | u8 i; |
436 | 406 | ||
@@ -438,7 +408,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) | |||
438 | ath_rc_priv->valid_rate_index[i] = 0; | 408 | ath_rc_priv->valid_rate_index[i] = 0; |
439 | } | 409 | } |
440 | 410 | ||
441 | static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, | 411 | static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv, |
442 | u8 index, int valid_tx_rate) | 412 | u8 index, int valid_tx_rate) |
443 | { | 413 | { |
444 | BUG_ON(index > ath_rc_priv->rate_table_size); | 414 | BUG_ON(index > ath_rc_priv->rate_table_size); |
@@ -519,7 +489,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, | |||
519 | 489 | ||
520 | ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; | 490 | ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; |
521 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 491 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
522 | ath_rc_set_valid_txmask(ath_rc_priv, i, 1); | 492 | ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1); |
523 | hi = i; | 493 | hi = i; |
524 | } | 494 | } |
525 | } | 495 | } |
@@ -538,7 +508,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, | |||
538 | for (i = 0; i < rateset->rs_nrates; i++) { | 508 | for (i = 0; i < rateset->rs_nrates; i++) { |
539 | for (j = 0; j < rate_table->rate_cnt; j++) { | 509 | for (j = 0; j < rate_table->rate_cnt; j++) { |
540 | u32 phy = rate_table->info[j].phy; | 510 | u32 phy = rate_table->info[j].phy; |
541 | u16 rate_flags = rate_table->info[i].rate_flags; | 511 | u16 rate_flags = rate_table->info[j].rate_flags; |
542 | u8 rate = rateset->rs_rates[i]; | 512 | u8 rate = rateset->rs_rates[i]; |
543 | u8 dot11rate = rate_table->info[j].dot11rate; | 513 | u8 dot11rate = rate_table->info[j].dot11rate; |
544 | 514 | ||
@@ -562,7 +532,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, | |||
562 | ath_rc_priv->valid_phy_rateidx[phy] | 532 | ath_rc_priv->valid_phy_rateidx[phy] |
563 | [valid_rate_count] = j; | 533 | [valid_rate_count] = j; |
564 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 534 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
565 | ath_rc_set_valid_txmask(ath_rc_priv, j, 1); | 535 | ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1); |
566 | hi = A_MAX(hi, j); | 536 | hi = A_MAX(hi, j); |
567 | } | 537 | } |
568 | } | 538 | } |
@@ -598,7 +568,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, | |||
598 | ath_rc_priv->valid_phy_rateidx[phy] | 568 | ath_rc_priv->valid_phy_rateidx[phy] |
599 | [ath_rc_priv->valid_phy_ratecnt[phy]] = j; | 569 | [ath_rc_priv->valid_phy_ratecnt[phy]] = j; |
600 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 570 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
601 | ath_rc_set_valid_txmask(ath_rc_priv, j, 1); | 571 | ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1); |
602 | hi = A_MAX(hi, j); | 572 | hi = A_MAX(hi, j); |
603 | } | 573 | } |
604 | } | 574 | } |
@@ -719,7 +689,8 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, | |||
719 | 689 | ||
720 | if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { | 690 | if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { |
721 | rate->flags |= IEEE80211_TX_RC_MCS; | 691 | rate->flags |= IEEE80211_TX_RC_MCS; |
722 | if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) | 692 | if (WLAN_RC_PHY_40(rate_table->info[rix].phy) && |
693 | conf_is_ht40(&txrc->hw->conf)) | ||
723 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 694 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
724 | if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) | 695 | if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) |
725 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | 696 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; |
@@ -791,7 +762,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
791 | */ | 762 | */ |
792 | try_per_rate = 4; | 763 | try_per_rate = 4; |
793 | 764 | ||
794 | rate_table = sc->cur_rate_table; | 765 | rate_table = ath_rc_priv->rate_table; |
795 | rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); | 766 | rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); |
796 | 767 | ||
797 | /* | 768 | /* |
@@ -822,7 +793,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
822 | 793 | ||
823 | tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 794 | tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
824 | } else { | 795 | } else { |
825 | /* Set the choosen rate. No RTS for first series entry. */ | 796 | /* Set the chosen rate. No RTS for first series entry. */ |
826 | ath_rc_rate_set_series(rate_table, &rates[i++], txrc, | 797 | ath_rc_rate_set_series(rate_table, &rates[i++], txrc, |
827 | try_per_rate, rix, 0); | 798 | try_per_rate, rix, 0); |
828 | } | 799 | } |
@@ -884,17 +855,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
884 | ath_rc_rate_set_rtscts(sc, rate_table, tx_info); | 855 | ath_rc_rate_set_rtscts(sc, rate_table, tx_info); |
885 | } | 856 | } |
886 | 857 | ||
887 | static bool ath_rc_update_per(struct ath_softc *sc, | 858 | static void ath_rc_update_per(struct ath_softc *sc, |
888 | const struct ath_rate_table *rate_table, | 859 | const struct ath_rate_table *rate_table, |
889 | struct ath_rate_priv *ath_rc_priv, | 860 | struct ath_rate_priv *ath_rc_priv, |
890 | struct ieee80211_tx_info *tx_info, | 861 | struct ieee80211_tx_info *tx_info, |
891 | int tx_rate, int xretries, int retries, | 862 | int tx_rate, int xretries, int retries, |
892 | u32 now_msec) | 863 | u32 now_msec) |
893 | { | 864 | { |
894 | bool state_change = false; | ||
895 | int count, n_bad_frames; | 865 | int count, n_bad_frames; |
896 | u8 last_per; | 866 | u8 last_per; |
897 | static u32 nretry_to_per_lookup[10] = { | 867 | static const u32 nretry_to_per_lookup[10] = { |
898 | 100 * 0 / 1, | 868 | 100 * 0 / 1, |
899 | 100 * 1 / 4, | 869 | 100 * 1 / 4, |
900 | 100 * 1 / 2, | 870 | 100 * 1 / 2, |
@@ -1022,8 +992,16 @@ static bool ath_rc_update_per(struct ath_softc *sc, | |||
1022 | 992 | ||
1023 | } | 993 | } |
1024 | } | 994 | } |
995 | } | ||
1025 | 996 | ||
1026 | return state_change; | 997 | static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, |
998 | int xretries, int retries, u8 per) | ||
999 | { | ||
1000 | struct ath_rc_stats *stats = &rc->rcstats[rix]; | ||
1001 | |||
1002 | stats->xretries += xretries; | ||
1003 | stats->retries += retries; | ||
1004 | stats->per = per; | ||
1027 | } | 1005 | } |
1028 | 1006 | ||
1029 | /* Update PER, RSSI and whatever else that the code thinks it is doing. | 1007 | /* Update PER, RSSI and whatever else that the code thinks it is doing. |
@@ -1037,8 +1015,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, | |||
1037 | u32 now_msec = jiffies_to_msecs(jiffies); | 1015 | u32 now_msec = jiffies_to_msecs(jiffies); |
1038 | int rate; | 1016 | int rate; |
1039 | u8 last_per; | 1017 | u8 last_per; |
1040 | bool state_change = false; | 1018 | const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; |
1041 | const struct ath_rate_table *rate_table = sc->cur_rate_table; | ||
1042 | int size = ath_rc_priv->rate_table_size; | 1019 | int size = ath_rc_priv->rate_table_size; |
1043 | 1020 | ||
1044 | if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) | 1021 | if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) |
@@ -1047,9 +1024,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, | |||
1047 | last_per = ath_rc_priv->per[tx_rate]; | 1024 | last_per = ath_rc_priv->per[tx_rate]; |
1048 | 1025 | ||
1049 | /* Update PER first */ | 1026 | /* Update PER first */ |
1050 | state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, | 1027 | ath_rc_update_per(sc, rate_table, ath_rc_priv, |
1051 | tx_info, tx_rate, xretries, | 1028 | tx_info, tx_rate, xretries, |
1052 | retries, now_msec); | 1029 | retries, now_msec); |
1053 | 1030 | ||
1054 | /* | 1031 | /* |
1055 | * If this rate looks bad (high PER) then stop using it for | 1032 | * If this rate looks bad (high PER) then stop using it for |
@@ -1098,7 +1075,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, | |||
1098 | ath_rc_priv->per_down_time = now_msec; | 1075 | ath_rc_priv->per_down_time = now_msec; |
1099 | } | 1076 | } |
1100 | 1077 | ||
1101 | ath_debug_stat_retries(sc, tx_rate, xretries, retries, | 1078 | ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, |
1102 | ath_rc_priv->per[tx_rate]); | 1079 | ath_rc_priv->per[tx_rate]); |
1103 | 1080 | ||
1104 | } | 1081 | } |
@@ -1107,13 +1084,12 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, | |||
1107 | struct ieee80211_tx_rate *rate) | 1084 | struct ieee80211_tx_rate *rate) |
1108 | { | 1085 | { |
1109 | int rix = 0, i = 0; | 1086 | int rix = 0, i = 0; |
1110 | int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 }; | 1087 | static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 }; |
1111 | 1088 | ||
1112 | if (!(rate->flags & IEEE80211_TX_RC_MCS)) | 1089 | if (!(rate->flags & IEEE80211_TX_RC_MCS)) |
1113 | return rate->idx; | 1090 | return rate->idx; |
1114 | 1091 | ||
1115 | while (rate->idx > mcs_rix_off[i] && | 1092 | while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) { |
1116 | i < sizeof(mcs_rix_off)/sizeof(int)) { | ||
1117 | rix++; i++; | 1093 | rix++; i++; |
1118 | } | 1094 | } |
1119 | 1095 | ||
@@ -1140,7 +1116,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, | |||
1140 | u8 flags; | 1116 | u8 flags; |
1141 | u32 i = 0, rix; | 1117 | u32 i = 0, rix; |
1142 | 1118 | ||
1143 | rate_table = sc->cur_rate_table; | 1119 | rate_table = ath_rc_priv->rate_table; |
1144 | 1120 | ||
1145 | /* | 1121 | /* |
1146 | * If the first rate is not the final index, there | 1122 | * If the first rate is not the final index, there |
@@ -1190,39 +1166,23 @@ static void ath_rc_tx_status(struct ath_softc *sc, | |||
1190 | static const | 1166 | static const |
1191 | struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, | 1167 | struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, |
1192 | enum ieee80211_band band, | 1168 | enum ieee80211_band band, |
1193 | bool is_ht, | 1169 | bool is_ht) |
1194 | bool is_cw_40) | ||
1195 | { | 1170 | { |
1196 | int mode = 0; | ||
1197 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1171 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1198 | 1172 | ||
1199 | switch(band) { | 1173 | switch(band) { |
1200 | case IEEE80211_BAND_2GHZ: | 1174 | case IEEE80211_BAND_2GHZ: |
1201 | mode = ATH9K_MODE_11G; | ||
1202 | if (is_ht) | 1175 | if (is_ht) |
1203 | mode = ATH9K_MODE_11NG_HT20; | 1176 | return &ar5416_11ng_ratetable; |
1204 | if (is_cw_40) | 1177 | return &ar5416_11g_ratetable; |
1205 | mode = ATH9K_MODE_11NG_HT40PLUS; | ||
1206 | break; | ||
1207 | case IEEE80211_BAND_5GHZ: | 1178 | case IEEE80211_BAND_5GHZ: |
1208 | mode = ATH9K_MODE_11A; | ||
1209 | if (is_ht) | 1179 | if (is_ht) |
1210 | mode = ATH9K_MODE_11NA_HT20; | 1180 | return &ar5416_11na_ratetable; |
1211 | if (is_cw_40) | 1181 | return &ar5416_11a_ratetable; |
1212 | mode = ATH9K_MODE_11NA_HT40PLUS; | ||
1213 | break; | ||
1214 | default: | 1182 | default: |
1215 | ath_print(common, ATH_DBG_CONFIG, "Invalid band\n"); | 1183 | ath_dbg(common, ATH_DBG_CONFIG, "Invalid band\n"); |
1216 | return NULL; | 1184 | return NULL; |
1217 | } | 1185 | } |
1218 | |||
1219 | BUG_ON(mode >= ATH9K_MODE_MAX); | ||
1220 | |||
1221 | ath_print(common, ATH_DBG_CONFIG, | ||
1222 | "Choosing rate table for mode: %d\n", mode); | ||
1223 | |||
1224 | sc->cur_rate_mode = mode; | ||
1225 | return hw_rate_table[mode]; | ||
1226 | } | 1186 | } |
1227 | 1187 | ||
1228 | static void ath_rc_init(struct ath_softc *sc, | 1188 | static void ath_rc_init(struct ath_softc *sc, |
@@ -1246,7 +1206,7 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1246 | } | 1206 | } |
1247 | 1207 | ||
1248 | /* Determine the valid rates */ | 1208 | /* Determine the valid rates */ |
1249 | ath_rc_init_valid_txmask(ath_rc_priv); | 1209 | ath_rc_init_valid_rate_idx(ath_rc_priv); |
1250 | 1210 | ||
1251 | for (i = 0; i < WLAN_RC_PHY_MAX; i++) { | 1211 | for (i = 0; i < WLAN_RC_PHY_MAX; i++) { |
1252 | for (j = 0; j < MAX_TX_RATE_PHY; j++) | 1212 | for (j = 0; j < MAX_TX_RATE_PHY; j++) |
@@ -1293,11 +1253,11 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1293 | ath_rc_priv->max_valid_rate = k; | 1253 | ath_rc_priv->max_valid_rate = k; |
1294 | ath_rc_sort_validrates(rate_table, ath_rc_priv); | 1254 | ath_rc_sort_validrates(rate_table, ath_rc_priv); |
1295 | ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; | 1255 | ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; |
1296 | sc->cur_rate_table = rate_table; | 1256 | ath_rc_priv->rate_table = rate_table; |
1297 | 1257 | ||
1298 | ath_print(common, ATH_DBG_CONFIG, | 1258 | ath_dbg(common, ATH_DBG_CONFIG, |
1299 | "RC Initialized with capabilities: 0x%x\n", | 1259 | "RC Initialized with capabilities: 0x%x\n", |
1300 | ath_rc_priv->ht_cap); | 1260 | ath_rc_priv->ht_cap); |
1301 | } | 1261 | } |
1302 | 1262 | ||
1303 | static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, | 1263 | static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, |
@@ -1320,10 +1280,35 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
1320 | return caps; | 1280 | return caps; |
1321 | } | 1281 | } |
1322 | 1282 | ||
1283 | static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, | ||
1284 | u8 tidno) | ||
1285 | { | ||
1286 | struct ath_atx_tid *txtid; | ||
1287 | |||
1288 | if (!(sc->sc_flags & SC_OP_TXAGGR)) | ||
1289 | return false; | ||
1290 | |||
1291 | txtid = ATH_AN_2_TID(an, tidno); | ||
1292 | |||
1293 | if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS))) | ||
1294 | return true; | ||
1295 | return false; | ||
1296 | } | ||
1297 | |||
1298 | |||
1323 | /***********************************/ | 1299 | /***********************************/ |
1324 | /* mac80211 Rate Control callbacks */ | 1300 | /* mac80211 Rate Control callbacks */ |
1325 | /***********************************/ | 1301 | /***********************************/ |
1326 | 1302 | ||
1303 | static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) | ||
1304 | { | ||
1305 | struct ath_rc_stats *stats; | ||
1306 | |||
1307 | stats = &rc->rcstats[final_rate]; | ||
1308 | stats->success++; | ||
1309 | } | ||
1310 | |||
1311 | |||
1327 | static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | 1312 | static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, |
1328 | struct ieee80211_sta *sta, void *priv_sta, | 1313 | struct ieee80211_sta *sta, void *priv_sta, |
1329 | struct sk_buff *skb) | 1314 | struct sk_buff *skb) |
@@ -1332,14 +1317,14 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1332 | struct ath_rate_priv *ath_rc_priv = priv_sta; | 1317 | struct ath_rate_priv *ath_rc_priv = priv_sta; |
1333 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1318 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
1334 | struct ieee80211_hdr *hdr; | 1319 | struct ieee80211_hdr *hdr; |
1335 | int final_ts_idx = 0, tx_status = 0, is_underrun = 0; | 1320 | int final_ts_idx = 0, tx_status = 0; |
1336 | int long_retry = 0; | 1321 | int long_retry = 0; |
1337 | __le16 fc; | 1322 | __le16 fc; |
1338 | int i; | 1323 | int i; |
1339 | 1324 | ||
1340 | hdr = (struct ieee80211_hdr *)skb->data; | 1325 | hdr = (struct ieee80211_hdr *)skb->data; |
1341 | fc = hdr->frame_control; | 1326 | fc = hdr->frame_control; |
1342 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 1327 | for (i = 0; i < sc->hw->max_rates; i++) { |
1343 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; | 1328 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; |
1344 | if (!rate->count) | 1329 | if (!rate->count) |
1345 | break; | 1330 | break; |
@@ -1359,32 +1344,23 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1359 | if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) | 1344 | if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) |
1360 | return; | 1345 | return; |
1361 | 1346 | ||
1362 | /* | 1347 | if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { |
1363 | * If an underrun error is seen assume it as an excessive retry only | 1348 | tx_info->status.ampdu_ack_len = |
1364 | * if max frame trigger level has been reached (2 KB for singel stream, | 1349 | (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); |
1365 | * and 4 KB for dual stream). Adjust the long retry as if the frame was | 1350 | tx_info->status.ampdu_len = 1; |
1366 | * tried hw->max_rate_tries times to affect how ratectrl updates PER for | ||
1367 | * the failed rate. In case of congestion on the bus penalizing these | ||
1368 | * type of underruns should help hardware actually transmit new frames | ||
1369 | * successfully by eventually preferring slower rates. This itself | ||
1370 | * should also alleviate congestion on the bus. | ||
1371 | */ | ||
1372 | if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) && | ||
1373 | (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) { | ||
1374 | tx_status = 1; | ||
1375 | is_underrun = 1; | ||
1376 | } | 1351 | } |
1377 | 1352 | ||
1378 | if (tx_info->pad[0] & ATH_TX_INFO_XRETRY) | 1353 | if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) |
1379 | tx_status = 1; | 1354 | tx_status = 1; |
1380 | 1355 | ||
1381 | ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, | 1356 | ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, |
1382 | (is_underrun) ? sc->hw->max_rate_tries : long_retry); | 1357 | long_retry); |
1383 | 1358 | ||
1384 | /* Check if aggregation has to be enabled for this tid */ | 1359 | /* Check if aggregation has to be enabled for this tid */ |
1385 | if (conf_is_ht(&sc->hw->conf) && | 1360 | if (conf_is_ht(&sc->hw->conf) && |
1386 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | 1361 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { |
1387 | if (ieee80211_is_data_qos(fc)) { | 1362 | if (ieee80211_is_data_qos(fc) && |
1363 | skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { | ||
1388 | u8 *qc, tid; | 1364 | u8 *qc, tid; |
1389 | struct ath_node *an; | 1365 | struct ath_node *an; |
1390 | 1366 | ||
@@ -1393,12 +1369,13 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1393 | an = (struct ath_node *)sta->drv_priv; | 1369 | an = (struct ath_node *)sta->drv_priv; |
1394 | 1370 | ||
1395 | if(ath_tx_aggr_check(sc, an, tid)) | 1371 | if(ath_tx_aggr_check(sc, an, tid)) |
1396 | ieee80211_start_tx_ba_session(sta, tid); | 1372 | ieee80211_start_tx_ba_session(sta, tid, 0); |
1397 | } | 1373 | } |
1398 | } | 1374 | } |
1399 | 1375 | ||
1400 | ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table, | 1376 | ath_debug_stat_rc(ath_rc_priv, |
1401 | &tx_info->status.rates[final_ts_idx])); | 1377 | ath_rc_get_rateindex(ath_rc_priv->rate_table, |
1378 | &tx_info->status.rates[final_ts_idx])); | ||
1402 | } | 1379 | } |
1403 | 1380 | ||
1404 | static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | 1381 | static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, |
@@ -1429,23 +1406,17 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
1429 | ath_rc_priv->neg_ht_rates.rs_nrates = j; | 1406 | ath_rc_priv->neg_ht_rates.rs_nrates = j; |
1430 | } | 1407 | } |
1431 | 1408 | ||
1432 | is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 1409 | is_cw40 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
1433 | 1410 | ||
1434 | if (is_cw40) | 1411 | if (is_cw40) |
1435 | is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; | 1412 | is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); |
1436 | else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) | 1413 | else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) |
1437 | is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; | 1414 | is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); |
1438 | 1415 | ||
1439 | /* Choose rate table first */ | 1416 | /* Choose rate table first */ |
1440 | 1417 | ||
1441 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || | 1418 | rate_table = ath_choose_rate_table(sc, sband->band, |
1442 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || | 1419 | sta->ht_cap.ht_supported); |
1443 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { | ||
1444 | rate_table = ath_choose_rate_table(sc, sband->band, | ||
1445 | sta->ht_cap.ht_supported, is_cw40); | ||
1446 | } else { | ||
1447 | rate_table = hw_rate_table[sc->cur_rate_mode]; | ||
1448 | } | ||
1449 | 1420 | ||
1450 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi); | 1421 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi); |
1451 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | 1422 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); |
@@ -1459,10 +1430,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, | |||
1459 | struct ath_rate_priv *ath_rc_priv = priv_sta; | 1430 | struct ath_rate_priv *ath_rc_priv = priv_sta; |
1460 | const struct ath_rate_table *rate_table = NULL; | 1431 | const struct ath_rate_table *rate_table = NULL; |
1461 | bool oper_cw40 = false, oper_sgi; | 1432 | bool oper_cw40 = false, oper_sgi; |
1462 | bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? | 1433 | bool local_cw40 = !!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); |
1463 | true : false; | 1434 | bool local_sgi = !!(ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG); |
1464 | bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? | ||
1465 | true : false; | ||
1466 | 1435 | ||
1467 | /* FIXME: Handle AP mode later when we support CWM */ | 1436 | /* FIXME: Handle AP mode later when we support CWM */ |
1468 | 1437 | ||
@@ -1485,24 +1454,109 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, | |||
1485 | 1454 | ||
1486 | if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) { | 1455 | if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) { |
1487 | rate_table = ath_choose_rate_table(sc, sband->band, | 1456 | rate_table = ath_choose_rate_table(sc, sband->band, |
1488 | sta->ht_cap.ht_supported, | 1457 | sta->ht_cap.ht_supported); |
1489 | oper_cw40); | ||
1490 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, | 1458 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, |
1491 | oper_cw40, oper_sgi); | 1459 | oper_cw40, oper_sgi); |
1492 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | 1460 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); |
1493 | 1461 | ||
1494 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, | 1462 | ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, |
1495 | "Operating HT Bandwidth changed to: %d\n", | 1463 | "Operating HT Bandwidth changed to: %d\n", |
1496 | sc->hw->conf.channel_type); | 1464 | sc->hw->conf.channel_type); |
1497 | sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode]; | 1465 | } |
1466 | } | ||
1467 | } | ||
1468 | |||
1469 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
1470 | |||
1471 | static int ath9k_debugfs_open(struct inode *inode, struct file *file) | ||
1472 | { | ||
1473 | file->private_data = inode->i_private; | ||
1474 | return 0; | ||
1475 | } | ||
1476 | |||
1477 | static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, | ||
1478 | size_t count, loff_t *ppos) | ||
1479 | { | ||
1480 | struct ath_rate_priv *rc = file->private_data; | ||
1481 | char *buf; | ||
1482 | unsigned int len = 0, max; | ||
1483 | int i = 0; | ||
1484 | ssize_t retval; | ||
1485 | |||
1486 | if (rc->rate_table == NULL) | ||
1487 | return 0; | ||
1488 | |||
1489 | max = 80 + rc->rate_table->rate_cnt * 1024 + 1; | ||
1490 | buf = kmalloc(max, GFP_KERNEL); | ||
1491 | if (buf == NULL) | ||
1492 | return -ENOMEM; | ||
1493 | |||
1494 | len += sprintf(buf, "%6s %6s %6s " | ||
1495 | "%10s %10s %10s %10s\n", | ||
1496 | "HT", "MCS", "Rate", | ||
1497 | "Success", "Retries", "XRetries", "PER"); | ||
1498 | |||
1499 | for (i = 0; i < rc->rate_table->rate_cnt; i++) { | ||
1500 | u32 ratekbps = rc->rate_table->info[i].ratekbps; | ||
1501 | struct ath_rc_stats *stats = &rc->rcstats[i]; | ||
1502 | char mcs[5]; | ||
1503 | char htmode[5]; | ||
1504 | int used_mcs = 0, used_htmode = 0; | ||
1505 | |||
1506 | if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { | ||
1507 | used_mcs = snprintf(mcs, 5, "%d", | ||
1508 | rc->rate_table->info[i].ratecode); | ||
1509 | |||
1510 | if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) | ||
1511 | used_htmode = snprintf(htmode, 5, "HT40"); | ||
1512 | else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) | ||
1513 | used_htmode = snprintf(htmode, 5, "HT20"); | ||
1514 | else | ||
1515 | used_htmode = snprintf(htmode, 5, "????"); | ||
1498 | } | 1516 | } |
1517 | |||
1518 | mcs[used_mcs] = '\0'; | ||
1519 | htmode[used_htmode] = '\0'; | ||
1520 | |||
1521 | len += snprintf(buf + len, max - len, | ||
1522 | "%6s %6s %3u.%d: " | ||
1523 | "%10u %10u %10u %10u\n", | ||
1524 | htmode, | ||
1525 | mcs, | ||
1526 | ratekbps / 1000, | ||
1527 | (ratekbps % 1000) / 100, | ||
1528 | stats->success, | ||
1529 | stats->retries, | ||
1530 | stats->xretries, | ||
1531 | stats->per); | ||
1499 | } | 1532 | } |
1533 | |||
1534 | if (len > max) | ||
1535 | len = max; | ||
1536 | |||
1537 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1538 | kfree(buf); | ||
1539 | return retval; | ||
1500 | } | 1540 | } |
1501 | 1541 | ||
1542 | static const struct file_operations fops_rcstat = { | ||
1543 | .read = read_file_rcstat, | ||
1544 | .open = ath9k_debugfs_open, | ||
1545 | .owner = THIS_MODULE | ||
1546 | }; | ||
1547 | |||
1548 | static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, | ||
1549 | struct dentry *dir) | ||
1550 | { | ||
1551 | struct ath_rate_priv *rc = priv_sta; | ||
1552 | debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat); | ||
1553 | } | ||
1554 | |||
1555 | #endif /* CONFIG_ATH9K_DEBUGFS */ | ||
1556 | |||
1502 | static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 1557 | static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
1503 | { | 1558 | { |
1504 | struct ath_wiphy *aphy = hw->priv; | 1559 | return hw->priv; |
1505 | return aphy->sc; | ||
1506 | } | 1560 | } |
1507 | 1561 | ||
1508 | static void ath_rate_free(void *priv) | 1562 | static void ath_rate_free(void *priv) |
@@ -1517,13 +1571,11 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp | |||
1517 | 1571 | ||
1518 | rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); | 1572 | rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); |
1519 | if (!rate_priv) { | 1573 | if (!rate_priv) { |
1520 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, | 1574 | ath_err(ath9k_hw_common(sc->sc_ah), |
1521 | "Unable to allocate private rc structure\n"); | 1575 | "Unable to allocate private rc structure\n"); |
1522 | return NULL; | 1576 | return NULL; |
1523 | } | 1577 | } |
1524 | 1578 | ||
1525 | rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; | ||
1526 | |||
1527 | return rate_priv; | 1579 | return rate_priv; |
1528 | } | 1580 | } |
1529 | 1581 | ||
@@ -1545,6 +1597,9 @@ static struct rate_control_ops ath_rate_ops = { | |||
1545 | .free = ath_rate_free, | 1597 | .free = ath_rate_free, |
1546 | .alloc_sta = ath_rate_alloc_sta, | 1598 | .alloc_sta = ath_rate_alloc_sta, |
1547 | .free_sta = ath_rate_free_sta, | 1599 | .free_sta = ath_rate_free_sta, |
1600 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
1601 | .add_sta_debugfs = ath_rate_add_sta_debugfs, | ||
1602 | #endif | ||
1548 | }; | 1603 | }; |
1549 | 1604 | ||
1550 | int ath_rate_control_register(void) | 1605 | int ath_rate_control_register(void) |