diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-12-11 10:49:24 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-12-11 10:49:24 -0500 |
commit | d9a577c35a5f874cb11d96993dec26775e9738f7 (patch) | |
tree | d993d7e3ff97e4ef9b082c950c8becd85d24eb92 | |
parent | d6b5075d73adbc10fac873ca86798e30c115a018 (diff) | |
parent | 9d10849e4ea8bf9d8da80afa73918a9fe45c09ef (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
30 files changed, 1538 insertions, 1592 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index 26fc550cd68c..41988f4b8a5a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h | |||
@@ -389,13 +389,6 @@ struct iwl_lq_sta { | |||
389 | u8 last_bt_traffic; | 389 | u8 last_bt_traffic; |
390 | }; | 390 | }; |
391 | 391 | ||
392 | static inline u8 num_of_ant(u8 mask) | ||
393 | { | ||
394 | return !!((mask) & ANT_A) + | ||
395 | !!((mask) & ANT_B) + | ||
396 | !!((mask) & ANT_C); | ||
397 | } | ||
398 | |||
399 | static inline u8 first_antenna(u8 mask) | 392 | static inline u8 first_antenna(u8 mask) |
400 | { | 393 | { |
401 | if (mask & ANT_A) | 394 | if (mask & ANT_A) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 1fef5240e6ad..e12b1a63c484 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -368,6 +368,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, | |||
368 | goto drop_unlock_priv; | 368 | goto drop_unlock_priv; |
369 | 369 | ||
370 | memset(dev_cmd, 0, sizeof(*dev_cmd)); | 370 | memset(dev_cmd, 0, sizeof(*dev_cmd)); |
371 | dev_cmd->hdr.cmd = REPLY_TX; | ||
371 | tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; | 372 | tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; |
372 | 373 | ||
373 | /* Total # bytes to be transmitted */ | 374 | /* Total # bytes to be transmitted */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 03fd9aa8bfda..0b916249669e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -129,6 +129,12 @@ enum iwl_led_mode { | |||
129 | #define ANT_BC (ANT_B | ANT_C) | 129 | #define ANT_BC (ANT_B | ANT_C) |
130 | #define ANT_ABC (ANT_A | ANT_B | ANT_C) | 130 | #define ANT_ABC (ANT_A | ANT_B | ANT_C) |
131 | 131 | ||
132 | static inline u8 num_of_ant(u8 mask) | ||
133 | { | ||
134 | return !!((mask) & ANT_A) + | ||
135 | !!((mask) & ANT_B) + | ||
136 | !!((mask) & ANT_C); | ||
137 | } | ||
132 | 138 | ||
133 | /* | 139 | /* |
134 | * @max_ll_items: max number of OTP blocks | 140 | * @max_ll_items: max number of OTP blocks |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 2fab203d3027..94aef22df73a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -283,7 +283,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
283 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | | 283 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | |
284 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); | 284 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); |
285 | 285 | ||
286 | if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) { | 286 | if (num_of_ant(data->valid_rx_ant) == 1 || |
287 | cfg->rx_with_siso_diversity) { | ||
287 | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | 288 | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | |
288 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | 289 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; |
289 | /* this works because NOT_SUPPORTED == 3 */ | 290 | /* this works because NOT_SUPPORTED == 3 */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index a70c7b9d9bad..f6412dae2659 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -102,6 +102,9 @@ | |||
102 | /* Device system time */ | 102 | /* Device system time */ |
103 | #define DEVICE_SYSTEM_TIME_REG 0xA0206C | 103 | #define DEVICE_SYSTEM_TIME_REG 0xA0206C |
104 | 104 | ||
105 | /* Device NMI register */ | ||
106 | #define DEVICE_SET_NMI_REG 0x00a01c30 | ||
107 | |||
105 | /***************************************************************************** | 108 | /***************************************************************************** |
106 | * 7000/3000 series SHR DTS addresses * | 109 | * 7000/3000 series SHR DTS addresses * |
107 | *****************************************************************************/ | 110 | *****************************************************************************/ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 6d73817850ce..285d8c7486f5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -5,6 +5,7 @@ iwlmvm-y += scan.o time-event.o rs.o | |||
5 | iwlmvm-y += power.o power_legacy.o bt-coex.o | 5 | iwlmvm-y += power.o power_legacy.o bt-coex.o |
6 | iwlmvm-y += led.o tt.o | 6 | iwlmvm-y += led.o tt.o |
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o |
8 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o | ||
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 9 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
9 | 10 | ||
10 | ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ | 11 | ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 75b72a956552..d126245c48de 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -396,7 +396,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
396 | BT_VALID_ANT_ISOLATION | | 396 | BT_VALID_ANT_ISOLATION | |
397 | BT_VALID_ANT_ISOLATION_THRS | | 397 | BT_VALID_ANT_ISOLATION_THRS | |
398 | BT_VALID_TXTX_DELTA_FREQ_THRS | | 398 | BT_VALID_TXTX_DELTA_FREQ_THRS | |
399 | BT_VALID_TXRX_MAX_FREQ_0); | 399 | BT_VALID_TXRX_MAX_FREQ_0 | |
400 | BT_VALID_SYNC_TO_SCO); | ||
400 | 401 | ||
401 | if (mvm->cfg->bt_shared_single_ant) | 402 | if (mvm->cfg->bt_shared_single_ant) |
402 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | 403 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, |
@@ -514,7 +515,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
514 | if (IS_ERR_OR_NULL(sta)) | 515 | if (IS_ERR_OR_NULL(sta)) |
515 | return 0; | 516 | return 0; |
516 | 517 | ||
517 | mvmsta = (void *)sta->drv_priv; | 518 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
518 | 519 | ||
519 | /* nothing to do */ | 520 | /* nothing to do */ |
520 | if (mvmsta->bt_reduced_txpower == enable) | 521 | if (mvmsta->bt_reduced_txpower == enable) |
@@ -846,7 +847,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
846 | if (IS_ERR_OR_NULL(sta)) | 847 | if (IS_ERR_OR_NULL(sta)) |
847 | return; | 848 | return; |
848 | 849 | ||
849 | mvmsta = (void *)sta->drv_priv; | 850 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
850 | 851 | ||
851 | data->num_bss_ifaces++; | 852 | data->num_bss_ifaces++; |
852 | 853 | ||
@@ -917,11 +918,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
917 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, | 918 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, |
918 | struct ieee80211_sta *sta) | 919 | struct ieee80211_sta *sta) |
919 | { | 920 | { |
920 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 921 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
921 | enum iwl_bt_coex_lut_type lut_type; | 922 | enum iwl_bt_coex_lut_type lut_type; |
922 | 923 | ||
923 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | 924 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < |
924 | BT_LOW_TRAFFIC) | 925 | BT_HIGH_TRAFFIC) |
925 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; | 926 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; |
926 | 927 | ||
927 | lut_type = iwl_get_coex_type(mvm, mvmsta->vif); | 928 | lut_type = iwl_get_coex_type(mvm, mvmsta->vif); |
@@ -936,7 +937,7 @@ u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, | |||
936 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | 937 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, |
937 | struct ieee80211_sta *sta) | 938 | struct ieee80211_sta *sta) |
938 | { | 939 | { |
939 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 940 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
940 | 941 | ||
941 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | 942 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < |
942 | BT_HIGH_TRAFFIC) | 943 | BT_HIGH_TRAFFIC) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b9b81e881dd0..665f87e788d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -1216,10 +1216,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1216 | if (len >= sizeof(u32) * 2) { | 1216 | if (len >= sizeof(u32) * 2) { |
1217 | mvm->d3_test_pme_ptr = | 1217 | mvm->d3_test_pme_ptr = |
1218 | le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); | 1218 | le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); |
1219 | } else if (test) { | ||
1220 | /* in test mode we require the pointer */ | ||
1221 | ret = -EIO; | ||
1222 | goto out; | ||
1223 | } | 1219 | } |
1224 | #endif | 1220 | #endif |
1225 | iwl_free_resp(&d3_cfg_cmd); | 1221 | iwl_free_resp(&d3_cfg_cmd); |
@@ -1231,10 +1227,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1231 | mvm->aux_sta.sta_id = old_aux_sta_id; | 1227 | mvm->aux_sta.sta_id = old_aux_sta_id; |
1232 | mvm_ap_sta->sta_id = old_ap_sta_id; | 1228 | mvm_ap_sta->sta_id = old_ap_sta_id; |
1233 | mvmvif->ap_sta_id = old_ap_sta_id; | 1229 | mvmvif->ap_sta_id = old_ap_sta_id; |
1234 | out_noreset: | 1230 | |
1235 | kfree(key_data.rsc_tsc); | ||
1236 | if (ret < 0) | 1231 | if (ret < 0) |
1237 | ieee80211_restart_hw(mvm->hw); | 1232 | ieee80211_restart_hw(mvm->hw); |
1233 | out_noreset: | ||
1234 | kfree(key_data.rsc_tsc); | ||
1238 | 1235 | ||
1239 | mutex_unlock(&mvm->mutex); | 1236 | mutex_unlock(&mvm->mutex); |
1240 | 1237 | ||
@@ -1537,10 +1534,16 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, | |||
1537 | struct iwl_mvm_d3_gtk_iter_data gtkdata = { | 1534 | struct iwl_mvm_d3_gtk_iter_data gtkdata = { |
1538 | .status = status, | 1535 | .status = status, |
1539 | }; | 1536 | }; |
1537 | u32 disconnection_reasons = | ||
1538 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||
1539 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; | ||
1540 | 1540 | ||
1541 | if (!status || !vif->bss_conf.bssid) | 1541 | if (!status || !vif->bss_conf.bssid) |
1542 | return false; | 1542 | return false; |
1543 | 1543 | ||
1544 | if (le32_to_cpu(status->wakeup_reasons) & disconnection_reasons) | ||
1545 | return false; | ||
1546 | |||
1544 | /* find last GTK that we used initially, if any */ | 1547 | /* find last GTK that we used initially, if any */ |
1545 | gtkdata.find_phase = true; | 1548 | gtkdata.find_phase = true; |
1546 | ieee80211_iter_keys(mvm->hw, vif, | 1549 | ieee80211_iter_keys(mvm->hw, vif, |
@@ -1805,6 +1808,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1805 | iwl_mvm_read_d3_sram(mvm); | 1808 | iwl_mvm_read_d3_sram(mvm); |
1806 | 1809 | ||
1807 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); | 1810 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); |
1811 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1812 | if (keep) | ||
1813 | mvm->keep_vif = vif; | ||
1814 | #endif | ||
1808 | /* has unlocked the mutex, so skip that */ | 1815 | /* has unlocked the mutex, so skip that */ |
1809 | goto out; | 1816 | goto out; |
1810 | 1817 | ||
@@ -1861,6 +1868,7 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) | |||
1861 | return err; | 1868 | return err; |
1862 | } | 1869 | } |
1863 | mvm->d3_test_active = true; | 1870 | mvm->d3_test_active = true; |
1871 | mvm->keep_vif = NULL; | ||
1864 | return 0; | 1872 | return 0; |
1865 | } | 1873 | } |
1866 | 1874 | ||
@@ -1871,10 +1879,14 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, | |||
1871 | u32 pme_asserted; | 1879 | u32 pme_asserted; |
1872 | 1880 | ||
1873 | while (true) { | 1881 | while (true) { |
1874 | pme_asserted = iwl_trans_read_mem32(mvm->trans, | 1882 | /* read pme_ptr if available */ |
1875 | mvm->d3_test_pme_ptr); | 1883 | if (mvm->d3_test_pme_ptr) { |
1876 | if (pme_asserted) | 1884 | pme_asserted = iwl_trans_read_mem32(mvm->trans, |
1877 | break; | 1885 | mvm->d3_test_pme_ptr); |
1886 | if (pme_asserted) | ||
1887 | break; | ||
1888 | } | ||
1889 | |||
1878 | if (msleep_interruptible(100)) | 1890 | if (msleep_interruptible(100)) |
1879 | break; | 1891 | break; |
1880 | } | 1892 | } |
@@ -1885,6 +1897,10 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, | |||
1885 | static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, | 1897 | static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, |
1886 | struct ieee80211_vif *vif) | 1898 | struct ieee80211_vif *vif) |
1887 | { | 1899 | { |
1900 | /* skip the one we keep connection on */ | ||
1901 | if (_data == vif) | ||
1902 | return; | ||
1903 | |||
1888 | if (vif->type == NL80211_IFTYPE_STATION) | 1904 | if (vif->type == NL80211_IFTYPE_STATION) |
1889 | ieee80211_connection_loss(vif); | 1905 | ieee80211_connection_loss(vif); |
1890 | } | 1906 | } |
@@ -1911,7 +1927,7 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) | |||
1911 | 1927 | ||
1912 | ieee80211_iterate_active_interfaces_atomic( | 1928 | ieee80211_iterate_active_interfaces_atomic( |
1913 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1929 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1914 | iwl_mvm_d3_test_disconn_work_iter, NULL); | 1930 | iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); |
1915 | 1931 | ||
1916 | ieee80211_wake_queues(mvm->hw); | 1932 | ieee80211_wake_queues(mvm->hw); |
1917 | 1933 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c new file mode 100644 index 000000000000..67f6a2071653 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | #include "mvm.h" | ||
64 | #include "debugfs.h" | ||
65 | |||
66 | static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | ||
67 | char __user *user_buf, | ||
68 | size_t count, loff_t *ppos) | ||
69 | { | ||
70 | struct ieee80211_vif *vif = file->private_data; | ||
71 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
72 | struct iwl_mvm *mvm = mvmvif->mvm; | ||
73 | u8 ap_sta_id; | ||
74 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
75 | char buf[512]; | ||
76 | int bufsz = sizeof(buf); | ||
77 | int pos = 0; | ||
78 | int i; | ||
79 | |||
80 | mutex_lock(&mvm->mutex); | ||
81 | |||
82 | ap_sta_id = mvmvif->ap_sta_id; | ||
83 | |||
84 | pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", | ||
85 | mvmvif->id, mvmvif->color); | ||
86 | pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", | ||
87 | vif->bss_conf.bssid); | ||
88 | pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); | ||
89 | for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) | ||
90 | pos += scnprintf(buf+pos, bufsz-pos, | ||
91 | "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", | ||
92 | i, mvmvif->queue_params[i].txop, | ||
93 | mvmvif->queue_params[i].cw_min, | ||
94 | mvmvif->queue_params[i].cw_max, | ||
95 | mvmvif->queue_params[i].aifs, | ||
96 | mvmvif->queue_params[i].uapsd); | ||
97 | |||
98 | if (vif->type == NL80211_IFTYPE_STATION && | ||
99 | ap_sta_id != IWL_MVM_STATION_COUNT) { | ||
100 | struct ieee80211_sta *sta; | ||
101 | struct iwl_mvm_sta *mvm_sta; | ||
102 | |||
103 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], | ||
104 | lockdep_is_held(&mvm->mutex)); | ||
105 | mvm_sta = (void *)sta->drv_priv; | ||
106 | pos += scnprintf(buf+pos, bufsz-pos, | ||
107 | "ap_sta_id %d - reduced Tx power %d\n", | ||
108 | ap_sta_id, mvm_sta->bt_reduced_txpower); | ||
109 | } | ||
110 | |||
111 | rcu_read_lock(); | ||
112 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
113 | if (chanctx_conf) | ||
114 | pos += scnprintf(buf+pos, bufsz-pos, | ||
115 | "idle rx chains %d, active rx chains: %d\n", | ||
116 | chanctx_conf->rx_chains_static, | ||
117 | chanctx_conf->rx_chains_dynamic); | ||
118 | rcu_read_unlock(); | ||
119 | |||
120 | mutex_unlock(&mvm->mutex); | ||
121 | |||
122 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
123 | } | ||
124 | |||
125 | #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ | ||
126 | if (!debugfs_create_file(#name, mode, parent, vif, \ | ||
127 | &iwl_dbgfs_##name##_ops)) \ | ||
128 | goto err; \ | ||
129 | } while (0) | ||
130 | |||
131 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); | ||
132 | |||
133 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
134 | { | ||
135 | struct dentry *dbgfs_dir = vif->debugfs_dir; | ||
136 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
137 | char buf[100]; | ||
138 | |||
139 | /* | ||
140 | * Check if debugfs directory already exist before creating it. | ||
141 | * This may happen when, for example, resetting hw or suspend-resume | ||
142 | */ | ||
143 | if (!dbgfs_dir || mvmvif->dbgfs_dir) | ||
144 | return; | ||
145 | |||
146 | mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); | ||
147 | mvmvif->mvm = mvm; | ||
148 | |||
149 | if (!mvmvif->dbgfs_dir) { | ||
150 | IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", | ||
151 | dbgfs_dir->d_name.name); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | ||
156 | S_IRUSR); | ||
157 | |||
158 | /* | ||
159 | * Create symlink for convenience pointing to interface specific | ||
160 | * debugfs entries for the driver. For example, under | ||
161 | * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ | ||
162 | * find | ||
163 | * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ | ||
164 | */ | ||
165 | snprintf(buf, 100, "../../../%s/%s/%s/%s", | ||
166 | dbgfs_dir->d_parent->d_parent->d_name.name, | ||
167 | dbgfs_dir->d_parent->d_name.name, | ||
168 | dbgfs_dir->d_name.name, | ||
169 | mvmvif->dbgfs_dir->d_name.name); | ||
170 | |||
171 | mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, | ||
172 | mvm->debugfs_dir, buf); | ||
173 | if (!mvmvif->dbgfs_slink) | ||
174 | IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", | ||
175 | dbgfs_dir->d_name.name); | ||
176 | return; | ||
177 | err: | ||
178 | IWL_ERR(mvm, "Can't create debugfs entity\n"); | ||
179 | } | ||
180 | |||
181 | void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
182 | { | ||
183 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
184 | |||
185 | debugfs_remove(mvmvif->dbgfs_slink); | ||
186 | mvmvif->dbgfs_slink = NULL; | ||
187 | |||
188 | debugfs_remove_recursive(mvmvif->dbgfs_dir); | ||
189 | mvmvif->dbgfs_dir = NULL; | ||
190 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index a8fe6b41f9a3..e8f62a6a1b57 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -63,30 +63,18 @@ | |||
63 | #include "mvm.h" | 63 | #include "mvm.h" |
64 | #include "sta.h" | 64 | #include "sta.h" |
65 | #include "iwl-io.h" | 65 | #include "iwl-io.h" |
66 | #include "iwl-prph.h" | ||
67 | #include "debugfs.h" | ||
66 | 68 | ||
67 | struct iwl_dbgfs_mvm_ctx { | 69 | static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, |
68 | struct iwl_mvm *mvm; | ||
69 | struct ieee80211_vif *vif; | ||
70 | }; | ||
71 | |||
72 | static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, | ||
73 | const char __user *user_buf, | ||
74 | size_t count, loff_t *ppos) | 70 | size_t count, loff_t *ppos) |
75 | { | 71 | { |
76 | struct iwl_mvm *mvm = file->private_data; | 72 | int ret; |
77 | |||
78 | char buf[16]; | ||
79 | int buf_size, ret; | ||
80 | u32 scd_q_msk; | 73 | u32 scd_q_msk; |
81 | 74 | ||
82 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | 75 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) |
83 | return -EIO; | 76 | return -EIO; |
84 | 77 | ||
85 | memset(buf, 0, sizeof(buf)); | ||
86 | buf_size = min(count, sizeof(buf) - 1); | ||
87 | if (copy_from_user(buf, user_buf, buf_size)) | ||
88 | return -EFAULT; | ||
89 | |||
90 | if (sscanf(buf, "%x", &scd_q_msk) != 1) | 78 | if (sscanf(buf, "%x", &scd_q_msk) != 1) |
91 | return -EINVAL; | 79 | return -EINVAL; |
92 | 80 | ||
@@ -99,24 +87,15 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, | |||
99 | return ret; | 87 | return ret; |
100 | } | 88 | } |
101 | 89 | ||
102 | static ssize_t iwl_dbgfs_sta_drain_write(struct file *file, | 90 | static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, |
103 | const char __user *user_buf, | ||
104 | size_t count, loff_t *ppos) | 91 | size_t count, loff_t *ppos) |
105 | { | 92 | { |
106 | struct iwl_mvm *mvm = file->private_data; | ||
107 | struct ieee80211_sta *sta; | 93 | struct ieee80211_sta *sta; |
108 | 94 | int sta_id, drain, ret; | |
109 | char buf[8]; | ||
110 | int buf_size, sta_id, drain, ret; | ||
111 | 95 | ||
112 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | 96 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) |
113 | return -EIO; | 97 | return -EIO; |
114 | 98 | ||
115 | memset(buf, 0, sizeof(buf)); | ||
116 | buf_size = min(count, sizeof(buf) - 1); | ||
117 | if (copy_from_user(buf, user_buf, buf_size)) | ||
118 | return -EFAULT; | ||
119 | |||
120 | if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) | 99 | if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) |
121 | return -EINVAL; | 100 | return -EINVAL; |
122 | if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT) | 101 | if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT) |
@@ -194,20 +173,11 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | |||
194 | return ret; | 173 | return ret; |
195 | } | 174 | } |
196 | 175 | ||
197 | static ssize_t iwl_dbgfs_sram_write(struct file *file, | 176 | static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, |
198 | const char __user *user_buf, size_t count, | 177 | size_t count, loff_t *ppos) |
199 | loff_t *ppos) | ||
200 | { | 178 | { |
201 | struct iwl_mvm *mvm = file->private_data; | ||
202 | char buf[64]; | ||
203 | int buf_size; | ||
204 | u32 offset, len; | 179 | u32 offset, len; |
205 | 180 | ||
206 | memset(buf, 0, sizeof(buf)); | ||
207 | buf_size = min(count, sizeof(buf) - 1); | ||
208 | if (copy_from_user(buf, user_buf, buf_size)) | ||
209 | return -EFAULT; | ||
210 | |||
211 | if (sscanf(buf, "%x,%x", &offset, &len) == 2) { | 181 | if (sscanf(buf, "%x,%x", &offset, &len) == 2) { |
212 | if ((offset & 0x3) || (len & 0x3)) | 182 | if ((offset & 0x3) || (len & 0x3)) |
213 | return -EINVAL; | 183 | return -EINVAL; |
@@ -267,22 +237,14 @@ static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file, | |||
267 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 237 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
268 | } | 238 | } |
269 | 239 | ||
270 | static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, | 240 | static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, |
271 | const char __user *user_buf, | ||
272 | size_t count, loff_t *ppos) | 241 | size_t count, loff_t *ppos) |
273 | { | 242 | { |
274 | struct iwl_mvm *mvm = file->private_data; | 243 | int ret, val; |
275 | char buf[64] = {}; | ||
276 | int ret; | ||
277 | int val; | ||
278 | 244 | ||
279 | if (!mvm->ucode_loaded) | 245 | if (!mvm->ucode_loaded) |
280 | return -EIO; | 246 | return -EIO; |
281 | 247 | ||
282 | count = min_t(size_t, count, sizeof(buf) - 1); | ||
283 | if (copy_from_user(buf, user_buf, count)) | ||
284 | return -EFAULT; | ||
285 | |||
286 | if (!strncmp("disable_power_off_d0=", buf, 21)) { | 248 | if (!strncmp("disable_power_off_d0=", buf, 21)) { |
287 | if (sscanf(buf + 21, "%d", &val) != 1) | 249 | if (sscanf(buf + 21, "%d", &val) != 1) |
288 | return -EINVAL; | 250 | return -EINVAL; |
@@ -302,212 +264,6 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, | |||
302 | return ret ?: count; | 264 | return ret ?: count; |
303 | } | 265 | } |
304 | 266 | ||
305 | static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, | ||
306 | struct ieee80211_vif *vif, | ||
307 | enum iwl_dbgfs_pm_mask param, int val) | ||
308 | { | ||
309 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
310 | struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm; | ||
311 | |||
312 | dbgfs_pm->mask |= param; | ||
313 | |||
314 | switch (param) { | ||
315 | case MVM_DEBUGFS_PM_KEEP_ALIVE: { | ||
316 | struct ieee80211_hw *hw = mvm->hw; | ||
317 | int dtimper = hw->conf.ps_dtim_period ?: 1; | ||
318 | int dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
319 | |||
320 | IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); | ||
321 | if (val * MSEC_PER_SEC < 3 * dtimper_msec) { | ||
322 | IWL_WARN(mvm, | ||
323 | "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", | ||
324 | val * MSEC_PER_SEC, 3 * dtimper_msec); | ||
325 | } | ||
326 | dbgfs_pm->keep_alive_seconds = val; | ||
327 | break; | ||
328 | } | ||
329 | case MVM_DEBUGFS_PM_SKIP_OVER_DTIM: | ||
330 | IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n", | ||
331 | val ? "enabled" : "disabled"); | ||
332 | dbgfs_pm->skip_over_dtim = val; | ||
333 | break; | ||
334 | case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS: | ||
335 | IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val); | ||
336 | dbgfs_pm->skip_dtim_periods = val; | ||
337 | break; | ||
338 | case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT: | ||
339 | IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val); | ||
340 | dbgfs_pm->rx_data_timeout = val; | ||
341 | break; | ||
342 | case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT: | ||
343 | IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); | ||
344 | dbgfs_pm->tx_data_timeout = val; | ||
345 | break; | ||
346 | case MVM_DEBUGFS_PM_DISABLE_POWER_OFF: | ||
347 | IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val); | ||
348 | dbgfs_pm->disable_power_off = val; | ||
349 | break; | ||
350 | case MVM_DEBUGFS_PM_LPRX_ENA: | ||
351 | IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled"); | ||
352 | dbgfs_pm->lprx_ena = val; | ||
353 | break; | ||
354 | case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD: | ||
355 | IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); | ||
356 | dbgfs_pm->lprx_rssi_threshold = val; | ||
357 | break; | ||
358 | case MVM_DEBUGFS_PM_SNOOZE_ENABLE: | ||
359 | IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); | ||
360 | dbgfs_pm->snooze_ena = val; | ||
361 | break; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | static ssize_t iwl_dbgfs_pm_params_write(struct file *file, | ||
366 | const char __user *user_buf, | ||
367 | size_t count, loff_t *ppos) | ||
368 | { | ||
369 | struct ieee80211_vif *vif = file->private_data; | ||
370 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
371 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
372 | enum iwl_dbgfs_pm_mask param; | ||
373 | char buf[32] = {}; | ||
374 | int val; | ||
375 | int ret; | ||
376 | |||
377 | count = min_t(size_t, count, sizeof(buf) - 1); | ||
378 | if (copy_from_user(buf, user_buf, count)) | ||
379 | return -EFAULT; | ||
380 | |||
381 | if (!strncmp("keep_alive=", buf, 11)) { | ||
382 | if (sscanf(buf + 11, "%d", &val) != 1) | ||
383 | return -EINVAL; | ||
384 | param = MVM_DEBUGFS_PM_KEEP_ALIVE; | ||
385 | } else if (!strncmp("skip_over_dtim=", buf, 15)) { | ||
386 | if (sscanf(buf + 15, "%d", &val) != 1) | ||
387 | return -EINVAL; | ||
388 | param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM; | ||
389 | } else if (!strncmp("skip_dtim_periods=", buf, 18)) { | ||
390 | if (sscanf(buf + 18, "%d", &val) != 1) | ||
391 | return -EINVAL; | ||
392 | param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS; | ||
393 | } else if (!strncmp("rx_data_timeout=", buf, 16)) { | ||
394 | if (sscanf(buf + 16, "%d", &val) != 1) | ||
395 | return -EINVAL; | ||
396 | param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT; | ||
397 | } else if (!strncmp("tx_data_timeout=", buf, 16)) { | ||
398 | if (sscanf(buf + 16, "%d", &val) != 1) | ||
399 | return -EINVAL; | ||
400 | param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; | ||
401 | } else if (!strncmp("disable_power_off=", buf, 18) && | ||
402 | !(mvm->fw->ucode_capa.flags & | ||
403 | IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) { | ||
404 | if (sscanf(buf + 18, "%d", &val) != 1) | ||
405 | return -EINVAL; | ||
406 | param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; | ||
407 | } else if (!strncmp("lprx=", buf, 5)) { | ||
408 | if (sscanf(buf + 5, "%d", &val) != 1) | ||
409 | return -EINVAL; | ||
410 | param = MVM_DEBUGFS_PM_LPRX_ENA; | ||
411 | } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) { | ||
412 | if (sscanf(buf + 20, "%d", &val) != 1) | ||
413 | return -EINVAL; | ||
414 | if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val < | ||
415 | POWER_LPRX_RSSI_THRESHOLD_MIN) | ||
416 | return -EINVAL; | ||
417 | param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; | ||
418 | } else if (!strncmp("snooze_enable=", buf, 14)) { | ||
419 | if (sscanf(buf + 14, "%d", &val) != 1) | ||
420 | return -EINVAL; | ||
421 | param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; | ||
422 | } else { | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | mutex_lock(&mvm->mutex); | ||
427 | iwl_dbgfs_update_pm(mvm, vif, param, val); | ||
428 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
429 | mutex_unlock(&mvm->mutex); | ||
430 | |||
431 | return ret ?: count; | ||
432 | } | ||
433 | |||
434 | static ssize_t iwl_dbgfs_pm_params_read(struct file *file, | ||
435 | char __user *user_buf, | ||
436 | size_t count, loff_t *ppos) | ||
437 | { | ||
438 | struct ieee80211_vif *vif = file->private_data; | ||
439 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
440 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
441 | char buf[512]; | ||
442 | int bufsz = sizeof(buf); | ||
443 | int pos; | ||
444 | |||
445 | pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); | ||
446 | |||
447 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
448 | } | ||
449 | |||
450 | static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | ||
451 | char __user *user_buf, | ||
452 | size_t count, loff_t *ppos) | ||
453 | { | ||
454 | struct ieee80211_vif *vif = file->private_data; | ||
455 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
456 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
457 | u8 ap_sta_id; | ||
458 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
459 | char buf[512]; | ||
460 | int bufsz = sizeof(buf); | ||
461 | int pos = 0; | ||
462 | int i; | ||
463 | |||
464 | mutex_lock(&mvm->mutex); | ||
465 | |||
466 | ap_sta_id = mvmvif->ap_sta_id; | ||
467 | |||
468 | pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", | ||
469 | mvmvif->id, mvmvif->color); | ||
470 | pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", | ||
471 | vif->bss_conf.bssid); | ||
472 | pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); | ||
473 | for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) { | ||
474 | pos += scnprintf(buf+pos, bufsz-pos, | ||
475 | "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", | ||
476 | i, mvmvif->queue_params[i].txop, | ||
477 | mvmvif->queue_params[i].cw_min, | ||
478 | mvmvif->queue_params[i].cw_max, | ||
479 | mvmvif->queue_params[i].aifs, | ||
480 | mvmvif->queue_params[i].uapsd); | ||
481 | } | ||
482 | |||
483 | if (vif->type == NL80211_IFTYPE_STATION && | ||
484 | ap_sta_id != IWL_MVM_STATION_COUNT) { | ||
485 | struct ieee80211_sta *sta; | ||
486 | struct iwl_mvm_sta *mvm_sta; | ||
487 | |||
488 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], | ||
489 | lockdep_is_held(&mvm->mutex)); | ||
490 | mvm_sta = (void *)sta->drv_priv; | ||
491 | pos += scnprintf(buf+pos, bufsz-pos, | ||
492 | "ap_sta_id %d - reduced Tx power %d\n", | ||
493 | ap_sta_id, mvm_sta->bt_reduced_txpower); | ||
494 | } | ||
495 | |||
496 | rcu_read_lock(); | ||
497 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
498 | if (chanctx_conf) { | ||
499 | pos += scnprintf(buf+pos, bufsz-pos, | ||
500 | "idle rx chains %d, active rx chains: %d\n", | ||
501 | chanctx_conf->rx_chains_static, | ||
502 | chanctx_conf->rx_chains_dynamic); | ||
503 | } | ||
504 | rcu_read_unlock(); | ||
505 | |||
506 | mutex_unlock(&mvm->mutex); | ||
507 | |||
508 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
509 | } | ||
510 | |||
511 | #define BT_MBOX_MSG(_notif, _num, _field) \ | 267 | #define BT_MBOX_MSG(_notif, _num, _field) \ |
512 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ | 268 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ |
513 | >> BT_MBOX##_num##_##_field##_POS) | 269 | >> BT_MBOX##_num##_##_field##_POS) |
@@ -783,11 +539,9 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | |||
783 | } | 539 | } |
784 | #undef PRINT_STAT_LE32 | 540 | #undef PRINT_STAT_LE32 |
785 | 541 | ||
786 | static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | 542 | static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, |
787 | const char __user *user_buf, | ||
788 | size_t count, loff_t *ppos) | 543 | size_t count, loff_t *ppos) |
789 | { | 544 | { |
790 | struct iwl_mvm *mvm = file->private_data; | ||
791 | int ret; | 545 | int ret; |
792 | 546 | ||
793 | mutex_lock(&mvm->mutex); | 547 | mutex_lock(&mvm->mutex); |
@@ -804,6 +558,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | |||
804 | return count; | 558 | return count; |
805 | } | 559 | } |
806 | 560 | ||
561 | static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, | ||
562 | size_t count, loff_t *ppos) | ||
563 | { | ||
564 | iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1); | ||
565 | |||
566 | return count; | ||
567 | } | ||
568 | |||
807 | static ssize_t | 569 | static ssize_t |
808 | iwl_dbgfs_scan_ant_rxchain_read(struct file *file, | 570 | iwl_dbgfs_scan_ant_rxchain_read(struct file *file, |
809 | char __user *user_buf, | 571 | char __user *user_buf, |
@@ -828,21 +590,11 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file, | |||
828 | } | 590 | } |
829 | 591 | ||
830 | static ssize_t | 592 | static ssize_t |
831 | iwl_dbgfs_scan_ant_rxchain_write(struct file *file, | 593 | iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, |
832 | const char __user *user_buf, | ||
833 | size_t count, loff_t *ppos) | 594 | size_t count, loff_t *ppos) |
834 | { | 595 | { |
835 | struct iwl_mvm *mvm = file->private_data; | ||
836 | char buf[8]; | ||
837 | int buf_size; | ||
838 | u8 scan_rx_ant; | 596 | u8 scan_rx_ant; |
839 | 597 | ||
840 | memset(buf, 0, sizeof(buf)); | ||
841 | buf_size = min(count, sizeof(buf) - 1); | ||
842 | |||
843 | /* get the argument from the user and check if it is valid */ | ||
844 | if (copy_from_user(buf, user_buf, buf_size)) | ||
845 | return -EFAULT; | ||
846 | if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) | 598 | if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) |
847 | return -EINVAL; | 599 | return -EINVAL; |
848 | if (scan_rx_ant > ANT_ABC) | 600 | if (scan_rx_ant > ANT_ABC) |
@@ -850,228 +602,17 @@ iwl_dbgfs_scan_ant_rxchain_write(struct file *file, | |||
850 | if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) | 602 | if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) |
851 | return -EINVAL; | 603 | return -EINVAL; |
852 | 604 | ||
853 | /* change the rx antennas for scan command */ | ||
854 | mvm->scan_rx_ant = scan_rx_ant; | 605 | mvm->scan_rx_ant = scan_rx_ant; |
855 | 606 | ||
856 | return count; | 607 | return count; |
857 | } | 608 | } |
858 | 609 | ||
859 | |||
860 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, | ||
861 | enum iwl_dbgfs_bf_mask param, int value) | ||
862 | { | ||
863 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
864 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; | ||
865 | |||
866 | dbgfs_bf->mask |= param; | ||
867 | |||
868 | switch (param) { | ||
869 | case MVM_DEBUGFS_BF_ENERGY_DELTA: | ||
870 | dbgfs_bf->bf_energy_delta = value; | ||
871 | break; | ||
872 | case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA: | ||
873 | dbgfs_bf->bf_roaming_energy_delta = value; | ||
874 | break; | ||
875 | case MVM_DEBUGFS_BF_ROAMING_STATE: | ||
876 | dbgfs_bf->bf_roaming_state = value; | ||
877 | break; | ||
878 | case MVM_DEBUGFS_BF_TEMP_THRESHOLD: | ||
879 | dbgfs_bf->bf_temp_threshold = value; | ||
880 | break; | ||
881 | case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: | ||
882 | dbgfs_bf->bf_temp_fast_filter = value; | ||
883 | break; | ||
884 | case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: | ||
885 | dbgfs_bf->bf_temp_slow_filter = value; | ||
886 | break; | ||
887 | case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: | ||
888 | dbgfs_bf->bf_enable_beacon_filter = value; | ||
889 | break; | ||
890 | case MVM_DEBUGFS_BF_DEBUG_FLAG: | ||
891 | dbgfs_bf->bf_debug_flag = value; | ||
892 | break; | ||
893 | case MVM_DEBUGFS_BF_ESCAPE_TIMER: | ||
894 | dbgfs_bf->bf_escape_timer = value; | ||
895 | break; | ||
896 | case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT: | ||
897 | dbgfs_bf->ba_enable_beacon_abort = value; | ||
898 | break; | ||
899 | case MVM_DEBUGFS_BA_ESCAPE_TIMER: | ||
900 | dbgfs_bf->ba_escape_timer = value; | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | |||
905 | static ssize_t iwl_dbgfs_bf_params_write(struct file *file, | ||
906 | const char __user *user_buf, | ||
907 | size_t count, loff_t *ppos) | ||
908 | { | ||
909 | struct ieee80211_vif *vif = file->private_data; | ||
910 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
911 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
912 | enum iwl_dbgfs_bf_mask param; | ||
913 | char buf[256]; | ||
914 | int buf_size; | ||
915 | int value; | ||
916 | int ret = 0; | ||
917 | |||
918 | memset(buf, 0, sizeof(buf)); | ||
919 | buf_size = min(count, sizeof(buf) - 1); | ||
920 | if (copy_from_user(buf, user_buf, buf_size)) | ||
921 | return -EFAULT; | ||
922 | |||
923 | if (!strncmp("bf_energy_delta=", buf, 16)) { | ||
924 | if (sscanf(buf+16, "%d", &value) != 1) | ||
925 | return -EINVAL; | ||
926 | if (value < IWL_BF_ENERGY_DELTA_MIN || | ||
927 | value > IWL_BF_ENERGY_DELTA_MAX) | ||
928 | return -EINVAL; | ||
929 | param = MVM_DEBUGFS_BF_ENERGY_DELTA; | ||
930 | } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) { | ||
931 | if (sscanf(buf+24, "%d", &value) != 1) | ||
932 | return -EINVAL; | ||
933 | if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN || | ||
934 | value > IWL_BF_ROAMING_ENERGY_DELTA_MAX) | ||
935 | return -EINVAL; | ||
936 | param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA; | ||
937 | } else if (!strncmp("bf_roaming_state=", buf, 17)) { | ||
938 | if (sscanf(buf+17, "%d", &value) != 1) | ||
939 | return -EINVAL; | ||
940 | if (value < IWL_BF_ROAMING_STATE_MIN || | ||
941 | value > IWL_BF_ROAMING_STATE_MAX) | ||
942 | return -EINVAL; | ||
943 | param = MVM_DEBUGFS_BF_ROAMING_STATE; | ||
944 | } else if (!strncmp("bf_temp_threshold=", buf, 18)) { | ||
945 | if (sscanf(buf+18, "%d", &value) != 1) | ||
946 | return -EINVAL; | ||
947 | if (value < IWL_BF_TEMP_THRESHOLD_MIN || | ||
948 | value > IWL_BF_TEMP_THRESHOLD_MAX) | ||
949 | return -EINVAL; | ||
950 | param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; | ||
951 | } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { | ||
952 | if (sscanf(buf+20, "%d", &value) != 1) | ||
953 | return -EINVAL; | ||
954 | if (value < IWL_BF_TEMP_FAST_FILTER_MIN || | ||
955 | value > IWL_BF_TEMP_FAST_FILTER_MAX) | ||
956 | return -EINVAL; | ||
957 | param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; | ||
958 | } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { | ||
959 | if (sscanf(buf+20, "%d", &value) != 1) | ||
960 | return -EINVAL; | ||
961 | if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || | ||
962 | value > IWL_BF_TEMP_SLOW_FILTER_MAX) | ||
963 | return -EINVAL; | ||
964 | param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; | ||
965 | } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { | ||
966 | if (sscanf(buf+24, "%d", &value) != 1) | ||
967 | return -EINVAL; | ||
968 | if (value < 0 || value > 1) | ||
969 | return -EINVAL; | ||
970 | param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER; | ||
971 | } else if (!strncmp("bf_debug_flag=", buf, 14)) { | ||
972 | if (sscanf(buf+14, "%d", &value) != 1) | ||
973 | return -EINVAL; | ||
974 | if (value < 0 || value > 1) | ||
975 | return -EINVAL; | ||
976 | param = MVM_DEBUGFS_BF_DEBUG_FLAG; | ||
977 | } else if (!strncmp("bf_escape_timer=", buf, 16)) { | ||
978 | if (sscanf(buf+16, "%d", &value) != 1) | ||
979 | return -EINVAL; | ||
980 | if (value < IWL_BF_ESCAPE_TIMER_MIN || | ||
981 | value > IWL_BF_ESCAPE_TIMER_MAX) | ||
982 | return -EINVAL; | ||
983 | param = MVM_DEBUGFS_BF_ESCAPE_TIMER; | ||
984 | } else if (!strncmp("ba_escape_timer=", buf, 16)) { | ||
985 | if (sscanf(buf+16, "%d", &value) != 1) | ||
986 | return -EINVAL; | ||
987 | if (value < IWL_BA_ESCAPE_TIMER_MIN || | ||
988 | value > IWL_BA_ESCAPE_TIMER_MAX) | ||
989 | return -EINVAL; | ||
990 | param = MVM_DEBUGFS_BA_ESCAPE_TIMER; | ||
991 | } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) { | ||
992 | if (sscanf(buf+23, "%d", &value) != 1) | ||
993 | return -EINVAL; | ||
994 | if (value < 0 || value > 1) | ||
995 | return -EINVAL; | ||
996 | param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT; | ||
997 | } else { | ||
998 | return -EINVAL; | ||
999 | } | ||
1000 | |||
1001 | mutex_lock(&mvm->mutex); | ||
1002 | iwl_dbgfs_update_bf(vif, param, value); | ||
1003 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { | ||
1004 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
1005 | } else { | ||
1006 | ret = iwl_mvm_enable_beacon_filter(mvm, vif); | ||
1007 | } | ||
1008 | mutex_unlock(&mvm->mutex); | ||
1009 | |||
1010 | return ret ?: count; | ||
1011 | } | ||
1012 | |||
1013 | static ssize_t iwl_dbgfs_bf_params_read(struct file *file, | ||
1014 | char __user *user_buf, | ||
1015 | size_t count, loff_t *ppos) | ||
1016 | { | ||
1017 | struct ieee80211_vif *vif = file->private_data; | ||
1018 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1019 | char buf[256]; | ||
1020 | int pos = 0; | ||
1021 | const size_t bufsz = sizeof(buf); | ||
1022 | struct iwl_beacon_filter_cmd cmd = { | ||
1023 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
1024 | .bf_enable_beacon_filter = | ||
1025 | cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), | ||
1026 | .ba_enable_beacon_abort = | ||
1027 | cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), | ||
1028 | }; | ||
1029 | |||
1030 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | ||
1031 | if (mvmvif->bf_data.bf_enabled) | ||
1032 | cmd.bf_enable_beacon_filter = cpu_to_le32(1); | ||
1033 | else | ||
1034 | cmd.bf_enable_beacon_filter = 0; | ||
1035 | |||
1036 | pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", | ||
1037 | le32_to_cpu(cmd.bf_energy_delta)); | ||
1038 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", | ||
1039 | le32_to_cpu(cmd.bf_roaming_energy_delta)); | ||
1040 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", | ||
1041 | le32_to_cpu(cmd.bf_roaming_state)); | ||
1042 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", | ||
1043 | le32_to_cpu(cmd.bf_temp_threshold)); | ||
1044 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", | ||
1045 | le32_to_cpu(cmd.bf_temp_fast_filter)); | ||
1046 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", | ||
1047 | le32_to_cpu(cmd.bf_temp_slow_filter)); | ||
1048 | pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", | ||
1049 | le32_to_cpu(cmd.bf_enable_beacon_filter)); | ||
1050 | pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", | ||
1051 | le32_to_cpu(cmd.bf_debug_flag)); | ||
1052 | pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", | ||
1053 | le32_to_cpu(cmd.bf_escape_timer)); | ||
1054 | pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", | ||
1055 | le32_to_cpu(cmd.ba_escape_timer)); | ||
1056 | pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", | ||
1057 | le32_to_cpu(cmd.ba_enable_beacon_abort)); | ||
1058 | |||
1059 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1060 | } | ||
1061 | |||
1062 | #ifdef CONFIG_PM_SLEEP | 610 | #ifdef CONFIG_PM_SLEEP |
1063 | static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, | 611 | static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, |
1064 | const char __user *user_buf, | ||
1065 | size_t count, loff_t *ppos) | 612 | size_t count, loff_t *ppos) |
1066 | { | 613 | { |
1067 | struct iwl_mvm *mvm = file->private_data; | ||
1068 | char buf[8] = {}; | ||
1069 | int store; | 614 | int store; |
1070 | 615 | ||
1071 | count = min_t(size_t, count, sizeof(buf) - 1); | ||
1072 | if (copy_from_user(buf, user_buf, count)) | ||
1073 | return -EFAULT; | ||
1074 | |||
1075 | if (sscanf(buf, "%d", &store) != 1) | 616 | if (sscanf(buf, "%d", &store) != 1) |
1076 | return -EINVAL; | 617 | return -EINVAL; |
1077 | 618 | ||
@@ -1124,61 +665,33 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | |||
1124 | } | 665 | } |
1125 | #endif | 666 | #endif |
1126 | 667 | ||
1127 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ | 668 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ |
1128 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 669 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
1129 | .read = iwl_dbgfs_##name##_read, \ | 670 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ |
1130 | .open = simple_open, \ | 671 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
1131 | .llseek = generic_file_llseek, \ | ||
1132 | } | ||
1133 | |||
1134 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \ | ||
1135 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
1136 | .write = iwl_dbgfs_##name##_write, \ | ||
1137 | .read = iwl_dbgfs_##name##_read, \ | ||
1138 | .open = simple_open, \ | ||
1139 | .llseek = generic_file_llseek, \ | ||
1140 | }; | ||
1141 | |||
1142 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ | ||
1143 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
1144 | .write = iwl_dbgfs_##name##_write, \ | ||
1145 | .open = simple_open, \ | ||
1146 | .llseek = generic_file_llseek, \ | ||
1147 | }; | ||
1148 | |||
1149 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ | 672 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ |
1150 | if (!debugfs_create_file(#name, mode, parent, mvm, \ | 673 | if (!debugfs_create_file(#name, mode, parent, mvm, \ |
1151 | &iwl_dbgfs_##name##_ops)) \ | 674 | &iwl_dbgfs_##name##_ops)) \ |
1152 | goto err; \ | 675 | goto err; \ |
1153 | } while (0) | 676 | } while (0) |
1154 | 677 | ||
1155 | #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ | ||
1156 | if (!debugfs_create_file(#name, mode, parent, vif, \ | ||
1157 | &iwl_dbgfs_##name##_ops)) \ | ||
1158 | goto err; \ | ||
1159 | } while (0) | ||
1160 | |||
1161 | /* Device wide debugfs entries */ | 678 | /* Device wide debugfs entries */ |
1162 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); | 679 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); |
1163 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); | 680 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); |
1164 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); | 681 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); |
1165 | MVM_DEBUGFS_READ_FILE_OPS(stations); | 682 | MVM_DEBUGFS_READ_FILE_OPS(stations); |
1166 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | 683 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); |
1167 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); | 684 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); |
1168 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off); | 685 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); |
1169 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); | 686 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); |
1170 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); | 687 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); |
1171 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); | 688 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); |
689 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); | ||
1172 | 690 | ||
1173 | #ifdef CONFIG_PM_SLEEP | 691 | #ifdef CONFIG_PM_SLEEP |
1174 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); | 692 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); |
1175 | #endif | 693 | #endif |
1176 | 694 | ||
1177 | /* Interface specific debugfs entries */ | ||
1178 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); | ||
1179 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params); | ||
1180 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params); | ||
1181 | |||
1182 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 695 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
1183 | { | 696 | { |
1184 | char buf[100]; | 697 | char buf[100]; |
@@ -1196,6 +709,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
1196 | S_IRUSR | S_IWUSR); | 709 | S_IRUSR | S_IWUSR); |
1197 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); | 710 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); |
1198 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 711 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
712 | MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); | ||
1199 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, | 713 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, |
1200 | S_IWUSR | S_IRUSR); | 714 | S_IWUSR | S_IRUSR); |
1201 | #ifdef CONFIG_PM_SLEEP | 715 | #ifdef CONFIG_PM_SLEEP |
@@ -1206,6 +720,19 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
1206 | goto err; | 720 | goto err; |
1207 | #endif | 721 | #endif |
1208 | 722 | ||
723 | if (!debugfs_create_blob("nvm_hw", S_IRUSR, | ||
724 | mvm->debugfs_dir, &mvm->nvm_hw_blob)) | ||
725 | goto err; | ||
726 | if (!debugfs_create_blob("nvm_sw", S_IRUSR, | ||
727 | mvm->debugfs_dir, &mvm->nvm_sw_blob)) | ||
728 | goto err; | ||
729 | if (!debugfs_create_blob("nvm_calib", S_IRUSR, | ||
730 | mvm->debugfs_dir, &mvm->nvm_calib_blob)) | ||
731 | goto err; | ||
732 | if (!debugfs_create_blob("nvm_prod", S_IRUSR, | ||
733 | mvm->debugfs_dir, &mvm->nvm_prod_blob)) | ||
734 | goto err; | ||
735 | |||
1209 | /* | 736 | /* |
1210 | * Create a symlink with mac80211. It will be removed when mac80211 | 737 | * Create a symlink with mac80211. It will be removed when mac80211 |
1211 | * exists (before the opmode exists which removes the target.) | 738 | * exists (before the opmode exists which removes the target.) |
@@ -1221,72 +748,3 @@ err: | |||
1221 | IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); | 748 | IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); |
1222 | return -ENOMEM; | 749 | return -ENOMEM; |
1223 | } | 750 | } |
1224 | |||
1225 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
1226 | { | ||
1227 | struct dentry *dbgfs_dir = vif->debugfs_dir; | ||
1228 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1229 | char buf[100]; | ||
1230 | |||
1231 | /* | ||
1232 | * Check if debugfs directory already exist before creating it. | ||
1233 | * This may happen when, for example, resetting hw or suspend-resume | ||
1234 | */ | ||
1235 | if (!dbgfs_dir || mvmvif->dbgfs_dir) | ||
1236 | return; | ||
1237 | |||
1238 | mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); | ||
1239 | mvmvif->dbgfs_data = mvm; | ||
1240 | |||
1241 | if (!mvmvif->dbgfs_dir) { | ||
1242 | IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", | ||
1243 | dbgfs_dir->d_name.name); | ||
1244 | return; | ||
1245 | } | ||
1246 | |||
1247 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && | ||
1248 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p) | ||
1249 | MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | | ||
1250 | S_IRUSR); | ||
1251 | |||
1252 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | ||
1253 | S_IRUSR); | ||
1254 | |||
1255 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && | ||
1256 | mvmvif == mvm->bf_allowed_vif) | ||
1257 | MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, | ||
1258 | S_IRUSR | S_IWUSR); | ||
1259 | |||
1260 | /* | ||
1261 | * Create symlink for convenience pointing to interface specific | ||
1262 | * debugfs entries for the driver. For example, under | ||
1263 | * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ | ||
1264 | * find | ||
1265 | * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ | ||
1266 | */ | ||
1267 | snprintf(buf, 100, "../../../%s/%s/%s/%s", | ||
1268 | dbgfs_dir->d_parent->d_parent->d_name.name, | ||
1269 | dbgfs_dir->d_parent->d_name.name, | ||
1270 | dbgfs_dir->d_name.name, | ||
1271 | mvmvif->dbgfs_dir->d_name.name); | ||
1272 | |||
1273 | mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, | ||
1274 | mvm->debugfs_dir, buf); | ||
1275 | if (!mvmvif->dbgfs_slink) | ||
1276 | IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", | ||
1277 | dbgfs_dir->d_name.name); | ||
1278 | return; | ||
1279 | err: | ||
1280 | IWL_ERR(mvm, "Can't create debugfs entity\n"); | ||
1281 | } | ||
1282 | |||
1283 | void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
1284 | { | ||
1285 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1286 | |||
1287 | debugfs_remove(mvmvif->dbgfs_slink); | ||
1288 | mvmvif->dbgfs_slink = NULL; | ||
1289 | |||
1290 | debugfs_remove_recursive(mvmvif->dbgfs_dir); | ||
1291 | mvmvif->dbgfs_dir = NULL; | ||
1292 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h new file mode 100644 index 000000000000..85f9f958bfd2 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h | |||
@@ -0,0 +1,101 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ | ||
65 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
66 | .read = iwl_dbgfs_##name##_read, \ | ||
67 | .open = simple_open, \ | ||
68 | .llseek = generic_file_llseek, \ | ||
69 | } | ||
70 | |||
71 | #define MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ | ||
72 | static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \ | ||
73 | const char __user *user_buf, \ | ||
74 | size_t count, loff_t *ppos) \ | ||
75 | { \ | ||
76 | argtype *arg = file->private_data; \ | ||
77 | char buf[buflen] = {}; \ | ||
78 | size_t buf_size = min(count, sizeof(buf) - 1); \ | ||
79 | \ | ||
80 | if (copy_from_user(buf, user_buf, buf_size)) \ | ||
81 | return -EFAULT; \ | ||
82 | \ | ||
83 | return iwl_dbgfs_##name##_write(arg, buf, buf_size, ppos); \ | ||
84 | } \ | ||
85 | |||
86 | #define _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \ | ||
87 | MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ | ||
88 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
89 | .write = _iwl_dbgfs_##name##_write, \ | ||
90 | .read = iwl_dbgfs_##name##_read, \ | ||
91 | .open = simple_open, \ | ||
92 | .llseek = generic_file_llseek, \ | ||
93 | }; | ||
94 | |||
95 | #define _MVM_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \ | ||
96 | MVM_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ | ||
97 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | ||
98 | .write = _iwl_dbgfs_##name##_write, \ | ||
99 | .open = simple_open, \ | ||
100 | .llseek = generic_file_llseek, \ | ||
101 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index 4ea5e24ca92d..af500996bbf1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | |||
@@ -127,6 +127,7 @@ enum iwl_bt_coex_valid_bit_msk { | |||
127 | BT_VALID_ANT_ISOLATION_THRS = BIT(15), | 127 | BT_VALID_ANT_ISOLATION_THRS = BIT(15), |
128 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), | 128 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), |
129 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), | 129 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), |
130 | BT_VALID_SYNC_TO_SCO = BIT(18), | ||
130 | }; | 131 | }; |
131 | 132 | ||
132 | /** | 133 | /** |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 538f1c7a5966..532312c7b937 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -281,8 +281,31 @@ enum { | |||
281 | /* # entries in rate scale table to support Tx retries */ | 281 | /* # entries in rate scale table to support Tx retries */ |
282 | #define LQ_MAX_RETRY_NUM 16 | 282 | #define LQ_MAX_RETRY_NUM 16 |
283 | 283 | ||
284 | /* Link quality command flags, only this one is available */ | 284 | /* Link quality command flags bit fields */ |
285 | #define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0) | 285 | |
286 | /* Bit 0: (0) Don't use RTS (1) Use RTS */ | ||
287 | #define LQ_FLAG_USE_RTS_POS 0 | ||
288 | #define LQ_FLAG_USE_RTS_MSK (1 << LQ_FLAG_USE_RTS_POS) | ||
289 | |||
290 | /* Bit 1-3: LQ command color. Used to match responses to LQ commands */ | ||
291 | #define LQ_FLAG_COLOR_POS 1 | ||
292 | #define LQ_FLAG_COLOR_MSK (7 << LQ_FLAG_COLOR_POS) | ||
293 | |||
294 | /* Bit 4-5: Tx RTS BW Signalling | ||
295 | * (0) No RTS BW signalling | ||
296 | * (1) Static BW signalling | ||
297 | * (2) Dynamic BW signalling | ||
298 | */ | ||
299 | #define LQ_FLAG_RTS_BW_SIG_POS 4 | ||
300 | #define LQ_FLAG_RTS_BW_SIG_NONE (0 << LQ_FLAG_RTS_BW_SIG_POS) | ||
301 | #define LQ_FLAG_RTS_BW_SIG_STATIC (1 << LQ_FLAG_RTS_BW_SIG_POS) | ||
302 | #define LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << LQ_FLAG_RTS_BW_SIG_POS) | ||
303 | |||
304 | /* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection | ||
305 | * Dyanmic BW selection allows Tx with narrower BW then requested in rates | ||
306 | */ | ||
307 | #define LQ_FLAG_DYNAMIC_BW_POS 6 | ||
308 | #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) | ||
286 | 309 | ||
287 | /** | 310 | /** |
288 | * struct iwl_lq_cmd - link quality command | 311 | * struct iwl_lq_cmd - link quality command |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index c3782b48ded1..b3ed59237cba 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -530,14 +530,13 @@ struct iwl_scan_offload_schedule { | |||
530 | /* | 530 | /* |
531 | * iwl_scan_offload_flags | 531 | * iwl_scan_offload_flags |
532 | * | 532 | * |
533 | * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match | 533 | * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering. |
534 | * ssid list. | ||
535 | * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. | 534 | * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan. |
536 | * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan | 535 | * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan |
537 | * on A band. | 536 | * on A band. |
538 | */ | 537 | */ |
539 | enum iwl_scan_offload_flags { | 538 | enum iwl_scan_offload_flags { |
540 | IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0), | 539 | IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0), |
541 | IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), | 540 | IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2), |
542 | IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), | 541 | IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3), |
543 | }; | 542 | }; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index f41f9b079831..fb93961da750 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -488,6 +488,40 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, | |||
488 | *ofdm_rates = ofdm; | 488 | *ofdm_rates = ofdm; |
489 | } | 489 | } |
490 | 490 | ||
491 | static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm, | ||
492 | struct ieee80211_vif *vif, | ||
493 | struct iwl_mac_ctx_cmd *cmd) | ||
494 | { | ||
495 | /* for both sta and ap, ht_operation_mode hold the protection_mode */ | ||
496 | u8 protection_mode = vif->bss_conf.ht_operation_mode & | ||
497 | IEEE80211_HT_OP_MODE_PROTECTION; | ||
498 | /* The fw does not distinguish between ht and fat */ | ||
499 | u32 ht_flag = MAC_PROT_FLG_HT_PROT | MAC_PROT_FLG_FAT_PROT; | ||
500 | |||
501 | IWL_DEBUG_RATE(mvm, "protection mode set to %d\n", protection_mode); | ||
502 | /* | ||
503 | * See section 9.23.3.1 of IEEE 80211-2012. | ||
504 | * Nongreenfield HT STAs Present is not supported. | ||
505 | */ | ||
506 | switch (protection_mode) { | ||
507 | case IEEE80211_HT_OP_MODE_PROTECTION_NONE: | ||
508 | break; | ||
509 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | ||
510 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | ||
511 | cmd->protection_flags |= cpu_to_le32(ht_flag); | ||
512 | break; | ||
513 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | ||
514 | /* Protect when channel wider than 20MHz */ | ||
515 | if (vif->bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) | ||
516 | cmd->protection_flags |= cpu_to_le32(ht_flag); | ||
517 | break; | ||
518 | default: | ||
519 | IWL_ERR(mvm, "Illegal protection mode %d\n", | ||
520 | protection_mode); | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | |||
491 | static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | 525 | static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, |
492 | struct ieee80211_vif *vif, | 526 | struct ieee80211_vif *vif, |
493 | struct iwl_mac_ctx_cmd *cmd, | 527 | struct iwl_mac_ctx_cmd *cmd, |
@@ -495,6 +529,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
495 | { | 529 | { |
496 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 530 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
497 | struct ieee80211_chanctx_conf *chanctx; | 531 | struct ieee80211_chanctx_conf *chanctx; |
532 | bool ht_enabled = !!(vif->bss_conf.ht_operation_mode & | ||
533 | IEEE80211_HT_OP_MODE_PROTECTION); | ||
498 | u8 cck_ack_rates, ofdm_ack_rates; | 534 | u8 cck_ack_rates, ofdm_ack_rates; |
499 | int i; | 535 | int i; |
500 | 536 | ||
@@ -573,16 +609,13 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
573 | cmd->protection_flags |= | 609 | cmd->protection_flags |= |
574 | cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); | 610 | cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); |
575 | } | 611 | } |
576 | 612 | IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n", | |
577 | /* | 613 | vif->bss_conf.use_cts_prot, |
578 | * I think that we should enable these 2 flags regardless the HT PROT | 614 | vif->bss_conf.ht_operation_mode); |
579 | * fields in the HT IE, but I am not sure. Someone knows whom to ask?... | 615 | if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
580 | */ | ||
581 | if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | ||
582 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); | 616 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); |
583 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT | | 617 | if (ht_enabled) |
584 | MAC_PROT_FLG_FAT_PROT); | 618 | iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd); |
585 | } | ||
586 | 619 | ||
587 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); | 620 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); |
588 | } | 621 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b56c989ad784..afc4419be46d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -256,7 +256,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
256 | } | 256 | } |
257 | 257 | ||
258 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | 258 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | |
259 | NL80211_FEATURE_P2P_GO_OPPPS; | 259 | NL80211_FEATURE_P2P_GO_OPPPS | |
260 | NL80211_FEATURE_LOW_PRIORITY_SCAN; | ||
260 | 261 | ||
261 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 262 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
262 | 263 | ||
@@ -990,6 +991,17 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, | |||
990 | struct ieee80211_bss_conf *bss_conf, | 991 | struct ieee80211_bss_conf *bss_conf, |
991 | u32 changes) | 992 | u32 changes) |
992 | { | 993 | { |
994 | enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT | | ||
995 | BSS_CHANGED_HT | | ||
996 | BSS_CHANGED_BANDWIDTH; | ||
997 | int ret; | ||
998 | |||
999 | if (changes & ht_change) { | ||
1000 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | ||
1001 | if (ret) | ||
1002 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | ||
1003 | } | ||
1004 | |||
993 | /* Need to send a new beacon template to the FW */ | 1005 | /* Need to send a new beacon template to the FW */ |
994 | if (changes & BSS_CHANGED_BEACON) { | 1006 | if (changes & BSS_CHANGED_BEACON) { |
995 | if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) | 1007 | if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) |
@@ -1080,7 +1092,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
1080 | struct ieee80211_sta *sta) | 1092 | struct ieee80211_sta *sta) |
1081 | { | 1093 | { |
1082 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1094 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1083 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1095 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1084 | 1096 | ||
1085 | switch (cmd) { | 1097 | switch (cmd) { |
1086 | case STA_NOTIFY_SLEEP: | 1098 | case STA_NOTIFY_SLEEP: |
@@ -1149,7 +1161,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
1149 | ret = iwl_mvm_update_sta(mvm, vif, sta); | 1161 | ret = iwl_mvm_update_sta(mvm, vif, sta); |
1150 | if (ret == 0) | 1162 | if (ret == 0) |
1151 | iwl_mvm_rs_rate_init(mvm, sta, | 1163 | iwl_mvm_rs_rate_init(mvm, sta, |
1152 | mvmvif->phy_ctxt->channel->band); | 1164 | mvmvif->phy_ctxt->channel->band, |
1165 | true); | ||
1153 | } else if (old_state == IEEE80211_STA_ASSOC && | 1166 | } else if (old_state == IEEE80211_STA_ASSOC && |
1154 | new_state == IEEE80211_STA_AUTHORIZED) { | 1167 | new_state == IEEE80211_STA_AUTHORIZED) { |
1155 | /* enable beacon filtering */ | 1168 | /* enable beacon filtering */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fed21ef4162d..7dc57cfe5803 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -323,9 +323,9 @@ struct iwl_mvm_vif { | |||
323 | #endif | 323 | #endif |
324 | 324 | ||
325 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 325 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
326 | struct iwl_mvm *mvm; | ||
326 | struct dentry *dbgfs_dir; | 327 | struct dentry *dbgfs_dir; |
327 | struct dentry *dbgfs_slink; | 328 | struct dentry *dbgfs_slink; |
328 | void *dbgfs_data; | ||
329 | struct iwl_dbgfs_pm dbgfs_pm; | 329 | struct iwl_dbgfs_pm dbgfs_pm; |
330 | struct iwl_dbgfs_bf dbgfs_bf; | 330 | struct iwl_dbgfs_bf dbgfs_bf; |
331 | #endif | 331 | #endif |
@@ -494,6 +494,11 @@ struct iwl_mvm { | |||
494 | u32 dbgfs_sram_offset, dbgfs_sram_len; | 494 | u32 dbgfs_sram_offset, dbgfs_sram_len; |
495 | bool disable_power_off; | 495 | bool disable_power_off; |
496 | bool disable_power_off_d3; | 496 | bool disable_power_off_d3; |
497 | |||
498 | struct debugfs_blob_wrapper nvm_hw_blob; | ||
499 | struct debugfs_blob_wrapper nvm_sw_blob; | ||
500 | struct debugfs_blob_wrapper nvm_calib_blob; | ||
501 | struct debugfs_blob_wrapper nvm_prod_blob; | ||
497 | #endif | 502 | #endif |
498 | 503 | ||
499 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; | 504 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; |
@@ -531,6 +536,7 @@ struct iwl_mvm { | |||
531 | bool store_d3_resume_sram; | 536 | bool store_d3_resume_sram; |
532 | void *d3_resume_sram; | 537 | void *d3_resume_sram; |
533 | u32 d3_test_pme_ptr; | 538 | u32 d3_test_pme_ptr; |
539 | struct ieee80211_vif *keep_vif; | ||
534 | #endif | 540 | #endif |
535 | #endif | 541 | #endif |
536 | 542 | ||
@@ -750,8 +756,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
750 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 756 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
751 | 757 | ||
752 | /* rate scaling */ | 758 | /* rate scaling */ |
753 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | 759 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); |
754 | u8 flags, bool init); | ||
755 | 760 | ||
756 | /* power managment */ | 761 | /* power managment */ |
757 | static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, | 762 | static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2beffd028b67..48089b1625ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -443,6 +443,29 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
443 | } | 443 | } |
444 | mvm->nvm_sections[section].data = temp; | 444 | mvm->nvm_sections[section].data = temp; |
445 | mvm->nvm_sections[section].length = ret; | 445 | mvm->nvm_sections[section].length = ret; |
446 | |||
447 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
448 | switch (section) { | ||
449 | case NVM_SECTION_TYPE_HW: | ||
450 | mvm->nvm_hw_blob.data = temp; | ||
451 | mvm->nvm_hw_blob.size = ret; | ||
452 | break; | ||
453 | case NVM_SECTION_TYPE_SW: | ||
454 | mvm->nvm_sw_blob.data = temp; | ||
455 | mvm->nvm_sw_blob.size = ret; | ||
456 | break; | ||
457 | case NVM_SECTION_TYPE_CALIBRATION: | ||
458 | mvm->nvm_calib_blob.data = temp; | ||
459 | mvm->nvm_calib_blob.size = ret; | ||
460 | break; | ||
461 | case NVM_SECTION_TYPE_PRODUCTION: | ||
462 | mvm->nvm_prod_blob.data = temp; | ||
463 | mvm->nvm_prod_blob.size = ret; | ||
464 | break; | ||
465 | default: | ||
466 | WARN(1, "section: %d", section); | ||
467 | } | ||
468 | #endif | ||
446 | } | 469 | } |
447 | kfree(nvm_buffer); | 470 | kfree(nvm_buffer); |
448 | if (ret < 0) | 471 | if (ret < 0) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 17e2bc827f9a..38165eba2a17 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -217,8 +217,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
217 | } else { | 217 | } else { |
218 | cmd.quotas[idx].quota = | 218 | cmd.quotas[idx].quota = |
219 | cpu_to_le32(quota * data.n_interfaces[i]); | 219 | cpu_to_le32(quota * data.n_interfaces[i]); |
220 | cmd.quotas[idx].max_duration = | 220 | cmd.quotas[idx].max_duration = cpu_to_le32(0); |
221 | cpu_to_le32(IWL_MVM_MAX_QUOTA); | ||
222 | } | 221 | } |
223 | idx++; | 222 | idx++; |
224 | } | 223 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a0b4cc8d9c3b..bf6e29f5b4d0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -47,28 +47,25 @@ | |||
47 | #define IWL_HT_NUMBER_TRY 3 | 47 | #define IWL_HT_NUMBER_TRY 3 |
48 | 48 | ||
49 | #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ | 49 | #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ |
50 | #define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ | 50 | #define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */ |
51 | #define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ | 51 | #define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ |
52 | 52 | ||
53 | /* max allowed rate miss before sync LQ cmd */ | 53 | /* max allowed rate miss before sync LQ cmd */ |
54 | #define IWL_MISSED_RATE_MAX 15 | 54 | #define IWL_MISSED_RATE_MAX 15 |
55 | /* max time to accum history 2 seconds */ | 55 | #define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ) |
56 | #define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) | 56 | |
57 | 57 | ||
58 | static u8 rs_ht_to_legacy[] = { | 58 | static u8 rs_ht_to_legacy[] = { |
59 | [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX, | 59 | [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, |
60 | [IWL_RATE_2M_INDEX] = IWL_RATE_6M_INDEX, | 60 | [IWL_RATE_MCS_1_INDEX] = IWL_RATE_9M_INDEX, |
61 | [IWL_RATE_5M_INDEX] = IWL_RATE_6M_INDEX, | 61 | [IWL_RATE_MCS_2_INDEX] = IWL_RATE_12M_INDEX, |
62 | [IWL_RATE_11M_INDEX] = IWL_RATE_6M_INDEX, | 62 | [IWL_RATE_MCS_3_INDEX] = IWL_RATE_18M_INDEX, |
63 | [IWL_RATE_6M_INDEX] = IWL_RATE_6M_INDEX, | 63 | [IWL_RATE_MCS_4_INDEX] = IWL_RATE_24M_INDEX, |
64 | [IWL_RATE_9M_INDEX] = IWL_RATE_6M_INDEX, | 64 | [IWL_RATE_MCS_5_INDEX] = IWL_RATE_36M_INDEX, |
65 | [IWL_RATE_12M_INDEX] = IWL_RATE_9M_INDEX, | 65 | [IWL_RATE_MCS_6_INDEX] = IWL_RATE_48M_INDEX, |
66 | [IWL_RATE_18M_INDEX] = IWL_RATE_12M_INDEX, | 66 | [IWL_RATE_MCS_7_INDEX] = IWL_RATE_54M_INDEX, |
67 | [IWL_RATE_24M_INDEX] = IWL_RATE_18M_INDEX, | 67 | [IWL_RATE_MCS_8_INDEX] = IWL_RATE_54M_INDEX, |
68 | [IWL_RATE_36M_INDEX] = IWL_RATE_24M_INDEX, | 68 | [IWL_RATE_MCS_9_INDEX] = IWL_RATE_54M_INDEX, |
69 | [IWL_RATE_48M_INDEX] = IWL_RATE_36M_INDEX, | ||
70 | [IWL_RATE_54M_INDEX] = IWL_RATE_48M_INDEX, | ||
71 | [IWL_RATE_60M_INDEX] = IWL_RATE_54M_INDEX, | ||
72 | }; | 69 | }; |
73 | 70 | ||
74 | static const u8 ant_toggle_lookup[] = { | 71 | static const u8 ant_toggle_lookup[] = { |
@@ -126,6 +123,190 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { | |||
126 | IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ | 123 | IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ |
127 | }; | 124 | }; |
128 | 125 | ||
126 | enum 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 | |||
136 | typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm, | ||
137 | struct ieee80211_sta *sta, | ||
138 | struct iwl_scale_tbl_info *tbl); | ||
139 | |||
140 | struct 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 | |||
148 | static 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 | |||
166 | static 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 | |||
175 | static 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 | |||
195 | static 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 | |||
129 | static inline u8 rs_extract_rate(u32 rate_n_flags) | 310 | static inline u8 rs_extract_rate(u32 rate_n_flags) |
130 | { | 311 | { |
131 | /* also works for HT because bits 7:6 are zero there */ | 312 | /* also works for HT because bits 7:6 are zero there */ |
@@ -175,7 +356,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
175 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); | 356 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); |
176 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); | 357 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); |
177 | 358 | ||
178 | |||
179 | #ifdef CONFIG_MAC80211_DEBUGFS | 359 | #ifdef CONFIG_MAC80211_DEBUGFS |
180 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | 360 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, |
181 | u32 *rate_n_flags); | 361 | u32 *rate_n_flags); |
@@ -264,6 +444,52 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | |||
264 | 444 | ||
265 | #define MCS_INDEX_PER_STREAM (8) | 445 | #define MCS_INDEX_PER_STREAM (8) |
266 | 446 | ||
447 | static const char *rs_pretty_ant(u8 ant) | ||
448 | { | ||
449 | static const char * const ant_name[] = { | ||
450 | [ANT_NONE] = "None", | ||
451 | [ANT_A] = "A", | ||
452 | [ANT_B] = "B", | ||
453 | [ANT_AB] = "AB", | ||
454 | [ANT_C] = "C", | ||
455 | [ANT_AC] = "AC", | ||
456 | [ANT_BC] = "BC", | ||
457 | [ANT_ABC] = "ABC", | ||
458 | }; | ||
459 | |||
460 | if (ant > ANT_ABC) | ||
461 | return "UNKNOWN"; | ||
462 | |||
463 | return ant_name[ant]; | ||
464 | } | ||
465 | |||
466 | static const char *rs_pretty_lq_type(enum iwl_table_type type) | ||
467 | { | ||
468 | static const char * const lq_types[] = { | ||
469 | [LQ_NONE] = "NONE", | ||
470 | [LQ_LEGACY_A] = "LEGACY_A", | ||
471 | [LQ_LEGACY_G] = "LEGACY_G", | ||
472 | [LQ_HT_SISO] = "HT SISO", | ||
473 | [LQ_HT_MIMO2] = "HT MIMO", | ||
474 | [LQ_VHT_SISO] = "VHT SISO", | ||
475 | [LQ_VHT_MIMO2] = "VHT MIMO", | ||
476 | }; | ||
477 | |||
478 | if (type < LQ_NONE || type >= LQ_MAX) | ||
479 | return "UNKNOWN"; | ||
480 | |||
481 | return lq_types[type]; | ||
482 | } | ||
483 | |||
484 | static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, | ||
485 | const char *prefix) | ||
486 | { | ||
487 | IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", | ||
488 | prefix, rs_pretty_lq_type(rate->type), | ||
489 | rate->index, rs_pretty_ant(rate->ant), | ||
490 | rate->bw, rate->sgi); | ||
491 | } | ||
492 | |||
267 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | 493 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) |
268 | { | 494 | { |
269 | window->data = 0; | 495 | window->data = 0; |
@@ -271,7 +497,6 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | |||
271 | window->success_ratio = IWL_INVALID_VALUE; | 497 | window->success_ratio = IWL_INVALID_VALUE; |
272 | window->counter = 0; | 498 | window->counter = 0; |
273 | window->average_tpt = IWL_INVALID_VALUE; | 499 | window->average_tpt = IWL_INVALID_VALUE; |
274 | window->stamp = 0; | ||
275 | } | 500 | } |
276 | 501 | ||
277 | static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) | 502 | static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) |
@@ -298,7 +523,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
298 | 523 | ||
299 | if (lq_sta->dbg_fixed_rate) { | 524 | if (lq_sta->dbg_fixed_rate) { |
300 | rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate); | 525 | rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate); |
301 | iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); | 526 | iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false); |
302 | } | 527 | } |
303 | } | 528 | } |
304 | #endif | 529 | #endif |
@@ -428,192 +653,174 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | |||
428 | else | 653 | else |
429 | window->average_tpt = IWL_INVALID_VALUE; | 654 | window->average_tpt = IWL_INVALID_VALUE; |
430 | 655 | ||
431 | /* Tag this window as having been updated */ | ||
432 | window->stamp = jiffies; | ||
433 | |||
434 | return 0; | 656 | return 0; |
435 | } | 657 | } |
436 | 658 | ||
437 | /* | 659 | /* Convert rs_rate object into ucode rate bitmask */ |
438 | * Fill uCode API rate_n_flags field, based on "search" or "active" table. | 660 | static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, |
439 | */ | 661 | struct rs_rate *rate) |
440 | /* FIXME:RS:remove this function and put the flags statically in the table */ | ||
441 | static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, | ||
442 | struct iwl_scale_tbl_info *tbl, int index) | ||
443 | { | 662 | { |
444 | u32 rate_n_flags = 0; | 663 | u32 ucode_rate = 0; |
664 | int index = rate->index; | ||
445 | 665 | ||
446 | rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & | 666 | ucode_rate |= ((rate->ant << RATE_MCS_ANT_POS) & |
447 | RATE_MCS_ANT_ABC_MSK); | 667 | RATE_MCS_ANT_ABC_MSK); |
448 | 668 | ||
449 | if (is_legacy(tbl->lq_type)) { | 669 | if (is_legacy(rate)) { |
450 | rate_n_flags |= iwl_rates[index].plcp; | 670 | ucode_rate |= iwl_rates[index].plcp; |
451 | if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) | 671 | if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) |
452 | rate_n_flags |= RATE_MCS_CCK_MSK; | 672 | ucode_rate |= RATE_MCS_CCK_MSK; |
453 | return rate_n_flags; | 673 | return ucode_rate; |
454 | } | 674 | } |
455 | 675 | ||
456 | if (is_ht(tbl->lq_type)) { | 676 | if (is_ht(rate)) { |
457 | if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) { | 677 | if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) { |
458 | IWL_ERR(mvm, "Invalid HT rate index %d\n", index); | 678 | IWL_ERR(mvm, "Invalid HT rate index %d\n", index); |
459 | index = IWL_LAST_HT_RATE; | 679 | index = IWL_LAST_HT_RATE; |
460 | } | 680 | } |
461 | rate_n_flags |= RATE_MCS_HT_MSK; | 681 | ucode_rate |= RATE_MCS_HT_MSK; |
462 | 682 | ||
463 | if (is_ht_siso(tbl->lq_type)) | 683 | if (is_ht_siso(rate)) |
464 | rate_n_flags |= iwl_rates[index].plcp_ht_siso; | 684 | ucode_rate |= iwl_rates[index].plcp_ht_siso; |
465 | else if (is_ht_mimo2(tbl->lq_type)) | 685 | else if (is_ht_mimo2(rate)) |
466 | rate_n_flags |= iwl_rates[index].plcp_ht_mimo2; | 686 | ucode_rate |= iwl_rates[index].plcp_ht_mimo2; |
467 | else | 687 | else |
468 | WARN_ON_ONCE(1); | 688 | WARN_ON_ONCE(1); |
469 | } else if (is_vht(tbl->lq_type)) { | 689 | } else if (is_vht(rate)) { |
470 | if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) { | 690 | if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) { |
471 | IWL_ERR(mvm, "Invalid VHT rate index %d\n", index); | 691 | IWL_ERR(mvm, "Invalid VHT rate index %d\n", index); |
472 | index = IWL_LAST_VHT_RATE; | 692 | index = IWL_LAST_VHT_RATE; |
473 | } | 693 | } |
474 | rate_n_flags |= RATE_MCS_VHT_MSK; | 694 | ucode_rate |= RATE_MCS_VHT_MSK; |
475 | if (is_vht_siso(tbl->lq_type)) | 695 | if (is_vht_siso(rate)) |
476 | rate_n_flags |= iwl_rates[index].plcp_vht_siso; | 696 | ucode_rate |= iwl_rates[index].plcp_vht_siso; |
477 | else if (is_vht_mimo2(tbl->lq_type)) | 697 | else if (is_vht_mimo2(rate)) |
478 | rate_n_flags |= iwl_rates[index].plcp_vht_mimo2; | 698 | ucode_rate |= iwl_rates[index].plcp_vht_mimo2; |
479 | else | 699 | else |
480 | WARN_ON_ONCE(1); | 700 | WARN_ON_ONCE(1); |
481 | 701 | ||
482 | } else { | 702 | } else { |
483 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); | 703 | IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); |
484 | } | 704 | } |
485 | 705 | ||
486 | rate_n_flags |= tbl->bw; | 706 | ucode_rate |= rate->bw; |
487 | if (tbl->is_SGI) | 707 | if (rate->sgi) |
488 | rate_n_flags |= RATE_MCS_SGI_MSK; | 708 | ucode_rate |= RATE_MCS_SGI_MSK; |
489 | 709 | ||
490 | return rate_n_flags; | 710 | return ucode_rate; |
491 | } | 711 | } |
492 | 712 | ||
493 | /* | 713 | /* Convert a ucode rate into an rs_rate object */ |
494 | * Interpret uCode API's rate_n_flags format, | 714 | static int rs_rate_from_ucode_rate(const u32 ucode_rate, |
495 | * fill "search" or "active" tx mode table. | 715 | enum ieee80211_band band, |
496 | */ | 716 | struct rs_rate *rate) |
497 | static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | ||
498 | enum ieee80211_band band, | ||
499 | struct iwl_scale_tbl_info *tbl, | ||
500 | int *rate_idx) | ||
501 | { | 717 | { |
502 | u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); | 718 | u32 ant_msk = ucode_rate & RATE_MCS_ANT_ABC_MSK; |
503 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); | 719 | u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate); |
504 | u8 nss; | 720 | u8 nss; |
505 | 721 | ||
506 | memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); | 722 | memset(rate, 0, sizeof(struct rs_rate)); |
507 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | 723 | rate->index = iwl_hwrate_to_plcp_idx(ucode_rate); |
508 | 724 | ||
509 | if (*rate_idx == IWL_RATE_INVALID) { | 725 | if (rate->index == IWL_RATE_INVALID) { |
510 | *rate_idx = -1; | 726 | rate->index = -1; |
511 | return -EINVAL; | 727 | return -EINVAL; |
512 | } | 728 | } |
513 | tbl->is_SGI = 0; /* default legacy setup */ | 729 | |
514 | tbl->bw = 0; | 730 | rate->ant = (ant_msk >> RATE_MCS_ANT_POS); |
515 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); | ||
516 | tbl->lq_type = LQ_NONE; | ||
517 | tbl->max_search = IWL_MAX_SEARCH; | ||
518 | 731 | ||
519 | /* Legacy */ | 732 | /* Legacy */ |
520 | if (!(rate_n_flags & RATE_MCS_HT_MSK) && | 733 | if (!(ucode_rate & RATE_MCS_HT_MSK) && |
521 | !(rate_n_flags & RATE_MCS_VHT_MSK)) { | 734 | !(ucode_rate & RATE_MCS_VHT_MSK)) { |
522 | if (num_of_ant == 1) { | 735 | if (num_of_ant == 1) { |
523 | if (band == IEEE80211_BAND_5GHZ) | 736 | if (band == IEEE80211_BAND_5GHZ) |
524 | tbl->lq_type = LQ_LEGACY_A; | 737 | rate->type = LQ_LEGACY_A; |
525 | else | 738 | else |
526 | tbl->lq_type = LQ_LEGACY_G; | 739 | rate->type = LQ_LEGACY_G; |
527 | } | 740 | } |
528 | 741 | ||
529 | return 0; | 742 | return 0; |
530 | } | 743 | } |
531 | 744 | ||
532 | /* HT or VHT */ | 745 | /* HT or VHT */ |
533 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 746 | if (ucode_rate & RATE_MCS_SGI_MSK) |
534 | tbl->is_SGI = 1; | 747 | rate->sgi = true; |
535 | 748 | ||
536 | tbl->bw = rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; | 749 | rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; |
537 | 750 | ||
538 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 751 | if (ucode_rate & RATE_MCS_HT_MSK) { |
539 | nss = ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >> | 752 | nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK) >> |
540 | RATE_HT_MCS_NSS_POS) + 1; | 753 | RATE_HT_MCS_NSS_POS) + 1; |
541 | 754 | ||
542 | if (nss == 1) { | 755 | if (nss == 1) { |
543 | tbl->lq_type = LQ_HT_SISO; | 756 | rate->type = LQ_HT_SISO; |
544 | WARN_ON_ONCE(num_of_ant != 1); | 757 | WARN_ON_ONCE(num_of_ant != 1); |
545 | } else if (nss == 2) { | 758 | } else if (nss == 2) { |
546 | tbl->lq_type = LQ_HT_MIMO2; | 759 | rate->type = LQ_HT_MIMO2; |
547 | WARN_ON_ONCE(num_of_ant != 2); | 760 | WARN_ON_ONCE(num_of_ant != 2); |
548 | } else { | 761 | } else { |
549 | WARN_ON_ONCE(1); | 762 | WARN_ON_ONCE(1); |
550 | } | 763 | } |
551 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | 764 | } else if (ucode_rate & RATE_MCS_VHT_MSK) { |
552 | nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | 765 | nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >> |
553 | RATE_VHT_MCS_NSS_POS) + 1; | 766 | RATE_VHT_MCS_NSS_POS) + 1; |
554 | 767 | ||
555 | if (nss == 1) { | 768 | if (nss == 1) { |
556 | tbl->lq_type = LQ_VHT_SISO; | 769 | rate->type = LQ_VHT_SISO; |
557 | WARN_ON_ONCE(num_of_ant != 1); | 770 | WARN_ON_ONCE(num_of_ant != 1); |
558 | } else if (nss == 2) { | 771 | } else if (nss == 2) { |
559 | tbl->lq_type = LQ_VHT_MIMO2; | 772 | rate->type = LQ_VHT_MIMO2; |
560 | WARN_ON_ONCE(num_of_ant != 2); | 773 | WARN_ON_ONCE(num_of_ant != 2); |
561 | } else { | 774 | } else { |
562 | WARN_ON_ONCE(1); | 775 | WARN_ON_ONCE(1); |
563 | } | 776 | } |
564 | } | 777 | } |
565 | 778 | ||
566 | WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_160); | 779 | WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_160); |
567 | WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_80 && | 780 | WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 && |
568 | !is_vht(tbl->lq_type)); | 781 | !is_vht(rate)); |
569 | 782 | ||
570 | return 0; | 783 | return 0; |
571 | } | 784 | } |
572 | 785 | ||
573 | /* switch to another antenna/antennas and return 1 */ | 786 | /* switch to another antenna/antennas and return 1 */ |
574 | /* if no other valid antenna found, return 0 */ | 787 | /* if no other valid antenna found, return 0 */ |
575 | static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, | 788 | static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate, |
576 | struct iwl_scale_tbl_info *tbl) | 789 | struct rs_rate *rate) |
577 | { | 790 | { |
578 | u8 new_ant_type; | 791 | u8 new_ant_type; |
579 | 792 | ||
580 | if (!tbl->ant_type || tbl->ant_type > ANT_ABC) | 793 | if (!rate->ant || rate->ant > ANT_ABC) |
581 | return 0; | 794 | return 0; |
582 | 795 | ||
583 | if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) | 796 | if (!rs_is_valid_ant(valid_ant, rate->ant)) |
584 | return 0; | 797 | return 0; |
585 | 798 | ||
586 | new_ant_type = ant_toggle_lookup[tbl->ant_type]; | 799 | new_ant_type = ant_toggle_lookup[rate->ant]; |
587 | 800 | ||
588 | while ((new_ant_type != tbl->ant_type) && | 801 | while ((new_ant_type != rate->ant) && |
589 | !rs_is_valid_ant(valid_ant, new_ant_type)) | 802 | !rs_is_valid_ant(valid_ant, new_ant_type)) |
590 | new_ant_type = ant_toggle_lookup[new_ant_type]; | 803 | new_ant_type = ant_toggle_lookup[new_ant_type]; |
591 | 804 | ||
592 | if (new_ant_type == tbl->ant_type) | 805 | if (new_ant_type == rate->ant) |
593 | return 0; | 806 | return 0; |
594 | 807 | ||
595 | tbl->ant_type = new_ant_type; | 808 | rate->ant = new_ant_type; |
596 | *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; | 809 | |
597 | *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; | 810 | /* TODO: get rid of ucode_rate here. This should handle only rs_rate */ |
811 | *ucode_rate &= ~RATE_MCS_ANT_ABC_MSK; | ||
812 | *ucode_rate |= new_ant_type << RATE_MCS_ANT_POS; | ||
598 | return 1; | 813 | return 1; |
599 | } | 814 | } |
600 | 815 | ||
601 | /** | ||
602 | * rs_get_supported_rates - get the available rates | ||
603 | * | ||
604 | * if management frame or broadcast frame only return | ||
605 | * basic available rates. | ||
606 | * | ||
607 | */ | ||
608 | static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, | 816 | static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, |
609 | struct ieee80211_hdr *hdr, | 817 | struct rs_rate *rate) |
610 | enum iwl_table_type rate_type) | ||
611 | { | 818 | { |
612 | if (is_legacy(rate_type)) | 819 | if (is_legacy(rate)) |
613 | return lq_sta->active_legacy_rate; | 820 | return lq_sta->active_legacy_rate; |
614 | else if (is_siso(rate_type)) | 821 | else if (is_siso(rate)) |
615 | return lq_sta->active_siso_rate; | 822 | return lq_sta->active_siso_rate; |
616 | else if (is_mimo2(rate_type)) | 823 | else if (is_mimo2(rate)) |
617 | return lq_sta->active_mimo2_rate; | 824 | return lq_sta->active_mimo2_rate; |
618 | 825 | ||
619 | WARN_ON_ONCE(1); | 826 | WARN_ON_ONCE(1); |
@@ -628,7 +835,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, | |||
628 | 835 | ||
629 | /* 802.11A or ht walks to the next literal adjacent rate in | 836 | /* 802.11A or ht walks to the next literal adjacent rate in |
630 | * the rate table */ | 837 | * the rate table */ |
631 | if (is_a_band(rate_type) || !is_legacy(rate_type)) { | 838 | if (is_type_a_band(rate_type) || !is_type_legacy(rate_type)) { |
632 | int i; | 839 | int i; |
633 | u32 mask; | 840 | u32 mask; |
634 | 841 | ||
@@ -677,7 +884,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, | |||
677 | } | 884 | } |
678 | 885 | ||
679 | static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | 886 | static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, |
680 | struct iwl_scale_tbl_info *tbl, | 887 | struct rs_rate *rate, |
681 | u8 scale_index, u8 ht_possible) | 888 | u8 scale_index, u8 ht_possible) |
682 | { | 889 | { |
683 | s32 low; | 890 | s32 low; |
@@ -689,30 +896,31 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
689 | /* check if we need to switch from HT to legacy rates. | 896 | /* check if we need to switch from HT to legacy rates. |
690 | * assumption is that mandatory rates (1Mbps or 6Mbps) | 897 | * assumption is that mandatory rates (1Mbps or 6Mbps) |
691 | * are always supported (spec demand) */ | 898 | * are always supported (spec demand) */ |
692 | if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { | 899 | if (!is_legacy(rate) && (!ht_possible || !scale_index)) { |
693 | switch_to_legacy = 1; | 900 | switch_to_legacy = 1; |
901 | WARN_ON_ONCE(scale_index < IWL_RATE_MCS_0_INDEX && | ||
902 | scale_index > IWL_RATE_MCS_9_INDEX); | ||
694 | scale_index = rs_ht_to_legacy[scale_index]; | 903 | scale_index = rs_ht_to_legacy[scale_index]; |
695 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | 904 | if (lq_sta->band == IEEE80211_BAND_5GHZ) |
696 | tbl->lq_type = LQ_LEGACY_A; | 905 | rate->type = LQ_LEGACY_A; |
697 | else | 906 | else |
698 | tbl->lq_type = LQ_LEGACY_G; | 907 | rate->type = LQ_LEGACY_G; |
699 | 908 | ||
700 | if (num_of_ant(tbl->ant_type) > 1) | 909 | if (num_of_ant(rate->ant) > 1) |
701 | tbl->ant_type = | 910 | rate->ant = |
702 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | 911 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
703 | 912 | ||
704 | tbl->bw = 0; | 913 | rate->bw = RATE_MCS_CHAN_WIDTH_20; |
705 | tbl->is_SGI = 0; | 914 | rate->sgi = false; |
706 | tbl->max_search = IWL_MAX_SEARCH; | ||
707 | } | 915 | } |
708 | 916 | ||
709 | rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); | 917 | rate_mask = rs_get_supported_rates(lq_sta, rate); |
710 | 918 | ||
711 | /* Mask with station rate restriction */ | 919 | /* Mask with station rate restriction */ |
712 | if (is_legacy(tbl->lq_type)) { | 920 | if (is_legacy(rate)) { |
713 | /* supp_rates has no CCK bits in A mode */ | 921 | /* supp_rates has no CCK bits in A mode */ |
714 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | 922 | if (lq_sta->band == IEEE80211_BAND_5GHZ) |
715 | rate_mask = (u16)(rate_mask & | 923 | rate_mask = (u16)(rate_mask & |
716 | (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); | 924 | (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); |
717 | else | 925 | else |
718 | rate_mask = (u16)(rate_mask & lq_sta->supp_rates); | 926 | rate_mask = (u16)(rate_mask & lq_sta->supp_rates); |
@@ -725,24 +933,22 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
725 | } | 933 | } |
726 | 934 | ||
727 | high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, | 935 | high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, |
728 | tbl->lq_type); | 936 | rate->type); |
729 | low = high_low & 0xff; | 937 | low = high_low & 0xff; |
730 | 938 | ||
731 | if (low == IWL_RATE_INVALID) | 939 | if (low == IWL_RATE_INVALID) |
732 | low = scale_index; | 940 | low = scale_index; |
733 | 941 | ||
734 | out: | 942 | out: |
735 | return rate_n_flags_from_tbl(lq_sta->drv, tbl, low); | 943 | rate->index = low; |
944 | return ucode_rate_from_rs_rate(lq_sta->drv, rate); | ||
736 | } | 945 | } |
737 | 946 | ||
738 | /* | 947 | /* Simple function to compare two rate scale table types */ |
739 | * Simple function to compare two rate scale table types | 948 | static inline bool rs_rate_match(struct rs_rate *a, |
740 | */ | 949 | struct rs_rate *b) |
741 | static bool table_type_matches(struct iwl_scale_tbl_info *a, | ||
742 | struct iwl_scale_tbl_info *b) | ||
743 | { | 950 | { |
744 | return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && | 951 | return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi); |
745 | (a->is_SGI == b->is_SGI); | ||
746 | } | 952 | } |
747 | 953 | ||
748 | static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) | 954 | static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) |
@@ -766,7 +972,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
766 | { | 972 | { |
767 | int legacy_success; | 973 | int legacy_success; |
768 | int retries; | 974 | int retries; |
769 | int rs_index, mac_index, i; | 975 | int mac_index, i; |
770 | struct iwl_lq_sta *lq_sta = priv_sta; | 976 | struct iwl_lq_sta *lq_sta = priv_sta; |
771 | struct iwl_lq_cmd *table; | 977 | struct iwl_lq_cmd *table; |
772 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 978 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
@@ -774,13 +980,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
774 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 980 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
775 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 981 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
776 | enum mac80211_rate_control_flags mac_flags; | 982 | enum mac80211_rate_control_flags mac_flags; |
777 | u32 tx_rate; | 983 | u32 ucode_rate; |
778 | struct iwl_scale_tbl_info tbl_type; | 984 | struct rs_rate rate; |
779 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; | 985 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; |
780 | 986 | ||
781 | IWL_DEBUG_RATE_LIMIT(mvm, | ||
782 | "get frame ack response, update rate scale window\n"); | ||
783 | |||
784 | /* Treat uninitialized rate scaling data same as non-existing. */ | 987 | /* Treat uninitialized rate scaling data same as non-existing. */ |
785 | if (!lq_sta) { | 988 | if (!lq_sta) { |
786 | IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); | 989 | IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); |
@@ -808,10 +1011,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
808 | * to a new "search" mode (which might become the new "active" mode). | 1011 | * to a new "search" mode (which might become the new "active" mode). |
809 | */ | 1012 | */ |
810 | table = &lq_sta->lq; | 1013 | table = &lq_sta->lq; |
811 | tx_rate = le32_to_cpu(table->rs_table[0]); | 1014 | ucode_rate = le32_to_cpu(table->rs_table[0]); |
812 | rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index); | 1015 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); |
813 | if (info->band == IEEE80211_BAND_5GHZ) | 1016 | if (info->band == IEEE80211_BAND_5GHZ) |
814 | rs_index -= IWL_FIRST_OFDM_RATE; | 1017 | rate.index -= IWL_FIRST_OFDM_RATE; |
815 | mac_flags = info->status.rates[0].flags; | 1018 | mac_flags = info->status.rates[0].flags; |
816 | mac_index = info->status.rates[0].idx; | 1019 | mac_index = info->status.rates[0].idx; |
817 | /* For HT packets, map MCS to PLCP */ | 1020 | /* For HT packets, map MCS to PLCP */ |
@@ -834,19 +1037,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
834 | 1037 | ||
835 | /* Here we actually compare this rate to the latest LQ command */ | 1038 | /* Here we actually compare this rate to the latest LQ command */ |
836 | if ((mac_index < 0) || | 1039 | if ((mac_index < 0) || |
837 | (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || | 1040 | (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || |
838 | (tbl_type.bw != rs_ch_width_from_mac_flags(mac_flags)) || | 1041 | (rate.bw != rs_ch_width_from_mac_flags(mac_flags)) || |
839 | (tbl_type.ant_type != info->status.antenna) || | 1042 | (rate.ant != info->status.antenna) || |
840 | (!!(tx_rate & RATE_MCS_HT_MSK) != | 1043 | (!!(ucode_rate & RATE_MCS_HT_MSK) != |
841 | !!(mac_flags & IEEE80211_TX_RC_MCS)) || | 1044 | !!(mac_flags & IEEE80211_TX_RC_MCS)) || |
842 | (!!(tx_rate & RATE_MCS_VHT_MSK) != | 1045 | (!!(ucode_rate & RATE_MCS_VHT_MSK) != |
843 | !!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) || | 1046 | !!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) || |
844 | (!!(tx_rate & RATE_HT_MCS_GF_MSK) != | 1047 | (!!(ucode_rate & RATE_HT_MCS_GF_MSK) != |
845 | !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || | 1048 | !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || |
846 | (rs_index != mac_index)) { | 1049 | (rate.index != mac_index)) { |
847 | IWL_DEBUG_RATE(mvm, | 1050 | IWL_DEBUG_RATE(mvm, |
848 | "initial rate %d does not match %d (0x%x)\n", | 1051 | "initial rate %d does not match %d (0x%x)\n", |
849 | mac_index, rs_index, tx_rate); | 1052 | mac_index, rate.index, ucode_rate); |
850 | /* | 1053 | /* |
851 | * Since rates mis-match, the last LQ command may have failed. | 1054 | * Since rates mis-match, the last LQ command may have failed. |
852 | * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with | 1055 | * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with |
@@ -855,7 +1058,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
855 | lq_sta->missed_rate_counter++; | 1058 | lq_sta->missed_rate_counter++; |
856 | if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { | 1059 | if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { |
857 | lq_sta->missed_rate_counter = 0; | 1060 | lq_sta->missed_rate_counter = 0; |
858 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | 1061 | IWL_DEBUG_RATE(mvm, |
1062 | "Too many rates mismatch. Send sync LQ. rs_state %d\n", | ||
1063 | lq_sta->rs_state); | ||
1064 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); | ||
859 | } | 1065 | } |
860 | /* Regardless, ignore this status info for outdated rate */ | 1066 | /* Regardless, ignore this status info for outdated rate */ |
861 | return; | 1067 | return; |
@@ -864,28 +1070,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
864 | lq_sta->missed_rate_counter = 0; | 1070 | lq_sta->missed_rate_counter = 0; |
865 | 1071 | ||
866 | /* Figure out if rate scale algorithm is in active or search table */ | 1072 | /* Figure out if rate scale algorithm is in active or search table */ |
867 | if (table_type_matches(&tbl_type, | 1073 | if (rs_rate_match(&rate, |
868 | &(lq_sta->lq_info[lq_sta->active_tbl]))) { | 1074 | &(lq_sta->lq_info[lq_sta->active_tbl].rate))) { |
869 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1075 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
870 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1076 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
871 | } else if (table_type_matches( | 1077 | } else if (rs_rate_match(&rate, |
872 | &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) { | 1078 | &lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) { |
873 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1079 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
874 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1080 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
875 | } else { | 1081 | } else { |
876 | IWL_DEBUG_RATE(mvm, | 1082 | IWL_DEBUG_RATE(mvm, |
877 | "Neither active nor search matches tx rate\n"); | 1083 | "Neither active nor search matches tx rate\n"); |
878 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1084 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
879 | IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n", | 1085 | rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); |
880 | tmp_tbl->lq_type, tmp_tbl->ant_type, | ||
881 | tmp_tbl->is_SGI); | ||
882 | tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1086 | tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
883 | IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n", | 1087 | rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); |
884 | tmp_tbl->lq_type, tmp_tbl->ant_type, | 1088 | rs_dump_rate(mvm, &rate, "ACTUAL"); |
885 | tmp_tbl->is_SGI); | 1089 | |
886 | IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n", | ||
887 | tbl_type.lq_type, tbl_type.ant_type, | ||
888 | tbl_type.is_SGI); | ||
889 | /* | 1090 | /* |
890 | * no matching table found, let's by-pass the data collection | 1091 | * no matching table found, let's by-pass the data collection |
891 | * and continue to perform rate scale to find the rate table | 1092 | * and continue to perform rate scale to find the rate table |
@@ -902,15 +1103,14 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
902 | * first index into rate scale table. | 1103 | * first index into rate scale table. |
903 | */ | 1104 | */ |
904 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | 1105 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { |
905 | tx_rate = le32_to_cpu(table->rs_table[0]); | 1106 | ucode_rate = le32_to_cpu(table->rs_table[0]); |
906 | rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, | 1107 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); |
907 | &rs_index); | 1108 | rs_collect_tx_data(curr_tbl, rate.index, |
908 | rs_collect_tx_data(curr_tbl, rs_index, | ||
909 | info->status.ampdu_len, | 1109 | info->status.ampdu_len, |
910 | info->status.ampdu_ack_len); | 1110 | info->status.ampdu_ack_len); |
911 | 1111 | ||
912 | /* Update success/fail counts if not searching for new mode */ | 1112 | /* Update success/fail counts if not searching for new mode */ |
913 | if (lq_sta->stay_in_tbl) { | 1113 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { |
914 | lq_sta->total_success += info->status.ampdu_ack_len; | 1114 | lq_sta->total_success += info->status.ampdu_ack_len; |
915 | lq_sta->total_failed += (info->status.ampdu_len - | 1115 | lq_sta->total_failed += (info->status.ampdu_len - |
916 | info->status.ampdu_ack_len); | 1116 | info->status.ampdu_ack_len); |
@@ -927,31 +1127,36 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
927 | legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); | 1127 | legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); |
928 | /* Collect data for each rate used during failed TX attempts */ | 1128 | /* Collect data for each rate used during failed TX attempts */ |
929 | for (i = 0; i <= retries; ++i) { | 1129 | for (i = 0; i <= retries; ++i) { |
930 | tx_rate = le32_to_cpu(table->rs_table[i]); | 1130 | ucode_rate = le32_to_cpu(table->rs_table[i]); |
931 | rs_get_tbl_info_from_mcs(tx_rate, info->band, | 1131 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); |
932 | &tbl_type, &rs_index); | ||
933 | /* | 1132 | /* |
934 | * Only collect stats if retried rate is in the same RS | 1133 | * Only collect stats if retried rate is in the same RS |
935 | * table as active/search. | 1134 | * table as active/search. |
936 | */ | 1135 | */ |
937 | if (table_type_matches(&tbl_type, curr_tbl)) | 1136 | if (rs_rate_match(&rate, &curr_tbl->rate)) |
938 | tmp_tbl = curr_tbl; | 1137 | tmp_tbl = curr_tbl; |
939 | else if (table_type_matches(&tbl_type, other_tbl)) | 1138 | else if (rs_rate_match(&rate, &other_tbl->rate)) |
940 | tmp_tbl = other_tbl; | 1139 | tmp_tbl = other_tbl; |
941 | else | 1140 | else { |
1141 | IWL_DEBUG_RATE(mvm, | ||
1142 | "Tx packet rate doesn't match ACTIVE or SEARCH tables\n"); | ||
1143 | rs_dump_rate(mvm, &rate, "Tx PACKET:"); | ||
1144 | rs_dump_rate(mvm, &curr_tbl->rate, "CURRENT:"); | ||
1145 | rs_dump_rate(mvm, &other_tbl->rate, "OTHER:"); | ||
942 | continue; | 1146 | continue; |
943 | rs_collect_tx_data(tmp_tbl, rs_index, 1, | 1147 | } |
1148 | rs_collect_tx_data(tmp_tbl, rate.index, 1, | ||
944 | i < retries ? 0 : legacy_success); | 1149 | i < retries ? 0 : legacy_success); |
945 | } | 1150 | } |
946 | 1151 | ||
947 | /* Update success/fail counts if not searching for new mode */ | 1152 | /* Update success/fail counts if not searching for new mode */ |
948 | if (lq_sta->stay_in_tbl) { | 1153 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { |
949 | lq_sta->total_success += legacy_success; | 1154 | lq_sta->total_success += legacy_success; |
950 | lq_sta->total_failed += retries + (1 - legacy_success); | 1155 | lq_sta->total_failed += retries + (1 - legacy_success); |
951 | } | 1156 | } |
952 | } | 1157 | } |
953 | /* The last TX rate is cached in lq_sta; it's set in if/else above */ | 1158 | /* The last TX rate is cached in lq_sta; it's set in if/else above */ |
954 | lq_sta->last_rate_n_flags = tx_rate; | 1159 | lq_sta->last_rate_n_flags = ucode_rate; |
955 | done: | 1160 | done: |
956 | /* See if there's a better rate or modulation mode to try. */ | 1161 | /* See if there's a better rate or modulation mode to try. */ |
957 | if (sta && sta->supp_rates[sband->band]) | 1162 | if (sta && sta->supp_rates[sband->band]) |
@@ -969,8 +1174,8 @@ done: | |||
969 | static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, | 1174 | static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, |
970 | struct iwl_lq_sta *lq_sta) | 1175 | struct iwl_lq_sta *lq_sta) |
971 | { | 1176 | { |
972 | IWL_DEBUG_RATE(mvm, "we are staying in the same table\n"); | 1177 | IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n"); |
973 | lq_sta->stay_in_tbl = 1; /* only place this gets set */ | 1178 | lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN; |
974 | if (is_legacy) { | 1179 | if (is_legacy) { |
975 | lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; | 1180 | lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; |
976 | lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; | 1181 | lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; |
@@ -984,37 +1189,31 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, | |||
984 | lq_sta->total_failed = 0; | 1189 | lq_sta->total_failed = 0; |
985 | lq_sta->total_success = 0; | 1190 | lq_sta->total_success = 0; |
986 | lq_sta->flush_timer = jiffies; | 1191 | lq_sta->flush_timer = jiffies; |
987 | lq_sta->action_counter = 0; | 1192 | lq_sta->visited_columns = 0; |
988 | } | 1193 | } |
989 | 1194 | ||
990 | /* | 1195 | static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, |
991 | * Find correct throughput table for given mode of modulation | 1196 | const struct rs_tx_column *column, |
992 | */ | 1197 | u32 bw) |
993 | static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | ||
994 | struct iwl_scale_tbl_info *tbl) | ||
995 | { | 1198 | { |
996 | /* Used to choose among HT tables */ | 1199 | /* Used to choose among HT tables */ |
997 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; | 1200 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; |
998 | 1201 | ||
999 | /* Check for invalid LQ type */ | 1202 | if (WARN_ON_ONCE(column->mode != RS_LEGACY && |
1000 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_ht(tbl->lq_type) && | 1203 | column->mode != RS_SISO && |
1001 | !(is_vht(tbl->lq_type)))) { | 1204 | column->mode != RS_MIMO2)) |
1002 | tbl->expected_tpt = expected_tpt_legacy; | 1205 | return expected_tpt_legacy; |
1003 | return; | ||
1004 | } | ||
1005 | 1206 | ||
1006 | /* Legacy rates have only one table */ | 1207 | /* Legacy rates have only one table */ |
1007 | if (is_legacy(tbl->lq_type)) { | 1208 | if (column->mode == RS_LEGACY) |
1008 | tbl->expected_tpt = expected_tpt_legacy; | 1209 | return expected_tpt_legacy; |
1009 | return; | ||
1010 | } | ||
1011 | 1210 | ||
1012 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | 1211 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; |
1013 | /* Choose among many HT tables depending on number of streams | 1212 | /* Choose among many HT tables depending on number of streams |
1014 | * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation | 1213 | * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation |
1015 | * status */ | 1214 | * status */ |
1016 | if (is_siso(tbl->lq_type)) { | 1215 | if (column->mode == RS_SISO) { |
1017 | switch (tbl->bw) { | 1216 | switch (bw) { |
1018 | case RATE_MCS_CHAN_WIDTH_20: | 1217 | case RATE_MCS_CHAN_WIDTH_20: |
1019 | ht_tbl_pointer = expected_tpt_siso_20MHz; | 1218 | ht_tbl_pointer = expected_tpt_siso_20MHz; |
1020 | break; | 1219 | break; |
@@ -1027,8 +1226,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1027 | default: | 1226 | default: |
1028 | WARN_ON_ONCE(1); | 1227 | WARN_ON_ONCE(1); |
1029 | } | 1228 | } |
1030 | } else if (is_mimo2(tbl->lq_type)) { | 1229 | } else if (column->mode == RS_MIMO2) { |
1031 | switch (tbl->bw) { | 1230 | switch (bw) { |
1032 | case RATE_MCS_CHAN_WIDTH_20: | 1231 | case RATE_MCS_CHAN_WIDTH_20: |
1033 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | 1232 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; |
1034 | break; | 1233 | break; |
@@ -1045,14 +1244,23 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1045 | WARN_ON_ONCE(1); | 1244 | WARN_ON_ONCE(1); |
1046 | } | 1245 | } |
1047 | 1246 | ||
1048 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ | 1247 | if (!column->sgi && !lq_sta->is_agg) /* Normal */ |
1049 | tbl->expected_tpt = ht_tbl_pointer[0]; | 1248 | return ht_tbl_pointer[0]; |
1050 | else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ | 1249 | else if (column->sgi && !lq_sta->is_agg) /* SGI */ |
1051 | tbl->expected_tpt = ht_tbl_pointer[1]; | 1250 | return ht_tbl_pointer[1]; |
1052 | else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ | 1251 | else if (!column->sgi && lq_sta->is_agg) /* AGG */ |
1053 | tbl->expected_tpt = ht_tbl_pointer[2]; | 1252 | return ht_tbl_pointer[2]; |
1054 | else /* AGG+SGI */ | 1253 | else /* AGG+SGI */ |
1055 | tbl->expected_tpt = ht_tbl_pointer[3]; | 1254 | return ht_tbl_pointer[3]; |
1255 | } | ||
1256 | |||
1257 | static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | ||
1258 | struct iwl_scale_tbl_info *tbl) | ||
1259 | { | ||
1260 | struct rs_rate *rate = &tbl->rate; | ||
1261 | const struct rs_tx_column *column = &rs_tx_columns[tbl->column]; | ||
1262 | |||
1263 | tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); | ||
1056 | } | 1264 | } |
1057 | 1265 | ||
1058 | /* | 1266 | /* |
@@ -1089,7 +1297,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1089 | 1297 | ||
1090 | while (1) { | 1298 | while (1) { |
1091 | high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, | 1299 | high_low = rs_get_adjacent_rate(mvm, rate, rate_mask, |
1092 | tbl->lq_type); | 1300 | tbl->rate.type); |
1093 | 1301 | ||
1094 | low = high_low & 0xff; | 1302 | low = high_low & 0xff; |
1095 | high = (high_low >> 8) & 0xff; | 1303 | high = (high_low >> 8) & 0xff; |
@@ -1110,7 +1318,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1110 | * "active" throughput (under perfect conditions). | 1318 | * "active" throughput (under perfect conditions). |
1111 | */ | 1319 | */ |
1112 | if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && | 1320 | if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && |
1113 | ((active_sr > IWL_RATE_DECREASE_TH) && | 1321 | ((active_sr > RS_SR_FORCE_DECREASE) && |
1114 | (active_sr <= IWL_RATE_HIGH_TH) && | 1322 | (active_sr <= IWL_RATE_HIGH_TH) && |
1115 | (tpt_tbl[rate] <= active_tpt))) || | 1323 | (tpt_tbl[rate] <= active_tpt))) || |
1116 | ((active_sr >= IWL_RATE_SCALE_SWITCH) && | 1324 | ((active_sr >= IWL_RATE_SCALE_SWITCH) && |
@@ -1157,417 +1365,14 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1157 | return new_rate; | 1365 | return new_rate; |
1158 | } | 1366 | } |
1159 | 1367 | ||
1160 | /* Move to the next action and wrap around to the first action in case | 1368 | static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) |
1161 | * we're at the last action. Assumes actions start at 0. | ||
1162 | */ | ||
1163 | static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl, | ||
1164 | u8 last_action) | ||
1165 | { | ||
1166 | BUILD_BUG_ON(IWL_LEGACY_FIRST_ACTION != 0); | ||
1167 | BUILD_BUG_ON(IWL_SISO_FIRST_ACTION != 0); | ||
1168 | BUILD_BUG_ON(IWL_MIMO2_FIRST_ACTION != 0); | ||
1169 | |||
1170 | tbl->action = (tbl->action + 1) % (last_action + 1); | ||
1171 | } | ||
1172 | |||
1173 | static void rs_set_bw_from_sta(struct iwl_scale_tbl_info *tbl, | ||
1174 | struct ieee80211_sta *sta) | ||
1175 | { | 1369 | { |
1176 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) | 1370 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) |
1177 | tbl->bw = RATE_MCS_CHAN_WIDTH_80; | 1371 | return RATE_MCS_CHAN_WIDTH_80; |
1178 | else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) | 1372 | else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) |
1179 | tbl->bw = RATE_MCS_CHAN_WIDTH_40; | 1373 | return RATE_MCS_CHAN_WIDTH_40; |
1180 | else | ||
1181 | tbl->bw = RATE_MCS_CHAN_WIDTH_20; | ||
1182 | } | ||
1183 | |||
1184 | static bool rs_sgi_allowed(struct iwl_scale_tbl_info *tbl, | ||
1185 | struct ieee80211_sta *sta) | ||
1186 | { | ||
1187 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1188 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
1189 | |||
1190 | if (is_ht20(tbl) && (ht_cap->cap & | ||
1191 | IEEE80211_HT_CAP_SGI_20)) | ||
1192 | return true; | ||
1193 | if (is_ht40(tbl) && (ht_cap->cap & | ||
1194 | IEEE80211_HT_CAP_SGI_40)) | ||
1195 | return true; | ||
1196 | if (is_ht80(tbl) && (vht_cap->cap & | ||
1197 | IEEE80211_VHT_CAP_SHORT_GI_80)) | ||
1198 | return true; | ||
1199 | |||
1200 | return false; | ||
1201 | } | ||
1202 | |||
1203 | /* | ||
1204 | * Set up search table for MIMO2 | ||
1205 | */ | ||
1206 | static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | ||
1207 | struct iwl_lq_sta *lq_sta, | ||
1208 | struct ieee80211_sta *sta, | ||
1209 | struct iwl_scale_tbl_info *tbl, int index) | ||
1210 | { | ||
1211 | u16 rate_mask; | ||
1212 | s32 rate; | ||
1213 | |||
1214 | if (!sta->ht_cap.ht_supported) | ||
1215 | return -1; | ||
1216 | |||
1217 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||
1218 | return -1; | ||
1219 | |||
1220 | /* Need both Tx chains/antennas to support MIMO */ | ||
1221 | if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) | ||
1222 | return -1; | ||
1223 | |||
1224 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); | ||
1225 | |||
1226 | tbl->lq_type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; | ||
1227 | tbl->action = 0; | ||
1228 | tbl->max_search = IWL_MAX_SEARCH; | ||
1229 | rate_mask = lq_sta->active_mimo2_rate; | ||
1230 | |||
1231 | rs_set_bw_from_sta(tbl, sta); | ||
1232 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1233 | |||
1234 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1235 | |||
1236 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n", | ||
1237 | rate, rate_mask); | ||
1238 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1239 | IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", | ||
1240 | rate, rate_mask); | ||
1241 | return -1; | ||
1242 | } | ||
1243 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); | ||
1244 | |||
1245 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", | ||
1246 | tbl->current_rate); | ||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * Set up search table for SISO | ||
1252 | */ | ||
1253 | static int rs_switch_to_siso(struct iwl_mvm *mvm, | ||
1254 | struct iwl_lq_sta *lq_sta, | ||
1255 | struct ieee80211_sta *sta, | ||
1256 | struct iwl_scale_tbl_info *tbl, int index) | ||
1257 | { | ||
1258 | u16 rate_mask; | ||
1259 | s32 rate; | ||
1260 | |||
1261 | if (!sta->ht_cap.ht_supported) | ||
1262 | return -1; | ||
1263 | |||
1264 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); | ||
1265 | |||
1266 | tbl->lq_type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; | ||
1267 | tbl->action = 0; | ||
1268 | tbl->max_search = IWL_MAX_SEARCH; | ||
1269 | rate_mask = lq_sta->active_siso_rate; | ||
1270 | |||
1271 | rs_set_bw_from_sta(tbl, sta); | ||
1272 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1273 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1274 | |||
1275 | IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask); | ||
1276 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1277 | IWL_DEBUG_RATE(mvm, | ||
1278 | "can not switch with index %d rate mask %x\n", | ||
1279 | rate, rate_mask); | ||
1280 | return -1; | ||
1281 | } | ||
1282 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); | ||
1283 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", | ||
1284 | tbl->current_rate); | ||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | /* | ||
1289 | * Try to switch to new modulation mode from legacy | ||
1290 | */ | ||
1291 | static int rs_move_legacy_other(struct iwl_mvm *mvm, | ||
1292 | struct iwl_lq_sta *lq_sta, | ||
1293 | struct ieee80211_sta *sta, | ||
1294 | int index) | ||
1295 | { | ||
1296 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1297 | struct iwl_scale_tbl_info *search_tbl = | ||
1298 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1299 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1300 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1301 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1302 | u8 start_action; | ||
1303 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | ||
1304 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1305 | int ret; | ||
1306 | u8 update_search_tbl_counter = 0; | ||
1307 | |||
1308 | start_action = tbl->action; | ||
1309 | while (1) { | ||
1310 | lq_sta->action_counter++; | ||
1311 | switch (tbl->action) { | ||
1312 | case IWL_LEGACY_SWITCH_ANTENNA: | ||
1313 | IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); | ||
1314 | |||
1315 | if (tx_chains_num <= 1) | ||
1316 | break; | ||
1317 | |||
1318 | /* Don't change antenna if success has been great */ | ||
1319 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1320 | break; | ||
1321 | |||
1322 | /* Set up search table to try other antenna */ | ||
1323 | memcpy(search_tbl, tbl, sz); | ||
1324 | |||
1325 | if (rs_toggle_antenna(valid_tx_ant, | ||
1326 | &search_tbl->current_rate, | ||
1327 | search_tbl)) { | ||
1328 | update_search_tbl_counter = 1; | ||
1329 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1330 | goto out; | ||
1331 | } | ||
1332 | break; | ||
1333 | case IWL_LEGACY_SWITCH_SISO: | ||
1334 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n"); | ||
1335 | |||
1336 | /* Set up search table to try SISO */ | ||
1337 | memcpy(search_tbl, tbl, sz); | ||
1338 | search_tbl->is_SGI = 0; | ||
1339 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1340 | search_tbl, index); | ||
1341 | if (!ret) { | ||
1342 | lq_sta->action_counter = 0; | ||
1343 | goto out; | ||
1344 | } | ||
1345 | |||
1346 | break; | ||
1347 | case IWL_LEGACY_SWITCH_MIMO2: | ||
1348 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); | ||
1349 | |||
1350 | /* Set up search table to try MIMO */ | ||
1351 | memcpy(search_tbl, tbl, sz); | ||
1352 | search_tbl->is_SGI = 0; | ||
1353 | |||
1354 | search_tbl->ant_type = ANT_AB; | ||
1355 | |||
1356 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1357 | search_tbl->ant_type)) | ||
1358 | break; | ||
1359 | |||
1360 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1361 | search_tbl, index); | ||
1362 | if (!ret) { | ||
1363 | lq_sta->action_counter = 0; | ||
1364 | goto out; | ||
1365 | } | ||
1366 | break; | ||
1367 | default: | ||
1368 | WARN_ON_ONCE(1); | ||
1369 | } | ||
1370 | rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); | ||
1371 | |||
1372 | if (tbl->action == start_action) | ||
1373 | break; | ||
1374 | } | ||
1375 | search_tbl->lq_type = LQ_NONE; | ||
1376 | return 0; | ||
1377 | |||
1378 | out: | ||
1379 | lq_sta->search_better_tbl = 1; | ||
1380 | rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); | ||
1381 | if (update_search_tbl_counter) | ||
1382 | search_tbl->action = tbl->action; | ||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * Try to switch to new modulation mode from SISO | ||
1388 | */ | ||
1389 | static int rs_move_siso_to_other(struct iwl_mvm *mvm, | ||
1390 | struct iwl_lq_sta *lq_sta, | ||
1391 | struct ieee80211_sta *sta, int index) | ||
1392 | { | ||
1393 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1394 | struct iwl_scale_tbl_info *search_tbl = | ||
1395 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1396 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1397 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1398 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1399 | u8 start_action; | ||
1400 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | ||
1401 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1402 | u8 update_search_tbl_counter = 0; | ||
1403 | int ret; | ||
1404 | |||
1405 | if (tbl->action == IWL_SISO_SWITCH_MIMO2 && | ||
1406 | !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) | ||
1407 | tbl->action = IWL_SISO_SWITCH_ANTENNA; | ||
1408 | |||
1409 | start_action = tbl->action; | ||
1410 | while (1) { | ||
1411 | lq_sta->action_counter++; | ||
1412 | switch (tbl->action) { | ||
1413 | case IWL_SISO_SWITCH_ANTENNA: | ||
1414 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); | ||
1415 | if (tx_chains_num <= 1) | ||
1416 | break; | ||
1417 | |||
1418 | if (window->success_ratio >= IWL_RS_GOOD_RATIO && | ||
1419 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, | ||
1420 | TRAFFIC_LOAD) == 0) | ||
1421 | break; | ||
1422 | |||
1423 | memcpy(search_tbl, tbl, sz); | ||
1424 | if (rs_toggle_antenna(valid_tx_ant, | ||
1425 | &search_tbl->current_rate, | ||
1426 | search_tbl)) { | ||
1427 | update_search_tbl_counter = 1; | ||
1428 | goto out; | ||
1429 | } | ||
1430 | break; | ||
1431 | case IWL_SISO_SWITCH_MIMO2: | ||
1432 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); | ||
1433 | memcpy(search_tbl, tbl, sz); | ||
1434 | search_tbl->is_SGI = 0; | ||
1435 | |||
1436 | search_tbl->ant_type = ANT_AB; | ||
1437 | |||
1438 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1439 | search_tbl->ant_type)) | ||
1440 | break; | ||
1441 | |||
1442 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1443 | search_tbl, index); | ||
1444 | if (!ret) | ||
1445 | goto out; | ||
1446 | break; | ||
1447 | case IWL_SISO_SWITCH_GI: | ||
1448 | if (!rs_sgi_allowed(tbl, sta)) | ||
1449 | break; | ||
1450 | |||
1451 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); | ||
1452 | |||
1453 | memcpy(search_tbl, tbl, sz); | ||
1454 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1455 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1456 | if (tbl->is_SGI) { | ||
1457 | s32 tpt = lq_sta->last_tpt / 100; | ||
1458 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1459 | break; | ||
1460 | } | ||
1461 | search_tbl->current_rate = | ||
1462 | rate_n_flags_from_tbl(mvm, search_tbl, index); | ||
1463 | update_search_tbl_counter = 1; | ||
1464 | goto out; | ||
1465 | default: | ||
1466 | WARN_ON_ONCE(1); | ||
1467 | } | ||
1468 | rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); | ||
1469 | |||
1470 | if (tbl->action == start_action) | ||
1471 | break; | ||
1472 | } | ||
1473 | search_tbl->lq_type = LQ_NONE; | ||
1474 | return 0; | ||
1475 | |||
1476 | out: | ||
1477 | lq_sta->search_better_tbl = 1; | ||
1478 | rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); | ||
1479 | if (update_search_tbl_counter) | ||
1480 | search_tbl->action = tbl->action; | ||
1481 | |||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * Try to switch to new modulation mode from MIMO2 | ||
1487 | */ | ||
1488 | static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | ||
1489 | struct iwl_lq_sta *lq_sta, | ||
1490 | struct ieee80211_sta *sta, int index) | ||
1491 | { | ||
1492 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1493 | struct iwl_scale_tbl_info *search_tbl = | ||
1494 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1495 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1496 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1497 | u8 start_action; | ||
1498 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | ||
1499 | u8 update_search_tbl_counter = 0; | ||
1500 | int ret; | ||
1501 | |||
1502 | start_action = tbl->action; | ||
1503 | while (1) { | ||
1504 | lq_sta->action_counter++; | ||
1505 | switch (tbl->action) { | ||
1506 | case IWL_MIMO2_SWITCH_SISO_A: | ||
1507 | case IWL_MIMO2_SWITCH_SISO_B: | ||
1508 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); | ||
1509 | |||
1510 | /* Set up new search table for SISO */ | ||
1511 | memcpy(search_tbl, tbl, sz); | ||
1512 | |||
1513 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) | ||
1514 | search_tbl->ant_type = ANT_A; | ||
1515 | else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */ | ||
1516 | search_tbl->ant_type = ANT_B; | ||
1517 | |||
1518 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1519 | search_tbl->ant_type)) | ||
1520 | break; | ||
1521 | |||
1522 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1523 | search_tbl, index); | ||
1524 | if (!ret) | ||
1525 | goto out; | ||
1526 | |||
1527 | break; | ||
1528 | |||
1529 | case IWL_MIMO2_SWITCH_GI: | ||
1530 | if (!rs_sgi_allowed(tbl, sta)) | ||
1531 | break; | ||
1532 | |||
1533 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); | ||
1534 | |||
1535 | /* Set up new search table for MIMO2 */ | ||
1536 | memcpy(search_tbl, tbl, sz); | ||
1537 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1538 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1539 | /* | ||
1540 | * If active table already uses the fastest possible | ||
1541 | * modulation (dual stream with short guard interval), | ||
1542 | * and it's working well, there's no need to look | ||
1543 | * for a better type of modulation! | ||
1544 | */ | ||
1545 | if (tbl->is_SGI) { | ||
1546 | s32 tpt = lq_sta->last_tpt / 100; | ||
1547 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1548 | break; | ||
1549 | } | ||
1550 | search_tbl->current_rate = | ||
1551 | rate_n_flags_from_tbl(mvm, search_tbl, index); | ||
1552 | update_search_tbl_counter = 1; | ||
1553 | goto out; | ||
1554 | default: | ||
1555 | WARN_ON_ONCE(1); | ||
1556 | } | ||
1557 | rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); | ||
1558 | |||
1559 | if (tbl->action == start_action) | ||
1560 | break; | ||
1561 | } | ||
1562 | search_tbl->lq_type = LQ_NONE; | ||
1563 | return 0; | ||
1564 | out: | ||
1565 | lq_sta->search_better_tbl = 1; | ||
1566 | rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); | ||
1567 | if (update_search_tbl_counter) | ||
1568 | search_tbl->action = tbl->action; | ||
1569 | 1374 | ||
1570 | return 0; | 1375 | return RATE_MCS_CHAN_WIDTH_20; |
1571 | } | 1376 | } |
1572 | 1377 | ||
1573 | /* | 1378 | /* |
@@ -1591,13 +1396,13 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1591 | tbl = &(lq_sta->lq_info[active_tbl]); | 1396 | tbl = &(lq_sta->lq_info[active_tbl]); |
1592 | 1397 | ||
1593 | /* If we've been disallowing search, see if we should now allow it */ | 1398 | /* If we've been disallowing search, see if we should now allow it */ |
1594 | if (lq_sta->stay_in_tbl) { | 1399 | if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { |
1595 | /* Elapsed time using current modulation mode */ | 1400 | /* Elapsed time using current modulation mode */ |
1596 | if (lq_sta->flush_timer) | 1401 | if (lq_sta->flush_timer) |
1597 | flush_interval_passed = | 1402 | flush_interval_passed = |
1598 | time_after(jiffies, | 1403 | time_after(jiffies, |
1599 | (unsigned long)(lq_sta->flush_timer + | 1404 | (unsigned long)(lq_sta->flush_timer + |
1600 | IWL_RATE_SCALE_FLUSH_INTVL)); | 1405 | RS_STAY_IN_COLUMN_TIMEOUT)); |
1601 | 1406 | ||
1602 | /* | 1407 | /* |
1603 | * Check if we should allow search for new modulation mode. | 1408 | * Check if we should allow search for new modulation mode. |
@@ -1619,10 +1424,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1619 | flush_interval_passed); | 1424 | flush_interval_passed); |
1620 | 1425 | ||
1621 | /* Allow search for new mode */ | 1426 | /* Allow search for new mode */ |
1622 | lq_sta->stay_in_tbl = 0; /* only place reset */ | 1427 | lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_STARTED; |
1428 | IWL_DEBUG_RATE(mvm, | ||
1429 | "Moving to RS_STATE_SEARCH_CYCLE_STARTED\n"); | ||
1623 | lq_sta->total_failed = 0; | 1430 | lq_sta->total_failed = 0; |
1624 | lq_sta->total_success = 0; | 1431 | lq_sta->total_success = 0; |
1625 | lq_sta->flush_timer = 0; | 1432 | lq_sta->flush_timer = 0; |
1433 | /* mark the current column as visited */ | ||
1434 | lq_sta->visited_columns = BIT(tbl->column); | ||
1626 | /* | 1435 | /* |
1627 | * Else if we've used this modulation mode enough repetitions | 1436 | * Else if we've used this modulation mode enough repetitions |
1628 | * (regardless of elapsed time or success/failure), reset | 1437 | * (regardless of elapsed time or success/failure), reset |
@@ -1646,7 +1455,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1646 | /* If transitioning to allow "search", reset all history | 1455 | /* If transitioning to allow "search", reset all history |
1647 | * bitmaps and stats in active table (this will become the new | 1456 | * bitmaps and stats in active table (this will become the new |
1648 | * "search" table). */ | 1457 | * "search" table). */ |
1649 | if (!lq_sta->stay_in_tbl) { | 1458 | if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { |
1459 | IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); | ||
1650 | for (i = 0; i < IWL_RATE_COUNT; i++) | 1460 | for (i = 0; i < IWL_RATE_COUNT; i++) |
1651 | rs_rate_scale_clear_window(&(tbl->win[i])); | 1461 | rs_rate_scale_clear_window(&(tbl->win[i])); |
1652 | } | 1462 | } |
@@ -1659,15 +1469,13 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1659 | static void rs_update_rate_tbl(struct iwl_mvm *mvm, | 1469 | static void rs_update_rate_tbl(struct iwl_mvm *mvm, |
1660 | struct ieee80211_sta *sta, | 1470 | struct ieee80211_sta *sta, |
1661 | struct iwl_lq_sta *lq_sta, | 1471 | struct iwl_lq_sta *lq_sta, |
1662 | struct iwl_scale_tbl_info *tbl, | 1472 | struct rs_rate *rate) |
1663 | int index) | ||
1664 | { | 1473 | { |
1665 | u32 rate; | 1474 | u32 ucode_rate; |
1666 | 1475 | ||
1667 | /* Update uCode's rate table. */ | 1476 | ucode_rate = ucode_rate_from_rs_rate(mvm, rate); |
1668 | rate = rate_n_flags_from_tbl(mvm, tbl, index); | 1477 | rs_fill_link_cmd(mvm, sta, lq_sta, ucode_rate); |
1669 | rs_fill_link_cmd(mvm, sta, lq_sta, rate); | 1478 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); |
1670 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | ||
1671 | } | 1479 | } |
1672 | 1480 | ||
1673 | static u8 rs_get_tid(struct iwl_lq_sta *lq_data, | 1481 | static u8 rs_get_tid(struct iwl_lq_sta *lq_data, |
@@ -1686,6 +1494,162 @@ static u8 rs_get_tid(struct iwl_lq_sta *lq_data, | |||
1686 | return tid; | 1494 | return tid; |
1687 | } | 1495 | } |
1688 | 1496 | ||
1497 | static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, | ||
1498 | struct iwl_lq_sta *lq_sta, | ||
1499 | struct ieee80211_sta *sta, | ||
1500 | struct iwl_scale_tbl_info *tbl) | ||
1501 | { | ||
1502 | int i, j, n; | ||
1503 | enum rs_column next_col_id; | ||
1504 | const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; | ||
1505 | const struct rs_tx_column *next_col; | ||
1506 | allow_column_func_t allow_func; | ||
1507 | u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw); | ||
1508 | s32 *expected_tpt_tbl; | ||
1509 | s32 tpt, max_expected_tpt; | ||
1510 | |||
1511 | for (i = 0; i < MAX_NEXT_COLUMNS; i++) { | ||
1512 | next_col_id = curr_col->next_columns[i]; | ||
1513 | |||
1514 | if (next_col_id == RS_COLUMN_INVALID) | ||
1515 | continue; | ||
1516 | |||
1517 | if (lq_sta->visited_columns & BIT(next_col_id)) { | ||
1518 | IWL_DEBUG_RATE(mvm, "Skip already visited column %d\n", | ||
1519 | next_col_id); | ||
1520 | continue; | ||
1521 | } | ||
1522 | |||
1523 | next_col = &rs_tx_columns[next_col_id]; | ||
1524 | |||
1525 | if (!rs_is_valid_ant(valid_ants, next_col->ant)) { | ||
1526 | IWL_DEBUG_RATE(mvm, | ||
1527 | "Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x\n", | ||
1528 | next_col_id, valid_ants, next_col->ant); | ||
1529 | continue; | ||
1530 | } | ||
1531 | |||
1532 | for (j = 0; j < MAX_COLUMN_CHECKS; j++) { | ||
1533 | allow_func = next_col->checks[j]; | ||
1534 | if (allow_func && !allow_func(mvm, sta, tbl)) | ||
1535 | break; | ||
1536 | } | ||
1537 | |||
1538 | if (j != MAX_COLUMN_CHECKS) { | ||
1539 | IWL_DEBUG_RATE(mvm, | ||
1540 | "Skip column %d: not allowed (check %d failed)\n", | ||
1541 | next_col_id, j); | ||
1542 | |||
1543 | continue; | ||
1544 | } | ||
1545 | |||
1546 | tpt = lq_sta->last_tpt / 100; | ||
1547 | expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col, | ||
1548 | tbl->rate.bw); | ||
1549 | if (WARN_ON_ONCE(!expected_tpt_tbl)) | ||
1550 | continue; | ||
1551 | |||
1552 | max_expected_tpt = 0; | ||
1553 | for (n = 0; n < IWL_RATE_COUNT; n++) | ||
1554 | if (expected_tpt_tbl[n] > max_expected_tpt) | ||
1555 | max_expected_tpt = expected_tpt_tbl[n]; | ||
1556 | |||
1557 | if (tpt >= max_expected_tpt) { | ||
1558 | IWL_DEBUG_RATE(mvm, | ||
1559 | "Skip column %d: can't beat current TPT. Max expected %d current %d\n", | ||
1560 | next_col_id, max_expected_tpt, tpt); | ||
1561 | continue; | ||
1562 | } | ||
1563 | |||
1564 | break; | ||
1565 | } | ||
1566 | |||
1567 | if (i == MAX_NEXT_COLUMNS) | ||
1568 | return RS_COLUMN_INVALID; | ||
1569 | |||
1570 | IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id); | ||
1571 | |||
1572 | return next_col_id; | ||
1573 | } | ||
1574 | |||
1575 | static int rs_switch_to_column(struct iwl_mvm *mvm, | ||
1576 | struct iwl_lq_sta *lq_sta, | ||
1577 | struct ieee80211_sta *sta, | ||
1578 | enum rs_column col_id) | ||
1579 | { | ||
1580 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1581 | struct iwl_scale_tbl_info *search_tbl = | ||
1582 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1583 | struct rs_rate *rate = &search_tbl->rate; | ||
1584 | const struct rs_tx_column *column = &rs_tx_columns[col_id]; | ||
1585 | const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; | ||
1586 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1587 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1588 | u16 rate_mask = 0; | ||
1589 | u32 rate_idx = 0; | ||
1590 | |||
1591 | memcpy(search_tbl, tbl, sz); | ||
1592 | |||
1593 | rate->sgi = column->sgi; | ||
1594 | rate->ant = column->ant; | ||
1595 | |||
1596 | if (column->mode == RS_LEGACY) { | ||
1597 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | ||
1598 | rate->type = LQ_LEGACY_A; | ||
1599 | else | ||
1600 | rate->type = LQ_LEGACY_G; | ||
1601 | |||
1602 | rate_mask = lq_sta->active_legacy_rate; | ||
1603 | } else if (column->mode == RS_SISO) { | ||
1604 | rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; | ||
1605 | rate_mask = lq_sta->active_siso_rate; | ||
1606 | } else if (column->mode == RS_MIMO2) { | ||
1607 | rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; | ||
1608 | rate_mask = lq_sta->active_mimo2_rate; | ||
1609 | } else { | ||
1610 | WARN_ON_ONCE("Bad column mode"); | ||
1611 | } | ||
1612 | |||
1613 | rate->bw = rs_bw_from_sta_bw(sta); | ||
1614 | search_tbl->column = col_id; | ||
1615 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1616 | |||
1617 | /* Get the best matching rate if we're changing modes. e.g. | ||
1618 | * SISO->MIMO, LEGACY->SISO, MIMO->SISO | ||
1619 | */ | ||
1620 | if (curr_column->mode != column->mode) { | ||
1621 | rate_idx = rs_get_best_rate(mvm, lq_sta, search_tbl, | ||
1622 | rate_mask, rate->index); | ||
1623 | |||
1624 | if ((rate_idx == IWL_RATE_INVALID) || | ||
1625 | !(BIT(rate_idx) & rate_mask)) { | ||
1626 | IWL_DEBUG_RATE(mvm, | ||
1627 | "can not switch with index %d" | ||
1628 | " rate mask %x\n", | ||
1629 | rate_idx, rate_mask); | ||
1630 | |||
1631 | goto err; | ||
1632 | } | ||
1633 | |||
1634 | rate->index = rate_idx; | ||
1635 | } | ||
1636 | |||
1637 | /* TODO: remove current_rate and keep using rs_rate all the way until | ||
1638 | * we need to fill in the rs_table in the LQ command | ||
1639 | */ | ||
1640 | search_tbl->current_rate = ucode_rate_from_rs_rate(mvm, rate); | ||
1641 | IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n", | ||
1642 | col_id, rate->index); | ||
1643 | |||
1644 | lq_sta->visited_columns |= BIT(col_id); | ||
1645 | return 0; | ||
1646 | |||
1647 | err: | ||
1648 | rate->type = LQ_NONE; | ||
1649 | return -1; | ||
1650 | } | ||
1651 | |||
1652 | |||
1689 | /* | 1653 | /* |
1690 | * Do rate scaling and search for new modulation mode. | 1654 | * Do rate scaling and search for new modulation mode. |
1691 | */ | 1655 | */ |
@@ -1715,10 +1679,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1715 | u16 high_low; | 1679 | u16 high_low; |
1716 | s32 sr; | 1680 | s32 sr; |
1717 | u8 tid = IWL_MAX_TID_COUNT; | 1681 | u8 tid = IWL_MAX_TID_COUNT; |
1682 | u8 prev_agg = lq_sta->is_agg; | ||
1718 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; | 1683 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; |
1719 | struct iwl_mvm_tid_data *tid_data; | 1684 | struct iwl_mvm_tid_data *tid_data; |
1720 | 1685 | struct rs_rate *rate; | |
1721 | IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n"); | ||
1722 | 1686 | ||
1723 | /* Send management frames and NO_ACK data using lowest rate. */ | 1687 | /* Send management frames and NO_ACK data using lowest rate. */ |
1724 | /* TODO: this could probably be improved.. */ | 1688 | /* TODO: this could probably be improved.. */ |
@@ -1751,20 +1715,23 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1751 | active_tbl = 1 - lq_sta->active_tbl; | 1715 | active_tbl = 1 - lq_sta->active_tbl; |
1752 | 1716 | ||
1753 | tbl = &(lq_sta->lq_info[active_tbl]); | 1717 | tbl = &(lq_sta->lq_info[active_tbl]); |
1718 | rate = &tbl->rate; | ||
1719 | |||
1720 | if (prev_agg != lq_sta->is_agg) { | ||
1721 | IWL_DEBUG_RATE(mvm, | ||
1722 | "Aggregation changed: prev %d current %d. Update expected TPT table\n", | ||
1723 | prev_agg, lq_sta->is_agg); | ||
1724 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1725 | } | ||
1754 | 1726 | ||
1755 | /* current tx rate */ | 1727 | /* current tx rate */ |
1756 | index = lq_sta->last_txrate_idx; | 1728 | index = lq_sta->last_txrate_idx; |
1757 | 1729 | ||
1758 | IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index, | ||
1759 | tbl->lq_type); | ||
1760 | |||
1761 | /* rates available for this association, and for modulation mode */ | 1730 | /* rates available for this association, and for modulation mode */ |
1762 | rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); | 1731 | rate_mask = rs_get_supported_rates(lq_sta, rate); |
1763 | |||
1764 | IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask); | ||
1765 | 1732 | ||
1766 | /* mask with station rate restriction */ | 1733 | /* mask with station rate restriction */ |
1767 | if (is_legacy(tbl->lq_type)) { | 1734 | if (is_legacy(rate)) { |
1768 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | 1735 | if (lq_sta->band == IEEE80211_BAND_5GHZ) |
1769 | /* supp_rates has no CCK bits in A mode */ | 1736 | /* supp_rates has no CCK bits in A mode */ |
1770 | rate_scale_index_msk = (u16) (rate_mask & | 1737 | rate_scale_index_msk = (u16) (rate_mask & |
@@ -1780,16 +1747,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1780 | if (!rate_scale_index_msk) | 1747 | if (!rate_scale_index_msk) |
1781 | rate_scale_index_msk = rate_mask; | 1748 | rate_scale_index_msk = rate_mask; |
1782 | 1749 | ||
1783 | if (!((1 << index) & rate_scale_index_msk)) { | 1750 | if (!((BIT(index) & rate_scale_index_msk))) { |
1784 | IWL_ERR(mvm, "Current Rate is not valid\n"); | 1751 | IWL_ERR(mvm, "Current Rate is not valid\n"); |
1785 | if (lq_sta->search_better_tbl) { | 1752 | if (lq_sta->search_better_tbl) { |
1786 | /* revert to active table if search table is not valid*/ | 1753 | /* revert to active table if search table is not valid*/ |
1787 | tbl->lq_type = LQ_NONE; | 1754 | rate->type = LQ_NONE; |
1788 | lq_sta->search_better_tbl = 0; | 1755 | lq_sta->search_better_tbl = 0; |
1789 | tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1756 | tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1790 | /* get "active" rate info */ | 1757 | /* get "active" rate info */ |
1791 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | 1758 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); |
1792 | rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); | 1759 | tbl->rate.index = index; |
1760 | rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); | ||
1793 | } | 1761 | } |
1794 | return; | 1762 | return; |
1795 | } | 1763 | } |
@@ -1806,6 +1774,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1806 | index = lq_sta->max_rate_idx; | 1774 | index = lq_sta->max_rate_idx; |
1807 | update_lq = 1; | 1775 | update_lq = 1; |
1808 | window = &(tbl->win[index]); | 1776 | window = &(tbl->win[index]); |
1777 | IWL_DEBUG_RATE(mvm, | ||
1778 | "Forcing user max rate %d\n", | ||
1779 | index); | ||
1809 | goto lq_update; | 1780 | goto lq_update; |
1810 | } | 1781 | } |
1811 | 1782 | ||
@@ -1822,8 +1793,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1822 | if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && | 1793 | if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && |
1823 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { | 1794 | (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { |
1824 | IWL_DEBUG_RATE(mvm, | 1795 | IWL_DEBUG_RATE(mvm, |
1825 | "LQ: still below TH. succ=%d total=%d for index %d\n", | 1796 | "(%s: %d): Test Window: succ %d total %d\n", |
1826 | window->success_counter, window->counter, index); | 1797 | rs_pretty_lq_type(rate->type), |
1798 | index, window->success_counter, window->counter); | ||
1827 | 1799 | ||
1828 | /* Can't calculate this yet; not enough history */ | 1800 | /* Can't calculate this yet; not enough history */ |
1829 | window->average_tpt = IWL_INVALID_VALUE; | 1801 | window->average_tpt = IWL_INVALID_VALUE; |
@@ -1838,8 +1810,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1838 | * actual average throughput */ | 1810 | * actual average throughput */ |
1839 | if (window->average_tpt != ((window->success_ratio * | 1811 | if (window->average_tpt != ((window->success_ratio * |
1840 | tbl->expected_tpt[index] + 64) / 128)) { | 1812 | tbl->expected_tpt[index] + 64) / 128)) { |
1841 | IWL_ERR(mvm, | ||
1842 | "expected_tpt should have been calculated by now\n"); | ||
1843 | window->average_tpt = ((window->success_ratio * | 1813 | window->average_tpt = ((window->success_ratio * |
1844 | tbl->expected_tpt[index] + 64) / 128); | 1814 | tbl->expected_tpt[index] + 64) / 128); |
1845 | } | 1815 | } |
@@ -1851,27 +1821,26 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1851 | * continuing to use the setup that we've been trying. */ | 1821 | * continuing to use the setup that we've been trying. */ |
1852 | if (window->average_tpt > lq_sta->last_tpt) { | 1822 | if (window->average_tpt > lq_sta->last_tpt) { |
1853 | IWL_DEBUG_RATE(mvm, | 1823 | IWL_DEBUG_RATE(mvm, |
1854 | "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n", | 1824 | "SWITCHING TO NEW TABLE SR: %d " |
1825 | "cur-tpt %d old-tpt %d\n", | ||
1855 | window->success_ratio, | 1826 | window->success_ratio, |
1856 | window->average_tpt, | 1827 | window->average_tpt, |
1857 | lq_sta->last_tpt); | 1828 | lq_sta->last_tpt); |
1858 | 1829 | ||
1859 | if (!is_legacy(tbl->lq_type)) | ||
1860 | lq_sta->enable_counter = 1; | ||
1861 | |||
1862 | /* Swap tables; "search" becomes "active" */ | 1830 | /* Swap tables; "search" becomes "active" */ |
1863 | lq_sta->active_tbl = active_tbl; | 1831 | lq_sta->active_tbl = active_tbl; |
1864 | current_tpt = window->average_tpt; | 1832 | current_tpt = window->average_tpt; |
1865 | /* Else poor success; go back to mode in "active" table */ | 1833 | /* Else poor success; go back to mode in "active" table */ |
1866 | } else { | 1834 | } else { |
1867 | IWL_DEBUG_RATE(mvm, | 1835 | IWL_DEBUG_RATE(mvm, |
1868 | "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n", | 1836 | "GOING BACK TO THE OLD TABLE: SR %d " |
1837 | "cur-tpt %d old-tpt %d\n", | ||
1869 | window->success_ratio, | 1838 | window->success_ratio, |
1870 | window->average_tpt, | 1839 | window->average_tpt, |
1871 | lq_sta->last_tpt); | 1840 | lq_sta->last_tpt); |
1872 | 1841 | ||
1873 | /* Nullify "search" table */ | 1842 | /* Nullify "search" table */ |
1874 | tbl->lq_type = LQ_NONE; | 1843 | rate->type = LQ_NONE; |
1875 | 1844 | ||
1876 | /* Revert to "active" table */ | 1845 | /* Revert to "active" table */ |
1877 | active_tbl = lq_sta->active_tbl; | 1846 | active_tbl = lq_sta->active_tbl; |
@@ -1895,7 +1864,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1895 | /* (Else) not in search of better modulation mode, try for better | 1864 | /* (Else) not in search of better modulation mode, try for better |
1896 | * starting rate, while staying in this mode. */ | 1865 | * starting rate, while staying in this mode. */ |
1897 | high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk, | 1866 | high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk, |
1898 | tbl->lq_type); | 1867 | rate->type); |
1899 | low = high_low & 0xff; | 1868 | low = high_low & 0xff; |
1900 | high = (high_low >> 8) & 0xff; | 1869 | high = (high_low >> 8) & 0xff; |
1901 | 1870 | ||
@@ -1913,20 +1882,31 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1913 | if (high != IWL_RATE_INVALID) | 1882 | if (high != IWL_RATE_INVALID) |
1914 | high_tpt = tbl->win[high].average_tpt; | 1883 | high_tpt = tbl->win[high].average_tpt; |
1915 | 1884 | ||
1885 | IWL_DEBUG_RATE(mvm, | ||
1886 | "(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n", | ||
1887 | rs_pretty_lq_type(rate->type), index, current_tpt, sr, | ||
1888 | low, high, low_tpt, high_tpt); | ||
1889 | |||
1916 | scale_action = 0; | 1890 | scale_action = 0; |
1917 | 1891 | ||
1918 | /* Too many failures, decrease rate */ | 1892 | /* Too many failures, decrease rate */ |
1919 | if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { | 1893 | if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) { |
1920 | IWL_DEBUG_RATE(mvm, | 1894 | IWL_DEBUG_RATE(mvm, |
1921 | "decrease rate because of low success_ratio\n"); | 1895 | "decrease rate because of low SR\n"); |
1922 | scale_action = -1; | 1896 | scale_action = -1; |
1923 | /* No throughput measured yet for adjacent rates; try increase. */ | 1897 | /* No throughput measured yet for adjacent rates; try increase. */ |
1924 | } else if ((low_tpt == IWL_INVALID_VALUE) && | 1898 | } else if ((low_tpt == IWL_INVALID_VALUE) && |
1925 | (high_tpt == IWL_INVALID_VALUE)) { | 1899 | (high_tpt == IWL_INVALID_VALUE)) { |
1926 | if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) | 1900 | if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) { |
1901 | IWL_DEBUG_RATE(mvm, | ||
1902 | "Good SR and no high rate measurement. " | ||
1903 | "Increase rate\n"); | ||
1927 | scale_action = 1; | 1904 | scale_action = 1; |
1928 | else if (low != IWL_RATE_INVALID) | 1905 | } else if (low != IWL_RATE_INVALID) { |
1906 | IWL_DEBUG_RATE(mvm, | ||
1907 | "Remain in current rate\n"); | ||
1929 | scale_action = 0; | 1908 | scale_action = 0; |
1909 | } | ||
1930 | } | 1910 | } |
1931 | 1911 | ||
1932 | /* Both adjacent throughputs are measured, but neither one has better | 1912 | /* Both adjacent throughputs are measured, but neither one has better |
@@ -1934,8 +1914,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1934 | else if ((low_tpt != IWL_INVALID_VALUE) && | 1914 | else if ((low_tpt != IWL_INVALID_VALUE) && |
1935 | (high_tpt != IWL_INVALID_VALUE) && | 1915 | (high_tpt != IWL_INVALID_VALUE) && |
1936 | (low_tpt < current_tpt) && | 1916 | (low_tpt < current_tpt) && |
1937 | (high_tpt < current_tpt)) | 1917 | (high_tpt < current_tpt)) { |
1918 | IWL_DEBUG_RATE(mvm, | ||
1919 | "Both high and low are worse. " | ||
1920 | "Maintain rate\n"); | ||
1938 | scale_action = 0; | 1921 | scale_action = 0; |
1922 | } | ||
1939 | 1923 | ||
1940 | /* At least one adjacent rate's throughput is measured, | 1924 | /* At least one adjacent rate's throughput is measured, |
1941 | * and may have better performance. */ | 1925 | * and may have better performance. */ |
@@ -1945,8 +1929,14 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1945 | /* Higher rate has better throughput */ | 1929 | /* Higher rate has better throughput */ |
1946 | if (high_tpt > current_tpt && | 1930 | if (high_tpt > current_tpt && |
1947 | sr >= IWL_RATE_INCREASE_TH) { | 1931 | sr >= IWL_RATE_INCREASE_TH) { |
1932 | IWL_DEBUG_RATE(mvm, | ||
1933 | "Higher rate is better and good " | ||
1934 | "SR. Increate rate\n"); | ||
1948 | scale_action = 1; | 1935 | scale_action = 1; |
1949 | } else { | 1936 | } else { |
1937 | IWL_DEBUG_RATE(mvm, | ||
1938 | "Higher rate isn't better OR " | ||
1939 | "no good SR. Maintain rate\n"); | ||
1950 | scale_action = 0; | 1940 | scale_action = 0; |
1951 | } | 1941 | } |
1952 | 1942 | ||
@@ -1955,9 +1945,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1955 | /* Lower rate has better throughput */ | 1945 | /* Lower rate has better throughput */ |
1956 | if (low_tpt > current_tpt) { | 1946 | if (low_tpt > current_tpt) { |
1957 | IWL_DEBUG_RATE(mvm, | 1947 | IWL_DEBUG_RATE(mvm, |
1958 | "decrease rate because of low tpt\n"); | 1948 | "Lower rate is better. " |
1949 | "Decrease rate\n"); | ||
1959 | scale_action = -1; | 1950 | scale_action = -1; |
1960 | } else if (sr >= IWL_RATE_INCREASE_TH) { | 1951 | } else if (sr >= IWL_RATE_INCREASE_TH) { |
1952 | IWL_DEBUG_RATE(mvm, | ||
1953 | "Lower rate isn't better and " | ||
1954 | "good SR. Increase rate\n"); | ||
1961 | scale_action = 1; | 1955 | scale_action = 1; |
1962 | } | 1956 | } |
1963 | } | 1957 | } |
@@ -1967,29 +1961,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1967 | * has been good at old rate. Don't change it. */ | 1961 | * has been good at old rate. Don't change it. */ |
1968 | if ((scale_action == -1) && (low != IWL_RATE_INVALID) && | 1962 | if ((scale_action == -1) && (low != IWL_RATE_INVALID) && |
1969 | ((sr > IWL_RATE_HIGH_TH) || | 1963 | ((sr > IWL_RATE_HIGH_TH) || |
1970 | (current_tpt > (100 * tbl->expected_tpt[low])))) | 1964 | (current_tpt > (100 * tbl->expected_tpt[low])))) { |
1965 | IWL_DEBUG_RATE(mvm, | ||
1966 | "Sanity check failed. Maintain rate\n"); | ||
1971 | scale_action = 0; | 1967 | scale_action = 0; |
1972 | |||
1973 | if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= | ||
1974 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { | ||
1975 | if (lq_sta->last_bt_traffic > | ||
1976 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { | ||
1977 | /* | ||
1978 | * don't set scale_action, don't want to scale up if | ||
1979 | * the rate scale doesn't otherwise think that is a | ||
1980 | * good idea. | ||
1981 | */ | ||
1982 | } else if (lq_sta->last_bt_traffic <= | ||
1983 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { | ||
1984 | scale_action = -1; | ||
1985 | } | ||
1986 | } | 1968 | } |
1987 | lq_sta->last_bt_traffic = | ||
1988 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); | ||
1989 | 1969 | ||
1990 | if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= | 1970 | /* Force a search in case BT doesn't like us being in MIMO */ |
1991 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { | 1971 | if (is_mimo(rate) && |
1992 | /* search for a new modulation */ | 1972 | !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) { |
1973 | IWL_DEBUG_RATE(mvm, | ||
1974 | "BT Coex forbids MIMO. Search for new config\n"); | ||
1993 | rs_stay_in_table(lq_sta, true); | 1975 | rs_stay_in_table(lq_sta, true); |
1994 | goto lq_update; | 1976 | goto lq_update; |
1995 | } | 1977 | } |
@@ -2000,6 +1982,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2000 | if (low != IWL_RATE_INVALID) { | 1982 | if (low != IWL_RATE_INVALID) { |
2001 | update_lq = 1; | 1983 | update_lq = 1; |
2002 | index = low; | 1984 | index = low; |
1985 | } else { | ||
1986 | IWL_DEBUG_RATE(mvm, | ||
1987 | "At the bottom rate. Can't decrease\n"); | ||
2003 | } | 1988 | } |
2004 | 1989 | ||
2005 | break; | 1990 | break; |
@@ -2008,6 +1993,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2008 | if (high != IWL_RATE_INVALID) { | 1993 | if (high != IWL_RATE_INVALID) { |
2009 | update_lq = 1; | 1994 | update_lq = 1; |
2010 | index = high; | 1995 | index = high; |
1996 | } else { | ||
1997 | IWL_DEBUG_RATE(mvm, | ||
1998 | "At the top rate. Can't increase\n"); | ||
2011 | } | 1999 | } |
2012 | 2000 | ||
2013 | break; | 2001 | break; |
@@ -2017,14 +2005,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2017 | break; | 2005 | break; |
2018 | } | 2006 | } |
2019 | 2007 | ||
2020 | IWL_DEBUG_RATE(mvm, | ||
2021 | "choose rate scale index %d action %d low %d high %d type %d\n", | ||
2022 | index, scale_action, low, high, tbl->lq_type); | ||
2023 | |||
2024 | lq_update: | 2008 | lq_update: |
2025 | /* Replace uCode's rate table for the destination station. */ | 2009 | /* Replace uCode's rate table for the destination station. */ |
2026 | if (update_lq) | 2010 | if (update_lq) { |
2027 | rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); | 2011 | tbl->rate.index = index; |
2012 | rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate); | ||
2013 | } | ||
2028 | 2014 | ||
2029 | rs_stay_in_table(lq_sta, false); | 2015 | rs_stay_in_table(lq_sta, false); |
2030 | 2016 | ||
@@ -2035,20 +2021,29 @@ lq_update: | |||
2035 | * 3) Allowing a new search | 2021 | * 3) Allowing a new search |
2036 | */ | 2022 | */ |
2037 | if (!update_lq && !done_search && | 2023 | if (!update_lq && !done_search && |
2038 | !lq_sta->stay_in_tbl && window->counter) { | 2024 | lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED |
2025 | && window->counter) { | ||
2026 | enum rs_column next_column; | ||
2027 | |||
2039 | /* Save current throughput to compare with "search" throughput*/ | 2028 | /* Save current throughput to compare with "search" throughput*/ |
2040 | lq_sta->last_tpt = current_tpt; | 2029 | lq_sta->last_tpt = current_tpt; |
2041 | 2030 | ||
2042 | /* Select a new "search" modulation mode to try. | 2031 | IWL_DEBUG_RATE(mvm, |
2043 | * If one is found, set up the new "search" table. */ | 2032 | "Start Search: update_lq %d done_search %d rs_state %d win->counter %d\n", |
2044 | if (is_legacy(tbl->lq_type)) | 2033 | update_lq, done_search, lq_sta->rs_state, |
2045 | rs_move_legacy_other(mvm, lq_sta, sta, index); | 2034 | window->counter); |
2046 | else if (is_siso(tbl->lq_type)) | 2035 | |
2047 | rs_move_siso_to_other(mvm, lq_sta, sta, index); | 2036 | next_column = rs_get_next_column(mvm, lq_sta, sta, tbl); |
2048 | else if (is_mimo2(tbl->lq_type)) | 2037 | if (next_column != RS_COLUMN_INVALID) { |
2049 | rs_move_mimo2_to_other(mvm, lq_sta, sta, index); | 2038 | int ret = rs_switch_to_column(mvm, lq_sta, sta, |
2050 | else | 2039 | next_column); |
2051 | WARN_ON_ONCE(1); | 2040 | if (!ret) |
2041 | lq_sta->search_better_tbl = 1; | ||
2042 | } else { | ||
2043 | IWL_DEBUG_RATE(mvm, | ||
2044 | "No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED\n"); | ||
2045 | lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_ENDED; | ||
2046 | } | ||
2052 | 2047 | ||
2053 | /* If new "search" mode was selected, set up in uCode table */ | 2048 | /* If new "search" mode was selected, set up in uCode table */ |
2054 | if (lq_sta->search_better_tbl) { | 2049 | if (lq_sta->search_better_tbl) { |
@@ -2060,34 +2055,29 @@ lq_update: | |||
2060 | /* Use new "search" start rate */ | 2055 | /* Use new "search" start rate */ |
2061 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | 2056 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); |
2062 | 2057 | ||
2063 | IWL_DEBUG_RATE(mvm, | 2058 | rs_dump_rate(mvm, &tbl->rate, |
2064 | "Switch current mcs: %X index: %d\n", | 2059 | "Switch to SEARCH TABLE:"); |
2065 | tbl->current_rate, index); | ||
2066 | rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); | 2060 | rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); |
2067 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | 2061 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); |
2068 | } else { | 2062 | } else { |
2069 | done_search = 1; | 2063 | done_search = 1; |
2070 | } | 2064 | } |
2071 | } | 2065 | } |
2072 | 2066 | ||
2073 | if (done_search && !lq_sta->stay_in_tbl) { | 2067 | if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) { |
2074 | /* If the "active" (non-search) mode was legacy, | 2068 | /* If the "active" (non-search) mode was legacy, |
2075 | * and we've tried switching antennas, | 2069 | * and we've tried switching antennas, |
2076 | * but we haven't been able to try HT modes (not available), | 2070 | * but we haven't been able to try HT modes (not available), |
2077 | * stay with best antenna legacy modulation for a while | 2071 | * stay with best antenna legacy modulation for a while |
2078 | * before next round of mode comparisons. */ | 2072 | * before next round of mode comparisons. */ |
2079 | tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); | 2073 | tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); |
2080 | if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported && | 2074 | if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) { |
2081 | lq_sta->action_counter > tbl1->max_search) { | ||
2082 | IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); | 2075 | IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); |
2083 | rs_set_stay_in_table(mvm, 1, lq_sta); | 2076 | rs_set_stay_in_table(mvm, 1, lq_sta); |
2084 | } | 2077 | } else { |
2085 | |||
2086 | /* If we're in an HT mode, and all 3 mode switch actions | 2078 | /* If we're in an HT mode, and all 3 mode switch actions |
2087 | * have been tried and compared, stay in this best modulation | 2079 | * have been tried and compared, stay in this best modulation |
2088 | * mode for a while before next round of mode comparisons. */ | 2080 | * mode for a while before next round of mode comparisons. */ |
2089 | if (lq_sta->enable_counter && | ||
2090 | (lq_sta->action_counter >= tbl1->max_search)) { | ||
2091 | if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && | 2081 | if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && |
2092 | (lq_sta->tx_agg_tid_en & (1 << tid)) && | 2082 | (lq_sta->tx_agg_tid_en & (1 << tid)) && |
2093 | (tid != IWL_MAX_TID_COUNT)) { | 2083 | (tid != IWL_MAX_TID_COUNT)) { |
@@ -2105,7 +2095,8 @@ lq_update: | |||
2105 | } | 2095 | } |
2106 | 2096 | ||
2107 | out: | 2097 | out: |
2108 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index); | 2098 | tbl->rate.index = index; |
2099 | tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate); | ||
2109 | lq_sta->last_txrate_idx = index; | 2100 | lq_sta->last_txrate_idx = index; |
2110 | } | 2101 | } |
2111 | 2102 | ||
@@ -2126,12 +2117,13 @@ out: | |||
2126 | static void rs_initialize_lq(struct iwl_mvm *mvm, | 2117 | static void rs_initialize_lq(struct iwl_mvm *mvm, |
2127 | struct ieee80211_sta *sta, | 2118 | struct ieee80211_sta *sta, |
2128 | struct iwl_lq_sta *lq_sta, | 2119 | struct iwl_lq_sta *lq_sta, |
2129 | enum ieee80211_band band) | 2120 | enum ieee80211_band band, |
2121 | bool init) | ||
2130 | { | 2122 | { |
2131 | struct iwl_scale_tbl_info *tbl; | 2123 | struct iwl_scale_tbl_info *tbl; |
2132 | int rate_idx; | 2124 | struct rs_rate *rate; |
2133 | int i; | 2125 | int i; |
2134 | u32 rate; | 2126 | u32 ucode_rate; |
2135 | u8 active_tbl = 0; | 2127 | u8 active_tbl = 0; |
2136 | u8 valid_tx_ant; | 2128 | u8 valid_tx_ant; |
2137 | 2129 | ||
@@ -2148,27 +2140,33 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2148 | active_tbl = 1 - lq_sta->active_tbl; | 2140 | active_tbl = 1 - lq_sta->active_tbl; |
2149 | 2141 | ||
2150 | tbl = &(lq_sta->lq_info[active_tbl]); | 2142 | tbl = &(lq_sta->lq_info[active_tbl]); |
2143 | rate = &tbl->rate; | ||
2151 | 2144 | ||
2152 | if ((i < 0) || (i >= IWL_RATE_COUNT)) | 2145 | if ((i < 0) || (i >= IWL_RATE_COUNT)) |
2153 | i = 0; | 2146 | i = 0; |
2154 | 2147 | ||
2155 | rate = iwl_rates[i].plcp; | 2148 | rate->index = i; |
2156 | tbl->ant_type = first_antenna(valid_tx_ant); | 2149 | rate->ant = first_antenna(valid_tx_ant); |
2157 | rate |= tbl->ant_type << RATE_MCS_ANT_POS; | 2150 | rate->sgi = false; |
2151 | rate->bw = RATE_MCS_CHAN_WIDTH_20; | ||
2152 | if (band == IEEE80211_BAND_5GHZ) | ||
2153 | rate->type = LQ_LEGACY_A; | ||
2154 | else | ||
2155 | rate->type = LQ_LEGACY_G; | ||
2158 | 2156 | ||
2159 | if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) | 2157 | ucode_rate = ucode_rate_from_rs_rate(mvm, rate); |
2160 | rate |= RATE_MCS_CCK_MSK; | 2158 | tbl->current_rate = ucode_rate; |
2161 | 2159 | ||
2162 | rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx); | 2160 | WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); |
2163 | if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) | 2161 | if (rate->ant == ANT_A) |
2164 | rs_toggle_antenna(valid_tx_ant, &rate, tbl); | 2162 | tbl->column = RS_COLUMN_LEGACY_ANT_A; |
2163 | else | ||
2164 | tbl->column = RS_COLUMN_LEGACY_ANT_B; | ||
2165 | 2165 | ||
2166 | rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx); | ||
2167 | tbl->current_rate = rate; | ||
2168 | rs_set_expected_tpt_table(lq_sta, tbl); | 2166 | rs_set_expected_tpt_table(lq_sta, tbl); |
2169 | rs_fill_link_cmd(NULL, NULL, lq_sta, rate); | 2167 | rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate); |
2170 | /* TODO restore station should remember the lq cmd */ | 2168 | /* TODO restore station should remember the lq cmd */ |
2171 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); | 2169 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init); |
2172 | } | 2170 | } |
2173 | 2171 | ||
2174 | static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | 2172 | static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, |
@@ -2182,8 +2180,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | |||
2182 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2180 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2183 | struct iwl_lq_sta *lq_sta = mvm_sta; | 2181 | struct iwl_lq_sta *lq_sta = mvm_sta; |
2184 | 2182 | ||
2185 | IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); | ||
2186 | |||
2187 | /* Get max rate if user set max rate */ | 2183 | /* Get max rate if user set max rate */ |
2188 | if (lq_sta) { | 2184 | if (lq_sta) { |
2189 | lq_sta->max_rate_idx = txrc->max_rate_idx; | 2185 | lq_sta->max_rate_idx = txrc->max_rate_idx; |
@@ -2242,11 +2238,51 @@ static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, | |||
2242 | return -1; | 2238 | return -1; |
2243 | } | 2239 | } |
2244 | 2240 | ||
2241 | static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, | ||
2242 | struct ieee80211_sta_vht_cap *vht_cap, | ||
2243 | struct iwl_lq_sta *lq_sta) | ||
2244 | { | ||
2245 | int i; | ||
2246 | int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1); | ||
2247 | |||
2248 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2249 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2250 | if (i == IWL_RATE_9M_INDEX) | ||
2251 | continue; | ||
2252 | |||
2253 | /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ | ||
2254 | if (i == IWL_RATE_MCS_9_INDEX && | ||
2255 | sta->bandwidth == IEEE80211_STA_RX_BW_20) | ||
2256 | continue; | ||
2257 | |||
2258 | lq_sta->active_siso_rate |= BIT(i); | ||
2259 | } | ||
2260 | } | ||
2261 | |||
2262 | if (sta->rx_nss < 2) | ||
2263 | return; | ||
2264 | |||
2265 | highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); | ||
2266 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2267 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2268 | if (i == IWL_RATE_9M_INDEX) | ||
2269 | continue; | ||
2270 | |||
2271 | /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ | ||
2272 | if (i == IWL_RATE_MCS_9_INDEX && | ||
2273 | sta->bandwidth == IEEE80211_STA_RX_BW_20) | ||
2274 | continue; | ||
2275 | |||
2276 | lq_sta->active_mimo2_rate |= BIT(i); | ||
2277 | } | ||
2278 | } | ||
2279 | } | ||
2280 | |||
2245 | /* | 2281 | /* |
2246 | * Called after adding a new station to initialize rate scaling | 2282 | * Called after adding a new station to initialize rate scaling |
2247 | */ | 2283 | */ |
2248 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 2284 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
2249 | enum ieee80211_band band) | 2285 | enum ieee80211_band band, bool init) |
2250 | { | 2286 | { |
2251 | int i, j; | 2287 | int i, j; |
2252 | struct ieee80211_hw *hw = mvm->hw; | 2288 | struct ieee80211_hw *hw = mvm->hw; |
@@ -2259,6 +2295,8 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2259 | 2295 | ||
2260 | sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; | 2296 | sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; |
2261 | lq_sta = &sta_priv->lq_sta; | 2297 | lq_sta = &sta_priv->lq_sta; |
2298 | memset(lq_sta, 0, sizeof(*lq_sta)); | ||
2299 | |||
2262 | sband = hw->wiphy->bands[band]; | 2300 | sband = hw->wiphy->bands[band]; |
2263 | 2301 | ||
2264 | lq_sta->lq.sta_id = sta_priv->sta_id; | 2302 | lq_sta->lq.sta_id = sta_priv->sta_id; |
@@ -2308,27 +2346,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2308 | 2346 | ||
2309 | lq_sta->is_vht = false; | 2347 | lq_sta->is_vht = false; |
2310 | } else { | 2348 | } else { |
2311 | int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1); | 2349 | rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); |
2312 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2313 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2314 | if (i == IWL_RATE_9M_INDEX) | ||
2315 | continue; | ||
2316 | |||
2317 | lq_sta->active_siso_rate |= BIT(i); | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2321 | highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); | ||
2322 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2323 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2324 | if (i == IWL_RATE_9M_INDEX) | ||
2325 | continue; | ||
2326 | |||
2327 | lq_sta->active_mimo2_rate |= BIT(i); | ||
2328 | } | ||
2329 | } | ||
2330 | |||
2331 | /* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */ | ||
2332 | lq_sta->is_vht = true; | 2350 | lq_sta->is_vht = true; |
2333 | } | 2351 | } |
2334 | 2352 | ||
@@ -2341,15 +2359,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2341 | /* These values will be overridden later */ | 2359 | /* These values will be overridden later */ |
2342 | lq_sta->lq.single_stream_ant_msk = | 2360 | lq_sta->lq.single_stream_ant_msk = |
2343 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | 2361 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
2344 | lq_sta->lq.dual_stream_ant_msk = | 2362 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; |
2345 | iwl_fw_valid_tx_ant(mvm->fw) & | ||
2346 | ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | ||
2347 | if (!lq_sta->lq.dual_stream_ant_msk) { | ||
2348 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; | ||
2349 | } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) { | ||
2350 | lq_sta->lq.dual_stream_ant_msk = | ||
2351 | iwl_fw_valid_tx_ant(mvm->fw); | ||
2352 | } | ||
2353 | 2363 | ||
2354 | /* as default allow aggregation for all tids */ | 2364 | /* as default allow aggregation for all tids */ |
2355 | lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; | 2365 | lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; |
@@ -2364,16 +2374,33 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2364 | lq_sta->dbg_fixed_rate = 0; | 2374 | lq_sta->dbg_fixed_rate = 0; |
2365 | #endif | 2375 | #endif |
2366 | 2376 | ||
2367 | rs_initialize_lq(mvm, sta, lq_sta, band); | 2377 | rs_initialize_lq(mvm, sta, lq_sta, band, init); |
2378 | } | ||
2379 | |||
2380 | static void rs_rate_update(void *mvm_r, | ||
2381 | struct ieee80211_supported_band *sband, | ||
2382 | struct cfg80211_chan_def *chandef, | ||
2383 | struct ieee80211_sta *sta, void *priv_sta, | ||
2384 | u32 changed) | ||
2385 | { | ||
2386 | u8 tid; | ||
2387 | struct iwl_op_mode *op_mode = | ||
2388 | (struct iwl_op_mode *)mvm_r; | ||
2389 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
2390 | |||
2391 | /* Stop any ongoing aggregations as rs starts off assuming no agg */ | ||
2392 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) | ||
2393 | ieee80211_stop_tx_ba_session(sta, tid); | ||
2394 | |||
2395 | iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); | ||
2368 | } | 2396 | } |
2369 | 2397 | ||
2370 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, | 2398 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, |
2371 | struct ieee80211_sta *sta, | 2399 | struct ieee80211_sta *sta, |
2372 | struct iwl_lq_sta *lq_sta, u32 new_rate) | 2400 | struct iwl_lq_sta *lq_sta, u32 new_rate) |
2373 | { | 2401 | { |
2374 | struct iwl_scale_tbl_info tbl_type; | 2402 | struct rs_rate rate; |
2375 | int index = 0; | 2403 | int index = 0; |
2376 | int rate_idx; | ||
2377 | int repeat_rate = 0; | 2404 | int repeat_rate = 0; |
2378 | u8 ant_toggle_cnt = 0; | 2405 | u8 ant_toggle_cnt = 0; |
2379 | u8 use_ht_possible = 1; | 2406 | u8 use_ht_possible = 1; |
@@ -2383,12 +2410,10 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2383 | /* Override starting rate (index 0) if needed for debug purposes */ | 2410 | /* Override starting rate (index 0) if needed for debug purposes */ |
2384 | rs_dbgfs_set_mcs(lq_sta, &new_rate); | 2411 | rs_dbgfs_set_mcs(lq_sta, &new_rate); |
2385 | 2412 | ||
2386 | /* Interpret new_rate (rate_n_flags) */ | 2413 | rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate); |
2387 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, | ||
2388 | &tbl_type, &rate_idx); | ||
2389 | 2414 | ||
2390 | /* How many times should we repeat the initial rate? */ | 2415 | /* How many times should we repeat the initial rate? */ |
2391 | if (is_legacy(tbl_type.lq_type)) { | 2416 | if (is_legacy(&rate)) { |
2392 | ant_toggle_cnt = 1; | 2417 | ant_toggle_cnt = 1; |
2393 | repeat_rate = IWL_NUMBER_TRY; | 2418 | repeat_rate = IWL_NUMBER_TRY; |
2394 | } else { | 2419 | } else { |
@@ -2396,15 +2421,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2396 | LINK_QUAL_AGG_DISABLE_START_DEF - 1); | 2421 | LINK_QUAL_AGG_DISABLE_START_DEF - 1); |
2397 | } | 2422 | } |
2398 | 2423 | ||
2399 | lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0; | 2424 | lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0; |
2400 | 2425 | ||
2401 | /* Fill 1st table entry (index 0) */ | 2426 | /* Fill 1st table entry (index 0) */ |
2402 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); | 2427 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); |
2403 | 2428 | ||
2404 | if (num_of_ant(tbl_type.ant_type) == 1) | 2429 | if (num_of_ant(rate.ant) == 1) |
2405 | lq_cmd->single_stream_ant_msk = tbl_type.ant_type; | 2430 | lq_cmd->single_stream_ant_msk = rate.ant; |
2406 | else if (num_of_ant(tbl_type.ant_type) == 2) | ||
2407 | lq_cmd->dual_stream_ant_msk = tbl_type.ant_type; | ||
2408 | /* otherwise we don't modify the existing value */ | 2431 | /* otherwise we don't modify the existing value */ |
2409 | 2432 | ||
2410 | index++; | 2433 | index++; |
@@ -2418,12 +2441,12 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2418 | * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. | 2441 | * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. |
2419 | * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ | 2442 | * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ |
2420 | while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { | 2443 | while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { |
2421 | if (is_legacy(tbl_type.lq_type)) { | 2444 | if (is_legacy(&rate)) { |
2422 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) | 2445 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) |
2423 | ant_toggle_cnt++; | 2446 | ant_toggle_cnt++; |
2424 | else if (mvm && | 2447 | else if (mvm && |
2425 | rs_toggle_antenna(valid_tx_ant, | 2448 | rs_toggle_antenna(valid_tx_ant, |
2426 | &new_rate, &tbl_type)) | 2449 | &new_rate, &rate)) |
2427 | ant_toggle_cnt = 1; | 2450 | ant_toggle_cnt = 1; |
2428 | } | 2451 | } |
2429 | 2452 | ||
@@ -2437,26 +2460,25 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2437 | index++; | 2460 | index++; |
2438 | } | 2461 | } |
2439 | 2462 | ||
2440 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, | 2463 | rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate); |
2441 | &rate_idx); | ||
2442 | 2464 | ||
2443 | /* Indicate to uCode which entries might be MIMO. | 2465 | /* Indicate to uCode which entries might be MIMO. |
2444 | * If initial rate was MIMO, this will finally end up | 2466 | * If initial rate was MIMO, this will finally end up |
2445 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ | 2467 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ |
2446 | if (is_mimo(tbl_type.lq_type)) | 2468 | if (is_mimo(&rate)) |
2447 | lq_cmd->mimo_delim = index; | 2469 | lq_cmd->mimo_delim = index; |
2448 | 2470 | ||
2449 | /* Get next rate */ | 2471 | /* Get next rate */ |
2450 | new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, | 2472 | new_rate = rs_get_lower_rate(lq_sta, &rate, rate.index, |
2451 | use_ht_possible); | 2473 | use_ht_possible); |
2452 | 2474 | ||
2453 | /* How many times should we repeat the next rate? */ | 2475 | /* How many times should we repeat the next rate? */ |
2454 | if (is_legacy(tbl_type.lq_type)) { | 2476 | if (is_legacy(&rate)) { |
2455 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) | 2477 | if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) |
2456 | ant_toggle_cnt++; | 2478 | ant_toggle_cnt++; |
2457 | else if (mvm && | 2479 | else if (mvm && |
2458 | rs_toggle_antenna(valid_tx_ant, | 2480 | rs_toggle_antenna(valid_tx_ant, |
2459 | &new_rate, &tbl_type)) | 2481 | &new_rate, &rate)) |
2460 | ant_toggle_cnt = 1; | 2482 | ant_toggle_cnt = 1; |
2461 | 2483 | ||
2462 | repeat_rate = IWL_NUMBER_TRY; | 2484 | repeat_rate = IWL_NUMBER_TRY; |
@@ -2527,7 +2549,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | |||
2527 | >> RATE_MCS_ANT_POS); | 2549 | >> RATE_MCS_ANT_POS); |
2528 | if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) { | 2550 | if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) { |
2529 | *rate_n_flags = lq_sta->dbg_fixed_rate; | 2551 | *rate_n_flags = lq_sta->dbg_fixed_rate; |
2530 | IWL_DEBUG_RATE(mvm, "Fixed rate ON\n"); | ||
2531 | } else { | 2552 | } else { |
2532 | lq_sta->dbg_fixed_rate = 0; | 2553 | lq_sta->dbg_fixed_rate = 0; |
2533 | IWL_ERR(mvm, | 2554 | IWL_ERR(mvm, |
@@ -2535,9 +2556,60 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | |||
2535 | ant_sel_tx, valid_tx_ant); | 2556 | ant_sel_tx, valid_tx_ant); |
2536 | IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); | 2557 | IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); |
2537 | } | 2558 | } |
2559 | } | ||
2560 | } | ||
2561 | |||
2562 | static int rs_pretty_print_rate(char *buf, const u32 rate) | ||
2563 | { | ||
2564 | |||
2565 | char *type, *bw; | ||
2566 | u8 mcs = 0, nss = 0; | ||
2567 | u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; | ||
2568 | |||
2569 | if (!(rate & RATE_MCS_HT_MSK) && | ||
2570 | !(rate & RATE_MCS_VHT_MSK)) { | ||
2571 | int index = iwl_hwrate_to_plcp_idx(rate); | ||
2572 | |||
2573 | return sprintf(buf, "Legacy | ANT: %s Rate: %s Mbps\n", | ||
2574 | rs_pretty_ant(ant), iwl_rate_mcs[index].mbps); | ||
2575 | } | ||
2576 | |||
2577 | if (rate & RATE_MCS_VHT_MSK) { | ||
2578 | type = "VHT"; | ||
2579 | mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; | ||
2580 | nss = ((rate & RATE_VHT_MCS_NSS_MSK) | ||
2581 | >> RATE_VHT_MCS_NSS_POS) + 1; | ||
2582 | } else if (rate & RATE_MCS_HT_MSK) { | ||
2583 | type = "HT"; | ||
2584 | mcs = rate & RATE_HT_MCS_INDEX_MSK; | ||
2538 | } else { | 2585 | } else { |
2539 | IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n"); | 2586 | type = "Unknown"; /* shouldn't happen */ |
2587 | } | ||
2588 | |||
2589 | switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { | ||
2590 | case RATE_MCS_CHAN_WIDTH_20: | ||
2591 | bw = "20Mhz"; | ||
2592 | break; | ||
2593 | case RATE_MCS_CHAN_WIDTH_40: | ||
2594 | bw = "40Mhz"; | ||
2595 | break; | ||
2596 | case RATE_MCS_CHAN_WIDTH_80: | ||
2597 | bw = "80Mhz"; | ||
2598 | break; | ||
2599 | case RATE_MCS_CHAN_WIDTH_160: | ||
2600 | bw = "160Mhz"; | ||
2601 | break; | ||
2602 | default: | ||
2603 | bw = "BAD BW"; | ||
2540 | } | 2604 | } |
2605 | |||
2606 | return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", | ||
2607 | type, rs_pretty_ant(ant), bw, mcs, nss, | ||
2608 | (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", | ||
2609 | (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", | ||
2610 | (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", | ||
2611 | (rate & RATE_MCS_BF_MSK) ? "BF " : "", | ||
2612 | (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); | ||
2541 | } | 2613 | } |
2542 | 2614 | ||
2543 | static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, | 2615 | static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, |
@@ -2572,15 +2644,14 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2572 | char *buff; | 2644 | char *buff; |
2573 | int desc = 0; | 2645 | int desc = 0; |
2574 | int i = 0; | 2646 | int i = 0; |
2575 | int index = 0; | ||
2576 | ssize_t ret; | 2647 | ssize_t ret; |
2577 | 2648 | ||
2578 | struct iwl_lq_sta *lq_sta = file->private_data; | 2649 | struct iwl_lq_sta *lq_sta = file->private_data; |
2579 | struct iwl_mvm *mvm; | 2650 | struct iwl_mvm *mvm; |
2580 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 2651 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
2581 | 2652 | struct rs_rate *rate = &tbl->rate; | |
2582 | mvm = lq_sta->drv; | 2653 | mvm = lq_sta->drv; |
2583 | buff = kmalloc(1024, GFP_KERNEL); | 2654 | buff = kmalloc(2048, GFP_KERNEL); |
2584 | if (!buff) | 2655 | if (!buff) |
2585 | return -ENOMEM; | 2656 | return -ENOMEM; |
2586 | 2657 | ||
@@ -2595,23 +2666,23 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2595 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", | 2666 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", |
2596 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); | 2667 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); |
2597 | desc += sprintf(buff+desc, "lq type %s\n", | 2668 | desc += sprintf(buff+desc, "lq type %s\n", |
2598 | (is_legacy(tbl->lq_type)) ? "legacy" : | 2669 | (is_legacy(rate)) ? "legacy" : |
2599 | is_vht(tbl->lq_type) ? "VHT" : "HT"); | 2670 | is_vht(rate) ? "VHT" : "HT"); |
2600 | if (is_ht(tbl->lq_type)) { | 2671 | if (!is_legacy(rate)) { |
2601 | desc += sprintf(buff+desc, " %s", | 2672 | desc += sprintf(buff+desc, " %s", |
2602 | (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); | 2673 | (is_siso(rate)) ? "SISO" : "MIMO2"); |
2603 | desc += sprintf(buff+desc, " %s", | 2674 | desc += sprintf(buff+desc, " %s", |
2604 | (is_ht20(tbl)) ? "20MHz" : | 2675 | (is_ht20(rate)) ? "20MHz" : |
2605 | (is_ht40(tbl)) ? "40MHz" : | 2676 | (is_ht40(rate)) ? "40MHz" : |
2606 | (is_ht80(tbl)) ? "80Mhz" : "BAD BW"); | 2677 | (is_ht80(rate)) ? "80Mhz" : "BAD BW"); |
2607 | desc += sprintf(buff+desc, " %s %s\n", | 2678 | desc += sprintf(buff+desc, " %s %s\n", |
2608 | (tbl->is_SGI) ? "SGI" : "", | 2679 | (rate->sgi) ? "SGI" : "NGI", |
2609 | (lq_sta->is_agg) ? "AGG on" : ""); | 2680 | (lq_sta->is_agg) ? "AGG on" : ""); |
2610 | } | 2681 | } |
2611 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | 2682 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", |
2612 | lq_sta->last_rate_n_flags); | 2683 | lq_sta->last_rate_n_flags); |
2613 | desc += sprintf(buff+desc, | 2684 | desc += sprintf(buff+desc, |
2614 | "general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", | 2685 | "general: flags=0x%X mimo-d=%d s-ant=0x%x d-ant=0x%x\n", |
2615 | lq_sta->lq.flags, | 2686 | lq_sta->lq.flags, |
2616 | lq_sta->lq.mimo_delim, | 2687 | lq_sta->lq.mimo_delim, |
2617 | lq_sta->lq.single_stream_ant_msk, | 2688 | lq_sta->lq.single_stream_ant_msk, |
@@ -2631,19 +2702,12 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2631 | lq_sta->lq.initial_rate_index[3]); | 2702 | lq_sta->lq.initial_rate_index[3]); |
2632 | 2703 | ||
2633 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | 2704 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { |
2634 | index = iwl_hwrate_to_plcp_idx( | 2705 | u32 rate = le32_to_cpu(lq_sta->lq.rs_table[i]); |
2635 | le32_to_cpu(lq_sta->lq.rs_table[i])); | 2706 | desc += sprintf(buff+desc, |
2636 | if (is_legacy(tbl->lq_type)) { | 2707 | " rate[%d] 0x%X ", |
2637 | desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", | 2708 | i, rate); |
2638 | i, le32_to_cpu(lq_sta->lq.rs_table[i]), | 2709 | |
2639 | iwl_rate_mcs[index].mbps); | 2710 | desc += rs_pretty_print_rate(buff+desc, rate); |
2640 | } else { | ||
2641 | desc += sprintf(buff+desc, | ||
2642 | " rate[%d] 0x%X %smbps (%s)\n", | ||
2643 | i, le32_to_cpu(lq_sta->lq.rs_table[i]), | ||
2644 | iwl_rate_mcs[index].mbps, | ||
2645 | iwl_rate_mcs[index].mcs); | ||
2646 | } | ||
2647 | } | 2711 | } |
2648 | 2712 | ||
2649 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); | 2713 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); |
@@ -2665,6 +2729,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
2665 | int i, j; | 2729 | int i, j; |
2666 | ssize_t ret; | 2730 | ssize_t ret; |
2667 | struct iwl_scale_tbl_info *tbl; | 2731 | struct iwl_scale_tbl_info *tbl; |
2732 | struct rs_rate *rate; | ||
2668 | struct iwl_lq_sta *lq_sta = file->private_data; | 2733 | struct iwl_lq_sta *lq_sta = file->private_data; |
2669 | 2734 | ||
2670 | buff = kmalloc(1024, GFP_KERNEL); | 2735 | buff = kmalloc(1024, GFP_KERNEL); |
@@ -2673,15 +2738,16 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
2673 | 2738 | ||
2674 | for (i = 0; i < LQ_SIZE; i++) { | 2739 | for (i = 0; i < LQ_SIZE; i++) { |
2675 | tbl = &(lq_sta->lq_info[i]); | 2740 | tbl = &(lq_sta->lq_info[i]); |
2741 | rate = &tbl->rate; | ||
2676 | desc += sprintf(buff+desc, | 2742 | desc += sprintf(buff+desc, |
2677 | "%s type=%d SGI=%d BW=%s DUP=0\n" | 2743 | "%s type=%d SGI=%d BW=%s DUP=0\n" |
2678 | "rate=0x%X\n", | 2744 | "rate=0x%X\n", |
2679 | lq_sta->active_tbl == i ? "*" : "x", | 2745 | lq_sta->active_tbl == i ? "*" : "x", |
2680 | tbl->lq_type, | 2746 | rate->type, |
2681 | tbl->is_SGI, | 2747 | rate->sgi, |
2682 | is_ht20(tbl) ? "20Mhz" : | 2748 | is_ht20(rate) ? "20Mhz" : |
2683 | is_ht40(tbl) ? "40Mhz" : | 2749 | is_ht40(rate) ? "40Mhz" : |
2684 | is_ht80(tbl) ? "80Mhz" : "ERR", | 2750 | is_ht80(rate) ? "80Mhz" : "ERR", |
2685 | tbl->current_rate); | 2751 | tbl->current_rate); |
2686 | for (j = 0; j < IWL_RATE_COUNT; j++) { | 2752 | for (j = 0; j < IWL_RATE_COUNT; j++) { |
2687 | desc += sprintf(buff+desc, | 2753 | desc += sprintf(buff+desc, |
@@ -2746,6 +2812,7 @@ static struct rate_control_ops rs_mvm_ops = { | |||
2746 | .free = rs_free, | 2812 | .free = rs_free, |
2747 | .alloc_sta = rs_alloc_sta, | 2813 | .alloc_sta = rs_alloc_sta, |
2748 | .free_sta = rs_free_sta, | 2814 | .free_sta = rs_free_sta, |
2815 | .rate_update = rs_rate_update, | ||
2749 | #ifdef CONFIG_MAC80211_DEBUGFS | 2816 | #ifdef CONFIG_MAC80211_DEBUGFS |
2750 | .add_sta_debugfs = rs_add_debugfs, | 2817 | .add_sta_debugfs = rs_add_debugfs, |
2751 | .remove_sta_debugfs = rs_remove_debugfs, | 2818 | .remove_sta_debugfs = rs_remove_debugfs, |
@@ -2778,13 +2845,13 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | |||
2778 | 2845 | ||
2779 | if (enable) { | 2846 | if (enable) { |
2780 | if (mvmsta->tx_protection == 0) | 2847 | if (mvmsta->tx_protection == 0) |
2781 | lq->flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; | 2848 | lq->flags |= LQ_FLAG_USE_RTS_MSK; |
2782 | mvmsta->tx_protection++; | 2849 | mvmsta->tx_protection++; |
2783 | } else { | 2850 | } else { |
2784 | mvmsta->tx_protection--; | 2851 | mvmsta->tx_protection--; |
2785 | if (mvmsta->tx_protection == 0) | 2852 | if (mvmsta->tx_protection == 0) |
2786 | lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK; | 2853 | lq->flags &= ~LQ_FLAG_USE_RTS_MSK; |
2787 | } | 2854 | } |
2788 | 2855 | ||
2789 | return iwl_mvm_send_lq_cmd(mvm, lq, CMD_ASYNC, false); | 2856 | return iwl_mvm_send_lq_cmd(mvm, lq, false); |
2790 | } | 2857 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 5d5344f7070b..b32960796384 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -155,38 +155,7 @@ enum { | |||
155 | #define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ | 155 | #define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ |
156 | #define IWL_RATE_HIGH_TH 10880 /* 85% */ | 156 | #define IWL_RATE_HIGH_TH 10880 /* 85% */ |
157 | #define IWL_RATE_INCREASE_TH 6400 /* 50% */ | 157 | #define IWL_RATE_INCREASE_TH 6400 /* 50% */ |
158 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ | 158 | #define RS_SR_FORCE_DECREASE 1920 /* 15% */ |
159 | |||
160 | /* possible actions when in legacy mode */ | ||
161 | enum { | ||
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 */ | ||
170 | enum { | ||
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 */ | ||
179 | enum { | ||
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 | 159 | ||
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) |
@@ -224,22 +193,45 @@ enum iwl_table_type { | |||
224 | LQ_MAX, | 193 | LQ_MAX, |
225 | }; | 194 | }; |
226 | 195 | ||
227 | #define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A)) | 196 | struct rs_rate { |
228 | #define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO) | 197 | int index; |
229 | #define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2) | 198 | enum iwl_table_type type; |
230 | #define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO) | 199 | u8 ant; |
231 | #define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2) | 200 | u32 bw; |
232 | #define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl)) | 201 | bool sgi; |
233 | #define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl)) | 202 | }; |
234 | #define is_mimo(tbl) (is_mimo2(tbl)) | 203 | |
235 | #define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl)) | 204 | |
236 | #define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl)) | 205 | #define is_type_legacy(type) (((type) == LQ_LEGACY_G) || \ |
237 | #define is_a_band(tbl) ((tbl) == LQ_LEGACY_A) | 206 | ((type) == LQ_LEGACY_A)) |
238 | #define is_g_band(tbl) ((tbl) == LQ_LEGACY_G) | 207 | #define is_type_ht_siso(type) ((type) == LQ_HT_SISO) |
239 | 208 | #define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2) | |
240 | #define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20) | 209 | #define is_type_vht_siso(type) ((type) == LQ_VHT_SISO) |
241 | #define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40) | 210 | #define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2) |
242 | #define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80) | 211 | #define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type)) |
212 | #define is_type_mimo2(type) (is_type_ht_mimo2(type) || is_type_vht_mimo2(type)) | ||
213 | #define is_type_mimo(type) (is_type_mimo2(type)) | ||
214 | #define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type)) | ||
215 | #define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type)) | ||
216 | #define is_type_a_band(type) ((type) == LQ_LEGACY_A) | ||
217 | #define is_type_g_band(type) ((type) == LQ_LEGACY_G) | ||
218 | |||
219 | #define is_legacy(rate) is_type_legacy((rate)->type) | ||
220 | #define is_ht_siso(rate) is_type_ht_siso((rate)->type) | ||
221 | #define is_ht_mimo2(rate) is_type_ht_mimo2((rate)->type) | ||
222 | #define is_vht_siso(rate) is_type_vht_siso((rate)->type) | ||
223 | #define is_vht_mimo2(rate) is_type_vht_mimo2((rate)->type) | ||
224 | #define is_siso(rate) is_type_siso((rate)->type) | ||
225 | #define is_mimo2(rate) is_type_mimo2((rate)->type) | ||
226 | #define is_mimo(rate) is_type_mimo((rate)->type) | ||
227 | #define is_ht(rate) is_type_ht((rate)->type) | ||
228 | #define is_vht(rate) is_type_vht((rate)->type) | ||
229 | #define is_a_band(rate) is_type_a_band((rate)->type) | ||
230 | #define is_g_band(rate) is_type_g_band((rate)->type) | ||
231 | |||
232 | #define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20) | ||
233 | #define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40) | ||
234 | #define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80) | ||
243 | 235 | ||
244 | #define IWL_MAX_MCS_DISPLAY_SIZE 12 | 236 | #define IWL_MAX_MCS_DISPLAY_SIZE 12 |
245 | 237 | ||
@@ -257,7 +249,23 @@ struct iwl_rate_scale_data { | |||
257 | s32 success_ratio; /* per-cent * 128 */ | 249 | s32 success_ratio; /* per-cent * 128 */ |
258 | s32 counter; /* number of frames attempted */ | 250 | s32 counter; /* number of frames attempted */ |
259 | s32 average_tpt; /* success ratio * expected throughput */ | 251 | s32 average_tpt; /* success ratio * expected throughput */ |
260 | unsigned long stamp; | 252 | }; |
253 | |||
254 | /* Possible Tx columns | ||
255 | * Tx Column = a combo of legacy/siso/mimo x antenna x SGI | ||
256 | */ | ||
257 | enum 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, | ||
261 | }; | 269 | }; |
262 | 270 | ||
263 | /** | 271 | /** |
@@ -267,17 +275,19 @@ struct iwl_rate_scale_data { | |||
267 | * one for "active", and one for "search". | 275 | * one for "active", and one for "search". |
268 | */ | 276 | */ |
269 | struct iwl_scale_tbl_info { | 277 | struct iwl_scale_tbl_info { |
270 | enum iwl_table_type lq_type; | 278 | struct rs_rate rate; |
271 | u8 ant_type; | 279 | enum rs_column column; |
272 | u8 is_SGI; /* 1 = short guard interval */ | ||
273 | u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */ | ||
274 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ | ||
275 | u8 max_search; /* maximun number of tables we can search */ | ||
276 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ | 280 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ |
277 | u32 current_rate; /* rate_n_flags, uCode API format */ | 281 | u32 current_rate; /* rate_n_flags, uCode API format */ |
278 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ | 282 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ |
279 | }; | 283 | }; |
280 | 284 | ||
285 | enum { | ||
286 | RS_STATE_SEARCH_CYCLE_STARTED, | ||
287 | RS_STATE_SEARCH_CYCLE_ENDED, | ||
288 | RS_STATE_STAY_IN_COLUMN, | ||
289 | }; | ||
290 | |||
281 | /** | 291 | /** |
282 | * struct iwl_lq_sta -- driver's rate scaling private structure | 292 | * struct iwl_lq_sta -- driver's rate scaling private structure |
283 | * | 293 | * |
@@ -285,8 +295,7 @@ struct iwl_scale_tbl_info { | |||
285 | */ | 295 | */ |
286 | struct iwl_lq_sta { | 296 | struct iwl_lq_sta { |
287 | u8 active_tbl; /* index of active table, range 0-1 */ | 297 | u8 active_tbl; /* index of active table, range 0-1 */ |
288 | u8 enable_counter; /* indicates HT mode */ | 298 | u8 rs_state; /* RS_STATE_* */ |
289 | u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ | ||
290 | u8 search_better_tbl; /* 1: currently trying alternate mode */ | 299 | u8 search_better_tbl; /* 1: currently trying alternate mode */ |
291 | s32 last_tpt; | 300 | s32 last_tpt; |
292 | 301 | ||
@@ -299,7 +308,9 @@ struct iwl_lq_sta { | |||
299 | u32 total_success; /* total successful frames, any/all rates */ | 308 | u32 total_success; /* total successful frames, any/all rates */ |
300 | u64 flush_timer; /* time staying in mode before new search */ | 309 | u64 flush_timer; /* time staying in mode before new search */ |
301 | 310 | ||
302 | u8 action_counter; /* # mode-switch actions tried */ | 311 | u32 visited_columns; /* Bitmask marking which Tx columns were |
312 | * explored during a search cycle | ||
313 | */ | ||
303 | bool is_vht; | 314 | bool is_vht; |
304 | enum ieee80211_band band; | 315 | enum ieee80211_band band; |
305 | 316 | ||
@@ -328,32 +339,11 @@ struct iwl_lq_sta { | |||
328 | u32 last_rate_n_flags; | 339 | u32 last_rate_n_flags; |
329 | /* packets destined for this STA are aggregated */ | 340 | /* packets destined for this STA are aggregated */ |
330 | u8 is_agg; | 341 | u8 is_agg; |
331 | /* BT traffic this sta was last updated in */ | ||
332 | u8 last_bt_traffic; | ||
333 | }; | ||
334 | |||
335 | enum iwl_bt_coex_profile_traffic_load { | ||
336 | IWL_BT_COEX_TRAFFIC_LOAD_NONE = 0, | ||
337 | IWL_BT_COEX_TRAFFIC_LOAD_LOW = 1, | ||
338 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 2, | ||
339 | IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS = 3, | ||
340 | /* | ||
341 | * There are no more even though below is a u8, the | ||
342 | * indication from the BT device only has two bits. | ||
343 | */ | ||
344 | }; | 342 | }; |
345 | 343 | ||
346 | |||
347 | static inline u8 num_of_ant(u8 mask) | ||
348 | { | ||
349 | return !!((mask) & ANT_A) + | ||
350 | !!((mask) & ANT_B) + | ||
351 | !!((mask) & ANT_C); | ||
352 | } | ||
353 | |||
354 | /* Initialize station's rate scaling information after adding station */ | 344 | /* Initialize station's rate scaling information after adding station */ |
355 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 345 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
356 | enum ieee80211_band band); | 346 | enum ieee80211_band band, bool init); |
357 | 347 | ||
358 | /** | 348 | /** |
359 | * iwl_rate_control_register - Register the rate control algorithm callbacks | 349 | * iwl_rate_control_register - Register the rate control algorithm callbacks |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e0cd100b40cd..4ce9bb581144 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -70,6 +70,9 @@ | |||
70 | 70 | ||
71 | #define IWL_PLCP_QUIET_THRESH 1 | 71 | #define IWL_PLCP_QUIET_THRESH 1 |
72 | #define IWL_ACTIVE_QUIET_TIME 10 | 72 | #define IWL_ACTIVE_QUIET_TIME 10 |
73 | #define LONG_OUT_TIME_PERIOD 600 | ||
74 | #define SHORT_OUT_TIME_PERIOD 200 | ||
75 | #define SUSPEND_TIME_PERIOD 100 | ||
73 | 76 | ||
74 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 77 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
75 | { | 78 | { |
@@ -87,20 +90,22 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | |||
87 | return cpu_to_le16(rx_chain); | 90 | return cpu_to_le16(rx_chain); |
88 | } | 91 | } |
89 | 92 | ||
90 | static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif) | 93 | static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif, |
94 | u32 flags, bool is_assoc) | ||
91 | { | 95 | { |
92 | if (vif->bss_conf.assoc) | 96 | if (!is_assoc) |
93 | return cpu_to_le32(200 * 1024); | ||
94 | else | ||
95 | return 0; | 97 | return 0; |
98 | if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | ||
99 | return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD)); | ||
100 | return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD)); | ||
96 | } | 101 | } |
97 | 102 | ||
98 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) | 103 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif, |
104 | bool is_assoc) | ||
99 | { | 105 | { |
100 | if (!vif->bss_conf.assoc) | 106 | if (!is_assoc) |
101 | return 0; | 107 | return 0; |
102 | 108 | return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD)); | |
103 | return cpu_to_le32(ieee80211_tu_to_usec(vif->bss_conf.beacon_int)); | ||
104 | } | 109 | } |
105 | 110 | ||
106 | static inline __le32 | 111 | static inline __le32 |
@@ -262,6 +267,15 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | |||
262 | return (u16)len; | 267 | return (u16)len; |
263 | } | 268 | } |
264 | 269 | ||
270 | static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac, | ||
271 | struct ieee80211_vif *vif) | ||
272 | { | ||
273 | bool *is_assoc = data; | ||
274 | |||
275 | if (vif->bss_conf.assoc) | ||
276 | *is_assoc = true; | ||
277 | } | ||
278 | |||
265 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 279 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
266 | struct ieee80211_vif *vif, | 280 | struct ieee80211_vif *vif, |
267 | struct cfg80211_scan_request *req) | 281 | struct cfg80211_scan_request *req) |
@@ -274,6 +288,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
274 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 288 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
275 | }; | 289 | }; |
276 | struct iwl_scan_cmd *cmd = mvm->scan_cmd; | 290 | struct iwl_scan_cmd *cmd = mvm->scan_cmd; |
291 | bool is_assoc = false; | ||
277 | int ret; | 292 | int ret; |
278 | u32 status; | 293 | u32 status; |
279 | int ssid_len = 0; | 294 | int ssid_len = 0; |
@@ -289,13 +304,17 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
289 | memset(cmd, 0, sizeof(struct iwl_scan_cmd) + | 304 | memset(cmd, 0, sizeof(struct iwl_scan_cmd) + |
290 | mvm->fw->ucode_capa.max_probe_length + | 305 | mvm->fw->ucode_capa.max_probe_length + |
291 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); | 306 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); |
292 | 307 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | |
308 | IEEE80211_IFACE_ITER_NORMAL, | ||
309 | iwl_mvm_vif_assoc_iterator, | ||
310 | &is_assoc); | ||
293 | cmd->channel_count = (u8)req->n_channels; | 311 | cmd->channel_count = (u8)req->n_channels; |
294 | cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); | 312 | cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); |
295 | cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | 313 | cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); |
296 | cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); | 314 | cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); |
297 | cmd->max_out_time = iwl_mvm_scan_max_out_time(vif); | 315 | cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, |
298 | cmd->suspend_time = iwl_mvm_scan_suspend_time(vif); | 316 | is_assoc); |
317 | cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); | ||
299 | cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); | 318 | cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); |
300 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 319 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
301 | MAC_FILTER_IN_BEACON); | 320 | MAC_FILTER_IN_BEACON); |
@@ -522,6 +541,12 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, | |||
522 | struct cfg80211_sched_scan_request *req, | 541 | struct cfg80211_sched_scan_request *req, |
523 | struct iwl_scan_offload_cmd *scan) | 542 | struct iwl_scan_offload_cmd *scan) |
524 | { | 543 | { |
544 | bool is_assoc = false; | ||
545 | |||
546 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
547 | IEEE80211_IFACE_ITER_NORMAL, | ||
548 | iwl_mvm_vif_assoc_iterator, | ||
549 | &is_assoc); | ||
525 | scan->channel_count = | 550 | scan->channel_count = |
526 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | 551 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + |
527 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | 552 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; |
@@ -529,8 +554,9 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, | |||
529 | scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | 554 | scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); |
530 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; | 555 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; |
531 | scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); | 556 | scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); |
532 | scan->max_out_time = cpu_to_le32(200 * 1024); | 557 | scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, |
533 | scan->suspend_time = iwl_mvm_scan_suspend_time(vif); | 558 | is_assoc); |
559 | scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); | ||
534 | scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 560 | scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
535 | MAC_FILTER_IN_BEACON); | 561 | MAC_FILTER_IN_BEACON); |
536 | scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); | 562 | scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); |
@@ -817,11 +843,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | |||
817 | IWL_DEBUG_SCAN(mvm, | 843 | IWL_DEBUG_SCAN(mvm, |
818 | "Sending scheduled scan with filtering, filter len %d\n", | 844 | "Sending scheduled scan with filtering, filter len %d\n", |
819 | req->n_match_sets); | 845 | req->n_match_sets); |
820 | scan_req.flags |= | ||
821 | cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID); | ||
822 | } else { | 846 | } else { |
823 | IWL_DEBUG_SCAN(mvm, | 847 | IWL_DEBUG_SCAN(mvm, |
824 | "Sending Scheduled scan without filtering\n"); | 848 | "Sending Scheduled scan without filtering\n"); |
849 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); | ||
825 | } | 850 | } |
826 | 851 | ||
827 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC, | 852 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 329952363a54..7a5b7473eafa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -840,7 +840,7 @@ static const u8 tid_to_ac[] = { | |||
840 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 840 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
841 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 841 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
842 | { | 842 | { |
843 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 843 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
844 | struct iwl_mvm_tid_data *tid_data; | 844 | struct iwl_mvm_tid_data *tid_data; |
845 | int txq_id; | 845 | int txq_id; |
846 | 846 | ||
@@ -895,7 +895,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
895 | int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 895 | int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
896 | struct ieee80211_sta *sta, u16 tid, u8 buf_size) | 896 | struct ieee80211_sta *sta, u16 tid, u8 buf_size) |
897 | { | 897 | { |
898 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 898 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
899 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | 899 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; |
900 | int queue, fifo, ret; | 900 | int queue, fifo, ret; |
901 | u16 ssn; | 901 | u16 ssn; |
@@ -945,13 +945,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
945 | */ | 945 | */ |
946 | } | 946 | } |
947 | 947 | ||
948 | return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); | 948 | return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false); |
949 | } | 949 | } |
950 | 950 | ||
951 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 951 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
952 | struct ieee80211_sta *sta, u16 tid) | 952 | struct ieee80211_sta *sta, u16 tid) |
953 | { | 953 | { |
954 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 954 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
955 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | 955 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; |
956 | u16 txq_id; | 956 | u16 txq_id; |
957 | int err; | 957 | int err; |
@@ -1023,7 +1023,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1023 | int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1023 | int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
1024 | struct ieee80211_sta *sta, u16 tid) | 1024 | struct ieee80211_sta *sta, u16 tid) |
1025 | { | 1025 | { |
1026 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1026 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1027 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | 1027 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; |
1028 | u16 txq_id; | 1028 | u16 txq_id; |
1029 | enum iwl_mvm_agg_state old_state; | 1029 | enum iwl_mvm_agg_state old_state; |
@@ -1416,7 +1416,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1416 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | 1416 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, |
1417 | struct ieee80211_sta *sta) | 1417 | struct ieee80211_sta *sta) |
1418 | { | 1418 | { |
1419 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1419 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1420 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1420 | struct iwl_mvm_add_sta_cmd_v6 cmd = { |
1421 | .add_modify = STA_MODE_MODIFY, | 1421 | .add_modify = STA_MODE_MODIFY, |
1422 | .sta_id = mvmsta->sta_id, | 1422 | .sta_id = mvmsta->sta_id, |
@@ -1438,7 +1438,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | |||
1438 | u16 sleep_state_flags = | 1438 | u16 sleep_state_flags = |
1439 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? | 1439 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? |
1440 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; | 1440 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; |
1441 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1441 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1442 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1442 | struct iwl_mvm_add_sta_cmd_v6 cmd = { |
1443 | .add_modify = STA_MODE_MODIFY, | 1443 | .add_modify = STA_MODE_MODIFY, |
1444 | .sta_id = mvmsta->sta_id, | 1444 | .sta_id = mvmsta->sta_id, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 4dfc359a4bdd..b34941148a98 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -298,6 +298,12 @@ struct iwl_mvm_sta { | |||
298 | bool tt_tx_protection; | 298 | bool tt_tx_protection; |
299 | }; | 299 | }; |
300 | 300 | ||
301 | static inline struct iwl_mvm_sta * | ||
302 | iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta) | ||
303 | { | ||
304 | return (void *)sta->drv_priv; | ||
305 | } | ||
306 | |||
301 | /** | 307 | /** |
302 | * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or | 308 | * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or |
303 | * broadcast) | 309 | * broadcast) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 1f3282dff513..18be04da8e3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -388,7 +388,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | |||
388 | lockdep_is_held(&mvm->mutex)); | 388 | lockdep_is_held(&mvm->mutex)); |
389 | if (IS_ERR_OR_NULL(sta)) | 389 | if (IS_ERR_OR_NULL(sta)) |
390 | continue; | 390 | continue; |
391 | mvmsta = (void *)sta->drv_priv; | 391 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
392 | if (enable == mvmsta->tt_tx_protection) | 392 | if (enable == mvmsta->tt_tx_protection) |
393 | continue; | 393 | continue; |
394 | err = iwl_mvm_tx_protection(mvm, mvmsta, enable); | 394 | err = iwl_mvm_tx_protection(mvm, mvmsta, enable); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 43d97c33a75a..d87649ac88e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -276,6 +276,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
276 | return NULL; | 276 | return NULL; |
277 | 277 | ||
278 | memset(dev_cmd, 0, sizeof(*dev_cmd)); | 278 | memset(dev_cmd, 0, sizeof(*dev_cmd)); |
279 | dev_cmd->hdr.cmd = TX_CMD; | ||
279 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; | 280 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; |
280 | 281 | ||
281 | if (info->control.hw_key) | 282 | if (info->control.hw_key) |
@@ -361,7 +362,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
361 | u8 txq_id = info->hw_queue; | 362 | u8 txq_id = info->hw_queue; |
362 | bool is_data_qos = false, is_ampdu = false; | 363 | bool is_data_qos = false, is_ampdu = false; |
363 | 364 | ||
364 | mvmsta = (void *)sta->drv_priv; | 365 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
365 | fc = hdr->frame_control; | 366 | fc = hdr->frame_control; |
366 | 367 | ||
367 | if (WARN_ON_ONCE(!mvmsta)) | 368 | if (WARN_ON_ONCE(!mvmsta)) |
@@ -432,7 +433,7 @@ drop: | |||
432 | static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, | 433 | static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, |
433 | struct ieee80211_sta *sta, u8 tid) | 434 | struct ieee80211_sta *sta, u8 tid) |
434 | { | 435 | { |
435 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 436 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
436 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | 437 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; |
437 | struct ieee80211_vif *vif = mvmsta->vif; | 438 | struct ieee80211_vif *vif = mvmsta->vif; |
438 | 439 | ||
@@ -662,7 +663,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
662 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | 663 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); |
663 | 664 | ||
664 | if (!IS_ERR_OR_NULL(sta)) { | 665 | if (!IS_ERR_OR_NULL(sta)) { |
665 | mvmsta = (void *)sta->drv_priv; | 666 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
666 | 667 | ||
667 | if (tid != IWL_TID_NON_QOS) { | 668 | if (tid != IWL_TID_NON_QOS) { |
668 | struct iwl_mvm_tid_data *tid_data = | 669 | struct iwl_mvm_tid_data *tid_data = |
@@ -793,7 +794,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | |||
793 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | 794 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); |
794 | 795 | ||
795 | if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { | 796 | if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { |
796 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 797 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
797 | mvmsta->tid_data[tid].rate_n_flags = | 798 | mvmsta->tid_data[tid].rate_n_flags = |
798 | le32_to_cpu(tx_resp->initial_rate); | 799 | le32_to_cpu(tx_resp->initial_rate); |
799 | } | 800 | } |
@@ -849,7 +850,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
849 | return 0; | 850 | return 0; |
850 | } | 851 | } |
851 | 852 | ||
852 | mvmsta = (void *)sta->drv_priv; | 853 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
853 | tid_data = &mvmsta->tid_data[tid]; | 854 | tid_data = &mvmsta->tid_data[tid]; |
854 | 855 | ||
855 | if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", | 856 | if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index ed69e9b78e82..56cf819bc0c7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -486,22 +486,18 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) | |||
486 | * this case to clear the state indicating that station creation is in | 486 | * this case to clear the state indicating that station creation is in |
487 | * progress. | 487 | * progress. |
488 | */ | 488 | */ |
489 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | 489 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) |
490 | u8 flags, bool init) | ||
491 | { | 490 | { |
492 | struct iwl_host_cmd cmd = { | 491 | struct iwl_host_cmd cmd = { |
493 | .id = LQ_CMD, | 492 | .id = LQ_CMD, |
494 | .len = { sizeof(struct iwl_lq_cmd), }, | 493 | .len = { sizeof(struct iwl_lq_cmd), }, |
495 | .flags = flags, | 494 | .flags = init ? CMD_SYNC : CMD_ASYNC, |
496 | .data = { lq, }, | 495 | .data = { lq, }, |
497 | }; | 496 | }; |
498 | 497 | ||
499 | if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT)) | 498 | if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT)) |
500 | return -EINVAL; | 499 | return -EINVAL; |
501 | 500 | ||
502 | if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) | ||
503 | return -EINVAL; | ||
504 | |||
505 | return iwl_mvm_send_cmd(mvm, &cmd); | 501 | return iwl_mvm_send_cmd(mvm, &cmd); |
506 | } | 502 | } |
507 | 503 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 86605027c41d..2e97a3995333 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -297,6 +297,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
297 | {IWL_PCI_DEVICE(0x08B2, 0x4370, iwl7260_2ac_cfg)}, | 297 | {IWL_PCI_DEVICE(0x08B2, 0x4370, iwl7260_2ac_cfg)}, |
298 | {IWL_PCI_DEVICE(0x08B2, 0x4360, iwl7260_2n_cfg)}, | 298 | {IWL_PCI_DEVICE(0x08B2, 0x4360, iwl7260_2n_cfg)}, |
299 | {IWL_PCI_DEVICE(0x08B1, 0x5070, iwl7260_2ac_cfg)}, | 299 | {IWL_PCI_DEVICE(0x08B1, 0x5070, iwl7260_2ac_cfg)}, |
300 | {IWL_PCI_DEVICE(0x08B1, 0x5072, iwl7260_2ac_cfg)}, | ||
301 | {IWL_PCI_DEVICE(0x08B1, 0x5170, iwl7260_2ac_cfg)}, | ||
302 | {IWL_PCI_DEVICE(0x08B1, 0x5770, iwl7260_2ac_cfg)}, | ||
300 | {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)}, | 303 | {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)}, |
301 | {IWL_PCI_DEVICE(0x08B1, 0x402A, iwl7260_2n_cfg)}, | 304 | {IWL_PCI_DEVICE(0x08B1, 0x402A, iwl7260_2n_cfg)}, |
302 | {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)}, | 305 | {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)}, |
@@ -350,6 +353,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
350 | {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)}, | 353 | {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)}, |
351 | {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)}, | 354 | {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)}, |
352 | {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)}, | 355 | {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)}, |
356 | {IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)}, | ||
357 | {IWL_PCI_DEVICE(0x08B3, 0x1170, iwl3160_2ac_cfg)}, | ||
353 | 358 | ||
354 | /* 7265 Series */ | 359 | /* 7265 Series */ |
355 | {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, | 360 | {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index be3995afa9d0..1d6bf7b98e2d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -1126,7 +1126,6 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1126 | struct iwl_trans *trans = data; | 1126 | struct iwl_trans *trans = data; |
1127 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1127 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1128 | u32 inta, inta_mask; | 1128 | u32 inta, inta_mask; |
1129 | irqreturn_t ret = IRQ_NONE; | ||
1130 | 1129 | ||
1131 | lockdep_assert_held(&trans_pcie->irq_lock); | 1130 | lockdep_assert_held(&trans_pcie->irq_lock); |
1132 | 1131 | ||
@@ -1155,7 +1154,16 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1155 | * or due to sporadic interrupts thrown from our NIC. */ | 1154 | * or due to sporadic interrupts thrown from our NIC. */ |
1156 | if (!inta) { | 1155 | if (!inta) { |
1157 | IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); | 1156 | IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); |
1158 | goto none; | 1157 | /* |
1158 | * Re-enable interrupts here since we don't have anything to | ||
1159 | * service, but only in case the handler won't run. Note that | ||
1160 | * the handler can be scheduled because of a previous | ||
1161 | * interrupt. | ||
1162 | */ | ||
1163 | if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||
1164 | !trans_pcie->inta) | ||
1165 | iwl_enable_interrupts(trans); | ||
1166 | return IRQ_NONE; | ||
1159 | } | 1167 | } |
1160 | 1168 | ||
1161 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | 1169 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { |
@@ -1173,19 +1181,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1173 | 1181 | ||
1174 | trans_pcie->inta |= inta; | 1182 | trans_pcie->inta |= inta; |
1175 | /* the thread will service interrupts and re-enable them */ | 1183 | /* the thread will service interrupts and re-enable them */ |
1176 | if (likely(inta)) | 1184 | return IRQ_WAKE_THREAD; |
1177 | return IRQ_WAKE_THREAD; | ||
1178 | |||
1179 | ret = IRQ_HANDLED; | ||
1180 | |||
1181 | none: | ||
1182 | /* re-enable interrupts here since we don't have anything to service. */ | ||
1183 | /* only Re-enable if disabled by irq and no schedules tasklet. */ | ||
1184 | if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||
1185 | !trans_pcie->inta) | ||
1186 | iwl_enable_interrupts(trans); | ||
1187 | |||
1188 | return ret; | ||
1189 | } | 1185 | } |
1190 | 1186 | ||
1191 | /* interrupt handler using ict table, with this interrupt driver will | 1187 | /* interrupt handler using ict table, with this interrupt driver will |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 0adde919a258..a4ef5cc11100 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -1542,30 +1542,24 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, | |||
1542 | } | 1542 | } |
1543 | 1543 | ||
1544 | if (!ret) { | 1544 | if (!ret) { |
1545 | if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { | 1545 | struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; |
1546 | struct iwl_txq *txq = | 1546 | struct iwl_queue *q = &txq->q; |
1547 | &trans_pcie->txq[trans_pcie->cmd_queue]; | ||
1548 | struct iwl_queue *q = &txq->q; | ||
1549 | 1547 | ||
1550 | IWL_ERR(trans, | 1548 | IWL_ERR(trans, "Error sending %s: time out after %dms.\n", |
1551 | "Error sending %s: time out after %dms.\n", | 1549 | get_cmd_string(trans_pcie, cmd->id), |
1552 | get_cmd_string(trans_pcie, cmd->id), | 1550 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); |
1553 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); | ||
1554 | 1551 | ||
1555 | IWL_ERR(trans, | 1552 | IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", |
1556 | "Current CMD queue read_ptr %d write_ptr %d\n", | 1553 | q->read_ptr, q->write_ptr); |
1557 | q->read_ptr, q->write_ptr); | ||
1558 | 1554 | ||
1559 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | 1555 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); |
1560 | IWL_DEBUG_INFO(trans, | 1556 | IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", |
1561 | "Clearing HCMD_ACTIVE for command %s\n", | 1557 | get_cmd_string(trans_pcie, cmd->id)); |
1562 | get_cmd_string(trans_pcie, cmd->id)); | 1558 | ret = -ETIMEDOUT; |
1563 | ret = -ETIMEDOUT; | ||
1564 | 1559 | ||
1565 | iwl_nic_error(trans); | 1560 | iwl_nic_error(trans); |
1566 | 1561 | ||
1567 | goto cancel; | 1562 | goto cancel; |
1568 | } | ||
1569 | } | 1563 | } |
1570 | 1564 | ||
1571 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { | 1565 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { |
@@ -1674,7 +1668,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1674 | txq->entries[q->write_ptr].skb = skb; | 1668 | txq->entries[q->write_ptr].skb = skb; |
1675 | txq->entries[q->write_ptr].cmd = dev_cmd; | 1669 | txq->entries[q->write_ptr].cmd = dev_cmd; |
1676 | 1670 | ||
1677 | dev_cmd->hdr.cmd = REPLY_TX; | ||
1678 | dev_cmd->hdr.sequence = | 1671 | dev_cmd->hdr.sequence = |
1679 | cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | | 1672 | cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | |
1680 | INDEX_TO_SEQ(q->write_ptr))); | 1673 | INDEX_TO_SEQ(q->write_ptr))); |