Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

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