diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2017-12-14 11:38:48 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2017-12-14 11:38:48 -0500 |
commit | 1dde35d0b8e3a9fbf24e13d16dc583f1cc5d027b (patch) | |
tree | 14418168dd854cc6a795cc200352646032c4e5bc | |
parent | 7de241f3b705396fe21f45d38ba1247c522aae81 (diff) | |
parent | 03a72288c546289cfa0eb1e3613fb9cdb302b4f9 (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
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 | |||
47 | config ATH10K_DEBUGFS | 47 | config 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 | ||
55 | config 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 | |||
56 | config ATH10K_TRACING | 63 | config 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 | ||
18 | ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o | 18 | ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o |
19 | ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o | 19 | ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o |
20 | ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o | 20 | ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o |
21 | ath10k_core-$(CONFIG_THERMAL) += thermal.o | 21 | ath10k_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 | ||
395 | static unsigned int ath10k_core_get_fw_feature_str(char *buf, | 450 | static 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 | ||
918 | static 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 | |||
863 | static int ath10k_download_and_run_otp(struct ath10k *ar) | 940 | static 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 | ||
2128 | out: | 2128 | out: |
@@ -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 | ||
57 | enum ath10k_dbg_aggr_mode { | 58 | enum 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 */ | ||
65 | enum ath_pktlog_type { | ||
66 | ATH_PKTLOG_TYPE_TX_CTRL = 1, | ||
67 | ATH_PKTLOG_TYPE_TX_STAT, | ||
68 | }; | ||
69 | |||
70 | struct 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); |
191 | void ath10k_sta_update_rx_duration(struct ath10k *ar, | 207 | void ath10k_sta_update_rx_duration(struct ath10k *ar, |
192 | struct ath10k_fw_stats *stats); | 208 | struct ath10k_fw_stats *stats); |
193 | void 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 |
197 | static inline | 210 | static inline |
198 | void ath10k_sta_update_rx_duration(struct ath10k *ar, | 211 | void 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 | ||
68 | void 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 | |||
95 | static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, | 68 | static 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 | |||
1503 | struct 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 | |||
1500 | union htt_rx_pn_t { | 1517 | union 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 | ||
977 | static void ath10k_process_rx(struct ath10k *ar, | 977 | static 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 | |||
989 | static 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 | ||
1520 | static void ath10k_htt_rx_h_deliver(struct ath10k *ar, | 1529 | static 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 | ||
1691 | static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, | 1699 | static 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 | ||
1896 | static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar, | 1904 | static 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 | ||
1949 | static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) | 1954 | static 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 | ||
2036 | static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar, | 2040 | static 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 | ||
2456 | static 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 | |||
2507 | out: | ||
2508 | spin_unlock_bh(&ar->data_lock); | ||
2509 | rcu_read_unlock(); | ||
2510 | } | ||
2511 | |||
2452 | bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | 2512 | bool 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 | } |
2632 | EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler); | 2696 | EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler); |
2633 | 2697 | ||
2698 | static 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 | |||
2634 | int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget) | 2716 | int 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 | |||
935 | const 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 | ||
558 | struct htt_rx_desc; | 566 | struct htt_rx_desc; |
@@ -567,6 +575,7 @@ struct ath10k_hw_ops { | |||
567 | extern const struct ath10k_hw_ops qca988x_ops; | 575 | extern const struct ath10k_hw_ops qca988x_ops; |
568 | extern const struct ath10k_hw_ops qca99x0_ops; | 576 | extern const struct ath10k_hw_ops qca99x0_ops; |
569 | extern const struct ath10k_hw_ops qca6174_ops; | 577 | extern const struct ath10k_hw_ops qca6174_ops; |
578 | extern const struct ath10k_hw_ops wcn3990_ops; | ||
570 | 579 | ||
571 | extern const struct ath10k_hw_clk_params qca6174_clk[]; | 580 | extern 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 | ||
7645 | static 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 | |||
7623 | static const struct ieee80211_ops ath10k_ops = { | 7673 | static 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 | ||
49 | int ath10k_spectral_process_fft(struct ath10k *ar, | 49 | int 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 | ||
920 | struct 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 | |||
929 | static 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 | |||
920 | static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, | 958 | static 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 | ||
2452 | static struct sk_buff * | 2486 | static struct sk_buff * |
2487 | ath10k_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 | |||
2562 | static struct sk_buff * | ||
2453 | ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, | 2563 | ath10k_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 | ||
26 | enum wmi_tlv_grp_id { | 27 | enum 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 | ||
1644 | void ath10k_wmi_tlv_attach(struct ath10k *ar); | 1749 | void ath10k_wmi_tlv_attach(struct ath10k *ar); |
1645 | 1750 | ||
1751 | struct 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 | ||
4460 | static void | ||
4461 | ath10k_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 | |||
4459 | void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) | 4528 | void 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 | ||
72 | config ATH9K_STATION_STATISTICS | 71 | config 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 | |||
194 | config 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 | ||
65 | ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o \ | 65 | ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o |
66 | common-spectral.o | 66 | ath9k_common-$(CONFIG_ATH9K_COMMON_SPECTRAL) += common-spectral.o |
67 | 67 | ||
68 | ath9k_htc-y += htc_hst.o \ | 68 | ath9k_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 |
155 | void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); | 155 | void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); |
156 | void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv); | 156 | void 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 | ||
1125 | enum wcn36xx_hal_scan_type { | ||
1126 | WCN36XX_HAL_SCAN_TYPE_PASSIVE = 0x00, | ||
1127 | WCN36XX_HAL_SCAN_TYPE_ACTIVE = WCN36XX_HAL_MAX_ENUM_SIZE | ||
1128 | }; | ||
1129 | |||
1130 | struct wcn36xx_hal_mac_ssid { | ||
1131 | u8 length; | ||
1132 | u8 ssid[32]; | ||
1133 | } __packed; | ||
1134 | |||
1135 | struct 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 | |||
1176 | struct 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 | |||
1183 | enum 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 | |||
1201 | struct 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 | |||
1209 | struct wcn36xx_hal_stop_scan_offload_req_msg { | ||
1210 | struct wcn36xx_hal_msg_header header; | ||
1211 | } __packed; | ||
1212 | |||
1213 | struct 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 | |||
1118 | enum wcn36xx_hal_rate_index { | 1220 | enum 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 | ||
1510 | struct 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. */ |
1517 | enum wcn36xx_hal_con_mode { | 1614 | enum 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 | ||
648 | static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, | 652 | static 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 | ||
618 | int 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 | } | ||
665 | out: | ||
666 | mutex_unlock(&wcn->hal_mutex); | ||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | int 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 | } | ||
692 | out: | ||
693 | mutex_unlock(&wcn->hal_mutex); | ||
694 | return ret; | ||
695 | } | ||
696 | |||
616 | static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len) | 697 | static 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 | ||
2123 | static 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 | |||
2042 | static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, | 2157 | static 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 | } |
2337 | int wcn36xx_smd_open(struct wcn36xx *wcn) | 2459 | int 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); | |||
65 | int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, | 65 | int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, |
66 | enum wcn36xx_hal_sys_mode mode); | 66 | enum wcn36xx_hal_sys_mode mode); |
67 | int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count); | 67 | int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count); |
68 | int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, | ||
69 | struct cfg80211_scan_request *req); | ||
70 | int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn); | ||
68 | int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif); | 71 | int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif); |
69 | int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr); | 72 | int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr); |
70 | int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index); | 73 | int 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 | ||
1734 | out: | 1741 | out: |
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, | |||
242 | static int wil_mbox_debugfs_show(struct seq_file *s, void *data) | 242 | static 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 | ||
266 | static int wil_debugfs_iomem_x32_set(void *data, u64 val) | 273 | static 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 | ||
274 | static int wil_debugfs_iomem_x32_get(void *data, u64 *val) | 292 | static 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, | |||
284 | static struct dentry *wil_debugfs_create_iomem_x32(const char *name, | 313 | static 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 | ||
293 | static int wil_debugfs_ulong_set(void *data, u64 val) | 333 | static 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, | |||
475 | static int wil_memread_debugfs_show(struct seq_file *s, void *data) | 516 | static 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 | ||
1614 | static const struct file_operations fops_suspend_stats = { | 1681 | static const struct file_operations fops_suspend_stats = { |
@@ -1736,14 +1803,31 @@ static const struct dbg_off dbg_statics[] = { | |||
1736 | {}, | 1803 | {}, |
1737 | }; | 1804 | }; |
1738 | 1805 | ||
1806 | static 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 | |||
1739 | int wil6210_debugfs_init(struct wil6210_priv *wil) | 1813 | int 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 | ||
93 | out_bad: | 108 | out_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 { \ | 29 | static 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 | ||
127 | static 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 | |||
135 | static int | 130 | static int |
136 | fw_handle_capabilities(struct wil6210_priv *wil, const void *data, | 131 | fw_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 | ||
361 | static 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 | |||
361 | static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | 380 | static 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 | ||
771 | void 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 | |||
770 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) | 790 | void 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 @@ | |||
21 | static int wil_open(struct net_device *ndev) | 21 | static 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 | ||
36 | static int wil_stop(struct net_device *ndev) | 45 | static 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 | ||
45 | static const struct net_device_ops wil_netdev_ops = { | 59 | static 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 | ||
25 | static bool use_msi = true; | 26 | static bool use_msi = true; |
26 | module_param(use_msi, bool, 0444); | 27 | module_param(use_msi, bool, 0444); |
@@ -31,10 +32,8 @@ module_param(ftm_mode, bool, 0444); | |||
31 | MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); | 32 | MODULE_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 | ||
35 | static int wil6210_pm_notify(struct notifier_block *notify_block, | 35 | static 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 | ||
40 | static | 39 | static |
@@ -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 | ||
92 | void wil_disable_irq(struct wil6210_priv *wil) | 89 | void 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[] = { | |||
386 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | 373 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); |
387 | 374 | ||
388 | #ifdef CONFIG_PM | 375 | #ifdef CONFIG_PM |
389 | #ifdef CONFIG_PM_SLEEP | ||
390 | 376 | ||
391 | static int wil6210_suspend(struct device *dev, bool is_runtime) | 377 | static 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 | } |
414 | out: | 405 | out: |
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 | ||
494 | static 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 | |||
504 | static int wil6210_pm_runtime_resume(struct device *dev) | ||
505 | { | ||
506 | return wil6210_resume(dev, true); | ||
507 | } | ||
508 | |||
509 | static 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 | ||
497 | static const struct dev_pm_ops wil6210_pm_ops = { | 523 | static 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 | ||
501 | static struct pci_driver wil6210_driver = { | 532 | static 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 | ||
20 | int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) | 23 | int 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 | ||
282 | int wil_suspend(struct wil6210_priv *wil, bool is_runtime) | 309 | int 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 | ||
310 | int wil_resume(struct wil6210_priv *wil, bool is_runtime) | 331 | int 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 | |||
346 | out: | 351 | out: |
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 | |||
357 | void 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 | |||
367 | void 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 | |||
375 | int 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 | |||
390 | void 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 | ||
85 | struct wil_suspend_stats { | 85 | struct 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 | |||
92 | struct 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 | ||
619 | struct wil_debugfs_iomem_data { | ||
620 | void *offset; | ||
621 | struct wil6210_priv *wil; | ||
622 | }; | ||
623 | |||
624 | struct wil_debugfs_data { | ||
625 | struct wil_debugfs_iomem_data *data_arr; | ||
626 | int iomem_data_count; | ||
627 | }; | ||
628 | |||
619 | extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; | 629 | extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; |
620 | extern u8 led_id; | 630 | extern u8 led_id; |
621 | extern u8 led_polarity; | 631 | extern 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); | |||
861 | int __wil_up(struct wil6210_priv *wil); | 870 | int __wil_up(struct wil6210_priv *wil); |
862 | int wil_down(struct wil6210_priv *wil); | 871 | int wil_down(struct wil6210_priv *wil); |
863 | int __wil_down(struct wil6210_priv *wil); | 872 | int __wil_down(struct wil6210_priv *wil); |
873 | void wil_refresh_fw_capabilities(struct wil6210_priv *wil); | ||
864 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); | 874 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); |
865 | int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); | 875 | int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); |
866 | void wil_set_ethtoolops(struct net_device *ndev); | 876 | void wil_set_ethtoolops(struct net_device *ndev); |
867 | 877 | ||
878 | void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); | ||
868 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); | 879 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); |
869 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); | 880 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); |
870 | int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | 881 | int 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); |
1000 | bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); | 1011 | bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); |
1001 | 1012 | ||
1013 | void wil_pm_runtime_allow(struct wil6210_priv *wil); | ||
1014 | void wil_pm_runtime_forbid(struct wil6210_priv *wil); | ||
1015 | int wil_pm_runtime_get(struct wil6210_priv *wil); | ||
1016 | void wil_pm_runtime_put(struct wil6210_priv *wil); | ||
1017 | |||
1002 | int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); | 1018 | int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); |
1003 | int wil_suspend(struct wil6210_priv *wil, bool is_runtime); | 1019 | int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on); |
1004 | int wil_resume(struct wil6210_priv *wil, bool is_runtime); | 1020 | int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on); |
1005 | bool wil_is_wmi_idle(struct wil6210_priv *wil); | 1021 | bool wil_is_wmi_idle(struct wil6210_priv *wil); |
1006 | int wmi_resume(struct wil6210_priv *wil); | 1022 | int wmi_resume(struct wil6210_priv *wil); |
1007 | int wmi_suspend(struct wil6210_priv *wil); | 1023 | int 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 | */ |
149 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) | 151 | void __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 | ||
172 | void __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 | ||
210 | static 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 | |||
322 | static 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 | |||
201 | static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | 436 | static 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 | ||
2046 | static 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 | |||
1804 | int wmi_suspend(struct wil6210_priv *wil) | 2056 | int 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 | ||
2117 | static 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 | |||
1864 | int wmi_resume(struct wil6210_priv *wil) | 2139 | int 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 | ||
2269 | enum wmi_traffic_suspend_status { | 2269 | enum 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 | ||
2285 | enum 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 */ |
2286 | struct wmi_traffic_resume_event { | 2294 | struct 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 */ |