aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Valo <kvalo@codeaurora.org>2017-12-14 11:38:48 -0500
committerKalle Valo <kvalo@codeaurora.org>2017-12-14 11:38:48 -0500
commit1dde35d0b8e3a9fbf24e13d16dc583f1cc5d027b (patch)
tree14418168dd854cc6a795cc200352646032c4e5bc
parent7de241f3b705396fe21f45d38ba1247c522aae81 (diff)
parent03a72288c546289cfa0eb1e3613fb9cdb302b4f9 (diff)
Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.16. Major changes: ath10k * enable multiqueue support for all hw using mac80211 wake_tx_queue op * new Kconfig option ATH10K_SPECTRAL to save RAM * show tx stats on QCA9880 * new qcom,ath10k-calibration-variant DT entry * WMI layer support for wcn3990 ath9k * new Kconfig option ATH9K_COMMON_SPECTRAL to save RAM wcn36xx * hardware scan offload support wil6210 * run-time PM support when interface is down
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt3
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig9
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c95
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h21
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c27
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h19
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c181
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h14
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c65
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h9
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c146
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h113
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c72
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h5
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig14
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h107
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c16
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c126
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.h3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c17
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c150
-rw-r--r--drivers/net/wireless/ath/wil6210/ethtool.c15
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c79
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c22
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c26
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c97
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c104
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h40
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c304
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h17
42 files changed, 1657 insertions, 337 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
index 74d7f0af209c..3d2a031217da 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
@@ -41,6 +41,9 @@ Optional properties:
41- qcom,msi_addr: MSI interrupt address. 41- qcom,msi_addr: MSI interrupt address.
42- qcom,msi_base: Base value to add before writing MSI data into 42- qcom,msi_base: Base value to add before writing MSI data into
43 MSI address register. 43 MSI address register.
44- qcom,ath10k-calibration-variant: string to search for in the board-2.bin
45 variant list with the same bus and device
46 specific ids
44- qcom,ath10k-calibration-data : calibration data + board specific data 47- qcom,ath10k-calibration-data : calibration data + board specific data
45 as an array, the length can vary between 48 as an array, the length can vary between
46 hw versions. 49 hw versions.
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 87f56d0e17a6..deb5ae21a559 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -47,12 +47,19 @@ config ATH10K_DEBUG
47config ATH10K_DEBUGFS 47config ATH10K_DEBUGFS
48 bool "Atheros ath10k debugfs support" 48 bool "Atheros ath10k debugfs support"
49 depends on ATH10K && DEBUG_FS 49 depends on ATH10K && DEBUG_FS
50 select RELAY
51 ---help--- 50 ---help---
52 Enabled debugfs support 51 Enabled debugfs support
53 52
54 If unsure, say Y to make it easier to debug problems. 53 If unsure, say Y to make it easier to debug problems.
55 54
55config ATH10K_SPECTRAL
56 bool "Atheros ath10k spectral scan support"
57 depends on ATH10K_DEBUGFS
58 select RELAY
59 default n
60 ---help---
61 Say Y to enable access to the FFT/spectral data via debugfs.
62
56config ATH10K_TRACING 63config ATH10K_TRACING
57 bool "Atheros ath10k tracing support" 64 bool "Atheros ath10k tracing support"
58 depends on ATH10K 65 depends on ATH10K
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 9492177e9063..8d9a59b7144e 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -15,7 +15,7 @@ ath10k_core-y += mac.o \
15 p2p.o \ 15 p2p.o \
16 swap.o 16 swap.o
17 17
18ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o 18ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o
19ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o 19ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
20ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o 20ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
21ath10k_core-$(CONFIG_THERMAL) += thermal.o 21ath10k_core-$(CONFIG_THERMAL) += thermal.o
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index b29fdbd21ead..6d065f8d7f78 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -75,6 +75,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
75 .vht160_mcs_rx_highest = 0, 75 .vht160_mcs_rx_highest = 0,
76 .vht160_mcs_tx_highest = 0, 76 .vht160_mcs_tx_highest = 0,
77 .n_cipher_suites = 8, 77 .n_cipher_suites = 8,
78 .num_peers = TARGET_TLV_NUM_PEERS,
79 .ast_skid_limit = 0x10,
80 .num_wds_entries = 0x20,
78 }, 81 },
79 { 82 {
80 .id = QCA9887_HW_1_0_VERSION, 83 .id = QCA9887_HW_1_0_VERSION,
@@ -99,6 +102,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
99 .vht160_mcs_rx_highest = 0, 102 .vht160_mcs_rx_highest = 0,
100 .vht160_mcs_tx_highest = 0, 103 .vht160_mcs_tx_highest = 0,
101 .n_cipher_suites = 8, 104 .n_cipher_suites = 8,
105 .num_peers = TARGET_TLV_NUM_PEERS,
106 .ast_skid_limit = 0x10,
107 .num_wds_entries = 0x20,
102 }, 108 },
103 { 109 {
104 .id = QCA6174_HW_2_1_VERSION, 110 .id = QCA6174_HW_2_1_VERSION,
@@ -122,6 +128,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
122 .vht160_mcs_rx_highest = 0, 128 .vht160_mcs_rx_highest = 0,
123 .vht160_mcs_tx_highest = 0, 129 .vht160_mcs_tx_highest = 0,
124 .n_cipher_suites = 8, 130 .n_cipher_suites = 8,
131 .num_peers = TARGET_TLV_NUM_PEERS,
132 .ast_skid_limit = 0x10,
133 .num_wds_entries = 0x20,
125 }, 134 },
126 { 135 {
127 .id = QCA6174_HW_2_1_VERSION, 136 .id = QCA6174_HW_2_1_VERSION,
@@ -145,6 +154,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
145 .vht160_mcs_rx_highest = 0, 154 .vht160_mcs_rx_highest = 0,
146 .vht160_mcs_tx_highest = 0, 155 .vht160_mcs_tx_highest = 0,
147 .n_cipher_suites = 8, 156 .n_cipher_suites = 8,
157 .num_peers = TARGET_TLV_NUM_PEERS,
158 .ast_skid_limit = 0x10,
159 .num_wds_entries = 0x20,
148 }, 160 },
149 { 161 {
150 .id = QCA6174_HW_3_0_VERSION, 162 .id = QCA6174_HW_3_0_VERSION,
@@ -168,6 +180,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
168 .vht160_mcs_rx_highest = 0, 180 .vht160_mcs_rx_highest = 0,
169 .vht160_mcs_tx_highest = 0, 181 .vht160_mcs_tx_highest = 0,
170 .n_cipher_suites = 8, 182 .n_cipher_suites = 8,
183 .num_peers = TARGET_TLV_NUM_PEERS,
184 .ast_skid_limit = 0x10,
185 .num_wds_entries = 0x20,
171 }, 186 },
172 { 187 {
173 .id = QCA6174_HW_3_2_VERSION, 188 .id = QCA6174_HW_3_2_VERSION,
@@ -194,6 +209,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
194 .vht160_mcs_rx_highest = 0, 209 .vht160_mcs_rx_highest = 0,
195 .vht160_mcs_tx_highest = 0, 210 .vht160_mcs_tx_highest = 0,
196 .n_cipher_suites = 8, 211 .n_cipher_suites = 8,
212 .num_peers = TARGET_TLV_NUM_PEERS,
213 .ast_skid_limit = 0x10,
214 .num_wds_entries = 0x20,
197 }, 215 },
198 { 216 {
199 .id = QCA99X0_HW_2_0_DEV_VERSION, 217 .id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -223,6 +241,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
223 .vht160_mcs_rx_highest = 0, 241 .vht160_mcs_rx_highest = 0,
224 .vht160_mcs_tx_highest = 0, 242 .vht160_mcs_tx_highest = 0,
225 .n_cipher_suites = 11, 243 .n_cipher_suites = 11,
244 .num_peers = TARGET_TLV_NUM_PEERS,
245 .ast_skid_limit = 0x10,
246 .num_wds_entries = 0x20,
226 }, 247 },
227 { 248 {
228 .id = QCA9984_HW_1_0_DEV_VERSION, 249 .id = QCA9984_HW_1_0_DEV_VERSION,
@@ -257,6 +278,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
257 .vht160_mcs_rx_highest = 1560, 278 .vht160_mcs_rx_highest = 1560,
258 .vht160_mcs_tx_highest = 1560, 279 .vht160_mcs_tx_highest = 1560,
259 .n_cipher_suites = 11, 280 .n_cipher_suites = 11,
281 .num_peers = TARGET_TLV_NUM_PEERS,
282 .ast_skid_limit = 0x10,
283 .num_wds_entries = 0x20,
260 }, 284 },
261 { 285 {
262 .id = QCA9888_HW_2_0_DEV_VERSION, 286 .id = QCA9888_HW_2_0_DEV_VERSION,
@@ -290,6 +314,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
290 .vht160_mcs_rx_highest = 780, 314 .vht160_mcs_rx_highest = 780,
291 .vht160_mcs_tx_highest = 780, 315 .vht160_mcs_tx_highest = 780,
292 .n_cipher_suites = 11, 316 .n_cipher_suites = 11,
317 .num_peers = TARGET_TLV_NUM_PEERS,
318 .ast_skid_limit = 0x10,
319 .num_wds_entries = 0x20,
293 }, 320 },
294 { 321 {
295 .id = QCA9377_HW_1_0_DEV_VERSION, 322 .id = QCA9377_HW_1_0_DEV_VERSION,
@@ -313,6 +340,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
313 .vht160_mcs_rx_highest = 0, 340 .vht160_mcs_rx_highest = 0,
314 .vht160_mcs_tx_highest = 0, 341 .vht160_mcs_tx_highest = 0,
315 .n_cipher_suites = 8, 342 .n_cipher_suites = 8,
343 .num_peers = TARGET_TLV_NUM_PEERS,
344 .ast_skid_limit = 0x10,
345 .num_wds_entries = 0x20,
316 }, 346 },
317 { 347 {
318 .id = QCA9377_HW_1_1_DEV_VERSION, 348 .id = QCA9377_HW_1_1_DEV_VERSION,
@@ -338,6 +368,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
338 .vht160_mcs_rx_highest = 0, 368 .vht160_mcs_rx_highest = 0,
339 .vht160_mcs_tx_highest = 0, 369 .vht160_mcs_tx_highest = 0,
340 .n_cipher_suites = 8, 370 .n_cipher_suites = 8,
371 .num_peers = TARGET_TLV_NUM_PEERS,
372 .ast_skid_limit = 0x10,
373 .num_wds_entries = 0x20,
341 }, 374 },
342 { 375 {
343 .id = QCA4019_HW_1_0_DEV_VERSION, 376 .id = QCA4019_HW_1_0_DEV_VERSION,
@@ -368,6 +401,27 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
368 .vht160_mcs_rx_highest = 0, 401 .vht160_mcs_rx_highest = 0,
369 .vht160_mcs_tx_highest = 0, 402 .vht160_mcs_tx_highest = 0,
370 .n_cipher_suites = 11, 403 .n_cipher_suites = 11,
404 .num_peers = TARGET_TLV_NUM_PEERS,
405 .ast_skid_limit = 0x10,
406 .num_wds_entries = 0x20,
407 },
408 {
409 .id = WCN3990_HW_1_0_DEV_VERSION,
410 .dev_id = 0,
411 .name = "wcn3990 hw1.0",
412 .continuous_frag_desc = true,
413 .tx_chain_mask = 0x7,
414 .rx_chain_mask = 0x7,
415 .max_spatial_stream = 4,
416 .fw = {
417 .dir = WCN3990_HW_1_0_FW_DIR,
418 },
419 .sw_decrypt_mcast_mgmt = true,
420 .hw_ops = &wcn3990_ops,
421 .decap_align_bytes = 1,
422 .num_peers = TARGET_HL_10_TLV_NUM_PEERS,
423 .ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT,
424 .num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES,
371 }, 425 },
372}; 426};
373 427
@@ -390,6 +444,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
390 [ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war", 444 [ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war",
391 [ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast", 445 [ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",
392 [ATH10K_FW_FEATURE_NO_PS] = "no-ps", 446 [ATH10K_FW_FEATURE_NO_PS] = "no-ps",
447 [ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
393}; 448};
394 449
395static unsigned int ath10k_core_get_fw_feature_str(char *buf, 450static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -860,6 +915,28 @@ static int ath10k_core_check_smbios(struct ath10k *ar)
860 return 0; 915 return 0;
861} 916}
862 917
918static int ath10k_core_check_dt(struct ath10k *ar)
919{
920 struct device_node *node;
921 const char *variant = NULL;
922
923 node = ar->dev->of_node;
924 if (!node)
925 return -ENOENT;
926
927 of_property_read_string(node, "qcom,ath10k-calibration-variant",
928 &variant);
929 if (!variant)
930 return -ENODATA;
931
932 if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0)
933 ath10k_dbg(ar, ATH10K_DBG_BOOT,
934 "bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
935 variant);
936
937 return 0;
938}
939
863static int ath10k_download_and_run_otp(struct ath10k *ar) 940static int ath10k_download_and_run_otp(struct ath10k *ar)
864{ 941{
865 u32 result, address = ar->hw_params.patch_load_addr; 942 u32 result, address = ar->hw_params.patch_load_addr;
@@ -1231,19 +1308,19 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
1231 /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ 1308 /* strlen(',variant=') + strlen(ar->id.bdf_ext) */
1232 char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; 1309 char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
1233 1310
1311 if (ar->id.bdf_ext[0] != '\0')
1312 scnprintf(variant, sizeof(variant), ",variant=%s",
1313 ar->id.bdf_ext);
1314
1234 if (ar->id.bmi_ids_valid) { 1315 if (ar->id.bmi_ids_valid) {
1235 scnprintf(name, name_len, 1316 scnprintf(name, name_len,
1236 "bus=%s,bmi-chip-id=%d,bmi-board-id=%d", 1317 "bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s",
1237 ath10k_bus_str(ar->hif.bus), 1318 ath10k_bus_str(ar->hif.bus),
1238 ar->id.bmi_chip_id, 1319 ar->id.bmi_chip_id,
1239 ar->id.bmi_board_id); 1320 ar->id.bmi_board_id, variant);
1240 goto out; 1321 goto out;
1241 } 1322 }
1242 1323
1243 if (ar->id.bdf_ext[0] != '\0')
1244 scnprintf(variant, sizeof(variant), ",variant=%s",
1245 ar->id.bdf_ext);
1246
1247 scnprintf(name, name_len, 1324 scnprintf(name, name_len,
1248 "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", 1325 "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",
1249 ath10k_bus_str(ar->hif.bus), 1326 ath10k_bus_str(ar->hif.bus),
@@ -2343,7 +2420,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
2343 2420
2344 ret = ath10k_core_check_smbios(ar); 2421 ret = ath10k_core_check_smbios(ar);
2345 if (ret) 2422 if (ret)
2346 ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not set.\n"); 2423 ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");
2424
2425 ret = ath10k_core_check_dt(ar);
2426 if (ret)
2427 ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");
2347 2428
2348 ret = ath10k_core_fetch_board_file(ar); 2429 ret = ath10k_core_fetch_board_file(ar);
2349 if (ret) { 2430 if (ret) {
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 643041ef3271..631df2137e25 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -67,7 +67,6 @@
67 67
68/* NAPI poll budget */ 68/* NAPI poll budget */
69#define ATH10K_NAPI_BUDGET 64 69#define ATH10K_NAPI_BUDGET 64
70#define ATH10K_NAPI_QUOTA_LIMIT 60
71 70
72/* SMBIOS type containing Board Data File Name Extension */ 71/* SMBIOS type containing Board Data File Name Extension */
73#define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8 72#define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8
@@ -364,11 +363,11 @@ struct ath10k_sta {
364 struct rate_info txrate; 363 struct rate_info txrate;
365 364
366 struct work_struct update_wk; 365 struct work_struct update_wk;
366 u64 rx_duration;
367 367
368#ifdef CONFIG_MAC80211_DEBUGFS 368#ifdef CONFIG_MAC80211_DEBUGFS
369 /* protected by conf_mutex */ 369 /* protected by conf_mutex */
370 bool aggr_mode; 370 bool aggr_mode;
371 u64 rx_duration;
372#endif 371#endif
373}; 372};
374 373
@@ -463,7 +462,7 @@ struct ath10k_fw_crash_data {
463 bool crashed_since_read; 462 bool crashed_since_read;
464 463
465 guid_t guid; 464 guid_t guid;
466 struct timespec timestamp; 465 struct timespec64 timestamp;
467 __le32 registers[REG_DUMP_COUNT_QCA988X]; 466 __le32 registers[REG_DUMP_COUNT_QCA988X];
468 struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX]; 467 struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX];
469}; 468};
@@ -488,7 +487,6 @@ struct ath10k_debug {
488 /* protected by conf_mutex */ 487 /* protected by conf_mutex */
489 u64 fw_dbglog_mask; 488 u64 fw_dbglog_mask;
490 u32 fw_dbglog_level; 489 u32 fw_dbglog_level;
491 u32 pktlog_filter;
492 u32 reg_addr; 490 u32 reg_addr;
493 u32 nf_cal_period; 491 u32 nf_cal_period;
494 void *cal_data; 492 void *cal_data;
@@ -615,6 +613,9 @@ enum ath10k_fw_features {
615 /* Firmware does not support power save in station mode. */ 613 /* Firmware does not support power save in station mode. */
616 ATH10K_FW_FEATURE_NO_PS = 17, 614 ATH10K_FW_FEATURE_NO_PS = 17,
617 615
616 /* Firmware allows management tx by reference instead of by value. */
617 ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18,
618
618 /* keep last */ 619 /* keep last */
619 ATH10K_FW_FEATURE_COUNT, 620 ATH10K_FW_FEATURE_COUNT,
620}; 621};
@@ -963,6 +964,7 @@ struct ath10k {
963 } spectral; 964 } spectral;
964#endif 965#endif
965 966
967 u32 pktlog_filter;
966 struct { 968 struct {
967 /* protected by conf_mutex */ 969 /* protected by conf_mutex */
968 struct ath10k_fw_components utf_mode_fw; 970 struct ath10k_fw_components utf_mode_fw;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index df514507d3f1..181fd8e2e615 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -720,7 +720,7 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
720 720
721 crash_data->crashed_since_read = true; 721 crash_data->crashed_since_read = true;
722 guid_gen(&crash_data->guid); 722 guid_gen(&crash_data->guid);
723 getnstimeofday(&crash_data->timestamp); 723 ktime_get_real_ts64(&crash_data->timestamp);
724 724
725 return crash_data; 725 return crash_data;
726} 726}
@@ -1950,14 +1950,14 @@ int ath10k_debug_start(struct ath10k *ar)
1950 ret); 1950 ret);
1951 } 1951 }
1952 1952
1953 if (ar->debug.pktlog_filter) { 1953 if (ar->pktlog_filter) {
1954 ret = ath10k_wmi_pdev_pktlog_enable(ar, 1954 ret = ath10k_wmi_pdev_pktlog_enable(ar,
1955 ar->debug.pktlog_filter); 1955 ar->pktlog_filter);
1956 if (ret) 1956 if (ret)
1957 /* not serious */ 1957 /* not serious */
1958 ath10k_warn(ar, 1958 ath10k_warn(ar,
1959 "failed to enable pktlog filter %x: %d\n", 1959 "failed to enable pktlog filter %x: %d\n",
1960 ar->debug.pktlog_filter, ret); 1960 ar->pktlog_filter, ret);
1961 } else { 1961 } else {
1962 ret = ath10k_wmi_pdev_pktlog_disable(ar); 1962 ret = ath10k_wmi_pdev_pktlog_disable(ar);
1963 if (ret) 1963 if (ret)
@@ -2097,12 +2097,12 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
2097 mutex_lock(&ar->conf_mutex); 2097 mutex_lock(&ar->conf_mutex);
2098 2098
2099 if (ar->state != ATH10K_STATE_ON) { 2099 if (ar->state != ATH10K_STATE_ON) {
2100 ar->debug.pktlog_filter = filter; 2100 ar->pktlog_filter = filter;
2101 ret = count; 2101 ret = count;
2102 goto out; 2102 goto out;
2103 } 2103 }
2104 2104
2105 if (filter == ar->debug.pktlog_filter) { 2105 if (filter == ar->pktlog_filter) {
2106 ret = count; 2106 ret = count;
2107 goto out; 2107 goto out;
2108 } 2108 }
@@ -2111,7 +2111,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
2111 ret = ath10k_wmi_pdev_pktlog_enable(ar, filter); 2111 ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
2112 if (ret) { 2112 if (ret) {
2113 ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n", 2113 ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
2114 ar->debug.pktlog_filter, ret); 2114 ar->pktlog_filter, ret);
2115 goto out; 2115 goto out;
2116 } 2116 }
2117 } else { 2117 } else {
@@ -2122,7 +2122,7 @@ static ssize_t ath10k_write_pktlog_filter(struct file *file,
2122 } 2122 }
2123 } 2123 }
2124 2124
2125 ar->debug.pktlog_filter = filter; 2125 ar->pktlog_filter = filter;
2126 ret = count; 2126 ret = count;
2127 2127
2128out: 2128out:
@@ -2139,7 +2139,7 @@ static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
2139 2139
2140 mutex_lock(&ar->conf_mutex); 2140 mutex_lock(&ar->conf_mutex);
2141 len = scnprintf(buf, sizeof(buf) - len, "%08x\n", 2141 len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
2142 ar->debug.pktlog_filter); 2142 ar->pktlog_filter);
2143 mutex_unlock(&ar->conf_mutex); 2143 mutex_unlock(&ar->conf_mutex);
2144 2144
2145 return simple_read_from_buffer(ubuf, count, ppos, buf, len); 2145 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 548ad5483a4a..5e662994c49a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -51,7 +51,8 @@ enum ath10k_pktlog_filter {
51 ATH10K_PKTLOG_RCFIND = 0x000000004, 51 ATH10K_PKTLOG_RCFIND = 0x000000004,
52 ATH10K_PKTLOG_RCUPDATE = 0x000000008, 52 ATH10K_PKTLOG_RCUPDATE = 0x000000008,
53 ATH10K_PKTLOG_DBG_PRINT = 0x000000010, 53 ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
54 ATH10K_PKTLOG_ANY = 0x00000001f, 54 ATH10K_PKTLOG_PEER_STATS = 0x000000040,
55 ATH10K_PKTLOG_ANY = 0x00000005f,
55}; 56};
56 57
57enum ath10k_dbg_aggr_mode { 58enum ath10k_dbg_aggr_mode {
@@ -60,6 +61,21 @@ enum ath10k_dbg_aggr_mode {
60 ATH10K_DBG_AGGR_MODE_MAX, 61 ATH10K_DBG_AGGR_MODE_MAX,
61}; 62};
62 63
64/* Types of packet log events */
65enum ath_pktlog_type {
66 ATH_PKTLOG_TYPE_TX_CTRL = 1,
67 ATH_PKTLOG_TYPE_TX_STAT,
68};
69
70struct ath10k_pktlog_hdr {
71 __le16 flags;
72 __le16 missed_cnt;
73 __le16 log_type; /* Type of log information foll this header */
74 __le16 size; /* Size of variable length log information in bytes */
75 __le32 timestamp;
76 u8 payload[0];
77} __packed;
78
63/* FIXME: How to calculate the buffer size sanely? */ 79/* FIXME: How to calculate the buffer size sanely? */
64#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) 80#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
65 81
@@ -190,9 +206,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
190 struct ieee80211_sta *sta, struct dentry *dir); 206 struct ieee80211_sta *sta, struct dentry *dir);
191void ath10k_sta_update_rx_duration(struct ath10k *ar, 207void ath10k_sta_update_rx_duration(struct ath10k *ar,
192 struct ath10k_fw_stats *stats); 208 struct ath10k_fw_stats *stats);
193void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
194 struct ieee80211_sta *sta,
195 struct station_info *sinfo);
196#else 209#else
197static inline 210static inline
198void ath10k_sta_update_rx_duration(struct ath10k *ar, 211void ath10k_sta_update_rx_duration(struct ath10k *ar,
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index d59ac6b83340..ff96f70d2282 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -65,33 +65,6 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar,
65 ath10k_sta_update_stats_rx_duration(ar, stats); 65 ath10k_sta_update_stats_rx_duration(ar, stats);
66} 66}
67 67
68void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
69 struct ieee80211_sta *sta,
70 struct station_info *sinfo)
71{
72 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
73 struct ath10k *ar = arsta->arvif->ar;
74
75 if (!ath10k_peer_stats_enabled(ar))
76 return;
77
78 sinfo->rx_duration = arsta->rx_duration;
79 sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
80
81 if (!arsta->txrate.legacy && !arsta->txrate.nss)
82 return;
83
84 if (arsta->txrate.legacy) {
85 sinfo->txrate.legacy = arsta->txrate.legacy;
86 } else {
87 sinfo->txrate.mcs = arsta->txrate.mcs;
88 sinfo->txrate.nss = arsta->txrate.nss;
89 sinfo->txrate.bw = arsta->txrate.bw;
90 }
91 sinfo->txrate.flags = arsta->txrate.flags;
92 sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
93}
94
95static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, 68static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
96 char __user *user_buf, 69 char __user *user_buf,
97 size_t count, loff_t *ppos) 70 size_t count, loff_t *ppos)
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6305308422c4..7bd93d627f6b 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1497,6 +1497,23 @@ struct htt_peer_tx_stats {
1497 u8 payload[0]; 1497 u8 payload[0];
1498} __packed; 1498} __packed;
1499 1499
1500#define ATH10K_10_2_TX_STATS_OFFSET 136
1501#define PEER_STATS_FOR_NO_OF_PPDUS 4
1502
1503struct ath10k_10_2_peer_tx_stats {
1504 u8 ratecode[PEER_STATS_FOR_NO_OF_PPDUS];
1505 u8 success_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
1506 __le16 success_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
1507 u8 retry_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
1508 __le16 retry_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
1509 u8 failed_pkts[PEER_STATS_FOR_NO_OF_PPDUS];
1510 __le16 failed_bytes[PEER_STATS_FOR_NO_OF_PPDUS];
1511 u8 flags[PEER_STATS_FOR_NO_OF_PPDUS];
1512 __le32 tx_duration;
1513 u8 tx_ppdu_cnt;
1514 u8 peer_id;
1515} __packed;
1516
1500union htt_rx_pn_t { 1517union htt_rx_pn_t {
1501 /* WEP: 24-bit PN */ 1518 /* WEP: 24-bit PN */
1502 u32 pn24; 1519 u32 pn24;
@@ -1695,7 +1712,7 @@ struct ath10k_htt {
1695 /* This is used to group tx/rx completions separately and process them 1712 /* This is used to group tx/rx completions separately and process them
1696 * in batches to reduce cache stalls 1713 * in batches to reduce cache stalls
1697 */ 1714 */
1698 struct sk_buff_head rx_compl_q; 1715 struct sk_buff_head rx_msdus_q;
1699 struct sk_buff_head rx_in_ord_compl_q; 1716 struct sk_buff_head rx_in_ord_compl_q;
1700 struct sk_buff_head tx_fetch_ind_q; 1717 struct sk_buff_head tx_fetch_ind_q;
1701 1718
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 7d295ee71534..620ed7dca836 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -227,7 +227,7 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
227{ 227{
228 del_timer_sync(&htt->rx_ring.refill_retry_timer); 228 del_timer_sync(&htt->rx_ring.refill_retry_timer);
229 229
230 skb_queue_purge(&htt->rx_compl_q); 230 skb_queue_purge(&htt->rx_msdus_q);
231 skb_queue_purge(&htt->rx_in_ord_compl_q); 231 skb_queue_purge(&htt->rx_in_ord_compl_q);
232 skb_queue_purge(&htt->tx_fetch_ind_q); 232 skb_queue_purge(&htt->tx_fetch_ind_q);
233 233
@@ -515,7 +515,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
515 htt->rx_ring.sw_rd_idx.msdu_payld = 0; 515 htt->rx_ring.sw_rd_idx.msdu_payld = 0;
516 hash_init(htt->rx_ring.skb_table); 516 hash_init(htt->rx_ring.skb_table);
517 517
518 skb_queue_head_init(&htt->rx_compl_q); 518 skb_queue_head_init(&htt->rx_msdus_q);
519 skb_queue_head_init(&htt->rx_in_ord_compl_q); 519 skb_queue_head_init(&htt->rx_in_ord_compl_q);
520 skb_queue_head_init(&htt->tx_fetch_ind_q); 520 skb_queue_head_init(&htt->tx_fetch_ind_q);
521 atomic_set(&htt->num_mpdus_ready, 0); 521 atomic_set(&htt->num_mpdus_ready, 0);
@@ -974,16 +974,25 @@ static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
974 return out; 974 return out;
975} 975}
976 976
977static void ath10k_process_rx(struct ath10k *ar, 977static void ath10k_htt_rx_h_queue_msdu(struct ath10k *ar,
978 struct ieee80211_rx_status *rx_status, 978 struct ieee80211_rx_status *rx_status,
979 struct sk_buff *skb) 979 struct sk_buff *skb)
980{
981 struct ieee80211_rx_status *status;
982
983 status = IEEE80211_SKB_RXCB(skb);
984 *status = *rx_status;
985
986 __skb_queue_tail(&ar->htt.rx_msdus_q, skb);
987}
988
989static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb)
980{ 990{
981 struct ieee80211_rx_status *status; 991 struct ieee80211_rx_status *status;
982 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 992 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
983 char tid[32]; 993 char tid[32];
984 994
985 status = IEEE80211_SKB_RXCB(skb); 995 status = IEEE80211_SKB_RXCB(skb);
986 *status = *rx_status;
987 996
988 ath10k_dbg(ar, ATH10K_DBG_DATA, 997 ath10k_dbg(ar, ATH10K_DBG_DATA,
989 "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", 998 "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
@@ -1517,7 +1526,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
1517 } 1526 }
1518} 1527}
1519 1528
1520static void ath10k_htt_rx_h_deliver(struct ath10k *ar, 1529static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
1521 struct sk_buff_head *amsdu, 1530 struct sk_buff_head *amsdu,
1522 struct ieee80211_rx_status *status) 1531 struct ieee80211_rx_status *status)
1523{ 1532{
@@ -1540,7 +1549,7 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
1540 status->flag |= RX_FLAG_ALLOW_SAME_PN; 1549 status->flag |= RX_FLAG_ALLOW_SAME_PN;
1541 } 1550 }
1542 1551
1543 ath10k_process_rx(ar, status, msdu); 1552 ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
1544 } 1553 }
1545} 1554}
1546 1555
@@ -1652,7 +1661,7 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
1652 struct ath10k *ar = htt->ar; 1661 struct ath10k *ar = htt->ar;
1653 struct ieee80211_rx_status *rx_status = &htt->rx_status; 1662 struct ieee80211_rx_status *rx_status = &htt->rx_status;
1654 struct sk_buff_head amsdu; 1663 struct sk_buff_head amsdu;
1655 int ret, num_msdus; 1664 int ret;
1656 1665
1657 __skb_queue_head_init(&amsdu); 1666 __skb_queue_head_init(&amsdu);
1658 1667
@@ -1674,7 +1683,6 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
1674 return ret; 1683 return ret;
1675 } 1684 }
1676 1685
1677 num_msdus = skb_queue_len(&amsdu);
1678 ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); 1686 ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
1679 1687
1680 /* only for ret = 1 indicates chained msdus */ 1688 /* only for ret = 1 indicates chained msdus */
@@ -1683,9 +1691,9 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
1683 1691
1684 ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); 1692 ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
1685 ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); 1693 ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
1686 ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); 1694 ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
1687 1695
1688 return num_msdus; 1696 return 0;
1689} 1697}
1690 1698
1691static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, 1699static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
@@ -1893,15 +1901,14 @@ static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
1893 RX_FLAG_MMIC_STRIPPED; 1901 RX_FLAG_MMIC_STRIPPED;
1894} 1902}
1895 1903
1896static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar, 1904static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
1897 struct sk_buff_head *list) 1905 struct sk_buff_head *list)
1898{ 1906{
1899 struct ath10k_htt *htt = &ar->htt; 1907 struct ath10k_htt *htt = &ar->htt;
1900 struct ieee80211_rx_status *status = &htt->rx_status; 1908 struct ieee80211_rx_status *status = &htt->rx_status;
1901 struct htt_rx_offload_msdu *rx; 1909 struct htt_rx_offload_msdu *rx;
1902 struct sk_buff *msdu; 1910 struct sk_buff *msdu;
1903 size_t offset; 1911 size_t offset;
1904 int num_msdu = 0;
1905 1912
1906 while ((msdu = __skb_dequeue(list))) { 1913 while ((msdu = __skb_dequeue(list))) {
1907 /* Offloaded frames don't have Rx descriptor. Instead they have 1914 /* Offloaded frames don't have Rx descriptor. Instead they have
@@ -1940,10 +1947,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
1940 1947
1941 ath10k_htt_rx_h_rx_offload_prot(status, msdu); 1948 ath10k_htt_rx_h_rx_offload_prot(status, msdu);
1942 ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id); 1949 ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
1943 ath10k_process_rx(ar, status, msdu); 1950 ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
1944 num_msdu++;
1945 } 1951 }
1946 return num_msdu;
1947} 1952}
1948 1953
1949static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) 1954static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
@@ -1959,7 +1964,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
1959 u8 tid; 1964 u8 tid;
1960 bool offload; 1965 bool offload;
1961 bool frag; 1966 bool frag;
1962 int ret, num_msdus = 0; 1967 int ret;
1963 1968
1964 lockdep_assert_held(&htt->rx_ring.lock); 1969 lockdep_assert_held(&htt->rx_ring.lock);
1965 1970
@@ -2001,7 +2006,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
2001 * separately. 2006 * separately.
2002 */ 2007 */
2003 if (offload) 2008 if (offload)
2004 num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list); 2009 ath10k_htt_rx_h_rx_offload(ar, &list);
2005 2010
2006 while (!skb_queue_empty(&list)) { 2011 while (!skb_queue_empty(&list)) {
2007 __skb_queue_head_init(&amsdu); 2012 __skb_queue_head_init(&amsdu);
@@ -2014,11 +2019,10 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
2014 * better to report something than nothing though. This 2019 * better to report something than nothing though. This
2015 * should still give an idea about rx rate to the user. 2020 * should still give an idea about rx rate to the user.
2016 */ 2021 */
2017 num_msdus += skb_queue_len(&amsdu);
2018 ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); 2022 ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
2019 ath10k_htt_rx_h_filter(ar, &amsdu, status); 2023 ath10k_htt_rx_h_filter(ar, &amsdu, status);
2020 ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false); 2024 ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
2021 ath10k_htt_rx_h_deliver(ar, &amsdu, status); 2025 ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
2022 break; 2026 break;
2023 case -EAGAIN: 2027 case -EAGAIN:
2024 /* fall through */ 2028 /* fall through */
@@ -2030,7 +2034,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
2030 return -EIO; 2034 return -EIO;
2031 } 2035 }
2032 } 2036 }
2033 return num_msdus; 2037 return ret;
2034} 2038}
2035 2039
2036static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar, 2040static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
@@ -2449,6 +2453,62 @@ out:
2449 rcu_read_unlock(); 2453 rcu_read_unlock();
2450} 2454}
2451 2455
2456static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data)
2457{
2458 struct ath10k_pktlog_hdr *hdr = (struct ath10k_pktlog_hdr *)data;
2459 struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats;
2460 struct ath10k_10_2_peer_tx_stats *tx_stats;
2461 struct ieee80211_sta *sta;
2462 struct ath10k_peer *peer;
2463 u16 log_type = __le16_to_cpu(hdr->log_type);
2464 u32 peer_id = 0, i;
2465
2466 if (log_type != ATH_PKTLOG_TYPE_TX_STAT)
2467 return;
2468
2469 tx_stats = (struct ath10k_10_2_peer_tx_stats *)((hdr->payload) +
2470 ATH10K_10_2_TX_STATS_OFFSET);
2471
2472 if (!tx_stats->tx_ppdu_cnt)
2473 return;
2474
2475 peer_id = tx_stats->peer_id;
2476
2477 rcu_read_lock();
2478 spin_lock_bh(&ar->data_lock);
2479 peer = ath10k_peer_find_by_id(ar, peer_id);
2480 if (!peer) {
2481 ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
2482 peer_id);
2483 goto out;
2484 }
2485
2486 sta = peer->sta;
2487 for (i = 0; i < tx_stats->tx_ppdu_cnt; i++) {
2488 p_tx_stats->succ_bytes =
2489 __le16_to_cpu(tx_stats->success_bytes[i]);
2490 p_tx_stats->retry_bytes =
2491 __le16_to_cpu(tx_stats->retry_bytes[i]);
2492 p_tx_stats->failed_bytes =
2493 __le16_to_cpu(tx_stats->failed_bytes[i]);
2494 p_tx_stats->ratecode = tx_stats->ratecode[i];
2495 p_tx_stats->flags = tx_stats->flags[i];
2496 p_tx_stats->succ_pkts = tx_stats->success_pkts[i];
2497 p_tx_stats->retry_pkts = tx_stats->retry_pkts[i];
2498 p_tx_stats->failed_pkts = tx_stats->failed_pkts[i];
2499
2500 ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats);
2501 }
2502 spin_unlock_bh(&ar->data_lock);
2503 rcu_read_unlock();
2504
2505 return;
2506
2507out:
2508 spin_unlock_bh(&ar->data_lock);
2509 rcu_read_unlock();
2510}
2511
2452bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) 2512bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
2453{ 2513{
2454 struct ath10k_htt *htt = &ar->htt; 2514 struct ath10k_htt *htt = &ar->htt;
@@ -2566,6 +2626,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
2566 skb->len - 2626 skb->len -
2567 offsetof(struct htt_resp, 2627 offsetof(struct htt_resp,
2568 pktlog_msg.payload)); 2628 pktlog_msg.payload));
2629
2630 if (ath10k_peer_stats_enabled(ar))
2631 ath10k_fetch_10_2_tx_stats(ar,
2632 resp->pktlog_msg.payload);
2569 break; 2633 break;
2570 } 2634 }
2571 case HTT_T2H_MSG_TYPE_RX_FLUSH: { 2635 case HTT_T2H_MSG_TYPE_RX_FLUSH: {
@@ -2631,6 +2695,24 @@ void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
2631} 2695}
2632EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler); 2696EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
2633 2697
2698static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
2699{
2700 struct sk_buff *skb;
2701
2702 while (quota < budget) {
2703 if (skb_queue_empty(&ar->htt.rx_msdus_q))
2704 break;
2705
2706 skb = __skb_dequeue(&ar->htt.rx_msdus_q);
2707 if (!skb)
2708 break;
2709 ath10k_process_rx(ar, skb);
2710 quota++;
2711 }
2712
2713 return quota;
2714}
2715
2634int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget) 2716int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
2635{ 2717{
2636 struct ath10k_htt *htt = &ar->htt; 2718 struct ath10k_htt *htt = &ar->htt;
@@ -2638,63 +2720,44 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
2638 struct sk_buff_head tx_ind_q; 2720 struct sk_buff_head tx_ind_q;
2639 struct sk_buff *skb; 2721 struct sk_buff *skb;
2640 unsigned long flags; 2722 unsigned long flags;
2641 int quota = 0, done, num_rx_msdus; 2723 int quota = 0, done, ret;
2642 bool resched_napi = false; 2724 bool resched_napi = false;
2643 2725
2644 __skb_queue_head_init(&tx_ind_q); 2726 __skb_queue_head_init(&tx_ind_q);
2645 2727
2646 /* Since in-ord-ind can deliver more than 1 A-MSDU in single event, 2728 /* Process pending frames before dequeuing more data
2647 * process it first to utilize full available quota. 2729 * from hardware.
2648 */ 2730 */
2649 while (quota < budget) { 2731 quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
2650 if (skb_queue_empty(&htt->rx_in_ord_compl_q)) 2732 if (quota == budget) {
2651 break; 2733 resched_napi = true;
2652 2734 goto exit;
2653 skb = __skb_dequeue(&htt->rx_in_ord_compl_q); 2735 }
2654 if (!skb) {
2655 resched_napi = true;
2656 goto exit;
2657 }
2658 2736
2737 while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
2659 spin_lock_bh(&htt->rx_ring.lock); 2738 spin_lock_bh(&htt->rx_ring.lock);
2660 num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb); 2739 ret = ath10k_htt_rx_in_ord_ind(ar, skb);
2661 spin_unlock_bh(&htt->rx_ring.lock); 2740 spin_unlock_bh(&htt->rx_ring.lock);
2662 if (num_rx_msdus < 0) {
2663 resched_napi = true;
2664 goto exit;
2665 }
2666 2741
2667 dev_kfree_skb_any(skb); 2742 dev_kfree_skb_any(skb);
2668 if (num_rx_msdus > 0) 2743 if (ret == -EIO) {
2669 quota += num_rx_msdus;
2670
2671 if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
2672 !skb_queue_empty(&htt->rx_in_ord_compl_q)) {
2673 resched_napi = true; 2744 resched_napi = true;
2674 goto exit; 2745 goto exit;
2675 } 2746 }
2676 } 2747 }
2677 2748
2678 while (quota < budget) { 2749 while (atomic_read(&htt->num_mpdus_ready)) {
2679 /* no more data to receive */ 2750 ret = ath10k_htt_rx_handle_amsdu(htt);
2680 if (!atomic_read(&htt->num_mpdus_ready)) 2751 if (ret == -EIO) {
2681 break;
2682
2683 num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
2684 if (num_rx_msdus < 0) {
2685 resched_napi = true; 2752 resched_napi = true;
2686 goto exit; 2753 goto exit;
2687 } 2754 }
2688
2689 quota += num_rx_msdus;
2690 atomic_dec(&htt->num_mpdus_ready); 2755 atomic_dec(&htt->num_mpdus_ready);
2691 if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
2692 atomic_read(&htt->num_mpdus_ready)) {
2693 resched_napi = true;
2694 goto exit;
2695 }
2696 } 2756 }
2697 2757
2758 /* Deliver received data after processing data from hardware */
2759 quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
2760
2698 /* From NAPI documentation: 2761 /* From NAPI documentation:
2699 * The napi poll() function may also process TX completions, in which 2762 * The napi poll() function may also process TX completions, in which
2700 * case if it processes the entire TX ring then it should count that 2763 * case if it processes the entire TX ring then it should count that
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 88955bbe20bd..c31eea632777 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -931,3 +931,5 @@ const struct ath10k_hw_ops qca6174_ops = {
931 .set_coverage_class = ath10k_hw_qca988x_set_coverage_class, 931 .set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
932 .enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock, 932 .enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock,
933}; 933};
934
935const struct ath10k_hw_ops wcn3990_ops = {};
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 05f26e5858ad..90ad39bdeec4 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -128,6 +128,10 @@ enum qca9377_chip_id_rev {
128#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin" 128#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
129#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234 129#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
130 130
131/* WCN3990 1.0 definitions */
132#define WCN3990_HW_1_0_DEV_VERSION ATH10K_HW_WCN3990
133#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw3.0"
134
131#define ATH10K_FW_FILE_BASE "firmware" 135#define ATH10K_FW_FILE_BASE "firmware"
132#define ATH10K_FW_API_MAX 6 136#define ATH10K_FW_API_MAX 6
133#define ATH10K_FW_API_MIN 2 137#define ATH10K_FW_API_MIN 2
@@ -553,6 +557,10 @@ struct ath10k_hw_params {
553 557
554 /* Number of ciphers supported (i.e First N) in cipher_suites array */ 558 /* Number of ciphers supported (i.e First N) in cipher_suites array */
555 int n_cipher_suites; 559 int n_cipher_suites;
560
561 u32 num_peers;
562 u32 ast_skid_limit;
563 u32 num_wds_entries;
556}; 564};
557 565
558struct htt_rx_desc; 566struct htt_rx_desc;
@@ -567,6 +575,7 @@ struct ath10k_hw_ops {
567extern const struct ath10k_hw_ops qca988x_ops; 575extern const struct ath10k_hw_ops qca988x_ops;
568extern const struct ath10k_hw_ops qca99x0_ops; 576extern const struct ath10k_hw_ops qca99x0_ops;
569extern const struct ath10k_hw_ops qca6174_ops; 577extern const struct ath10k_hw_ops qca6174_ops;
578extern const struct ath10k_hw_ops wcn3990_ops;
570 579
571extern const struct ath10k_hw_clk_params qca6174_clk[]; 580extern const struct ath10k_hw_clk_params qca6174_clk[];
572 581
@@ -663,6 +672,11 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
663#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) 672#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
664#define TARGET_TLV_NUM_WOW_PATTERNS 22 673#define TARGET_TLV_NUM_WOW_PATTERNS 22
665 674
675/* Target specific defines for WMI-HL-1.0 firmware */
676#define TARGET_HL_10_TLV_NUM_PEERS 14
677#define TARGET_HL_10_TLV_AST_SKID_LIMIT 6
678#define TARGET_HL_10_TLV_NUM_WDS_ENTRIES 2
679
666/* Diagnostic Window */ 680/* Diagnostic Window */
667#define CE_DIAG_PIPE 7 681#define CE_DIAG_PIPE 7
668 682
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0a947eef348d..75726f12a31c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2563,7 +2563,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
2563 } 2563 }
2564 break; 2564 break;
2565 case WMI_VDEV_TYPE_STA: 2565 case WMI_VDEV_TYPE_STA:
2566 if (vif->bss_conf.qos) 2566 if (sta->wme)
2567 arg->peer_flags |= arvif->ar->wmi.peer_flags->qos; 2567 arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
2568 break; 2568 break;
2569 case WMI_VDEV_TYPE_IBSS: 2569 case WMI_VDEV_TYPE_IBSS:
@@ -3574,7 +3574,9 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
3574 return ATH10K_MAC_TX_HTT; 3574 return ATH10K_MAC_TX_HTT;
3575 case ATH10K_HW_TXRX_MGMT: 3575 case ATH10K_HW_TXRX_MGMT:
3576 if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, 3576 if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
3577 ar->running_fw->fw_file.fw_features)) 3577 ar->running_fw->fw_file.fw_features) ||
3578 test_bit(WMI_SERVICE_MGMT_TX_WMI,
3579 ar->wmi.svc_map))
3578 return ATH10K_MAC_TX_WMI_MGMT; 3580 return ATH10K_MAC_TX_WMI_MGMT;
3579 else if (ar->htt.target_version_major >= 3) 3581 else if (ar->htt.target_version_major >= 3)
3580 return ATH10K_MAC_TX_HTT; 3582 return ATH10K_MAC_TX_HTT;
@@ -6201,6 +6203,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
6201 "mac vdev %d peer delete %pM sta %pK (sta gone)\n", 6203 "mac vdev %d peer delete %pM sta %pK (sta gone)\n",
6202 arvif->vdev_id, sta->addr, sta); 6204 arvif->vdev_id, sta->addr, sta);
6203 6205
6206 if (sta->tdls) {
6207 ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id,
6208 sta,
6209 WMI_TDLS_PEER_STATE_TEARDOWN);
6210 if (ret)
6211 ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n",
6212 sta->addr,
6213 WMI_TDLS_PEER_STATE_TEARDOWN, ret);
6214 }
6215
6204 ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); 6216 ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
6205 if (ret) 6217 if (ret)
6206 ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", 6218 ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
@@ -7536,6 +7548,16 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
7536 arvif->vdev_id, ret); 7548 arvif->vdev_id, ret);
7537 } 7549 }
7538 7550
7551 if (ath10k_peer_stats_enabled(ar)) {
7552 ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS;
7553 ret = ath10k_wmi_pdev_pktlog_enable(ar,
7554 ar->pktlog_filter);
7555 if (ret) {
7556 ath10k_warn(ar, "failed to enable pktlog %d\n", ret);
7557 goto err_stop;
7558 }
7559 }
7560
7539 mutex_unlock(&ar->conf_mutex); 7561 mutex_unlock(&ar->conf_mutex);
7540 return 0; 7562 return 0;
7541 7563
@@ -7620,6 +7642,34 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
7620 peer->removed = true; 7642 peer->removed = true;
7621} 7643}
7622 7644
7645static void ath10k_sta_statistics(struct ieee80211_hw *hw,
7646 struct ieee80211_vif *vif,
7647 struct ieee80211_sta *sta,
7648 struct station_info *sinfo)
7649{
7650 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
7651 struct ath10k *ar = arsta->arvif->ar;
7652
7653 if (!ath10k_peer_stats_enabled(ar))
7654 return;
7655
7656 sinfo->rx_duration = arsta->rx_duration;
7657 sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
7658
7659 if (!arsta->txrate.legacy && !arsta->txrate.nss)
7660 return;
7661
7662 if (arsta->txrate.legacy) {
7663 sinfo->txrate.legacy = arsta->txrate.legacy;
7664 } else {
7665 sinfo->txrate.mcs = arsta->txrate.mcs;
7666 sinfo->txrate.nss = arsta->txrate.nss;
7667 sinfo->txrate.bw = arsta->txrate.bw;
7668 }
7669 sinfo->txrate.flags = arsta->txrate.flags;
7670 sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
7671}
7672
7623static const struct ieee80211_ops ath10k_ops = { 7673static const struct ieee80211_ops ath10k_ops = {
7624 .tx = ath10k_mac_op_tx, 7674 .tx = ath10k_mac_op_tx,
7625 .wake_tx_queue = ath10k_mac_op_wake_tx_queue, 7675 .wake_tx_queue = ath10k_mac_op_wake_tx_queue,
@@ -7661,6 +7711,7 @@ static const struct ieee80211_ops ath10k_ops = {
7661 .unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx, 7711 .unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
7662 .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx, 7712 .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
7663 .sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove, 7713 .sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove,
7714 .sta_statistics = ath10k_sta_statistics,
7664 7715
7665 CFG80211_TESTMODE_CMD(ath10k_tm_cmd) 7716 CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
7666 7717
@@ -7671,7 +7722,6 @@ static const struct ieee80211_ops ath10k_ops = {
7671#endif 7722#endif
7672#ifdef CONFIG_MAC80211_DEBUGFS 7723#ifdef CONFIG_MAC80211_DEBUGFS
7673 .sta_add_debugfs = ath10k_sta_add_debugfs, 7724 .sta_add_debugfs = ath10k_sta_add_debugfs,
7674 .sta_statistics = ath10k_sta_statistics,
7675#endif 7725#endif
7676}; 7726};
7677 7727
@@ -8329,15 +8379,6 @@ int ath10k_mac_register(struct ath10k *ar)
8329 ath10k_warn(ar, "failed to initialise DFS pattern detector\n"); 8379 ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
8330 } 8380 }
8331 8381
8332 /* Current wake_tx_queue implementation imposes a significant
8333 * performance penalty in some setups. The tx scheduling code needs
8334 * more work anyway so disable the wake_tx_queue unless firmware
8335 * supports the pull-push mechanism.
8336 */
8337 if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
8338 ar->running_fw->fw_file.fw_features))
8339 ar->ops->wake_tx_queue = NULL;
8340
8341 ret = ath10k_mac_init_rd(ar); 8382 ret = ath10k_mac_init_rd(ar);
8342 if (ret) { 8383 if (ret) {
8343 ath10k_err(ar, "failed to derive regdom: %d\n", ret); 8384 ath10k_err(ar, "failed to derive regdom: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h
index 89b0ad769d4f..b2a2e8ae04b8 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.h
+++ b/drivers/net/wireless/ath/ath10k/spectral.h
@@ -44,7 +44,7 @@ enum ath10k_spectral_mode {
44 SPECTRAL_MANUAL, 44 SPECTRAL_MANUAL,
45}; 45};
46 46
47#ifdef CONFIG_ATH10K_DEBUGFS 47#ifdef CONFIG_ATH10K_SPECTRAL
48 48
49int ath10k_spectral_process_fft(struct ath10k *ar, 49int ath10k_spectral_process_fft(struct ath10k *ar,
50 struct wmi_phyerr_ev_arg *phyerr, 50 struct wmi_phyerr_ev_arg *phyerr,
@@ -85,6 +85,6 @@ static inline void ath10k_spectral_destroy(struct ath10k *ar)
85{ 85{
86} 86}
87 87
88#endif /* CONFIG_ATH10K_DEBUGFS */ 88#endif /* CONFIG_ATH10K_SPECTRAL */
89 89
90#endif /* SPECTRAL_H */ 90#endif /* SPECTRAL_H */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 2fc3f24ff1ca..41eef942ab2c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -377,6 +377,7 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
377 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); 377 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
378 struct sk_buff *skb; 378 struct sk_buff *skb;
379 int ret; 379 int ret;
380 u32 mgmt_tx_cmdid;
380 381
381 if (!ar->wmi.ops->gen_mgmt_tx) 382 if (!ar->wmi.ops->gen_mgmt_tx)
382 return -EOPNOTSUPP; 383 return -EOPNOTSUPP;
@@ -385,7 +386,13 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
385 if (IS_ERR(skb)) 386 if (IS_ERR(skb))
386 return PTR_ERR(skb); 387 return PTR_ERR(skb);
387 388
388 ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid); 389 if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
390 ar->running_fw->fw_file.fw_features))
391 mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
392 else
393 mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
394
395 ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
389 if (ret) 396 if (ret)
390 return ret; 397 return ret;
391 398
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 7616c1c4bbd3..8d53063bd503 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -917,33 +917,69 @@ ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len,
917 return -ENOMEM; 917 return -ENOMEM;
918} 918}
919 919
920struct wmi_tlv_svc_rdy_parse {
921 const struct hal_reg_capabilities *reg;
922 const struct wmi_tlv_svc_rdy_ev *ev;
923 const __le32 *svc_bmap;
924 const struct wlan_host_mem_req *mem_reqs;
925 bool svc_bmap_done;
926 bool dbs_hw_mode_done;
927};
928
929static int ath10k_wmi_tlv_svc_rdy_parse(struct ath10k *ar, u16 tag, u16 len,
930 const void *ptr, void *data)
931{
932 struct wmi_tlv_svc_rdy_parse *svc_rdy = data;
933
934 switch (tag) {
935 case WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT:
936 svc_rdy->ev = ptr;
937 break;
938 case WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES:
939 svc_rdy->reg = ptr;
940 break;
941 case WMI_TLV_TAG_ARRAY_STRUCT:
942 svc_rdy->mem_reqs = ptr;
943 break;
944 case WMI_TLV_TAG_ARRAY_UINT32:
945 if (!svc_rdy->svc_bmap_done) {
946 svc_rdy->svc_bmap_done = true;
947 svc_rdy->svc_bmap = ptr;
948 } else if (!svc_rdy->dbs_hw_mode_done) {
949 svc_rdy->dbs_hw_mode_done = true;
950 }
951 break;
952 default:
953 break;
954 }
955 return 0;
956}
957
920static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, 958static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
921 struct sk_buff *skb, 959 struct sk_buff *skb,
922 struct wmi_svc_rdy_ev_arg *arg) 960 struct wmi_svc_rdy_ev_arg *arg)
923{ 961{
924 const void **tb;
925 const struct hal_reg_capabilities *reg; 962 const struct hal_reg_capabilities *reg;
926 const struct wmi_tlv_svc_rdy_ev *ev; 963 const struct wmi_tlv_svc_rdy_ev *ev;
927 const __le32 *svc_bmap; 964 const __le32 *svc_bmap;
928 const struct wlan_host_mem_req *mem_reqs; 965 const struct wlan_host_mem_req *mem_reqs;
966 struct wmi_tlv_svc_rdy_parse svc_rdy = { };
929 int ret; 967 int ret;
930 968
931 tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); 969 ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
932 if (IS_ERR(tb)) { 970 ath10k_wmi_tlv_svc_rdy_parse, &svc_rdy);
933 ret = PTR_ERR(tb); 971 if (ret) {
934 ath10k_warn(ar, "failed to parse tlv: %d\n", ret); 972 ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
935 return ret; 973 return ret;
936 } 974 }
937 975
938 ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; 976 ev = svc_rdy.ev;
939 reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; 977 reg = svc_rdy.reg;
940 svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; 978 svc_bmap = svc_rdy.svc_bmap;
941 mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; 979 mem_reqs = svc_rdy.mem_reqs;
942 980
943 if (!ev || !reg || !svc_bmap || !mem_reqs) { 981 if (!ev || !reg || !svc_bmap || !mem_reqs)
944 kfree(tb);
945 return -EPROTO; 982 return -EPROTO;
946 }
947 983
948 /* This is an internal ABI compatibility check for WMI TLV so check it 984 /* This is an internal ABI compatibility check for WMI TLV so check it
949 * here instead of the generic WMI code. 985 * here instead of the generic WMI code.
@@ -961,7 +997,6 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
961 __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || 997 __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
962 __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || 998 __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
963 __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { 999 __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
964 kfree(tb);
965 return -ENOTSUPP; 1000 return -ENOTSUPP;
966 } 1001 }
967 1002
@@ -982,12 +1017,10 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
982 ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), 1017 ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
983 ath10k_wmi_tlv_parse_mem_reqs, arg); 1018 ath10k_wmi_tlv_parse_mem_reqs, arg);
984 if (ret) { 1019 if (ret) {
985 kfree(tb);
986 ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret); 1020 ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
987 return ret; 1021 return ret;
988 } 1022 }
989 1023
990 kfree(tb);
991 return 0; 1024 return 0;
992} 1025}
993 1026
@@ -1406,7 +1439,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
1406 cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); 1439 cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
1407 1440
1408 cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); 1441 cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
1409 cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); 1442
1443 cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers);
1444 cfg->ast_skid_limit = __cpu_to_le32(ar->hw_params.ast_skid_limit);
1445 cfg->num_wds_entries = __cpu_to_le32(ar->hw_params.num_wds_entries);
1410 1446
1411 if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { 1447 if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
1412 cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); 1448 cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
@@ -1418,7 +1454,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
1418 1454
1419 cfg->num_peer_keys = __cpu_to_le32(2); 1455 cfg->num_peer_keys = __cpu_to_le32(2);
1420 cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); 1456 cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
1421 cfg->ast_skid_limit = __cpu_to_le32(0x10);
1422 cfg->tx_chain_mask = __cpu_to_le32(0x7); 1457 cfg->tx_chain_mask = __cpu_to_le32(0x7);
1423 cfg->rx_chain_mask = __cpu_to_le32(0x7); 1458 cfg->rx_chain_mask = __cpu_to_le32(0x7);
1424 cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); 1459 cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
@@ -1434,7 +1469,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
1434 cfg->num_mcast_table_elems = __cpu_to_le32(0); 1469 cfg->num_mcast_table_elems = __cpu_to_le32(0);
1435 cfg->mcast2ucast_mode = __cpu_to_le32(0); 1470 cfg->mcast2ucast_mode = __cpu_to_le32(0);
1436 cfg->tx_dbg_log_size = __cpu_to_le32(0x400); 1471 cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
1437 cfg->num_wds_entries = __cpu_to_le32(0x20);
1438 cfg->dma_burst_size = __cpu_to_le32(0); 1472 cfg->dma_burst_size = __cpu_to_le32(0);
1439 cfg->mac_aggr_delim = __cpu_to_le32(0); 1473 cfg->mac_aggr_delim = __cpu_to_le32(0);
1440 cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); 1474 cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
@@ -2450,6 +2484,82 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
2450} 2484}
2451 2485
2452static struct sk_buff * 2486static struct sk_buff *
2487ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
2488{
2489 struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
2490 struct wmi_tlv_mgmt_tx_cmd *cmd;
2491 struct wmi_tlv *tlv;
2492 struct ieee80211_hdr *hdr;
2493 struct sk_buff *skb;
2494 void *ptr;
2495 int len;
2496 u32 buf_len = msdu->len;
2497 u16 fc;
2498 struct ath10k_vif *arvif;
2499 dma_addr_t mgmt_frame_dma;
2500 u32 vdev_id;
2501
2502 if (!cb->vif)
2503 return ERR_PTR(-EINVAL);
2504
2505 hdr = (struct ieee80211_hdr *)msdu->data;
2506 fc = le16_to_cpu(hdr->frame_control);
2507 arvif = (void *)cb->vif->drv_priv;
2508 vdev_id = arvif->vdev_id;
2509
2510 if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
2511 return ERR_PTR(-EINVAL);
2512
2513 len = sizeof(*cmd) + 2 * sizeof(*tlv);
2514
2515 if ((ieee80211_is_action(hdr->frame_control) ||
2516 ieee80211_is_deauth(hdr->frame_control) ||
2517 ieee80211_is_disassoc(hdr->frame_control)) &&
2518 ieee80211_has_protected(hdr->frame_control)) {
2519 len += IEEE80211_CCMP_MIC_LEN;
2520 buf_len += IEEE80211_CCMP_MIC_LEN;
2521 }
2522
2523 buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
2524 buf_len = round_up(buf_len, 4);
2525
2526 len += buf_len;
2527 len = round_up(len, 4);
2528 skb = ath10k_wmi_alloc_skb(ar, len);
2529 if (!skb)
2530 return ERR_PTR(-ENOMEM);
2531
2532 ptr = (void *)skb->data;
2533 tlv = ptr;
2534 tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
2535 tlv->len = __cpu_to_le16(sizeof(*cmd));
2536 cmd = (void *)tlv->value;
2537 cmd->vdev_id = __cpu_to_le32(vdev_id);
2538 cmd->desc_id = 0;
2539 cmd->chanfreq = 0;
2540 cmd->buf_len = __cpu_to_le32(buf_len);
2541 cmd->frame_len = __cpu_to_le32(msdu->len);
2542 mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data,
2543 msdu->len, DMA_TO_DEVICE);
2544 if (!mgmt_frame_dma)
2545 return ERR_PTR(-ENOMEM);
2546
2547 cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
2548
2549 ptr += sizeof(*tlv);
2550 ptr += sizeof(*cmd);
2551
2552 tlv = ptr;
2553 tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
2554 tlv->len = __cpu_to_le16(buf_len);
2555
2556 ptr += sizeof(*tlv);
2557 memcpy(ptr, msdu->data, buf_len);
2558
2559 return skb;
2560}
2561
2562static struct sk_buff *
2453ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, 2563ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
2454 enum wmi_force_fw_hang_type type, 2564 enum wmi_force_fw_hang_type type,
2455 u32 delay_ms) 2565 u32 delay_ms)
@@ -3258,6 +3368,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
3258 .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID, 3368 .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
3259 .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID, 3369 .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
3260 .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID, 3370 .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
3371 .mgmt_tx_send_cmdid = WMI_TLV_MGMT_TX_SEND_CMD,
3261 .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID, 3372 .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
3262 .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID, 3373 .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
3263 .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID, 3374 .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
@@ -3592,6 +3703,7 @@ static const struct wmi_ops wmi_tlv_ops = {
3592 .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, 3703 .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
3593 .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, 3704 .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
3594 /* .gen_mgmt_tx = not implemented; HTT is used */ 3705 /* .gen_mgmt_tx = not implemented; HTT is used */
3706 .gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
3595 .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, 3707 .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
3596 .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, 3708 .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
3597 .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, 3709 .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 22cf011e839a..4faaa64a40d5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -22,6 +22,7 @@
22#define WMI_TLV_CMD_UNSUPPORTED 0 22#define WMI_TLV_CMD_UNSUPPORTED 0
23#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0 23#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
24#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0 24#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
25#define WMI_TLV_MGMT_TX_FRAME_MAX_LEN 64
25 26
26enum wmi_tlv_grp_id { 27enum wmi_tlv_grp_id {
27 WMI_TLV_GRP_START = 0x3, 28 WMI_TLV_GRP_START = 0x3,
@@ -132,6 +133,7 @@ enum wmi_tlv_cmd_id {
132 WMI_TLV_PRB_REQ_FILTER_RX_CMDID, 133 WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
133 WMI_TLV_MGMT_TX_CMDID, 134 WMI_TLV_MGMT_TX_CMDID,
134 WMI_TLV_PRB_TMPL_CMDID, 135 WMI_TLV_PRB_TMPL_CMDID,
136 WMI_TLV_MGMT_TX_SEND_CMD,
135 WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG), 137 WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
136 WMI_TLV_ADDBA_SEND_CMDID, 138 WMI_TLV_ADDBA_SEND_CMDID,
137 WMI_TLV_ADDBA_STATUS_CMDID, 139 WMI_TLV_ADDBA_STATUS_CMDID,
@@ -890,6 +892,63 @@ enum wmi_tlv_tag {
890 WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, 892 WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
891 WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, 893 WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
892 WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, 894 WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
895 WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_CMD,
896 WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_EVENT,
897 WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_CMD,
898 WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_RESP_EVENT,
899 WMI_TLV_TAG_STRUCT_OCB_SET_UTC_TIME_CMD,
900 WMI_TLV_TAG_STRUCT_OCB_START_TIMING_ADVERT_CMD,
901 WMI_TLV_TAG_STRUCT_OCB_STOP_TIMING_ADVERT_CMD,
902 WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_CMD,
903 WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_RESP_EVENT,
904 WMI_TLV_TAG_STRUCT_DCC_GET_STATS_CMD,
905 WMI_TLV_TAG_STRUCT_DCC_CHANNEL_STATS_REQUEST,
906 WMI_TLV_TAG_STRUCT_DCC_GET_STATS_RESP_EVENT,
907 WMI_TLV_TAG_STRUCT_DCC_CLEAR_STATS_CMD,
908 WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_CMD,
909 WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_RESP_EVENT,
910 WMI_TLV_TAG_STRUCT_DCC_STATS_EVENT,
911 WMI_TLV_TAG_STRUCT_OCB_CHANNEL,
912 WMI_TLV_TAG_STRUCT_OCB_SCHEDULE_ELEMENT,
913 WMI_TLV_TAG_STRUCT_DCC_NDL_STATS_PER_CHANNEL,
914 WMI_TLV_TAG_STRUCT_DCC_NDL_CHAN,
915 WMI_TLV_TAG_STRUCT_QOS_PARAMETER,
916 WMI_TLV_TAG_STRUCT_DCC_NDL_ACTIVE_STATE_CONFIG,
917 WMI_TLV_TAG_STRUCT_ROAM_SCAN_EXTENDED_THRESHOLD_PARAM,
918 WMI_TLV_TAG_STRUCT_ROAM_FILTER_FIXED_PARAM,
919 WMI_TLV_TAG_STRUCT_PASSPOINT_CONFIG_CMD,
920 WMI_TLV_TAG_STRUCT_PASSPOINT_EVENT_HDR,
921 WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMD,
922 WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_SSID_MATCH_EVENT,
923 WMI_TLV_TAG_STRUCT_VDEV_TSF_TSTAMP_ACTION_CMD,
924 WMI_TLV_TAG_STRUCT_VDEV_TSF_REPORT_EVENT,
925 WMI_TLV_TAG_STRUCT_GET_FW_MEM_DUMP,
926 WMI_TLV_TAG_STRUCT_UPDATE_FW_MEM_DUMP,
927 WMI_TLV_TAG_STRUCT_FW_MEM_DUMP_PARAMS,
928 WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH,
929 WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH_COMPLETE,
930 WMI_TLV_TAG_STRUCT_PEER_SET_RATE_REPORT_CONDITION,
931 WMI_TLV_TAG_STRUCT_ROAM_SUBNET_CHANGE_CONFIG,
932 WMI_TLV_TAG_STRUCT_VDEV_SET_IE_CMD,
933 WMI_TLV_TAG_STRUCT_RSSI_BREACH_MONITOR_CONFIG,
934 WMI_TLV_TAG_STRUCT_RSSI_BREACH_EVENT,
935 WMI_TLV_TAG_STRUCT_EVENT_INITIAL_WAKEUP,
936 WMI_TLV_TAG_STRUCT_SOC_SET_PCL_CMD,
937 WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_CMD,
938 WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_EVENT,
939 WMI_TLV_TAG_STRUCT_SOC_HW_MODE_TRANSITION_EVENT,
940 WMI_TLV_TAG_STRUCT_VDEV_TXRX_STREAMS,
941 WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY,
942 WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_CMD,
943 WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_RESPONSE_EVENT,
944 WMI_TLV_TAG_STRUCT_IOAC_SOCK_PATTERN_T,
945 WMI_TLV_TAG_STRUCT_WOW_ENABLE_ICMPV6_NA_FLT_CMD,
946 WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_CONFIG,
947 WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_SUPPORTED_EVENT,
948 WMI_TLV_TAG_STRUCT_PACKET_FILTER_CONFIG,
949 WMI_TLV_TAG_STRUCT_PACKET_FILTER_ENABLE,
950 WMI_TLV_TAG_STRUCT_SAP_SET_BLACKLIST_PARAM_CMD,
951 WMI_TLV_TAG_STRUCT_MGMT_TX_CMD,
893 952
894 WMI_TLV_TAG_MAX 953 WMI_TLV_TAG_MAX
895}; 954};
@@ -965,6 +1024,50 @@ enum wmi_tlv_service {
965 WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, 1024 WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
966 WMI_TLV_SERVICE_MDNS_OFFLOAD, 1025 WMI_TLV_SERVICE_MDNS_OFFLOAD,
967 WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, 1026 WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
1027 WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
1028 WMI_TLV_SERVICE_OCB,
1029 WMI_TLV_SERVICE_AP_ARPNS_OFFLOAD,
1030 WMI_TLV_SERVICE_PER_BAND_CHAINMASK_SUPPORT,
1031 WMI_TLV_SERVICE_PACKET_FILTER_OFFLOAD,
1032 WMI_TLV_SERVICE_MGMT_TX_HTT,
1033 WMI_TLV_SERVICE_MGMT_TX_WMI,
1034 WMI_TLV_SERVICE_EXT_MSG,
1035 WMI_TLV_SERVICE_MAWC,
1036 WMI_TLV_SERVICE_PEER_ASSOC_CONF,
1037 WMI_TLV_SERVICE_EGAP,
1038 WMI_TLV_SERVICE_STA_PMF_OFFLOAD,
1039 WMI_TLV_SERVICE_UNIFIED_WOW_CAPABILITY,
1040 WMI_TLV_SERVICE_ENHANCED_PROXY_STA,
1041 WMI_TLV_SERVICE_ATF,
1042 WMI_TLV_SERVICE_COEX_GPIO,
1043 WMI_TLV_SERVICE_AUX_SPECTRAL_INTF,
1044 WMI_TLV_SERVICE_AUX_CHAN_LOAD_INTF,
1045 WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64,
1046 WMI_TLV_SERVICE_ENTERPRISE_MESH,
1047 WMI_TLV_SERVICE_RESTRT_CHNL_SUPPORT,
1048 WMI_TLV_SERVICE_BPF_OFFLOAD,
1049 WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
1050 WMI_TLV_SERVICE_SMART_ANTENNA_SW_SUPPORT,
1051 WMI_TLV_SERVICE_SMART_ANTENNA_HW_SUPPORT,
1052 WMI_TLV_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES,
1053 WMI_TLV_SERVICE_NAN_DATA,
1054 WMI_TLV_SERVICE_NAN_RTT,
1055 WMI_TLV_SERVICE_11AX,
1056 WMI_TLV_SERVICE_DEPRECATED_REPLACE,
1057 WMI_TLV_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
1058 WMI_TLV_SERVICE_ENHANCED_MCAST_FILTER,
1059 WMI_TLV_SERVICE_PERIODIC_CHAN_STAT_SUPPORT,
1060 WMI_TLV_SERVICE_MESH_11S,
1061 WMI_TLV_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT,
1062 WMI_TLV_SERVICE_VDEV_RX_FILTER,
1063 WMI_TLV_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT,
1064 WMI_TLV_SERVICE_MARK_FIRST_WAKEUP_PACKET,
1065 WMI_TLV_SERVICE_MULTIPLE_MCAST_FILTER_SET,
1066 WMI_TLV_SERVICE_HOST_MANAGED_RX_REORDER,
1067 WMI_TLV_SERVICE_FLASH_RDWR_SUPPORT,
1068 WMI_TLV_SERVICE_WLAN_STATS_REPORT,
1069 WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT,
1070 WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD,
968}; 1071};
969 1072
970#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ 1073#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
@@ -1121,6 +1224,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
1121 WMI_SERVICE_MDNS_OFFLOAD, len); 1224 WMI_SERVICE_MDNS_OFFLOAD, len);
1122 SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, 1225 SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
1123 WMI_SERVICE_SAP_AUTH_OFFLOAD, len); 1226 WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
1227 SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
1228 WMI_SERVICE_MGMT_TX_WMI, len);
1124} 1229}
1125 1230
1126#undef SVCMAP 1231#undef SVCMAP
@@ -1643,4 +1748,12 @@ struct wmi_tlv_tx_pause_ev {
1643 1748
1644void ath10k_wmi_tlv_attach(struct ath10k *ar); 1749void ath10k_wmi_tlv_attach(struct ath10k *ar);
1645 1750
1751struct wmi_tlv_mgmt_tx_cmd {
1752 __le32 vdev_id;
1753 __le32 desc_id;
1754 __le32 chanfreq;
1755 __le64 paddr;
1756 __le32 frame_len;
1757 __le32 buf_len;
1758} __packed;
1646#endif 1759#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index cad2e42dcef6..b6cbc0281fe1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -29,6 +29,7 @@
29#include "p2p.h" 29#include "p2p.h"
30#include "hw.h" 30#include "hw.h"
31#include "hif.h" 31#include "hif.h"
32#include "txrx.h"
32 33
33#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9 34#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9
34#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ) 35#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ)
@@ -4456,6 +4457,74 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
4456 __le32_to_cpu(ev->rate_max)); 4457 __le32_to_cpu(ev->rate_max));
4457} 4458}
4458 4459
4460static void
4461ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
4462{
4463 struct wmi_tdls_peer_event *ev;
4464 struct ath10k_peer *peer;
4465 struct ath10k_vif *arvif;
4466 int vdev_id;
4467 int peer_status;
4468 int peer_reason;
4469 u8 reason;
4470
4471 if (skb->len < sizeof(*ev)) {
4472 ath10k_err(ar, "received tdls peer event with invalid size (%d bytes)\n",
4473 skb->len);
4474 return;
4475 }
4476
4477 ev = (struct wmi_tdls_peer_event *)skb->data;
4478 vdev_id = __le32_to_cpu(ev->vdev_id);
4479 peer_status = __le32_to_cpu(ev->peer_status);
4480 peer_reason = __le32_to_cpu(ev->peer_reason);
4481
4482 spin_lock_bh(&ar->data_lock);
4483 peer = ath10k_peer_find(ar, vdev_id, ev->peer_macaddr.addr);
4484 spin_unlock_bh(&ar->data_lock);
4485
4486 if (!peer) {
4487 ath10k_warn(ar, "failed to find peer entry for %pM\n",
4488 ev->peer_macaddr.addr);
4489 return;
4490 }
4491
4492 switch (peer_status) {
4493 case WMI_TDLS_SHOULD_TEARDOWN:
4494 switch (peer_reason) {
4495 case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
4496 case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE:
4497 case WMI_TDLS_TEARDOWN_REASON_RSSI:
4498 reason = WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE;
4499 break;
4500 default:
4501 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
4502 break;
4503 }
4504
4505 arvif = ath10k_get_arvif(ar, vdev_id);
4506 if (!arvif) {
4507 ath10k_warn(ar, "received tdls peer event for invalid vdev id %u\n",
4508 vdev_id);
4509 return;
4510 }
4511
4512 ieee80211_tdls_oper_request(arvif->vif, ev->peer_macaddr.addr,
4513 NL80211_TDLS_TEARDOWN, reason,
4514 GFP_ATOMIC);
4515
4516 ath10k_dbg(ar, ATH10K_DBG_WMI,
4517 "received tdls teardown event for peer %pM reason %u\n",
4518 ev->peer_macaddr.addr, peer_reason);
4519 break;
4520 default:
4521 ath10k_dbg(ar, ATH10K_DBG_WMI,
4522 "received unknown tdls peer event %u\n",
4523 peer_status);
4524 break;
4525 }
4526}
4527
4459void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) 4528void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
4460{ 4529{
4461 ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); 4530 ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
@@ -5477,6 +5546,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
5477 case WMI_10_4_PDEV_TPC_CONFIG_EVENTID: 5546 case WMI_10_4_PDEV_TPC_CONFIG_EVENTID:
5478 ath10k_wmi_event_pdev_tpc_config(ar, skb); 5547 ath10k_wmi_event_pdev_tpc_config(ar, skb);
5479 break; 5548 break;
5549 case WMI_10_4_TDLS_PEER_EVENTID:
5550 ath10k_wmi_handle_tdls_peer_event(ar, skb);
5551 break;
5480 default: 5552 default:
5481 ath10k_warn(ar, "Unknown eventid: %d\n", id); 5553 ath10k_warn(ar, "Unknown eventid: %d\n", id);
5482 break; 5554 break;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index c02b21cff38d..f6d60dc16d1c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -195,6 +195,7 @@ enum wmi_service {
195 WMI_SERVICE_SMART_LOGGING_SUPPORT, 195 WMI_SERVICE_SMART_LOGGING_SUPPORT,
196 WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, 196 WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
197 WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, 197 WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
198 WMI_SERVICE_MGMT_TX_WMI,
198 199
199 /* keep last */ 200 /* keep last */
200 WMI_SERVICE_MAX, 201 WMI_SERVICE_MAX,
@@ -797,6 +798,7 @@ struct wmi_cmd_map {
797 u32 bcn_filter_rx_cmdid; 798 u32 bcn_filter_rx_cmdid;
798 u32 prb_req_filter_rx_cmdid; 799 u32 prb_req_filter_rx_cmdid;
799 u32 mgmt_tx_cmdid; 800 u32 mgmt_tx_cmdid;
801 u32 mgmt_tx_send_cmdid;
800 u32 prb_tmpl_cmdid; 802 u32 prb_tmpl_cmdid;
801 u32 addba_clear_resp_cmdid; 803 u32 addba_clear_resp_cmdid;
802 u32 addba_send_cmdid; 804 u32 addba_send_cmdid;
@@ -5236,7 +5238,8 @@ enum wmi_10_4_vdev_param {
5236#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) 5238#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
5237 5239
5238#define WMI_TXBF_STS_CAP_OFFSET_LSB 4 5240#define WMI_TXBF_STS_CAP_OFFSET_LSB 4
5239#define WMI_TXBF_STS_CAP_OFFSET_MASK 0xf0 5241#define WMI_TXBF_STS_CAP_OFFSET_MASK 0x70
5242#define WMI_TXBF_CONF_IMPLICIT_BF BIT(7)
5240#define WMI_BF_SOUND_DIM_OFFSET_LSB 8 5243#define WMI_BF_SOUND_DIM_OFFSET_LSB 8
5241#define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00 5244#define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00
5242 5245
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b53eb2b85f02..2ba8cf3f38af 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2766,7 +2766,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2766 struct ieee80211_mgmt *mgmt; 2766 struct ieee80211_mgmt *mgmt;
2767 bool hidden = false; 2767 bool hidden = false;
2768 u8 *ies; 2768 u8 *ies;
2769 int ies_len;
2770 struct wmi_connect_cmd p; 2769 struct wmi_connect_cmd p;
2771 int res; 2770 int res;
2772 int i, ret; 2771 int i, ret;
@@ -2804,7 +2803,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
2804 ies = mgmt->u.beacon.variable; 2803 ies = mgmt->u.beacon.variable;
2805 if (ies > info->beacon.head + info->beacon.head_len) 2804 if (ies > info->beacon.head + info->beacon.head_len)
2806 return -EINVAL; 2805 return -EINVAL;
2807 ies_len = info->beacon.head + info->beacon.head_len - ies;
2808 2806
2809 if (info->ssid == NULL) 2807 if (info->ssid == NULL)
2810 return -EINVAL; 2808 return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 1379906bf849..8da9506f8c2b 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -1001,7 +1001,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr,
1001 1001
1002 while (amsdu_len > mac_hdr_len) { 1002 while (amsdu_len > mac_hdr_len) {
1003 hdr = (struct ethhdr *) framep; 1003 hdr = (struct ethhdr *) framep;
1004 payload_8023_len = ntohs(hdr->h_proto); 1004 payload_8023_len = be16_to_cpu(hdr->h_proto);
1005 1005
1006 if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || 1006 if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN ||
1007 payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) { 1007 payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 783a38f1a626..1f3523019509 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -61,13 +61,12 @@ config ATH9K_DEBUGFS
61 depends on ATH9K && DEBUG_FS 61 depends on ATH9K && DEBUG_FS
62 select MAC80211_DEBUGFS 62 select MAC80211_DEBUGFS
63 select ATH9K_COMMON_DEBUG 63 select ATH9K_COMMON_DEBUG
64 select RELAY
65 ---help--- 64 ---help---
66 Say Y, if you need access to ath9k's statistics for 65 Say Y, if you need access to ath9k's statistics for
67 interrupts, rate control, etc. 66 interrupts, rate control, etc.
68 67
69 Also required for changing debug message flags at run time. 68 Also required for changing debug message flags at run time and for
70 As well as access to the FFT/spectral data and TX99. 69 TX99.
71 70
72config ATH9K_STATION_STATISTICS 71config ATH9K_STATION_STATISTICS
73 bool "Detailed station statistics" 72 bool "Detailed station statistics"
@@ -177,7 +176,6 @@ config ATH9K_HTC_DEBUGFS
177 bool "Atheros ath9k_htc debugging" 176 bool "Atheros ath9k_htc debugging"
178 depends on ATH9K_HTC && DEBUG_FS 177 depends on ATH9K_HTC && DEBUG_FS
179 select ATH9K_COMMON_DEBUG 178 select ATH9K_COMMON_DEBUG
180 select RELAY
181 ---help--- 179 ---help---
182 Say Y, if you need access to ath9k_htc's statistics. 180 Say Y, if you need access to ath9k_htc's statistics.
183 As well as access to the FFT/spectral data. 181 As well as access to the FFT/spectral data.
@@ -192,3 +190,11 @@ config ATH9K_HWRNG
192 190
193 Say Y, feeds the entropy directly from the WiFi driver to the input 191 Say Y, feeds the entropy directly from the WiFi driver to the input
194 pool. 192 pool.
193
194config ATH9K_COMMON_SPECTRAL
195 bool "Atheros ath9k/ath9k_htc spectral scan support"
196 depends on ATH9K_DEBUGFS || ATH9K_HTC_DEBUGFS
197 select RELAY
198 default n
199 ---help---
200 Say Y to enable access to the FFT/spectral data via debugfs.
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index d804ce7391a0..f71b2ad8275c 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -62,8 +62,8 @@ ath9k_common-y:= common.o \
62 common-init.o \ 62 common-init.o \
63 common-beacon.o \ 63 common-beacon.o \
64 64
65ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o \ 65ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o
66 common-spectral.o 66ath9k_common-$(CONFIG_ATH9K_COMMON_SPECTRAL) += common-spectral.o
67 67
68ath9k_htc-y += htc_hst.o \ 68ath9k_htc-y += htc_hst.o \
69 hif_usb.o \ 69 hif_usb.o \
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 5d1a51d83aa6..303ab470ce34 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -151,7 +151,7 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
151 return bins[0] & 0x3f; 151 return bins[0] & 0x3f;
152} 152}
153 153
154#ifdef CONFIG_ATH9K_COMMON_DEBUG 154#ifdef CONFIG_ATH9K_COMMON_SPECTRAL
155void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); 155void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy);
156void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv); 156void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv);
157 157
@@ -183,6 +183,6 @@ static inline int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv,
183{ 183{
184 return 0; 184 return 0;
185} 185}
186#endif /* CONFIG_ATH9K_COMMON_DEBUG */ 186#endif /* CONFIG_ATH9K_COMMON_SPECTRAL */
187 187
188#endif /* SPECTRAL_H */ 188#endif /* SPECTRAL_H */
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
index 40a397fd0e0e..6fee9a464cce 100644
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -123,11 +123,9 @@ static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
123 fft = (struct ath9k_dfs_fft_40 *) (data + 2); 123 fft = (struct ath9k_dfs_fft_40 *) (data + 2);
124 ath_dbg(common, DFS, "fixing datalen by 2\n"); 124 ath_dbg(common, DFS, "fixing datalen by 2\n");
125 } 125 }
126 if (IS_CHAN_HT40MINUS(ah->curchan)) { 126 if (IS_CHAN_HT40MINUS(ah->curchan))
127 int temp = is_ctl; 127 swap(is_ctl, is_ext);
128 is_ctl = is_ext; 128
129 is_ext = temp;
130 }
131 for (i = 0; i < FFT_NUM_SAMPLES; i++) 129 for (i = 0; i < FFT_NUM_SAMPLES; i++)
132 max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, 130 max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
133 is_ext); 131 is_ext);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index f808e5833d7e..a82ad739ab80 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1683,6 +1683,10 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1683 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1683 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1684 break; 1684 break;
1685 case IEEE80211_AMPDU_TX_OPERATIONAL: 1685 case IEEE80211_AMPDU_TX_OPERATIONAL:
1686 if (tid >= ATH9K_HTC_MAX_TID) {
1687 ret = -EINVAL;
1688 break;
1689 }
1686 ista = (struct ath9k_htc_sta *) sta->drv_priv; 1690 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1687 spin_lock_bh(&priv->tx.tx_lock); 1691 spin_lock_bh(&priv->tx.tx_lock);
1688 ista->tid_state[tid] = AGGR_OPERATIONAL; 1692 ista->tid_state[tid] = AGGR_OPERATIONAL;
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index b765c647319d..182963522941 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -348,6 +348,13 @@ enum wcn36xx_hal_host_msg_type {
348 WCN36XX_HAL_DHCP_START_IND = 189, 348 WCN36XX_HAL_DHCP_START_IND = 189,
349 WCN36XX_HAL_DHCP_STOP_IND = 190, 349 WCN36XX_HAL_DHCP_STOP_IND = 190,
350 350
351 /* Scan Offload(hw) APIs */
352 WCN36XX_HAL_START_SCAN_OFFLOAD_REQ = 204,
353 WCN36XX_HAL_START_SCAN_OFFLOAD_RSP = 205,
354 WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ = 206,
355 WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP = 207,
356 WCN36XX_HAL_SCAN_OFFLOAD_IND = 210,
357
351 WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233, 358 WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
352 359
353 WCN36XX_HAL_PRINT_REG_INFO_IND = 259, 360 WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
@@ -1115,6 +1122,101 @@ struct wcn36xx_hal_finish_scan_rsp_msg {
1115 1122
1116} __packed; 1123} __packed;
1117 1124
1125enum wcn36xx_hal_scan_type {
1126 WCN36XX_HAL_SCAN_TYPE_PASSIVE = 0x00,
1127 WCN36XX_HAL_SCAN_TYPE_ACTIVE = WCN36XX_HAL_MAX_ENUM_SIZE
1128};
1129
1130struct wcn36xx_hal_mac_ssid {
1131 u8 length;
1132 u8 ssid[32];
1133} __packed;
1134
1135struct wcn36xx_hal_start_scan_offload_req_msg {
1136 struct wcn36xx_hal_msg_header header;
1137
1138 /* BSSIDs hot list */
1139 u8 num_bssid;
1140 u8 bssids[4][ETH_ALEN];
1141
1142 /* Directed probe-requests will be sent for listed SSIDs (max 10)*/
1143 u8 num_ssid;
1144 struct wcn36xx_hal_mac_ssid ssids[10];
1145
1146 /* Report AP with hidden ssid */
1147 u8 scan_hidden;
1148
1149 /* Self MAC address */
1150 u8 mac[ETH_ALEN];
1151
1152 /* BSS type */
1153 enum wcn36xx_hal_bss_type bss_type;
1154
1155 /* Scan type */
1156 enum wcn36xx_hal_scan_type scan_type;
1157
1158 /* Minimum scanning time on each channel (ms) */
1159 u32 min_ch_time;
1160
1161 /* Maximum scanning time on each channel */
1162 u32 max_ch_time;
1163
1164 /* Is a p2p search */
1165 u8 p2p_search;
1166
1167 /* Channels to scan */
1168 u8 num_channel;
1169 u8 channels[80];
1170
1171 /* IE field */
1172 u16 ie_len;
1173 u8 ie[0];
1174} __packed;
1175
1176struct wcn36xx_hal_start_scan_offload_rsp_msg {
1177 struct wcn36xx_hal_msg_header header;
1178
1179 /* success or failure */
1180 u32 status;
1181} __packed;
1182
1183enum wcn36xx_hal_scan_offload_ind_type {
1184 /* Scan has been started */
1185 WCN36XX_HAL_SCAN_IND_STARTED = 0x01,
1186 /* Scan has been completed */
1187 WCN36XX_HAL_SCAN_IND_COMPLETED = 0x02,
1188 /* Moved to foreign channel */
1189 WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL = 0x08,
1190 /* scan request has been dequeued */
1191 WCN36XX_HAL_SCAN_IND_DEQUEUED = 0x10,
1192 /* preempted by other high priority scan */
1193 WCN36XX_HAL_SCAN_IND_PREEMPTED = 0x20,
1194 /* scan start failed */
1195 WCN36XX_HAL_SCAN_IND_FAILED = 0x40,
1196 /*scan restarted */
1197 WCN36XX_HAL_SCAN_IND_RESTARTED = 0x80,
1198 WCN36XX_HAL_SCAN_IND_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
1199};
1200
1201struct wcn36xx_hal_scan_offload_ind {
1202 struct wcn36xx_hal_msg_header header;
1203
1204 u32 type;
1205 u32 channel_mhz;
1206 u32 scan_id;
1207} __packed;
1208
1209struct wcn36xx_hal_stop_scan_offload_req_msg {
1210 struct wcn36xx_hal_msg_header header;
1211} __packed;
1212
1213struct wcn36xx_hal_stop_scan_offload_rsp_msg {
1214 struct wcn36xx_hal_msg_header header;
1215
1216 /* success or failure */
1217 u32 status;
1218} __packed;
1219
1118enum wcn36xx_hal_rate_index { 1220enum wcn36xx_hal_rate_index {
1119 HW_RATE_INDEX_1MBPS = 0x82, 1221 HW_RATE_INDEX_1MBPS = 0x82,
1120 HW_RATE_INDEX_2MBPS = 0x84, 1222 HW_RATE_INDEX_2MBPS = 0x84,
@@ -1507,11 +1609,6 @@ struct wcn36xx_hal_edca_param_record {
1507 u16 txop_limit; 1609 u16 txop_limit;
1508} __packed; 1610} __packed;
1509 1611
1510struct wcn36xx_hal_mac_ssid {
1511 u8 length;
1512 u8 ssid[32];
1513} __packed;
1514
1515/* Concurrency role. These are generic IDs that identify the various roles 1612/* Concurrency role. These are generic IDs that identify the various roles
1516 * in the software system. */ 1613 * in the software system. */
1517enum wcn36xx_hal_con_mode { 1614enum wcn36xx_hal_con_mode {
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index f7d228b5ba93..5bed323f1100 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -629,7 +629,6 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
629 struct ieee80211_scan_request *hw_req) 629 struct ieee80211_scan_request *hw_req)
630{ 630{
631 struct wcn36xx *wcn = hw->priv; 631 struct wcn36xx *wcn = hw->priv;
632
633 mutex_lock(&wcn->scan_lock); 632 mutex_lock(&wcn->scan_lock);
634 if (wcn->scan_req) { 633 if (wcn->scan_req) {
635 mutex_unlock(&wcn->scan_lock); 634 mutex_unlock(&wcn->scan_lock);
@@ -638,11 +637,16 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
638 637
639 wcn->scan_aborted = false; 638 wcn->scan_aborted = false;
640 wcn->scan_req = &hw_req->req; 639 wcn->scan_req = &hw_req->req;
640
641 mutex_unlock(&wcn->scan_lock); 641 mutex_unlock(&wcn->scan_lock);
642 642
643 schedule_work(&wcn->scan_work); 643 if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) {
644 /* legacy manual/sw scan */
645 schedule_work(&wcn->scan_work);
646 return 0;
647 }
644 648
645 return 0; 649 return wcn36xx_smd_start_hw_scan(wcn, vif, &hw_req->req);
646} 650}
647 651
648static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, 652static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
@@ -650,6 +654,12 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
650{ 654{
651 struct wcn36xx *wcn = hw->priv; 655 struct wcn36xx *wcn = hw->priv;
652 656
657 if (!wcn36xx_smd_stop_hw_scan(wcn)) {
658 struct cfg80211_scan_info scan_info = { .aborted = true };
659
660 ieee80211_scan_completed(wcn->hw, &scan_info);
661 }
662
653 mutex_lock(&wcn->scan_lock); 663 mutex_lock(&wcn->scan_lock);
654 wcn->scan_aborted = true; 664 wcn->scan_aborted = true;
655 mutex_unlock(&wcn->scan_lock); 665 mutex_unlock(&wcn->scan_lock);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 9c6590d5348a..2914618a0335 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -73,6 +73,8 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
73 WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), 73 WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
74 WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), 74 WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
75 WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), 75 WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
76 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000),
77 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000),
76 WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), 78 WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
77 WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), 79 WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
78}; 80};
@@ -613,6 +615,85 @@ out:
613 return ret; 615 return ret;
614} 616}
615 617
618int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
619 struct cfg80211_scan_request *req)
620{
621 struct wcn36xx_hal_start_scan_offload_req_msg msg_body;
622 int ret, i;
623
624 mutex_lock(&wcn->hal_mutex);
625 INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);
626
627 msg_body.scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;
628 msg_body.min_ch_time = 30;
629 msg_body.min_ch_time = 100;
630 msg_body.scan_hidden = 1;
631 memcpy(msg_body.mac, vif->addr, ETH_ALEN);
632 msg_body.p2p_search = vif->p2p;
633
634 msg_body.num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body.ssids));
635 for (i = 0; i < msg_body.num_ssid; i++) {
636 msg_body.ssids[i].length = min_t(u8, req->ssids[i].ssid_len,
637 sizeof(msg_body.ssids[i].ssid));
638 memcpy(msg_body.ssids[i].ssid, req->ssids[i].ssid,
639 msg_body.ssids[i].length);
640 }
641
642 msg_body.num_channel = min_t(u8, req->n_channels,
643 sizeof(msg_body.channels));
644 for (i = 0; i < msg_body.num_channel; i++)
645 msg_body.channels[i] = req->channels[i]->hw_value;
646
647 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
648
649 wcn36xx_dbg(WCN36XX_DBG_HAL,
650 "hal start hw-scan (channels: %u; ssids: %u; p2p: %s)\n",
651 msg_body.num_channel, msg_body.num_ssid,
652 msg_body.p2p_search ? "yes" : "no");
653
654 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
655 if (ret) {
656 wcn36xx_err("Sending hal_start_scan_offload failed\n");
657 goto out;
658 }
659 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
660 if (ret) {
661 wcn36xx_err("hal_start_scan_offload response failed err=%d\n",
662 ret);
663 goto out;
664 }
665out:
666 mutex_unlock(&wcn->hal_mutex);
667 return ret;
668}
669
670int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn)
671{
672 struct wcn36xx_hal_stop_scan_offload_req_msg msg_body;
673 int ret;
674
675 mutex_lock(&wcn->hal_mutex);
676 INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ);
677 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
678
679 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal stop hw-scan\n");
680
681 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
682 if (ret) {
683 wcn36xx_err("Sending hal_stop_scan_offload failed\n");
684 goto out;
685 }
686 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
687 if (ret) {
688 wcn36xx_err("hal_stop_scan_offload response failed err=%d\n",
689 ret);
690 goto out;
691 }
692out:
693 mutex_unlock(&wcn->hal_mutex);
694 return ret;
695}
696
616static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len) 697static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)
617{ 698{
618 struct wcn36xx_hal_switch_channel_rsp_msg *rsp; 699 struct wcn36xx_hal_switch_channel_rsp_msg *rsp;
@@ -2039,6 +2120,40 @@ static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len)
2039 return 0; 2120 return 0;
2040} 2121}
2041 2122
2123static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
2124{
2125 struct wcn36xx_hal_scan_offload_ind *rsp = buf;
2126 struct cfg80211_scan_info scan_info = {};
2127
2128 if (len != sizeof(*rsp)) {
2129 wcn36xx_warn("Corrupted delete scan indication\n");
2130 return -EIO;
2131 }
2132
2133 wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)", rsp->type);
2134
2135 switch (rsp->type) {
2136 case WCN36XX_HAL_SCAN_IND_FAILED:
2137 scan_info.aborted = true;
2138 case WCN36XX_HAL_SCAN_IND_COMPLETED:
2139 mutex_lock(&wcn->scan_lock);
2140 wcn->scan_req = NULL;
2141 mutex_unlock(&wcn->scan_lock);
2142 ieee80211_scan_completed(wcn->hw, &scan_info);
2143 break;
2144 case WCN36XX_HAL_SCAN_IND_STARTED:
2145 case WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL:
2146 case WCN36XX_HAL_SCAN_IND_DEQUEUED:
2147 case WCN36XX_HAL_SCAN_IND_PREEMPTED:
2148 case WCN36XX_HAL_SCAN_IND_RESTARTED:
2149 break;
2150 default:
2151 wcn36xx_warn("Unknown scan indication type %x\n", rsp->type);
2152 }
2153
2154 return 0;
2155}
2156
2042static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, 2157static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
2043 void *buf, 2158 void *buf,
2044 size_t len) 2159 size_t len)
@@ -2250,6 +2365,8 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
2250 case WCN36XX_HAL_CH_SWITCH_RSP: 2365 case WCN36XX_HAL_CH_SWITCH_RSP:
2251 case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: 2366 case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
2252 case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: 2367 case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
2368 case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP:
2369 case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP:
2253 memcpy(wcn->hal_buf, buf, len); 2370 memcpy(wcn->hal_buf, buf, len);
2254 wcn->hal_rsp_len = len; 2371 wcn->hal_rsp_len = len;
2255 complete(&wcn->hal_rsp_compl); 2372 complete(&wcn->hal_rsp_compl);
@@ -2262,6 +2379,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
2262 case WCN36XX_HAL_MISSED_BEACON_IND: 2379 case WCN36XX_HAL_MISSED_BEACON_IND:
2263 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: 2380 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
2264 case WCN36XX_HAL_PRINT_REG_INFO_IND: 2381 case WCN36XX_HAL_PRINT_REG_INFO_IND:
2382 case WCN36XX_HAL_SCAN_OFFLOAD_IND:
2265 msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC); 2383 msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
2266 if (!msg_ind) { 2384 if (!msg_ind) {
2267 wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n", 2385 wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
@@ -2298,6 +2416,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
2298 hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, 2416 hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
2299 struct wcn36xx_hal_ind_msg, 2417 struct wcn36xx_hal_ind_msg,
2300 list); 2418 list);
2419 list_del(wcn->hal_ind_queue.next);
2420 spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
2301 2421
2302 msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; 2422 msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
2303 2423
@@ -2326,12 +2446,14 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
2326 hal_ind_msg->msg, 2446 hal_ind_msg->msg,
2327 hal_ind_msg->msg_len); 2447 hal_ind_msg->msg_len);
2328 break; 2448 break;
2449 case WCN36XX_HAL_SCAN_OFFLOAD_IND:
2450 wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
2451 hal_ind_msg->msg_len);
2452 break;
2329 default: 2453 default:
2330 wcn36xx_err("SMD_EVENT (%d) not supported\n", 2454 wcn36xx_err("SMD_EVENT (%d) not supported\n",
2331 msg_header->msg_type); 2455 msg_header->msg_type);
2332 } 2456 }
2333 list_del(wcn->hal_ind_queue.next);
2334 spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
2335 kfree(hal_ind_msg); 2457 kfree(hal_ind_msg);
2336} 2458}
2337int wcn36xx_smd_open(struct wcn36xx *wcn) 2459int wcn36xx_smd_open(struct wcn36xx *wcn)
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 013fc9546f56..8076edf40ac8 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -65,6 +65,9 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
65int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, 65int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
66 enum wcn36xx_hal_sys_mode mode); 66 enum wcn36xx_hal_sys_mode mode);
67int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count); 67int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
68int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
69 struct cfg80211_scan_request *req);
70int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn);
68int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif); 71int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
69int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr); 72int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
70int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index); 73int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 85d5c04618eb..771a534d6ca9 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -901,7 +901,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
901 u64 *cookie) 901 u64 *cookie)
902{ 902{
903 const u8 *buf = params->buf; 903 const u8 *buf = params->buf;
904 size_t len = params->len; 904 size_t len = params->len, total;
905 struct wil6210_priv *wil = wiphy_to_wil(wiphy); 905 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
906 int rc; 906 int rc;
907 bool tx_status = false; 907 bool tx_status = false;
@@ -926,7 +926,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
926 if (len < sizeof(struct ieee80211_hdr_3addr)) 926 if (len < sizeof(struct ieee80211_hdr_3addr))
927 return -EINVAL; 927 return -EINVAL;
928 928
929 cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); 929 total = sizeof(*cmd) + len;
930 if (total < len)
931 return -EINVAL;
932
933 cmd = kmalloc(total, GFP_KERNEL);
930 if (!cmd) { 934 if (!cmd) {
931 rc = -ENOMEM; 935 rc = -ENOMEM;
932 goto out; 936 goto out;
@@ -936,7 +940,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
936 cmd->len = cpu_to_le16(len); 940 cmd->len = cpu_to_le16(len);
937 memcpy(cmd->payload, buf, len); 941 memcpy(cmd->payload, buf, len);
938 942
939 rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, 943 rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total,
940 WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); 944 WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
941 if (rc == 0) 945 if (rc == 0)
942 tx_status = !evt.evt.status; 946 tx_status = !evt.evt.status;
@@ -1727,9 +1731,12 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
1727 1731
1728 wil_dbg_pm(wil, "suspending\n"); 1732 wil_dbg_pm(wil, "suspending\n");
1729 1733
1730 wil_p2p_stop_discovery(wil); 1734 mutex_lock(&wil->mutex);
1731 1735 mutex_lock(&wil->p2p_wdev_mutex);
1736 wil_p2p_stop_radio_operations(wil);
1732 wil_abort_scan(wil, true); 1737 wil_abort_scan(wil, true);
1738 mutex_unlock(&wil->p2p_wdev_mutex);
1739 mutex_unlock(&wil->mutex);
1733 1740
1734out: 1741out:
1735 return rc; 1742 return rc;
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index e58dc6dc1f9c..4475937faf25 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -242,12 +242,19 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
242static int wil_mbox_debugfs_show(struct seq_file *s, void *data) 242static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
243{ 243{
244 struct wil6210_priv *wil = s->private; 244 struct wil6210_priv *wil = s->private;
245 int ret;
246
247 ret = wil_pm_runtime_get(wil);
248 if (ret < 0)
249 return ret;
245 250
246 wil_print_ring(s, "tx", wil->csr + HOST_MBOX + 251 wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
247 offsetof(struct wil6210_mbox_ctl, tx)); 252 offsetof(struct wil6210_mbox_ctl, tx));
248 wil_print_ring(s, "rx", wil->csr + HOST_MBOX + 253 wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
249 offsetof(struct wil6210_mbox_ctl, rx)); 254 offsetof(struct wil6210_mbox_ctl, rx));
250 255
256 wil_pm_runtime_put(wil);
257
251 return 0; 258 return 0;
252} 259}
253 260
@@ -265,15 +272,37 @@ static const struct file_operations fops_mbox = {
265 272
266static int wil_debugfs_iomem_x32_set(void *data, u64 val) 273static int wil_debugfs_iomem_x32_set(void *data, u64 val)
267{ 274{
268 writel(val, (void __iomem *)data); 275 struct wil_debugfs_iomem_data *d = (struct
276 wil_debugfs_iomem_data *)data;
277 struct wil6210_priv *wil = d->wil;
278 int ret;
279
280 ret = wil_pm_runtime_get(wil);
281 if (ret < 0)
282 return ret;
283
284 writel(val, (void __iomem *)d->offset);
269 wmb(); /* make sure write propagated to HW */ 285 wmb(); /* make sure write propagated to HW */
270 286
287 wil_pm_runtime_put(wil);
288
271 return 0; 289 return 0;
272} 290}
273 291
274static int wil_debugfs_iomem_x32_get(void *data, u64 *val) 292static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
275{ 293{
276 *val = readl((void __iomem *)data); 294 struct wil_debugfs_iomem_data *d = (struct
295 wil_debugfs_iomem_data *)data;
296 struct wil6210_priv *wil = d->wil;
297 int ret;
298
299 ret = wil_pm_runtime_get(wil);
300 if (ret < 0)
301 return ret;
302
303 *val = readl((void __iomem *)d->offset);
304
305 wil_pm_runtime_put(wil);
277 306
278 return 0; 307 return 0;
279} 308}
@@ -284,10 +313,21 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
284static struct dentry *wil_debugfs_create_iomem_x32(const char *name, 313static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
285 umode_t mode, 314 umode_t mode,
286 struct dentry *parent, 315 struct dentry *parent,
287 void *value) 316 void *value,
317 struct wil6210_priv *wil)
288{ 318{
289 return debugfs_create_file(name, mode, parent, value, 319 struct dentry *file;
290 &fops_iomem_x32); 320 struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
321 wil->dbg_data.iomem_data_count];
322
323 data->wil = wil;
324 data->offset = value;
325
326 file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
327 if (!IS_ERR_OR_NULL(file))
328 wil->dbg_data.iomem_data_count++;
329
330 return file;
291} 331}
292 332
293static int wil_debugfs_ulong_set(void *data, u64 val) 333static int wil_debugfs_ulong_set(void *data, u64 val)
@@ -346,7 +386,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
346 case doff_io32: 386 case doff_io32:
347 f = wil_debugfs_create_iomem_x32(tbl[i].name, 387 f = wil_debugfs_create_iomem_x32(tbl[i].name,
348 tbl[i].mode, dbg, 388 tbl[i].mode, dbg,
349 base + tbl[i].off); 389 base + tbl[i].off,
390 wil);
350 break; 391 break;
351 case doff_u8: 392 case doff_u8:
352 f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, 393 f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
@@ -475,13 +516,22 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
475static int wil_memread_debugfs_show(struct seq_file *s, void *data) 516static int wil_memread_debugfs_show(struct seq_file *s, void *data)
476{ 517{
477 struct wil6210_priv *wil = s->private; 518 struct wil6210_priv *wil = s->private;
478 void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); 519 void __iomem *a;
520 int ret;
521
522 ret = wil_pm_runtime_get(wil);
523 if (ret < 0)
524 return ret;
525
526 a = wmi_buffer(wil, cpu_to_le32(mem_addr));
479 527
480 if (a) 528 if (a)
481 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a)); 529 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
482 else 530 else
483 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); 531 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
484 532
533 wil_pm_runtime_put(wil);
534
485 return 0; 535 return 0;
486} 536}
487 537
@@ -502,10 +552,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
502{ 552{
503 enum { max_count = 4096 }; 553 enum { max_count = 4096 };
504 struct wil_blob_wrapper *wil_blob = file->private_data; 554 struct wil_blob_wrapper *wil_blob = file->private_data;
555 struct wil6210_priv *wil = wil_blob->wil;
505 loff_t pos = *ppos; 556 loff_t pos = *ppos;
506 size_t available = wil_blob->blob.size; 557 size_t available = wil_blob->blob.size;
507 void *buf; 558 void *buf;
508 size_t ret; 559 size_t ret;
560 int rc;
509 561
510 if (test_bit(wil_status_suspending, wil_blob->wil->status) || 562 if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
511 test_bit(wil_status_suspended, wil_blob->wil->status)) 563 test_bit(wil_status_suspended, wil_blob->wil->status))
@@ -526,10 +578,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
526 if (!buf) 578 if (!buf)
527 return -ENOMEM; 579 return -ENOMEM;
528 580
581 rc = wil_pm_runtime_get(wil);
582 if (rc < 0) {
583 kfree(buf);
584 return rc;
585 }
586
529 wil_memcpy_fromio_32(buf, (const void __iomem *) 587 wil_memcpy_fromio_32(buf, (const void __iomem *)
530 wil_blob->blob.data + pos, count); 588 wil_blob->blob.data + pos, count);
531 589
532 ret = copy_to_user(user_buf, buf, count); 590 ret = copy_to_user(user_buf, buf, count);
591
592 wil_pm_runtime_put(wil);
593
533 kfree(buf); 594 kfree(buf);
534 if (ret == count) 595 if (ret == count)
535 return -EFAULT; 596 return -EFAULT;
@@ -1571,8 +1632,6 @@ static ssize_t wil_write_suspend_stats(struct file *file,
1571 struct wil6210_priv *wil = file->private_data; 1632 struct wil6210_priv *wil = file->private_data;
1572 1633
1573 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); 1634 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
1574 wil->suspend_stats.min_suspend_time = ULONG_MAX;
1575 wil->suspend_stats.collection_start = ktime_get();
1576 1635
1577 return len; 1636 return len;
1578} 1637}
@@ -1582,33 +1641,41 @@ static ssize_t wil_read_suspend_stats(struct file *file,
1582 size_t count, loff_t *ppos) 1641 size_t count, loff_t *ppos)
1583{ 1642{
1584 struct wil6210_priv *wil = file->private_data; 1643 struct wil6210_priv *wil = file->private_data;
1585 static char text[400]; 1644 char *text;
1586 int n; 1645 int n, ret, text_size = 500;
1587 unsigned long long stats_collection_time =
1588 ktime_to_us(ktime_sub(ktime_get(),
1589 wil->suspend_stats.collection_start));
1590 1646
1591 n = snprintf(text, sizeof(text), 1647 text = kmalloc(text_size, GFP_KERNEL);
1592 "Suspend statistics:\n" 1648 if (!text)
1649 return -ENOMEM;
1650
1651 n = snprintf(text, text_size,
1652 "Radio on suspend statistics:\n"
1653 "successful suspends:%ld failed suspends:%ld\n"
1654 "successful resumes:%ld failed resumes:%ld\n"
1655 "rejected by device:%ld\n"
1656 "Radio off suspend statistics:\n"
1593 "successful suspends:%ld failed suspends:%ld\n" 1657 "successful suspends:%ld failed suspends:%ld\n"
1594 "successful resumes:%ld failed resumes:%ld\n" 1658 "successful resumes:%ld failed resumes:%ld\n"
1595 "rejected by host:%ld rejected by device:%ld\n" 1659 "General statistics:\n"
1596 "total suspend time:%lld min suspend time:%lld\n" 1660 "rejected by host:%ld\n",
1597 "max suspend time:%lld stats collection time: %lld\n", 1661 wil->suspend_stats.r_on.successful_suspends,
1598 wil->suspend_stats.successful_suspends, 1662 wil->suspend_stats.r_on.failed_suspends,
1599 wil->suspend_stats.failed_suspends, 1663 wil->suspend_stats.r_on.successful_resumes,
1600 wil->suspend_stats.successful_resumes, 1664 wil->suspend_stats.r_on.failed_resumes,
1601 wil->suspend_stats.failed_resumes,
1602 wil->suspend_stats.rejected_by_host,
1603 wil->suspend_stats.rejected_by_device, 1665 wil->suspend_stats.rejected_by_device,
1604 wil->suspend_stats.total_suspend_time, 1666 wil->suspend_stats.r_off.successful_suspends,
1605 wil->suspend_stats.min_suspend_time, 1667 wil->suspend_stats.r_off.failed_suspends,
1606 wil->suspend_stats.max_suspend_time, 1668 wil->suspend_stats.r_off.successful_resumes,
1607 stats_collection_time); 1669 wil->suspend_stats.r_off.failed_resumes,
1670 wil->suspend_stats.rejected_by_host);
1671
1672 n = min_t(int, n, text_size);
1608 1673
1609 n = min_t(int, n, sizeof(text)); 1674 ret = simple_read_from_buffer(user_buf, count, ppos, text, n);
1610 1675
1611 return simple_read_from_buffer(user_buf, count, ppos, text, n); 1676 kfree(text);
1677
1678 return ret;
1612} 1679}
1613 1680
1614static const struct file_operations fops_suspend_stats = { 1681static const struct file_operations fops_suspend_stats = {
@@ -1736,14 +1803,31 @@ static const struct dbg_off dbg_statics[] = {
1736 {}, 1803 {},
1737}; 1804};
1738 1805
1806static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
1807 ARRAY_SIZE(dbg_wil_regs) - 1 +
1808 ARRAY_SIZE(pseudo_isr_off) - 1 +
1809 ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
1810 ARRAY_SIZE(tx_itr_cnt_off) - 1 +
1811 ARRAY_SIZE(rx_itr_cnt_off) - 1;
1812
1739int wil6210_debugfs_init(struct wil6210_priv *wil) 1813int wil6210_debugfs_init(struct wil6210_priv *wil)
1740{ 1814{
1741 struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, 1815 struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
1742 wil_to_wiphy(wil)->debugfsdir); 1816 wil_to_wiphy(wil)->debugfsdir);
1743
1744 if (IS_ERR_OR_NULL(dbg)) 1817 if (IS_ERR_OR_NULL(dbg))
1745 return -ENODEV; 1818 return -ENODEV;
1746 1819
1820 wil->dbg_data.data_arr = kcalloc(dbg_off_count,
1821 sizeof(struct wil_debugfs_iomem_data),
1822 GFP_KERNEL);
1823 if (!wil->dbg_data.data_arr) {
1824 debugfs_remove_recursive(dbg);
1825 wil->debug = NULL;
1826 return -ENOMEM;
1827 }
1828
1829 wil->dbg_data.iomem_data_count = 0;
1830
1747 wil_pmc_init(wil); 1831 wil_pmc_init(wil);
1748 1832
1749 wil6210_debugfs_init_files(wil, dbg); 1833 wil6210_debugfs_init_files(wil, dbg);
@@ -1758,8 +1842,6 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
1758 1842
1759 wil6210_debugfs_create_ITR_CNT(wil, dbg); 1843 wil6210_debugfs_create_ITR_CNT(wil, dbg);
1760 1844
1761 wil->suspend_stats.collection_start = ktime_get();
1762
1763 return 0; 1845 return 0;
1764} 1846}
1765 1847
@@ -1768,6 +1850,8 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
1768 debugfs_remove_recursive(wil->debug); 1850 debugfs_remove_recursive(wil->debug);
1769 wil->debug = NULL; 1851 wil->debug = NULL;
1770 1852
1853 kfree(wil->dbg_data.data_arr);
1854
1771 /* free pmc memory without sending command to fw, as it will 1855 /* free pmc memory without sending command to fw, as it will
1772 * be reset on the way down anyway 1856 * be reset on the way down anyway
1773 */ 1857 */
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index adcfef4dabf7..66200f616a37 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -47,9 +47,14 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
47 struct wil6210_priv *wil = ndev_to_wil(ndev); 47 struct wil6210_priv *wil = ndev_to_wil(ndev);
48 u32 tx_itr_en, tx_itr_val = 0; 48 u32 tx_itr_en, tx_itr_val = 0;
49 u32 rx_itr_en, rx_itr_val = 0; 49 u32 rx_itr_en, rx_itr_val = 0;
50 int ret;
50 51
51 wil_dbg_misc(wil, "ethtoolops_get_coalesce\n"); 52 wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");
52 53
54 ret = wil_pm_runtime_get(wil);
55 if (ret < 0)
56 return ret;
57
53 tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); 58 tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
54 if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) 59 if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
55 tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); 60 tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH);
@@ -58,6 +63,8 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
58 if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) 63 if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
59 rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); 64 rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);
60 65
66 wil_pm_runtime_put(wil);
67
61 cp->tx_coalesce_usecs = tx_itr_val; 68 cp->tx_coalesce_usecs = tx_itr_val;
62 cp->rx_coalesce_usecs = rx_itr_val; 69 cp->rx_coalesce_usecs = rx_itr_val;
63 return 0; 70 return 0;
@@ -67,6 +74,7 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
67 struct ethtool_coalesce *cp) 74 struct ethtool_coalesce *cp)
68{ 75{
69 struct wil6210_priv *wil = ndev_to_wil(ndev); 76 struct wil6210_priv *wil = ndev_to_wil(ndev);
77 int ret;
70 78
71 wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", 79 wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
72 cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); 80 cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
@@ -86,8 +94,15 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
86 94
87 wil->tx_max_burst_duration = cp->tx_coalesce_usecs; 95 wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
88 wil->rx_max_burst_duration = cp->rx_coalesce_usecs; 96 wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
97
98 ret = wil_pm_runtime_get(wil);
99 if (ret < 0)
100 return ret;
101
89 wil_configure_interrupt_moderation(wil); 102 wil_configure_interrupt_moderation(wil);
90 103
104 wil_pm_runtime_put(wil);
105
91 return 0; 106 return 0;
92 107
93out_bad: 108out_bad:
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index e01acac88825..77d1902947e3 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -26,14 +26,17 @@
26 prefix_type, rowsize, \ 26 prefix_type, rowsize, \
27 groupsize, buf, len, ascii) 27 groupsize, buf, len, ascii)
28 28
29#define FW_ADDR_CHECK(ioaddr, val, msg) do { \ 29static bool wil_fw_addr_check(struct wil6210_priv *wil,
30 ioaddr = wmi_buffer(wil, val); \ 30 void __iomem **ioaddr, __le32 val,
31 if (!ioaddr) { \ 31 u32 size, const char *msg)
32 wil_err_fw(wil, "bad " msg ": 0x%08x\n", \ 32{
33 le32_to_cpu(val)); \ 33 *ioaddr = wmi_buffer_block(wil, val, size);
34 return -EINVAL; \ 34 if (!(*ioaddr)) {
35 } \ 35 wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val));
36 } while (0) 36 return false;
37 }
38 return true;
39}
37 40
38/** 41/**
39 * wil_fw_verify - verify firmware file validity 42 * wil_fw_verify - verify firmware file validity
@@ -124,24 +127,19 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
124 return 0; 127 return 0;
125} 128}
126 129
127static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
128 size_t size)
129{
130 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
131
132 return 0;
133}
134
135static int 130static int
136fw_handle_capabilities(struct wil6210_priv *wil, const void *data, 131fw_handle_comment(struct wil6210_priv *wil, const void *data,
137 size_t size) 132 size_t size)
138{ 133{
139 const struct wil_fw_record_capabilities *rec = data; 134 const struct wil_fw_record_capabilities *rec = data;
140 size_t capa_size; 135 size_t capa_size;
141 136
142 if (size < sizeof(*rec) || 137 if (size < sizeof(*rec) ||
143 le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) 138 le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
139 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
140 data, size, true);
144 return 0; 141 return 0;
142 }
145 143
146 capa_size = size - offsetof(struct wil_fw_record_capabilities, 144 capa_size = size - offsetof(struct wil_fw_record_capabilities,
147 capabilities); 145 capabilities);
@@ -165,7 +163,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
165 return -EINVAL; 163 return -EINVAL;
166 } 164 }
167 165
168 FW_ADDR_CHECK(dst, d->addr, "address"); 166 if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
167 return -EINVAL;
169 wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), 168 wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
170 s); 169 s);
171 wil_memcpy_toio_32(dst, d->data, s); 170 wil_memcpy_toio_32(dst, d->data, s);
@@ -197,7 +196,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
197 return -EINVAL; 196 return -EINVAL;
198 } 197 }
199 198
200 FW_ADDR_CHECK(dst, d->addr, "address"); 199 if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
200 return -EINVAL;
201 201
202 v = le32_to_cpu(d->value); 202 v = le32_to_cpu(d->value);
203 wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n", 203 wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
@@ -253,7 +253,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
253 u32 v = le32_to_cpu(block[i].value); 253 u32 v = le32_to_cpu(block[i].value);
254 u32 x, y; 254 u32 x, y;
255 255
256 FW_ADDR_CHECK(dst, block[i].addr, "address"); 256 if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address"))
257 return -EINVAL;
257 258
258 x = readl(dst); 259 x = readl(dst);
259 y = (x & m) | (v & ~m); 260 y = (x & m) | (v & ~m);
@@ -319,10 +320,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
319 wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", 320 wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
320 n, gw_cmd); 321 n, gw_cmd);
321 322
322 FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); 323 if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
323 FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr"); 324 "gateway_addr_addr") ||
324 FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); 325 !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0,
325 FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); 326 "gateway_value_addr") ||
327 !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
328 "gateway_cmd_addr") ||
329 !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
330 "gateway_ctrl_address"))
331 return -EINVAL;
326 332
327 wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x" 333 wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
328 " cmd 0x%08x ctl 0x%08x\n", 334 " cmd 0x%08x ctl 0x%08x\n",
@@ -378,12 +384,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
378 wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", 384 wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
379 n, gw_cmd); 385 n, gw_cmd);
380 386
381 FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); 387 if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
388 "gateway_addr_addr"))
389 return -EINVAL;
382 for (k = 0; k < ARRAY_SIZE(block->value); k++) 390 for (k = 0; k < ARRAY_SIZE(block->value); k++)
383 FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k], 391 if (!wil_fw_addr_check(wil, &gwa_val[k],
384 "gateway_value_addr"); 392 d->gateway_value_addr[k],
385 FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); 393 0, "gateway_value_addr"))
386 FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); 394 return -EINVAL;
395 if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
396 "gateway_cmd_addr") ||
397 !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
398 "gateway_ctrl_address"))
399 return -EINVAL;
387 400
388 wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n", 401 wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
389 le32_to_cpu(d->gateway_addr_addr), 402 le32_to_cpu(d->gateway_addr_addr),
@@ -422,7 +435,7 @@ static const struct {
422 int (*parse_handler)(struct wil6210_priv *wil, const void *data, 435 int (*parse_handler)(struct wil6210_priv *wil, const void *data,
423 size_t size); 436 size_t size);
424} wil_fw_handlers[] = { 437} wil_fw_handlers[] = {
425 {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities}, 438 {wil_fw_type_comment, fw_handle_comment, fw_handle_comment},
426 {wil_fw_type_data, fw_handle_data, fw_ignore_section}, 439 {wil_fw_type_data, fw_handle_data, fw_ignore_section},
427 {wil_fw_type_fill, fw_handle_fill, fw_ignore_section}, 440 {wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
428 /* wil_fw_type_action */ 441 /* wil_fw_type_action */
@@ -517,7 +530,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
517 530
518 rc = request_firmware(&fw, name, wil_to_dev(wil)); 531 rc = request_firmware(&fw, name, wil_to_dev(wil));
519 if (rc) { 532 if (rc) {
520 wil_err_fw(wil, "Failed to load firmware %s\n", name); 533 wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc);
521 return rc; 534 return rc;
522 } 535 }
523 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); 536 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 59def4f3fcf3..5cf341702dc1 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -358,6 +358,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil)
358 wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); 358 wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
359} 359}
360 360
361static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
362{
363 size_t min_size = sizeof(struct wil6210_mbox_hdr) +
364 sizeof(struct wmi_cmd_hdr);
365
366 if (wil->mbox_ctl.rx.entry_size < min_size) {
367 wil_err(wil, "rx mbox entry too small (%d)\n",
368 wil->mbox_ctl.rx.entry_size);
369 return false;
370 }
371 if (wil->mbox_ctl.tx.entry_size < min_size) {
372 wil_err(wil, "tx mbox entry too small (%d)\n",
373 wil->mbox_ctl.tx.entry_size);
374 return false;
375 }
376
377 return true;
378}
379
361static irqreturn_t wil6210_irq_misc(int irq, void *cookie) 380static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
362{ 381{
363 struct wil6210_priv *wil = cookie; 382 struct wil6210_priv *wil = cookie;
@@ -393,7 +412,8 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
393 if (isr & ISR_MISC_FW_READY) { 412 if (isr & ISR_MISC_FW_READY) {
394 wil_dbg_irq(wil, "IRQ: FW ready\n"); 413 wil_dbg_irq(wil, "IRQ: FW ready\n");
395 wil_cache_mbox_regs(wil); 414 wil_cache_mbox_regs(wil);
396 set_bit(wil_status_mbox_ready, wil->status); 415 if (wil_validate_mbox_regs(wil))
416 set_bit(wil_status_mbox_ready, wil->status);
397 /** 417 /**
398 * Actual FW ready indicated by the 418 * Actual FW ready indicated by the
399 * WMI_FW_READY_EVENTID 419 * WMI_FW_READY_EVENTID
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 885924abf61c..1b53cd3f272b 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -579,7 +579,6 @@ int wil_priv_init(struct wil6210_priv *wil)
579 wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | 579 wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
580 WMI_WAKEUP_TRIGGER_BCAST; 580 WMI_WAKEUP_TRIGGER_BCAST;
581 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); 581 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
582 wil->suspend_stats.min_suspend_time = ULONG_MAX;
583 wil->vring_idle_trsh = 16; 582 wil->vring_idle_trsh = 16;
584 583
585 return 0; 584 return 0;
@@ -760,6 +759,8 @@ static void wil_collect_fw_info(struct wil6210_priv *wil)
760 u8 retry_short; 759 u8 retry_short;
761 int rc; 760 int rc;
762 761
762 wil_refresh_fw_capabilities(wil);
763
763 rc = wmi_get_mgmt_retry(wil, &retry_short); 764 rc = wmi_get_mgmt_retry(wil, &retry_short);
764 if (!rc) { 765 if (!rc) {
765 wiphy->retry_short = retry_short; 766 wiphy->retry_short = retry_short;
@@ -767,6 +768,25 @@ static void wil_collect_fw_info(struct wil6210_priv *wil)
767 } 768 }
768} 769}
769 770
771void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
772{
773 struct wiphy *wiphy = wil_to_wiphy(wil);
774
775 wil->keep_radio_on_during_sleep =
776 wil->platform_ops.keep_radio_on_during_sleep &&
777 wil->platform_ops.keep_radio_on_during_sleep(
778 wil->platform_handle) &&
779 test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
780
781 wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
782 wil->keep_radio_on_during_sleep);
783
784 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
785 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
786 else
787 wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
788}
789
770void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) 790void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
771{ 791{
772 le32_to_cpus(&r->base); 792 le32_to_cpus(&r->base);
@@ -1071,11 +1091,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
1071 return rc; 1091 return rc;
1072 } 1092 }
1073 1093
1094 wil_collect_fw_info(wil);
1095
1074 if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) 1096 if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
1075 wil_ps_update(wil, wil->ps_profile); 1097 wil_ps_update(wil, wil->ps_profile);
1076 1098
1077 wil_collect_fw_info(wil);
1078
1079 if (wil->platform_ops.notify) { 1099 if (wil->platform_ops.notify) {
1080 rc = wil->platform_ops.notify(wil->platform_handle, 1100 rc = wil->platform_ops.notify(wil->platform_handle,
1081 WIL_PLATFORM_EVT_FW_RDY); 1101 WIL_PLATFORM_EVT_FW_RDY);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 4a6ab2d0fdf1..b641ac17a053 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -21,6 +21,7 @@
21static int wil_open(struct net_device *ndev) 21static int wil_open(struct net_device *ndev)
22{ 22{
23 struct wil6210_priv *wil = ndev_to_wil(ndev); 23 struct wil6210_priv *wil = ndev_to_wil(ndev);
24 int rc;
24 25
25 wil_dbg_misc(wil, "open\n"); 26 wil_dbg_misc(wil, "open\n");
26 27
@@ -30,16 +31,29 @@ static int wil_open(struct net_device *ndev)
30 return -EINVAL; 31 return -EINVAL;
31 } 32 }
32 33
33 return wil_up(wil); 34 rc = wil_pm_runtime_get(wil);
35 if (rc < 0)
36 return rc;
37
38 rc = wil_up(wil);
39 if (rc)
40 wil_pm_runtime_put(wil);
41
42 return rc;
34} 43}
35 44
36static int wil_stop(struct net_device *ndev) 45static int wil_stop(struct net_device *ndev)
37{ 46{
38 struct wil6210_priv *wil = ndev_to_wil(ndev); 47 struct wil6210_priv *wil = ndev_to_wil(ndev);
48 int rc;
39 49
40 wil_dbg_misc(wil, "stop\n"); 50 wil_dbg_misc(wil, "stop\n");
41 51
42 return wil_down(wil); 52 rc = wil_down(wil);
53 if (!rc)
54 wil_pm_runtime_put(wil);
55
56 return rc;
43} 57}
44 58
45static const struct net_device_ops wil_netdev_ops = { 59static const struct net_device_ops wil_netdev_ops = {
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 6a3ab4bf916d..42a5480c764d 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -21,6 +21,7 @@
21#include <linux/suspend.h> 21#include <linux/suspend.h>
22#include "wil6210.h" 22#include "wil6210.h"
23#include <linux/rtnetlink.h> 23#include <linux/rtnetlink.h>
24#include <linux/pm_runtime.h>
24 25
25static bool use_msi = true; 26static bool use_msi = true;
26module_param(use_msi, bool, 0444); 27module_param(use_msi, bool, 0444);
@@ -31,10 +32,8 @@ module_param(ftm_mode, bool, 0444);
31MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); 32MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
32 33
33#ifdef CONFIG_PM 34#ifdef CONFIG_PM
34#ifdef CONFIG_PM_SLEEP
35static int wil6210_pm_notify(struct notifier_block *notify_block, 35static int wil6210_pm_notify(struct notifier_block *notify_block,
36 unsigned long mode, void *unused); 36 unsigned long mode, void *unused);
37#endif /* CONFIG_PM_SLEEP */
38#endif /* CONFIG_PM */ 37#endif /* CONFIG_PM */
39 38
40static 39static
@@ -84,9 +83,7 @@ void wil_set_capabilities(struct wil6210_priv *wil)
84 83
85 /* extract FW capabilities from file without loading the FW */ 84 /* extract FW capabilities from file without loading the FW */
86 wil_request_firmware(wil, wil->wil_fw_name, false); 85 wil_request_firmware(wil, wil->wil_fw_name, false);
87 86 wil_refresh_fw_capabilities(wil);
88 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
89 wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM;
90} 87}
91 88
92void wil_disable_irq(struct wil6210_priv *wil) 89void wil_disable_irq(struct wil6210_priv *wil)
@@ -296,15 +293,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
296 wil_set_capabilities(wil); 293 wil_set_capabilities(wil);
297 wil6210_clear_irq(wil); 294 wil6210_clear_irq(wil);
298 295
299 wil->keep_radio_on_during_sleep =
300 wil->platform_ops.keep_radio_on_during_sleep &&
301 wil->platform_ops.keep_radio_on_during_sleep(
302 wil->platform_handle) &&
303 test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
304
305 wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
306 wil->keep_radio_on_during_sleep);
307
308 /* FW should raise IRQ when ready */ 296 /* FW should raise IRQ when ready */
309 rc = wil_if_pcie_enable(wil); 297 rc = wil_if_pcie_enable(wil);
310 if (rc) { 298 if (rc) {
@@ -320,7 +308,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
320 } 308 }
321 309
322#ifdef CONFIG_PM 310#ifdef CONFIG_PM
323#ifdef CONFIG_PM_SLEEP
324 wil->pm_notify.notifier_call = wil6210_pm_notify; 311 wil->pm_notify.notifier_call = wil6210_pm_notify;
325 rc = register_pm_notifier(&wil->pm_notify); 312 rc = register_pm_notifier(&wil->pm_notify);
326 if (rc) 313 if (rc)
@@ -328,11 +315,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
328 * be prevented in a later phase if needed 315 * be prevented in a later phase if needed
329 */ 316 */
330 wil_err(wil, "register_pm_notifier failed: %d\n", rc); 317 wil_err(wil, "register_pm_notifier failed: %d\n", rc);
331#endif /* CONFIG_PM_SLEEP */
332#endif /* CONFIG_PM */ 318#endif /* CONFIG_PM */
333 319
334 wil6210_debugfs_init(wil); 320 wil6210_debugfs_init(wil);
335 321
322 wil_pm_runtime_allow(wil);
336 323
337 return 0; 324 return 0;
338 325
@@ -360,11 +347,11 @@ static void wil_pcie_remove(struct pci_dev *pdev)
360 wil_dbg_misc(wil, "pcie_remove\n"); 347 wil_dbg_misc(wil, "pcie_remove\n");
361 348
362#ifdef CONFIG_PM 349#ifdef CONFIG_PM
363#ifdef CONFIG_PM_SLEEP
364 unregister_pm_notifier(&wil->pm_notify); 350 unregister_pm_notifier(&wil->pm_notify);
365#endif /* CONFIG_PM_SLEEP */
366#endif /* CONFIG_PM */ 351#endif /* CONFIG_PM */
367 352
353 wil_pm_runtime_forbid(wil);
354
368 wil6210_debugfs_remove(wil); 355 wil6210_debugfs_remove(wil);
369 rtnl_lock(); 356 rtnl_lock();
370 wil_p2p_wdev_free(wil); 357 wil_p2p_wdev_free(wil);
@@ -386,13 +373,15 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
386MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 373MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
387 374
388#ifdef CONFIG_PM 375#ifdef CONFIG_PM
389#ifdef CONFIG_PM_SLEEP
390 376
391static int wil6210_suspend(struct device *dev, bool is_runtime) 377static int wil6210_suspend(struct device *dev, bool is_runtime)
392{ 378{
393 int rc = 0; 379 int rc = 0;
394 struct pci_dev *pdev = to_pci_dev(dev); 380 struct pci_dev *pdev = to_pci_dev(dev);
395 struct wil6210_priv *wil = pci_get_drvdata(pdev); 381 struct wil6210_priv *wil = pci_get_drvdata(pdev);
382 struct net_device *ndev = wil_to_ndev(wil);
383 bool keep_radio_on = ndev->flags & IFF_UP &&
384 wil->keep_radio_on_during_sleep;
396 385
397 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 386 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
398 387
@@ -400,16 +389,18 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
400 if (rc) 389 if (rc)
401 goto out; 390 goto out;
402 391
403 rc = wil_suspend(wil, is_runtime); 392 rc = wil_suspend(wil, is_runtime, keep_radio_on);
404 if (!rc) { 393 if (!rc) {
405 wil->suspend_stats.successful_suspends++; 394 /* In case radio stays on, platform device will control
406 395 * PCIe master
407 /* If platform device supports keep_radio_on_during_sleep
408 * it will control PCIe master
409 */ 396 */
410 if (!wil->keep_radio_on_during_sleep) 397 if (!keep_radio_on) {
411 /* disable bus mastering */ 398 /* disable bus mastering */
412 pci_clear_master(pdev); 399 pci_clear_master(pdev);
400 wil->suspend_stats.r_off.successful_suspends++;
401 } else {
402 wil->suspend_stats.r_on.successful_suspends++;
403 }
413 } 404 }
414out: 405out:
415 return rc; 406 return rc;
@@ -420,23 +411,32 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
420 int rc = 0; 411 int rc = 0;
421 struct pci_dev *pdev = to_pci_dev(dev); 412 struct pci_dev *pdev = to_pci_dev(dev);
422 struct wil6210_priv *wil = pci_get_drvdata(pdev); 413 struct wil6210_priv *wil = pci_get_drvdata(pdev);
414 struct net_device *ndev = wil_to_ndev(wil);
415 bool keep_radio_on = ndev->flags & IFF_UP &&
416 wil->keep_radio_on_during_sleep;
423 417
424 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 418 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
425 419
426 /* If platform device supports keep_radio_on_during_sleep it will 420 /* In case radio stays on, platform device will control
427 * control PCIe master 421 * PCIe master
428 */ 422 */
429 if (!wil->keep_radio_on_during_sleep) 423 if (!keep_radio_on)
430 /* allow master */ 424 /* allow master */
431 pci_set_master(pdev); 425 pci_set_master(pdev);
432 rc = wil_resume(wil, is_runtime); 426 rc = wil_resume(wil, is_runtime, keep_radio_on);
433 if (rc) { 427 if (rc) {
434 wil_err(wil, "device failed to resume (%d)\n", rc); 428 wil_err(wil, "device failed to resume (%d)\n", rc);
435 wil->suspend_stats.failed_resumes++; 429 if (!keep_radio_on) {
436 if (!wil->keep_radio_on_during_sleep)
437 pci_clear_master(pdev); 430 pci_clear_master(pdev);
431 wil->suspend_stats.r_off.failed_resumes++;
432 } else {
433 wil->suspend_stats.r_on.failed_resumes++;
434 }
438 } else { 435 } else {
439 wil->suspend_stats.successful_resumes++; 436 if (keep_radio_on)
437 wil->suspend_stats.r_on.successful_resumes++;
438 else
439 wil->suspend_stats.r_off.successful_resumes++;
440 } 440 }
441 441
442 return rc; 442 return rc;
@@ -490,12 +490,43 @@ static int wil6210_pm_resume(struct device *dev)
490{ 490{
491 return wil6210_resume(dev, false); 491 return wil6210_resume(dev, false);
492} 492}
493#endif /* CONFIG_PM_SLEEP */
494 493
494static int wil6210_pm_runtime_idle(struct device *dev)
495{
496 struct pci_dev *pdev = to_pci_dev(dev);
497 struct wil6210_priv *wil = pci_get_drvdata(pdev);
498
499 wil_dbg_pm(wil, "Runtime idle\n");
500
501 return wil_can_suspend(wil, true);
502}
503
504static int wil6210_pm_runtime_resume(struct device *dev)
505{
506 return wil6210_resume(dev, true);
507}
508
509static int wil6210_pm_runtime_suspend(struct device *dev)
510{
511 struct pci_dev *pdev = to_pci_dev(dev);
512 struct wil6210_priv *wil = pci_get_drvdata(pdev);
513
514 if (test_bit(wil_status_suspended, wil->status)) {
515 wil_dbg_pm(wil, "trying to suspend while suspended\n");
516 return 1;
517 }
518
519 return wil6210_suspend(dev, true);
520}
495#endif /* CONFIG_PM */ 521#endif /* CONFIG_PM */
496 522
497static const struct dev_pm_ops wil6210_pm_ops = { 523static const struct dev_pm_ops wil6210_pm_ops = {
524#ifdef CONFIG_PM
498 SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) 525 SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
526 SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
527 wil6210_pm_runtime_resume,
528 wil6210_pm_runtime_idle)
529#endif /* CONFIG_PM */
499}; 530};
500 531
501static struct pci_driver wil6210_driver = { 532static struct pci_driver wil6210_driver = {
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 8f5d1b447aaa..056b180fad7f 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -16,15 +16,30 @@
16 16
17#include "wil6210.h" 17#include "wil6210.h"
18#include <linux/jiffies.h> 18#include <linux/jiffies.h>
19#include <linux/pm_runtime.h>
20
21#define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
19 22
20int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) 23int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
21{ 24{
22 int rc = 0; 25 int rc = 0;
23 struct wireless_dev *wdev = wil->wdev; 26 struct wireless_dev *wdev = wil->wdev;
24 struct net_device *ndev = wil_to_ndev(wil); 27 struct net_device *ndev = wil_to_ndev(wil);
28 bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
29 wil->fw_capabilities);
25 30
26 wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); 31 wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
27 32
33 if (wmi_only || debug_fw) {
34 wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
35 wmi_only ? "wmi_only" : "debug_fw");
36 rc = -EBUSY;
37 goto out;
38 }
39 if (is_runtime && !wil->platform_ops.suspend) {
40 rc = -EBUSY;
41 goto out;
42 }
28 if (!(ndev->flags & IFF_UP)) { 43 if (!(ndev->flags & IFF_UP)) {
29 /* can always sleep when down */ 44 /* can always sleep when down */
30 wil_dbg_pm(wil, "Interface is down\n"); 45 wil_dbg_pm(wil, "Interface is down\n");
@@ -44,6 +59,10 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
44 /* interface is running */ 59 /* interface is running */
45 switch (wdev->iftype) { 60 switch (wdev->iftype) {
46 case NL80211_IFTYPE_MONITOR: 61 case NL80211_IFTYPE_MONITOR:
62 wil_dbg_pm(wil, "Sniffer\n");
63 rc = -EBUSY;
64 goto out;
65 /* for STA-like interface, don't runtime suspend */
47 case NL80211_IFTYPE_STATION: 66 case NL80211_IFTYPE_STATION:
48 case NL80211_IFTYPE_P2P_CLIENT: 67 case NL80211_IFTYPE_P2P_CLIENT:
49 if (test_bit(wil_status_fwconnecting, wil->status)) { 68 if (test_bit(wil_status_fwconnecting, wil->status)) {
@@ -51,6 +70,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
51 rc = -EBUSY; 70 rc = -EBUSY;
52 goto out; 71 goto out;
53 } 72 }
73 /* Runtime pm not supported in case the interface is up */
74 if (is_runtime) {
75 wil_dbg_pm(wil, "STA-like interface\n");
76 rc = -EBUSY;
77 goto out;
78 }
54 break; 79 break;
55 /* AP-like interface - can't suspend */ 80 /* AP-like interface - can't suspend */
56 default: 81 default:
@@ -158,7 +183,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
158 break; 183 break;
159 wil_err(wil, 184 wil_err(wil,
160 "TO waiting for idle RX, suspend failed\n"); 185 "TO waiting for idle RX, suspend failed\n");
161 wil->suspend_stats.failed_suspends++; 186 wil->suspend_stats.r_on.failed_suspends++;
162 goto resume_after_fail; 187 goto resume_after_fail;
163 } 188 }
164 wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n"); 189 wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n");
@@ -174,7 +199,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
174 */ 199 */
175 if (!wil_is_wmi_idle(wil)) { 200 if (!wil_is_wmi_idle(wil)) {
176 wil_err(wil, "suspend failed due to pending WMI events\n"); 201 wil_err(wil, "suspend failed due to pending WMI events\n");
177 wil->suspend_stats.failed_suspends++; 202 wil->suspend_stats.r_on.failed_suspends++;
178 goto resume_after_fail; 203 goto resume_after_fail;
179 } 204 }
180 205
@@ -188,7 +213,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
188 if (rc) { 213 if (rc) {
189 wil_err(wil, "platform device failed to suspend (%d)\n", 214 wil_err(wil, "platform device failed to suspend (%d)\n",
190 rc); 215 rc);
191 wil->suspend_stats.failed_suspends++; 216 wil->suspend_stats.r_on.failed_suspends++;
192 wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); 217 wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
193 wil_unmask_irq(wil); 218 wil_unmask_irq(wil);
194 goto resume_after_fail; 219 goto resume_after_fail;
@@ -235,6 +260,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
235 rc = wil_down(wil); 260 rc = wil_down(wil);
236 if (rc) { 261 if (rc) {
237 wil_err(wil, "wil_down : %d\n", rc); 262 wil_err(wil, "wil_down : %d\n", rc);
263 wil->suspend_stats.r_off.failed_suspends++;
238 goto out; 264 goto out;
239 } 265 }
240 } 266 }
@@ -247,6 +273,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
247 rc = wil->platform_ops.suspend(wil->platform_handle, false); 273 rc = wil->platform_ops.suspend(wil->platform_handle, false);
248 if (rc) { 274 if (rc) {
249 wil_enable_irq(wil); 275 wil_enable_irq(wil);
276 wil->suspend_stats.r_off.failed_suspends++;
250 goto out; 277 goto out;
251 } 278 }
252 } 279 }
@@ -279,12 +306,9 @@ static int wil_resume_radio_off(struct wil6210_priv *wil)
279 return rc; 306 return rc;
280} 307}
281 308
282int wil_suspend(struct wil6210_priv *wil, bool is_runtime) 309int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
283{ 310{
284 int rc = 0; 311 int rc = 0;
285 struct net_device *ndev = wil_to_ndev(wil);
286 bool keep_radio_on = ndev->flags & IFF_UP &&
287 wil->keep_radio_on_during_sleep;
288 312
289 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 313 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
290 314
@@ -301,19 +325,12 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
301 wil_dbg_pm(wil, "suspend: %s => %d\n", 325 wil_dbg_pm(wil, "suspend: %s => %d\n",
302 is_runtime ? "runtime" : "system", rc); 326 is_runtime ? "runtime" : "system", rc);
303 327
304 if (!rc)
305 wil->suspend_stats.suspend_start_time = ktime_get();
306
307 return rc; 328 return rc;
308} 329}
309 330
310int wil_resume(struct wil6210_priv *wil, bool is_runtime) 331int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
311{ 332{
312 int rc = 0; 333 int rc = 0;
313 struct net_device *ndev = wil_to_ndev(wil);
314 bool keep_radio_on = ndev->flags & IFF_UP &&
315 wil->keep_radio_on_during_sleep;
316 unsigned long long suspend_time_usec = 0;
317 334
318 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 335 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
319 336
@@ -331,20 +348,49 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
331 else 348 else
332 rc = wil_resume_radio_off(wil); 349 rc = wil_resume_radio_off(wil);
333 350
334 if (rc)
335 goto out;
336
337 suspend_time_usec =
338 ktime_to_us(ktime_sub(ktime_get(),
339 wil->suspend_stats.suspend_start_time));
340 wil->suspend_stats.total_suspend_time += suspend_time_usec;
341 if (suspend_time_usec < wil->suspend_stats.min_suspend_time)
342 wil->suspend_stats.min_suspend_time = suspend_time_usec;
343 if (suspend_time_usec > wil->suspend_stats.max_suspend_time)
344 wil->suspend_stats.max_suspend_time = suspend_time_usec;
345
346out: 351out:
347 wil_dbg_pm(wil, "resume: %s => %d, suspend time %lld usec\n", 352 wil_dbg_pm(wil, "resume: %s => %d\n", is_runtime ? "runtime" : "system",
348 is_runtime ? "runtime" : "system", rc, suspend_time_usec); 353 rc);
349 return rc; 354 return rc;
350} 355}
356
357void wil_pm_runtime_allow(struct wil6210_priv *wil)
358{
359 struct device *dev = wil_to_dev(wil);
360
361 pm_runtime_put_noidle(dev);
362 pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS);
363 pm_runtime_use_autosuspend(dev);
364 pm_runtime_allow(dev);
365}
366
367void wil_pm_runtime_forbid(struct wil6210_priv *wil)
368{
369 struct device *dev = wil_to_dev(wil);
370
371 pm_runtime_forbid(dev);
372 pm_runtime_get_noresume(dev);
373}
374
375int wil_pm_runtime_get(struct wil6210_priv *wil)
376{
377 int rc;
378 struct device *dev = wil_to_dev(wil);
379
380 rc = pm_runtime_get_sync(dev);
381 if (rc < 0) {
382 wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc);
383 pm_runtime_put_noidle(dev);
384 return rc;
385 }
386
387 return 0;
388}
389
390void wil_pm_runtime_put(struct wil6210_priv *wil)
391{
392 struct device *dev = wil_to_dev(wil);
393
394 pm_runtime_mark_last_busy(dev);
395 pm_runtime_put_autosuspend(dev);
396}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 1e340d04bd70..cf27d9711dde 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -82,18 +82,18 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
82 */ 82 */
83#define WIL_MAX_MPDU_OVERHEAD (62) 83#define WIL_MAX_MPDU_OVERHEAD (62)
84 84
85struct wil_suspend_stats { 85struct wil_suspend_count_stats {
86 unsigned long successful_suspends; 86 unsigned long successful_suspends;
87 unsigned long failed_suspends;
88 unsigned long successful_resumes; 87 unsigned long successful_resumes;
88 unsigned long failed_suspends;
89 unsigned long failed_resumes; 89 unsigned long failed_resumes;
90 unsigned long rejected_by_device; 90};
91
92struct wil_suspend_stats {
93 struct wil_suspend_count_stats r_off;
94 struct wil_suspend_count_stats r_on;
95 unsigned long rejected_by_device; /* only radio on */
91 unsigned long rejected_by_host; 96 unsigned long rejected_by_host;
92 unsigned long long total_suspend_time;
93 unsigned long long min_suspend_time;
94 unsigned long long max_suspend_time;
95 ktime_t collection_start;
96 ktime_t suspend_start_time;
97}; 97};
98 98
99/* Calculate MAC buffer size for the firmware. It includes all overhead, 99/* Calculate MAC buffer size for the firmware. It includes all overhead,
@@ -616,6 +616,16 @@ struct blink_on_off_time {
616 u32 off_ms; 616 u32 off_ms;
617}; 617};
618 618
619struct wil_debugfs_iomem_data {
620 void *offset;
621 struct wil6210_priv *wil;
622};
623
624struct wil_debugfs_data {
625 struct wil_debugfs_iomem_data *data_arr;
626 int iomem_data_count;
627};
628
619extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; 629extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
620extern u8 led_id; 630extern u8 led_id;
621extern u8 led_polarity; 631extern u8 led_polarity;
@@ -708,6 +718,7 @@ struct wil6210_priv {
708 u8 abft_len; 718 u8 abft_len;
709 u8 wakeup_trigger; 719 u8 wakeup_trigger;
710 struct wil_suspend_stats suspend_stats; 720 struct wil_suspend_stats suspend_stats;
721 struct wil_debugfs_data dbg_data;
711 722
712 void *platform_handle; 723 void *platform_handle;
713 struct wil_platform_ops platform_ops; 724 struct wil_platform_ops platform_ops;
@@ -732,9 +743,7 @@ struct wil6210_priv {
732 int fw_calib_result; 743 int fw_calib_result;
733 744
734#ifdef CONFIG_PM 745#ifdef CONFIG_PM
735#ifdef CONFIG_PM_SLEEP
736 struct notifier_block pm_notify; 746 struct notifier_block pm_notify;
737#endif /* CONFIG_PM_SLEEP */
738#endif /* CONFIG_PM */ 747#endif /* CONFIG_PM */
739 748
740 bool suspend_resp_rcvd; 749 bool suspend_resp_rcvd;
@@ -861,10 +870,12 @@ int wil_up(struct wil6210_priv *wil);
861int __wil_up(struct wil6210_priv *wil); 870int __wil_up(struct wil6210_priv *wil);
862int wil_down(struct wil6210_priv *wil); 871int wil_down(struct wil6210_priv *wil);
863int __wil_down(struct wil6210_priv *wil); 872int __wil_down(struct wil6210_priv *wil);
873void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
864void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); 874void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
865int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); 875int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
866void wil_set_ethtoolops(struct net_device *ndev); 876void wil_set_ethtoolops(struct net_device *ndev);
867 877
878void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
868void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); 879void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
869void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); 880void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
870int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, 881int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
@@ -999,9 +1010,14 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
999 bool load); 1010 bool load);
1000bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); 1011bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
1001 1012
1013void wil_pm_runtime_allow(struct wil6210_priv *wil);
1014void wil_pm_runtime_forbid(struct wil6210_priv *wil);
1015int wil_pm_runtime_get(struct wil6210_priv *wil);
1016void wil_pm_runtime_put(struct wil6210_priv *wil);
1017
1002int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); 1018int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
1003int wil_suspend(struct wil6210_priv *wil, bool is_runtime); 1019int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on);
1004int wil_resume(struct wil6210_priv *wil, bool is_runtime); 1020int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on);
1005bool wil_is_wmi_idle(struct wil6210_priv *wil); 1021bool wil_is_wmi_idle(struct wil6210_priv *wil);
1006int wmi_resume(struct wil6210_priv *wil); 1022int wmi_resume(struct wil6210_priv *wil);
1007int wmi_suspend(struct wil6210_priv *wil); 1023int wmi_suspend(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index ffdd2fa401b1..8ace618d0fd9 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -140,13 +140,15 @@ static u32 wmi_addr_remap(u32 x)
140/** 140/**
141 * Check address validity for WMI buffer; remap if needed 141 * Check address validity for WMI buffer; remap if needed
142 * @ptr - internal (linker) fw/ucode address 142 * @ptr - internal (linker) fw/ucode address
143 * @size - if non zero, validate the block does not
144 * exceed the device memory (bar)
143 * 145 *
144 * Valid buffer should be DWORD aligned 146 * Valid buffer should be DWORD aligned
145 * 147 *
146 * return address for accessing buffer from the host; 148 * return address for accessing buffer from the host;
147 * if buffer is not valid, return NULL. 149 * if buffer is not valid, return NULL.
148 */ 150 */
149void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) 151void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
150{ 152{
151 u32 off; 153 u32 off;
152 u32 ptr = le32_to_cpu(ptr_); 154 u32 ptr = le32_to_cpu(ptr_);
@@ -161,10 +163,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
161 off = HOSTADDR(ptr); 163 off = HOSTADDR(ptr);
162 if (off > wil->bar_size - 4) 164 if (off > wil->bar_size - 4)
163 return NULL; 165 return NULL;
166 if (size && ((off + size > wil->bar_size) || (off + size < off)))
167 return NULL;
164 168
165 return wil->csr + off; 169 return wil->csr + off;
166} 170}
167 171
172void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
173{
174 return wmi_buffer_block(wil, ptr_, 0);
175}
176
168/** 177/**
169 * Check address validity 178 * Check address validity
170 */ 179 */
@@ -198,6 +207,232 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
198 return 0; 207 return 0;
199} 208}
200 209
210static const char *cmdid2name(u16 cmdid)
211{
212 switch (cmdid) {
213 case WMI_NOTIFY_REQ_CMDID:
214 return "WMI_NOTIFY_REQ_CMD";
215 case WMI_START_SCAN_CMDID:
216 return "WMI_START_SCAN_CMD";
217 case WMI_CONNECT_CMDID:
218 return "WMI_CONNECT_CMD";
219 case WMI_DISCONNECT_CMDID:
220 return "WMI_DISCONNECT_CMD";
221 case WMI_SW_TX_REQ_CMDID:
222 return "WMI_SW_TX_REQ_CMD";
223 case WMI_GET_RF_SECTOR_PARAMS_CMDID:
224 return "WMI_GET_RF_SECTOR_PARAMS_CMD";
225 case WMI_SET_RF_SECTOR_PARAMS_CMDID:
226 return "WMI_SET_RF_SECTOR_PARAMS_CMD";
227 case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID:
228 return "WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD";
229 case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID:
230 return "WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD";
231 case WMI_BRP_SET_ANT_LIMIT_CMDID:
232 return "WMI_BRP_SET_ANT_LIMIT_CMD";
233 case WMI_TOF_SESSION_START_CMDID:
234 return "WMI_TOF_SESSION_START_CMD";
235 case WMI_AOA_MEAS_CMDID:
236 return "WMI_AOA_MEAS_CMD";
237 case WMI_PMC_CMDID:
238 return "WMI_PMC_CMD";
239 case WMI_TOF_GET_TX_RX_OFFSET_CMDID:
240 return "WMI_TOF_GET_TX_RX_OFFSET_CMD";
241 case WMI_TOF_SET_TX_RX_OFFSET_CMDID:
242 return "WMI_TOF_SET_TX_RX_OFFSET_CMD";
243 case WMI_VRING_CFG_CMDID:
244 return "WMI_VRING_CFG_CMD";
245 case WMI_BCAST_VRING_CFG_CMDID:
246 return "WMI_BCAST_VRING_CFG_CMD";
247 case WMI_TRAFFIC_SUSPEND_CMDID:
248 return "WMI_TRAFFIC_SUSPEND_CMD";
249 case WMI_TRAFFIC_RESUME_CMDID:
250 return "WMI_TRAFFIC_RESUME_CMD";
251 case WMI_ECHO_CMDID:
252 return "WMI_ECHO_CMD";
253 case WMI_SET_MAC_ADDRESS_CMDID:
254 return "WMI_SET_MAC_ADDRESS_CMD";
255 case WMI_LED_CFG_CMDID:
256 return "WMI_LED_CFG_CMD";
257 case WMI_PCP_START_CMDID:
258 return "WMI_PCP_START_CMD";
259 case WMI_PCP_STOP_CMDID:
260 return "WMI_PCP_STOP_CMD";
261 case WMI_SET_SSID_CMDID:
262 return "WMI_SET_SSID_CMD";
263 case WMI_GET_SSID_CMDID:
264 return "WMI_GET_SSID_CMD";
265 case WMI_SET_PCP_CHANNEL_CMDID:
266 return "WMI_SET_PCP_CHANNEL_CMD";
267 case WMI_GET_PCP_CHANNEL_CMDID:
268 return "WMI_GET_PCP_CHANNEL_CMD";
269 case WMI_P2P_CFG_CMDID:
270 return "WMI_P2P_CFG_CMD";
271 case WMI_START_LISTEN_CMDID:
272 return "WMI_START_LISTEN_CMD";
273 case WMI_START_SEARCH_CMDID:
274 return "WMI_START_SEARCH_CMD";
275 case WMI_DISCOVERY_STOP_CMDID:
276 return "WMI_DISCOVERY_STOP_CMD";
277 case WMI_DELETE_CIPHER_KEY_CMDID:
278 return "WMI_DELETE_CIPHER_KEY_CMD";
279 case WMI_ADD_CIPHER_KEY_CMDID:
280 return "WMI_ADD_CIPHER_KEY_CMD";
281 case WMI_SET_APPIE_CMDID:
282 return "WMI_SET_APPIE_CMD";
283 case WMI_CFG_RX_CHAIN_CMDID:
284 return "WMI_CFG_RX_CHAIN_CMD";
285 case WMI_TEMP_SENSE_CMDID:
286 return "WMI_TEMP_SENSE_CMD";
287 case WMI_DEL_STA_CMDID:
288 return "WMI_DEL_STA_CMD";
289 case WMI_DISCONNECT_STA_CMDID:
290 return "WMI_DISCONNECT_STA_CMD";
291 case WMI_VRING_BA_EN_CMDID:
292 return "WMI_VRING_BA_EN_CMD";
293 case WMI_VRING_BA_DIS_CMDID:
294 return "WMI_VRING_BA_DIS_CMD";
295 case WMI_RCP_DELBA_CMDID:
296 return "WMI_RCP_DELBA_CMD";
297 case WMI_RCP_ADDBA_RESP_CMDID:
298 return "WMI_RCP_ADDBA_RESP_CMD";
299 case WMI_PS_DEV_PROFILE_CFG_CMDID:
300 return "WMI_PS_DEV_PROFILE_CFG_CMD";
301 case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
302 return "WMI_SET_MGMT_RETRY_LIMIT_CMD";
303 case WMI_GET_MGMT_RETRY_LIMIT_CMDID:
304 return "WMI_GET_MGMT_RETRY_LIMIT_CMD";
305 case WMI_ABORT_SCAN_CMDID:
306 return "WMI_ABORT_SCAN_CMD";
307 case WMI_NEW_STA_CMDID:
308 return "WMI_NEW_STA_CMD";
309 case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
310 return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
311 case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
312 return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
313 case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
314 return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
315 case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
316 return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
317 default:
318 return "Untracked CMD";
319 }
320}
321
322static const char *eventid2name(u16 eventid)
323{
324 switch (eventid) {
325 case WMI_NOTIFY_REQ_DONE_EVENTID:
326 return "WMI_NOTIFY_REQ_DONE_EVENT";
327 case WMI_DISCONNECT_EVENTID:
328 return "WMI_DISCONNECT_EVENT";
329 case WMI_SW_TX_COMPLETE_EVENTID:
330 return "WMI_SW_TX_COMPLETE_EVENT";
331 case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID:
332 return "WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT";
333 case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID:
334 return "WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT";
335 case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
336 return "WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
337 case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
338 return "WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
339 case WMI_BRP_SET_ANT_LIMIT_EVENTID:
340 return "WMI_BRP_SET_ANT_LIMIT_EVENT";
341 case WMI_FW_READY_EVENTID:
342 return "WMI_FW_READY_EVENT";
343 case WMI_TRAFFIC_RESUME_EVENTID:
344 return "WMI_TRAFFIC_RESUME_EVENT";
345 case WMI_TOF_GET_TX_RX_OFFSET_EVENTID:
346 return "WMI_TOF_GET_TX_RX_OFFSET_EVENT";
347 case WMI_TOF_SET_TX_RX_OFFSET_EVENTID:
348 return "WMI_TOF_SET_TX_RX_OFFSET_EVENT";
349 case WMI_VRING_CFG_DONE_EVENTID:
350 return "WMI_VRING_CFG_DONE_EVENT";
351 case WMI_READY_EVENTID:
352 return "WMI_READY_EVENT";
353 case WMI_RX_MGMT_PACKET_EVENTID:
354 return "WMI_RX_MGMT_PACKET_EVENT";
355 case WMI_TX_MGMT_PACKET_EVENTID:
356 return "WMI_TX_MGMT_PACKET_EVENT";
357 case WMI_SCAN_COMPLETE_EVENTID:
358 return "WMI_SCAN_COMPLETE_EVENT";
359 case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID:
360 return "WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT";
361 case WMI_CONNECT_EVENTID:
362 return "WMI_CONNECT_EVENT";
363 case WMI_EAPOL_RX_EVENTID:
364 return "WMI_EAPOL_RX_EVENT";
365 case WMI_BA_STATUS_EVENTID:
366 return "WMI_BA_STATUS_EVENT";
367 case WMI_RCP_ADDBA_REQ_EVENTID:
368 return "WMI_RCP_ADDBA_REQ_EVENT";
369 case WMI_DELBA_EVENTID:
370 return "WMI_DELBA_EVENT";
371 case WMI_VRING_EN_EVENTID:
372 return "WMI_VRING_EN_EVENT";
373 case WMI_DATA_PORT_OPEN_EVENTID:
374 return "WMI_DATA_PORT_OPEN_EVENT";
375 case WMI_AOA_MEAS_EVENTID:
376 return "WMI_AOA_MEAS_EVENT";
377 case WMI_TOF_SESSION_END_EVENTID:
378 return "WMI_TOF_SESSION_END_EVENT";
379 case WMI_TOF_GET_CAPABILITIES_EVENTID:
380 return "WMI_TOF_GET_CAPABILITIES_EVENT";
381 case WMI_TOF_SET_LCR_EVENTID:
382 return "WMI_TOF_SET_LCR_EVENT";
383 case WMI_TOF_SET_LCI_EVENTID:
384 return "WMI_TOF_SET_LCI_EVENT";
385 case WMI_TOF_FTM_PER_DEST_RES_EVENTID:
386 return "WMI_TOF_FTM_PER_DEST_RES_EVENT";
387 case WMI_TOF_CHANNEL_INFO_EVENTID:
388 return "WMI_TOF_CHANNEL_INFO_EVENT";
389 case WMI_TRAFFIC_SUSPEND_EVENTID:
390 return "WMI_TRAFFIC_SUSPEND_EVENT";
391 case WMI_ECHO_RSP_EVENTID:
392 return "WMI_ECHO_RSP_EVENT";
393 case WMI_LED_CFG_DONE_EVENTID:
394 return "WMI_LED_CFG_DONE_EVENT";
395 case WMI_PCP_STARTED_EVENTID:
396 return "WMI_PCP_STARTED_EVENT";
397 case WMI_PCP_STOPPED_EVENTID:
398 return "WMI_PCP_STOPPED_EVENT";
399 case WMI_GET_SSID_EVENTID:
400 return "WMI_GET_SSID_EVENT";
401 case WMI_GET_PCP_CHANNEL_EVENTID:
402 return "WMI_GET_PCP_CHANNEL_EVENT";
403 case WMI_P2P_CFG_DONE_EVENTID:
404 return "WMI_P2P_CFG_DONE_EVENT";
405 case WMI_LISTEN_STARTED_EVENTID:
406 return "WMI_LISTEN_STARTED_EVENT";
407 case WMI_SEARCH_STARTED_EVENTID:
408 return "WMI_SEARCH_STARTED_EVENT";
409 case WMI_DISCOVERY_STOPPED_EVENTID:
410 return "WMI_DISCOVERY_STOPPED_EVENT";
411 case WMI_CFG_RX_CHAIN_DONE_EVENTID:
412 return "WMI_CFG_RX_CHAIN_DONE_EVENT";
413 case WMI_TEMP_SENSE_DONE_EVENTID:
414 return "WMI_TEMP_SENSE_DONE_EVENT";
415 case WMI_RCP_ADDBA_RESP_SENT_EVENTID:
416 return "WMI_RCP_ADDBA_RESP_SENT_EVENT";
417 case WMI_PS_DEV_PROFILE_CFG_EVENTID:
418 return "WMI_PS_DEV_PROFILE_CFG_EVENT";
419 case WMI_SET_MGMT_RETRY_LIMIT_EVENTID:
420 return "WMI_SET_MGMT_RETRY_LIMIT_EVENT";
421 case WMI_GET_MGMT_RETRY_LIMIT_EVENTID:
422 return "WMI_GET_MGMT_RETRY_LIMIT_EVENT";
423 case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
424 return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
425 case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
426 return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
427 case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
428 return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
429 case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
430 return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
431 default:
432 return "Untracked EVENT";
433 }
434}
435
201static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) 436static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
202{ 437{
203 struct { 438 struct {
@@ -222,7 +457,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
222 uint retry; 457 uint retry;
223 int rc = 0; 458 int rc = 0;
224 459
225 if (sizeof(cmd) + len > r->entry_size) { 460 if (len > r->entry_size - sizeof(cmd)) {
226 wil_err(wil, "WMI size too large: %d bytes, max is %d\n", 461 wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
227 (int)(sizeof(cmd) + len), r->entry_size); 462 (int)(sizeof(cmd) + len), r->entry_size);
228 return -ERANGE; 463 return -ERANGE;
@@ -294,7 +529,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
294 } 529 }
295 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); 530 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
296 /* set command */ 531 /* set command */
297 wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len); 532 wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n",
533 cmdid2name(cmdid), cmdid, len);
298 wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, 534 wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
299 sizeof(cmd), true); 535 sizeof(cmd), true);
300 wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, 536 wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
@@ -963,8 +1199,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
963 } 1199 }
964 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); 1200 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
965 1201
966 wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", 1202 wil_dbg_wmi(wil, "recv %s (0x%04x) MID %d @%d msec\n",
967 id, wmi->mid, tstamp); 1203 eventid2name(id), id, wmi->mid, tstamp);
968 trace_wil6210_wmi_event(wmi, &wmi[1], 1204 trace_wil6210_wmi_event(wmi, &wmi[1],
969 len - sizeof(*wmi)); 1205 len - sizeof(*wmi));
970 } 1206 }
@@ -1380,8 +1616,14 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
1380 }; 1616 };
1381 int rc; 1617 int rc;
1382 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; 1618 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
1383 struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); 1619 struct wmi_set_appie_cmd *cmd;
1620
1621 if (len < ie_len) {
1622 rc = -EINVAL;
1623 goto out;
1624 }
1384 1625
1626 cmd = kzalloc(len, GFP_KERNEL);
1385 if (!cmd) { 1627 if (!cmd) {
1386 rc = -ENOMEM; 1628 rc = -ENOMEM;
1387 goto out; 1629 goto out;
@@ -1801,6 +2043,16 @@ void wmi_event_flush(struct wil6210_priv *wil)
1801 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); 2043 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1802} 2044}
1803 2045
2046static const char *suspend_status2name(u8 status)
2047{
2048 switch (status) {
2049 case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
2050 return "LINK_NOT_IDLE";
2051 default:
2052 return "Untracked status";
2053 }
2054}
2055
1804int wmi_suspend(struct wil6210_priv *wil) 2056int wmi_suspend(struct wil6210_priv *wil)
1805{ 2057{
1806 int rc; 2058 int rc;
@@ -1816,7 +2068,7 @@ int wmi_suspend(struct wil6210_priv *wil)
1816 wil->suspend_resp_rcvd = false; 2068 wil->suspend_resp_rcvd = false;
1817 wil->suspend_resp_comp = false; 2069 wil->suspend_resp_comp = false;
1818 2070
1819 reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED; 2071 reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
1820 2072
1821 rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd), 2073 rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
1822 WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), 2074 WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
@@ -1848,8 +2100,9 @@ int wmi_suspend(struct wil6210_priv *wil)
1848 } 2100 }
1849 2101
1850 wil_dbg_wmi(wil, "suspend_response_completed rcvd\n"); 2102 wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
1851 if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) { 2103 if (reply.evt.status != WMI_TRAFFIC_SUSPEND_APPROVED) {
1852 wil_dbg_pm(wil, "device rejected the suspend\n"); 2104 wil_dbg_pm(wil, "device rejected the suspend, %s\n",
2105 suspend_status2name(reply.evt.status));
1853 wil->suspend_stats.rejected_by_device++; 2106 wil->suspend_stats.rejected_by_device++;
1854 } 2107 }
1855 rc = reply.evt.status; 2108 rc = reply.evt.status;
@@ -1861,21 +2114,50 @@ out:
1861 return rc; 2114 return rc;
1862} 2115}
1863 2116
2117static void resume_triggers2string(u32 triggers, char *string, int str_size)
2118{
2119 string[0] = '\0';
2120
2121 if (!triggers) {
2122 strlcat(string, " UNKNOWN", str_size);
2123 return;
2124 }
2125
2126 if (triggers & WMI_RESUME_TRIGGER_HOST)
2127 strlcat(string, " HOST", str_size);
2128
2129 if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
2130 strlcat(string, " UCAST_RX", str_size);
2131
2132 if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
2133 strlcat(string, " BCAST_RX", str_size);
2134
2135 if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
2136 strlcat(string, " WMI_EVT", str_size);
2137}
2138
1864int wmi_resume(struct wil6210_priv *wil) 2139int wmi_resume(struct wil6210_priv *wil)
1865{ 2140{
1866 int rc; 2141 int rc;
2142 char string[100];
1867 struct { 2143 struct {
1868 struct wmi_cmd_hdr wmi; 2144 struct wmi_cmd_hdr wmi;
1869 struct wmi_traffic_resume_event evt; 2145 struct wmi_traffic_resume_event evt;
1870 } __packed reply; 2146 } __packed reply;
1871 2147
1872 reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; 2148 reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
2149 reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
1873 2150
1874 rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0, 2151 rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
1875 WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), 2152 WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
1876 WIL_WAIT_FOR_SUSPEND_RESUME_COMP); 2153 WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
1877 if (rc) 2154 if (rc)
1878 return rc; 2155 return rc;
2156 resume_triggers2string(le32_to_cpu(reply.evt.resume_triggers), string,
2157 sizeof(string));
2158 wil_dbg_pm(wil, "device resume %s, resume triggers:%s (0x%x)\n",
2159 reply.evt.status ? "failed" : "passed", string,
2160 le32_to_cpu(reply.evt.resume_triggers));
1879 2161
1880 return reply.evt.status; 2162 return reply.evt.status;
1881} 2163}
@@ -1906,8 +2188,8 @@ static void wmi_event_handle(struct wil6210_priv *wil,
1906 void *evt_data = (void *)(&wmi[1]); 2188 void *evt_data = (void *)(&wmi[1]);
1907 u16 id = le16_to_cpu(wmi->command_id); 2189 u16 id = le16_to_cpu(wmi->command_id);
1908 2190
1909 wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n", 2191 wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
1910 id, wil->reply_id); 2192 eventid2name(id), id, wil->reply_id);
1911 /* check if someone waits for this event */ 2193 /* check if someone waits for this event */
1912 if (wil->reply_id && wil->reply_id == id) { 2194 if (wil->reply_id && wil->reply_id == id) {
1913 WARN_ON(wil->reply_buf); 2195 WARN_ON(wil->reply_buf);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 5263ee717a4f..d9e220a8c0f4 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -2267,8 +2267,8 @@ struct wmi_link_maintain_cfg_read_done_event {
2267} __packed; 2267} __packed;
2268 2268
2269enum wmi_traffic_suspend_status { 2269enum wmi_traffic_suspend_status {
2270 WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, 2270 WMI_TRAFFIC_SUSPEND_APPROVED = 0x0,
2271 WMI_TRAFFIC_SUSPEND_REJECTED = 0x1, 2271 WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1,
2272}; 2272};
2273 2273
2274/* WMI_TRAFFIC_SUSPEND_EVENTID */ 2274/* WMI_TRAFFIC_SUSPEND_EVENTID */
@@ -2282,10 +2282,21 @@ enum wmi_traffic_resume_status {
2282 WMI_TRAFFIC_RESUME_FAILED = 0x1, 2282 WMI_TRAFFIC_RESUME_FAILED = 0x1,
2283}; 2283};
2284 2284
2285enum wmi_resume_trigger {
2286 WMI_RESUME_TRIGGER_UNKNOWN = 0x0,
2287 WMI_RESUME_TRIGGER_HOST = 0x1,
2288 WMI_RESUME_TRIGGER_UCAST_RX = 0x2,
2289 WMI_RESUME_TRIGGER_BCAST_RX = 0x4,
2290 WMI_RESUME_TRIGGER_WMI_EVT = 0x8,
2291};
2292
2285/* WMI_TRAFFIC_RESUME_EVENTID */ 2293/* WMI_TRAFFIC_RESUME_EVENTID */
2286struct wmi_traffic_resume_event { 2294struct wmi_traffic_resume_event {
2287 /* enum wmi_traffic_resume_status_e */ 2295 /* enum wmi_traffic_resume_status */
2288 u8 status; 2296 u8 status;
2297 u8 reserved[3];
2298 /* enum wmi_resume_trigger bitmap */
2299 __le32 resume_triggers;
2289} __packed; 2300} __packed;
2290 2301
2291/* Power Save command completion status codes */ 2302/* Power Save command completion status codes */