From 4415d58c47e5a48dfd202c63fcfd3d6e653e543b Mon Sep 17 00:00:00 2001 From: Timothy Redaelli Date: Tue, 27 Mar 2018 11:25:25 +0300 Subject: [PATCH 01/18] ath9k: fix DFS detector synchronization some userspace programs (e.g. hostapd) need to set the regulatory domain before selecting the operating channel. Synchronize DFS detector regardless of the value of ah->curchan, to avoid situations where wireless scan can't be done on some 5GHz sub-bands, because dfs_region is constantly UNSET. Acked-by: Felix Fietkau Signed-off-by: Timothy Redaelli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e479fae5aab9..b71b16715f6a 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -257,6 +257,11 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, reg); + /* synchronize DFS detector if regulatory domain changed */ + if (sc->dfs_detector != NULL) + sc->dfs_detector->set_dfs_domain(sc->dfs_detector, + request->dfs_region); + /* Set tx power */ if (!ah->curchan) return; @@ -267,10 +272,6 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, sc->cur_chan->txpower, &sc->cur_chan->cur_txpower); - /* synchronize DFS detector if regulatory domain changed */ - if (sc->dfs_detector != NULL) - sc->dfs_detector->set_dfs_domain(sc->dfs_detector, - request->dfs_region); ath9k_ps_restore(sc); } From 55cc11da69895a680940c1733caabc37be685f5e Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 27 Mar 2018 11:25:29 +0300 Subject: [PATCH 02/18] Revert "ath10k: send (re)assoc peer command when NSS changed" This reverts commit 55884c045d31a29cf69db8332d1064a1b61dd159. When Ath10k is in AP mode and an unassociated STA sends a VHT action frame (Operating Mode Notification for the NSS change) periodically to AP this causes ath10k to call ath10k_station_assoc() which sends WMI_PEER_ASSOC_CMDID during NSS update. Over the time (with a certain client it can happen within 15 mins when there are over 500 of these VHT action frames) continuous calls of WMI_PEER_ASSOC_CMDID cause firmware to assert due to resource exhaust. To my knowledge setting WMI_PEER_NSS peer param itself enough to handle NSS updates and no need to call ath10k_station_assoc(). So revert the original commit from 2014 as it's unclear why the change was really needed. Now the firmware assert doesn't happen anymore. Issue observed in QCA9984 platform with firmware version:10.4-3.5.3-00053. This Change tested in QCA9984 with firmware version: 10.4-3.5.3-00053 and QCA988x platform with firmware version: 10.2.4-1.0-00036. Firmware Assert log: ath10k_pci 0002:01:00.0: firmware crashed! (guid e61f1274-9acd-4c5b-bcca-e032ea6e723c) ath10k_pci 0002:01:00.0: qca9984/qca9994 hw1.0 target 0x01000000 chip_id 0x00000000 sub 168c:cafe ath10k_pci 0002:01:00.0: kconfig debug 1 debugfs 1 tracing 0 dfs 1 testmode 1 ath10k_pci 0002:01:00.0: firmware ver 10.4-3.5.3-00053 api 5 features no-p2p,mfp,peer-flow-ctrl,btcoex-param,allows-mesh-bcast crc32 4c56a386 ath10k_pci 0002:01:00.0: board_file api 2 bmi_id 0:4 crc32 c2271344 ath10k_pci 0002:01:00.0: htt-ver 2.2 wmi-op 6 htt-op 4 cal otp max-sta 512 raw 0 hwcrypto 1 ath10k_pci 0002:01:00.0: firmware register dump: ath10k_pci 0002:01:00.0: [00]: 0x0000000A 0x000015B3 0x00981E5F 0x00975B31 ath10k_pci 0002:01:00.0: [04]: 0x00981E5F 0x00060530 0x00000011 0x00446C60 ath10k_pci 0002:01:00.0: [08]: 0x0042F1FC 0x00458080 0x00000017 0x00000000 ath10k_pci 0002:01:00.0: [12]: 0x00000009 0x00000000 0x00973ABC 0x00973AD2 ath10k_pci 0002:01:00.0: [16]: 0x00973AB0 0x00960E62 0x009606CA 0x00000000 ath10k_pci 0002:01:00.0: [20]: 0x40981E5F 0x004066DC 0x00400000 0x00981E34 ath10k_pci 0002:01:00.0: [24]: 0x80983B48 0x0040673C 0x000000C0 0xC0981E5F ath10k_pci 0002:01:00.0: [28]: 0x80993DEB 0x0040676C 0x00431AB8 0x0045D0C4 ath10k_pci 0002:01:00.0: [32]: 0x80993E5C 0x004067AC 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [36]: 0x80994AAB 0x004067DC 0x00000000 0x0045D0C4 ath10k_pci 0002:01:00.0: [40]: 0x809971A0 0x0040681C 0x004303C0 0x00441B00 ath10k_pci 0002:01:00.0: [44]: 0x80991904 0x0040688C 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [48]: 0x80963AD3 0x00406A7C 0x004303C0 0x009918FC ath10k_pci 0002:01:00.0: [52]: 0x80960E80 0x00406A9C 0x0000001F 0x00400000 ath10k_pci 0002:01:00.0: [56]: 0x80960E51 0x00406ACC 0x00400000 0x00000000 ath10k_pci 0002:01:00.0: Copy Engine register dump: ath10k_pci 0002:01:00.0: index: addr: sr_wr_idx: sr_r_idx: dst_wr_idx: dst_r_idx: ath10k_pci 0002:01:00.0: [00]: 0x0004a000 15 15 3 3 ath10k_pci 0002:01:00.0: [01]: 0x0004a400 17 17 212 213 ath10k_pci 0002:01:00.0: [02]: 0x0004a800 21 21 20 21 ath10k_pci 0002:01:00.0: [03]: 0x0004ac00 25 25 27 25 ath10k_pci 0002:01:00.0: [04]: 0x0004b000 515 515 144 104 ath10k_pci 0002:01:00.0: [05]: 0x0004b400 28 28 155 156 ath10k_pci 0002:01:00.0: [06]: 0x0004b800 12 12 12 12 ath10k_pci 0002:01:00.0: [07]: 0x0004bc00 1 1 1 1 ath10k_pci 0002:01:00.0: [08]: 0x0004c000 0 0 127 0 ath10k_pci 0002:01:00.0: [09]: 0x0004c400 1 1 1 1 ath10k_pci 0002:01:00.0: [10]: 0x0004c800 0 0 0 0 ath10k_pci 0002:01:00.0: [11]: 0x0004cc00 0 0 0 0 ath10k_pci 0002:01:00.0: CE[1] write_index 212 sw_index 213 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: CE[2] write_index 20 sw_index 21 hw_index 0 nentries_mask 0x0000007f ath10k_pci 0002:01:00.0: CE[5] write_index 155 sw_index 156 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: DMA addr: nbytes: meta data: byte swap: gather: ath10k_pci 0002:01:00.0: [455]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [456]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [457]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [458]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [459]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [460]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [461]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [462]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [463]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [464]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [465]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [466]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [467]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [468]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [469]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [470]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [471]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [472]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [473]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [474]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [475]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [476]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [477]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [478]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [479]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [480]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [481]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [482]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [483]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [484]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [485]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [486]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [487]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [488]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [489]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [490]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [491]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [492]: 0x58174040 0 1 0 0 ath10k_pci 0002:01:00.0: [493]: 0x5a946040 0 1 0 0 ath10k_pci 0002:01:00.0: [494]: 0x59909040 0 1 0 0 ath10k_pci 0002:01:00.0: [495]: 0x5ae5a040 0 1 0 0 ath10k_pci 0002:01:00.0: [496]: 0x58096040 0 1 0 0 ath10k_pci 0002:01:00.0: [497]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [498]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [499]: 0x5c1e0040 0 1 0 0 ath10k_pci 0002:01:00.0: [500]: 0x58153040 0 1 0 0 ath10k_pci 0002:01:00.0: [501]: 0x58129040 0 1 0 0 ath10k_pci 0002:01:00.0: [502]: 0x5952f040 0 1 0 0 ath10k_pci 0002:01:00.0: [503]: 0x59535040 0 1 0 0 ath10k_pci 0002:01:00.0: [504]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [505]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [506]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [507]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [508]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [509]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [510]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [511]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [512]: 0x5adcc040 0 1 0 0 ath10k_pci 0002:01:00.0: [513]: 0x5cf3d040 0 1 0 0 ath10k_pci 0002:01:00.0: [514]: 0x5c1e9040 64 1 0 0 ath10k_pci 0002:01:00.0: [515]: 0x00000000 0 0 0 0 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 02674ee04435..1cc87cb15620 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6046,9 +6046,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || - changed & IEEE80211_RC_NSS_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); From e98199a8c27f6ac8900307bc611ca4b15467f324 Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Tue, 27 Mar 2018 11:25:36 +0300 Subject: [PATCH 03/18] ath10k: enable QCA6174/QCA9377 to read the chip temperature The firmware of QCA6174/QCA9377 already support the feature, just enable it to be able to handle the get_temperature command and process the event. You can read the temperature by using the hwmon interface, cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input Verified with the following hardware and software combination, QCA6174, only firmware-4.bin doesn't support this, otherwise all support. QCA9377, all the firmwares upstreamed support this command Signed-off-by: Ryan Hsu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 39 +++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 11 +++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 523af3f8bb62..57bd8a70d242 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -413,6 +413,19 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar, + struct sk_buff *skb) +{ + const struct wmi_tlv_pdev_temperature_event *ev; + + ev = (struct wmi_tlv_pdev_temperature_event *)skb->data; + if (WARN_ON(skb->len < sizeof(*ev))) + return -EPROTO; + + ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature)); + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -553,6 +566,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_TX_PAUSE_EVENTID: ath10k_wmi_tlv_event_tx_pause(ar, skb); break; + case WMI_TLV_PDEV_TEMPERATURE_EVENTID: + ath10k_wmi_tlv_event_temperature(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -2657,6 +2673,25 @@ ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter) return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_get_temperature(struct ath10k *ar) +{ + struct wmi_tlv_pdev_get_temp_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature tlv\n"); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) { @@ -3439,7 +3474,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, - .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, + .pdev_get_temperature_cmdid = WMI_TLV_PDEV_GET_TEMPERATURE_CMDID, .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID, @@ -3702,7 +3737,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, /* .gen_pdev_set_quiet_mode not implemented */ - /* .gen_pdev_get_temperature not implemented */ + .gen_pdev_get_temperature = ath10k_wmi_tlv_op_gen_pdev_get_temperature, /* .gen_addba_clear_resp not implemented */ /* .gen_addba_send not implemented */ /* .gen_addba_set_resp not implemented */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index da89128e8dd6..b07b690544e7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1340,6 +1340,17 @@ struct wmi_tlv_init_cmd { __le32 num_host_mem_chunks; } __packed; +struct wmi_tlv_pdev_get_temp_cmd { + __le32 pdev_id; /* not used */ +} __packed; + +struct wmi_tlv_pdev_temperature_event { + __le32 tlv_hdr; + /* temperature value in Celcius degree */ + __le32 temperature; + __le32 pdev_id; +} __packed; + struct wmi_tlv_pdev_set_param_cmd { __le32 pdev_id; /* not used yet */ __le32 param_id; From e3814bec380f6f848ab619abcdfff320a839cabc Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Tue, 27 Mar 2018 11:25:38 +0300 Subject: [PATCH 04/18] ath10k: add FW API 6 firmware image for QCA9377 Firmware WLAN.TF.2.1-00014-QCARMSWP-1 now supports reading the board ID information and also required 9 IRAM bank, which older ath10k version don't have the support will fail to be enabled, so in order to maintain the backward compatibility, we need to update the FW API to 6. Signed-off-by: Ryan Hsu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 808f3d67ba90..561c722979ec 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3718,5 +3718,6 @@ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA9377 1.0 firmware files */ +MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE); From 606204bb863fa3b0bb54929d79b4dc46338f9180 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Tue, 27 Mar 2018 11:26:46 +0300 Subject: [PATCH 05/18] ath10k: suppress "Unknown eventid: 36925" warnings FW has Smart Logging feature enabled by default for detecting failures and processing FATAL_CONDITION_EVENTID (36925 - 0x903D) back to host. Since ath10k doesn't implement the Smart Logging and FATAL CONDITION EVENT processing yet, suppressing the unknown event ID warning by moving this under ATH10K_DBG_WMI. Simulated the same issue by having associated STA powered off when ping flood was running from AP backbone. This triggerd STA KICKOUT in AP followed by FATAL CONDITION event 36925. Issue was reproduced and verified in below DUT ------------------------------------------------ AP mode of OpenWRT QCA9984 running 6.0.8 with FW ver 10.4-3.5.3-00053 Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9649bb752bbd..5947d33d6810 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5786,6 +5786,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: case WMI_10_4_PEER_RATECODE_LIST_EVENTID: case WMI_10_4_WDS_PEER_EVENTID: + case WMI_10_4_DEBUG_FATAL_CONDITION_EVENTID: ath10k_dbg(ar, ATH10K_DBG_WMI, "received event id %d not implemented\n", id); break; From 10c2288430817981cab70fc4b78e405765be93b1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Mar 2018 11:26:50 +0300 Subject: [PATCH 06/18] ath10k: refactor ath10k_pci_dump_memory() in preparation for QCA9984 support As QCA9984 needs two region types refactor the code to make it easier add the new types. No functional changes. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 55 ++++++++++++++++++--------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 561c722979ec..ad2a14678be7 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1584,6 +1584,36 @@ static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config) return 0; } +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_generic(struct ath10k *ar, + const struct ath10k_mem_region *current_region, + u8 *buf) +{ + int ret; + + if (current_region->section_table.size > 0) + /* Copy each section individually. */ + return ath10k_pci_dump_memory_section(ar, + current_region, + buf, + current_region->len); + + /* No individiual memory sections defined so we can + * copy the entire memory region. + */ + ret = ath10k_pci_diag_read_mem(ar, + current_region->start, + buf, + current_region->len); + if (ret) { + ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", + current_region->name, ret); + return ret; + } + + return current_region->len; +} + static void ath10k_pci_dump_memory(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { @@ -1642,27 +1672,14 @@ static void ath10k_pci_dump_memory(struct ath10k *ar, buf += sizeof(*hdr); buf_len -= sizeof(*hdr); - if (current_region->section_table.size > 0) { - /* Copy each section individually. */ - count = ath10k_pci_dump_memory_section(ar, - current_region, - buf, - current_region->len); - } else { - /* No individiual memory sections defined so we can - * copy the entire memory region. - */ - ret = ath10k_pci_diag_read_mem(ar, - current_region->start, - buf, - current_region->len); - if (ret) { - ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", - current_region->name, ret); + switch (current_region->type) { + default: + ret = ath10k_pci_dump_memory_generic(ar, current_region, buf); + if (ret < 0) break; - } - count = current_region->len; + count = ret; + break; } hdr->region_type = cpu_to_le32(current_region->type); From 219cc084c67061ee7eafc47e68874d451fa2fff8 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 27 Mar 2018 11:26:52 +0300 Subject: [PATCH 07/18] ath10k: add memory dump support QCA9984 QCA9984/QCA99X0/QCA4019 chipsets have 8 memory regions, dump all of them to the firmware coredump file. Some of the regions need to be read using ioread() so add new region types for them. Signed-off-by: Anilkumar Kolli [kvalo: refactoring etc] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/coredump.c | 90 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/coredump.h | 2 + drivers/net/wireless/ath/ath10k/pci.c | 43 +++++++++++ 3 files changed, 135 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 7173b3743b43..f90cec0ebb1c 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -701,6 +701,89 @@ static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = { }, }; +static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x80000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x98000, + .len = 0x50000, + .name = "IRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOSRAM, + .start = 0xC0000, + .len = 0x40000, + .name = "SRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x30000, + .len = 0x7000, + .name = "APB REG 1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x3f000, + .len = 0x3000, + .name = "APB REG 2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x43000, + .len = 0x3000, + .name = "WIFI REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x4A000, + .len = 0x5000, + .name = "CE REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x80000, + .len = 0x6000, + .name = "SOC REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, @@ -758,6 +841,13 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca988x_hw20_mem_regions), }, }, + { + .hw_id = QCA9984_HW_1_0_DEV_VERSION, + .region_table = { + .regions = qca9984_hw10_mem_regions, + .size = ARRAY_SIZE(qca9984_hw10_mem_regions), + }, + }, }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index bfee13038e59..3baaf9d2cbcd 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -124,6 +124,8 @@ enum ath10k_mem_region_type { ATH10K_MEM_REGION_TYPE_AXI = 3, ATH10K_MEM_REGION_TYPE_IRAM1 = 4, ATH10K_MEM_REGION_TYPE_IRAM2 = 5, + ATH10K_MEM_REGION_TYPE_IOSRAM = 6, + ATH10K_MEM_REGION_TYPE_IOREG = 7, }; /* Define a section of the region which should be copied. As not all parts diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ad2a14678be7..fd1566cd7d2b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -57,6 +57,10 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); */ #define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 +#define QCA99X0_PCIE_BAR0_START_REG 0x81030 +#define QCA99X0_CPU_MEM_ADDR_REG 0x4d00c +#define QCA99X0_CPU_MEM_DATA_REG 0x4d010 + static const struct pci_device_id ath10k_pci_id_table[] = { /* PCI-E QCA988X V2 (Ubiquiti branded) */ { PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) }, @@ -1584,6 +1588,39 @@ static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config) return 0; } +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_sram(struct ath10k *ar, + const struct ath10k_mem_region *region, + u8 *buf) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + u32 base_addr, i; + + base_addr = ioread32(ar_pci->mem + QCA99X0_PCIE_BAR0_START_REG); + base_addr += region->start; + + for (i = 0; i < region->len; i += 4) { + iowrite32(base_addr + i, ar_pci->mem + QCA99X0_CPU_MEM_ADDR_REG); + *(u32 *)(buf + i) = ioread32(ar_pci->mem + QCA99X0_CPU_MEM_DATA_REG); + } + + return region->len; +} + +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_reg(struct ath10k *ar, + const struct ath10k_mem_region *region, + u8 *buf) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + u32 i; + + for (i = 0; i < region->len; i += 4) + *(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i); + + return region->len; +} + /* if an error happened returns < 0, otherwise the length */ static int ath10k_pci_dump_memory_generic(struct ath10k *ar, const struct ath10k_mem_region *current_region, @@ -1673,6 +1710,12 @@ static void ath10k_pci_dump_memory(struct ath10k *ar, buf_len -= sizeof(*hdr); switch (current_region->type) { + case ATH10K_MEM_REGION_TYPE_IOSRAM: + count = ath10k_pci_dump_memory_sram(ar, current_region, buf); + break; + case ATH10K_MEM_REGION_TYPE_IOREG: + count = ath10k_pci_dump_memory_reg(ar, current_region, buf); + break; default: ret = ath10k_pci_dump_memory_generic(ar, current_region, buf); if (ret < 0) From ee35eecb08220978f68a6987f71c5132f40d4a10 Mon Sep 17 00:00:00 2001 From: Ramon Fried Date: Tue, 27 Mar 2018 11:26:55 +0300 Subject: [PATCH 08/18] wcn36xx: turn off probe response offloading It appears that the WCN36xx firmware doesn't actually respond to probe requests. Until it's resolved, switch the probe response responsibility to the 802.11 layer to allow creation of hidden SSID AP's. Signed-off-by: Ramon Fried Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 621e72b6ec99..69d6be59d97f 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1152,8 +1152,6 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) wcn->hw->wiphy->cipher_suites = cipher_suites; wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - #ifdef CONFIG_PM wcn->hw->wiphy->wowlan = &wowlan_support; #endif From e5f9908155c96d945b6d1053701b6168c4e8decc Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 27 Mar 2018 11:26:57 +0300 Subject: [PATCH 09/18] wcn36xx: Fix firmware crash due to corrupted buffer address wcn36xx_start_tx function retrieves the buffer descriptor from the channel control queue to start filling tx buffer information. However, nothing prevents this same buffer to be concurrently accessed in a concurent tx call, leading to potential buffer coruption and firmware crash (observed during iperf test). The channel control queue should only be accessed and updated with the channel lock. Fix this issue by using a local buffer descriptor which will be copied in the thread-safe wcn36xx_dxe_tx_frame. Note that buffer descriptor size is few bytes so the introduced copy overhead is insignificant. Moreover, this allows to keep the locked section minimal. Signed-off-by: Loic Poulain Signed-off-by: Ramon Fried Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 13 ++++------ drivers/net/wireless/ath/wcn36xx/dxe.h | 3 ++- drivers/net/wireless/ath/wcn36xx/txrx.c | 32 ++++++++----------------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 7d5ecaf02288..2c3b899a88fa 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -27,15 +27,6 @@ #include "wcn36xx.h" #include "txrx.h" -void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) -{ - struct wcn36xx_dxe_ch *ch = is_low ? - &wcn->dxe_tx_l_ch : - &wcn->dxe_tx_h_ch; - - return ch->head_blk_ctl->bd_cpu_addr; -} - static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data) { wcn36xx_dbg(WCN36XX_DBG_DXE, @@ -648,6 +639,7 @@ void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn) int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct wcn36xx_vif *vif_priv, + struct wcn36xx_tx_bd *bd, struct sk_buff *skb, bool is_low) { @@ -681,6 +673,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, ctl->skb = NULL; desc = ctl->desc; + /* write buffer descriptor */ + memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd)); + /* Set source address of the BD we send */ desc->src_addr_l = ctl->bd_phy_addr; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index 2bc376c5391b..ce580960d109 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -452,6 +452,7 @@ struct wcn36xx_dxe_mem_pool { dma_addr_t phy_addr; }; +struct wcn36xx_tx_bd; struct wcn36xx_vif; int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn); void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn); @@ -463,8 +464,8 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn); int wcn36xx_dxe_init_channels(struct wcn36xx *wcn); int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct wcn36xx_vif *vif_priv, + struct wcn36xx_tx_bd *bd, struct sk_buff *skb, bool is_low); void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); -void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low); #endif /* _DXE_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 22304edc5948..b1768ed6b0be 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -272,21 +272,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bool is_low = ieee80211_is_data(hdr->frame_control); bool bcast = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); - struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low); + struct wcn36xx_tx_bd bd; - if (!bd) { - /* - * TX DXE are used in pairs. One for the BD and one for the - * actual frame. The BD DXE's has a preallocated buffer while - * the skb ones does not. If this isn't true something is really - * wierd. TODO: Recover from this situation - */ - - wcn36xx_err("bd address may not be NULL for BD DXE\n"); - return -EINVAL; - } - - memset(bd, 0, sizeof(*bd)); + memset(&bd, 0, sizeof(bd)); wcn36xx_dbg(WCN36XX_DBG_TX, "tx skb %p len %d fc %04x sn %d %s %s\n", @@ -296,10 +284,10 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len); - bd->dpu_rf = WCN36XX_BMU_WQ_TX; + bd.dpu_rf = WCN36XX_BMU_WQ_TX; - bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); - if (bd->tx_comp) { + bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); + if (bd.tx_comp) { wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); spin_lock_irqsave(&wcn->dxe_lock, flags); if (wcn->tx_ack_skb) { @@ -321,13 +309,13 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, /* Data frames served first*/ if (is_low) - wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast); + wcn36xx_set_tx_data(&bd, wcn, &vif_priv, sta_priv, skb, bcast); else /* MGMT and CTRL frames are handeld here*/ - wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast); + wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast); - buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); - bd->tx_bd_sign = 0xbdbdbdbd; + buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32)); + bd.tx_bd_sign = 0xbdbdbdbd; - return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low); + return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); } From f276ba06e8b2db6d43b78964ec89b827d6b33537 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 27 Mar 2018 11:26:58 +0300 Subject: [PATCH 10/18] wcn36xx: dequeue all pending indicator messages In case wcn36xx_smd_rsp_process() is called more than once before hal_ind_work was dispatched, the messages will end up in hal_ind_queue, but wcn36xx_ind_smd_work() will only look at the first message in that list. Fix this by dequeing the messages from the list in a loop, and only stop when it's empty. This issue was found during a review of the driver. In my tests, that race never actually occured. Signed-off-by: Daniel Mack Reviewed-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 95 ++++++++++++++------------ 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index def6b23b777f..8932af5e4d8d 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2411,54 +2411,63 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) { struct wcn36xx *wcn = container_of(work, struct wcn36xx, hal_ind_work); - struct wcn36xx_hal_msg_header *msg_header; - struct wcn36xx_hal_ind_msg *hal_ind_msg; - unsigned long flags; - spin_lock_irqsave(&wcn->hal_ind_lock, flags); + for (;;) { + struct wcn36xx_hal_msg_header *msg_header; + struct wcn36xx_hal_ind_msg *hal_ind_msg; + unsigned long flags; - hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, - struct wcn36xx_hal_ind_msg, - list); - list_del(wcn->hal_ind_queue.next); - spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + spin_lock_irqsave(&wcn->hal_ind_lock, flags); - msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; + if (list_empty(&wcn->hal_ind_queue)) { + spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + return; + } - switch (msg_header->msg_type) { - case WCN36XX_HAL_COEX_IND: - case WCN36XX_HAL_DEL_BA_IND: - case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: - break; - case WCN36XX_HAL_OTA_TX_COMPL_IND: - wcn36xx_smd_tx_compl_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_MISSED_BEACON_IND: - wcn36xx_smd_missed_beacon_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: - wcn36xx_smd_delete_sta_context_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_PRINT_REG_INFO_IND: - wcn36xx_smd_print_reg_info_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_SCAN_OFFLOAD_IND: - wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - default: - wcn36xx_err("SMD_EVENT (%d) not supported\n", - msg_header->msg_type); + hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, + struct wcn36xx_hal_ind_msg, + list); + list_del(&hal_ind_msg->list); + spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + + msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; + + switch (msg_header->msg_type) { + case WCN36XX_HAL_COEX_IND: + case WCN36XX_HAL_DEL_BA_IND: + case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: + break; + case WCN36XX_HAL_OTA_TX_COMPL_IND: + wcn36xx_smd_tx_compl_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_MISSED_BEACON_IND: + wcn36xx_smd_missed_beacon_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: + wcn36xx_smd_delete_sta_context_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_PRINT_REG_INFO_IND: + wcn36xx_smd_print_reg_info_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_SCAN_OFFLOAD_IND: + wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + default: + wcn36xx_err("SMD_EVENT (%d) not supported\n", + msg_header->msg_type); + } + + kfree(hal_ind_msg); } - kfree(hal_ind_msg); } int wcn36xx_smd_open(struct wcn36xx *wcn) { From 802ca335496e0c30518434d59f744596eff079b0 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 28 Mar 2018 12:12:52 +0300 Subject: [PATCH 11/18] ath10k: enable TDLS peer buffer STA feature Enable TDLS peer buffer STA feature. QCA6174 firmware(version: WLAN.RM.4.4) support TDLS peer buffer STA, it reports this capability through wmi service map in wmi service ready event. Set related parameter in TDLS WMI command to enable this feature. Signed-off-by: Yingying Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 +++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1cc87cb15620..c684d6f803f5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8325,6 +8325,9 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); } + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA); + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 57bd8a70d242..cb723a7312dc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2886,6 +2886,9 @@ ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id, */ u32 options = 0; + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + options |= WMI_TLV_TDLS_BUFFER_STA_EN; + len = sizeof(*tlv) + sizeof(*cmd); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) From 4c9f8d114660c68b43918f671bd8fc6bdf3bdbd8 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 28 Mar 2018 12:13:07 +0300 Subject: [PATCH 12/18] ath10k: enable TDLS peer inactivity detection Enable TDLS peer inactivity detetion feature. QCA6174 firmware(version: WLAN.RM.4.4) support TDLS link inactivity detecting. Set related parameters in TDLS WMI command to enable this feature. Signed-off-by: Yingying Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 52 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 7 +++ drivers/net/wireless/ath/ath10k/wmi.h | 1 + 3 files changed, 60 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index cb723a7312dc..9d1b0a459069 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -426,6 +426,49 @@ static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar, return 0; } +static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *station; + const struct wmi_tlv_tdls_peer_event *ev; + const void **tb; + struct ath10k_vif *arvif; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ath10k_warn(ar, "tdls peer failed to parse tlv"); + return; + } + ev = tb[WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT]; + if (!ev) { + kfree(tb); + ath10k_warn(ar, "tdls peer NULL event"); + return; + } + + switch (__le32_to_cpu(ev->peer_reason)) { + case WMI_TDLS_TEARDOWN_REASON_TX: + case WMI_TDLS_TEARDOWN_REASON_RSSI: + case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT: + station = ieee80211_find_sta_by_ifaddr(ar->hw, + ev->peer_macaddr.addr, + NULL); + if (!station) { + ath10k_warn(ar, "did not find station from tdls peer event"); + kfree(tb); + return; + } + arvif = ath10k_get_arvif(ar, __le32_to_cpu(ev->vdev_id)); + ieee80211_tdls_oper_request( + arvif->vif, station->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE, + GFP_ATOMIC + ); + break; + } + kfree(tb); +} + /***********/ /* TLV ops */ /***********/ @@ -569,6 +612,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_PDEV_TEMPERATURE_EVENTID: ath10k_wmi_tlv_event_temperature(ar, skb); break; + case WMI_TLV_TDLS_PEER_EVENTID: + ath10k_wmi_event_tdls_peer(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -2889,6 +2935,12 @@ ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id, if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) options |= WMI_TLV_TDLS_BUFFER_STA_EN; + /* WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL means firm will handle TDLS + * link inactivity detecting logic. + */ + if (state == WMI_TDLS_ENABLE_ACTIVE) + state = WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL; + len = sizeof(*tlv) + sizeof(*cmd); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index b07b690544e7..fa3773ec7c68 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1757,6 +1757,13 @@ struct wmi_tlv_tx_pause_ev { __le32 tid_map; } __packed; +struct wmi_tlv_tdls_peer_event { + struct wmi_mac_addr peer_macaddr; + __le32 peer_status; + __le32 peer_reason; + __le32 vdev_id; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); struct wmi_tlv_mgmt_tx_cmd { diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c8fc45d8090e..6da2583c341f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6792,6 +6792,7 @@ enum wmi_tdls_state { WMI_TDLS_DISABLE, WMI_TDLS_ENABLE_PASSIVE, WMI_TDLS_ENABLE_ACTIVE, + WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL, }; enum wmi_tdls_peer_state { From c3816c9ee12c235dde8f382619a38a5ce86fb548 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 28 Mar 2018 12:15:23 +0300 Subject: [PATCH 13/18] ath10k: avoid to set WEP key for TDLS peer TDLS peer do not need WEP key. Setting WEP key will lead to TDLS setup failure. Add fix to avoid setting WEP key for TDLS peer. Signed-off-by: Yingying Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c684d6f803f5..659b23809b47 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2977,7 +2977,7 @@ static int ath10k_station_assoc(struct ath10k *ar, } /* Plumb cached keys only for static WEP */ - if (arvif->def_wep_key_idx != -1) { + if ((arvif->def_wep_key_idx != -1) && (!sta->tdls)) { ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", From 9cdd005750293c0e7e9276546e02b290d0bafeb0 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Wed, 28 Mar 2018 12:15:35 +0300 Subject: [PATCH 14/18] ath10k: fix TDLS peer TX data failure issue on encryped AP For WPA encryption, QCA6174 firmware(version: WLAN.RM.4.4) will unblock data when M4 was sent successfully. For other encryption which didn't need 4-way handshake firmware will unblock the data when peer authorized. Since TDLS is 3-way handshake host need send authorize cmd to firmware to unblock data. Signed-off-by: Yingying Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 659b23809b47..0a249cd0662e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5932,6 +5932,10 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr); spin_unlock_bh(&ar->data_lock); + if (sta && sta->tdls) + ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_AUTHORIZE, 1); + exit: mutex_unlock(&ar->conf_mutex); return ret; From 8ebee73b574ad3dd1f14d461f65ceaffbd637650 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Wed, 28 Mar 2018 12:19:40 +0300 Subject: [PATCH 15/18] ath10k: advertize beacon_int_min_gcd This patch fixes regression caused by 0c317a02ca98 ("cfg80211: support virtual interfaces with different beacon intervals"), with this change cfg80211 expects the driver to advertize 'beacon_int_min_gcd' to support different beacon intervals in multivap scenario. This support is added for, QCA988X/QCA99X0/QCA9984/QCA4019. Verifed AP + mesh bring up on QCA9984 with beacon interval 100msec and 1000msec respectively. Frimware: firmware-5.bin_10.4-3.5.3-00053 Fixes: 0c317a02ca98 ("cfg80211: support virtual interfaces with different beacon intervals") Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0a249cd0662e..bf05a3689558 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7905,6 +7905,7 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { .max_interfaces = 8, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | @@ -8028,6 +8029,7 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { .max_interfaces = 16, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | From 91493e8e10f0f495b04a5c32096d56ea1f254c93 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 28 Mar 2018 12:19:55 +0300 Subject: [PATCH 16/18] ath10k: fix recent bandwidth conversion bug The commit "cfg80211: make RATE_INFO_BW_20 the default" changed the index of RATE_INFO_BW_20, but the updates to ath10k missed the special bandwidth calculation case in ath10k_update_per_peer_tx_stats(). This will fix below warning, WARNING: CPU: 0 PID: 609 at net/wireless/util.c:1254 cfg80211_calculate_bitrate+0x174/0x220 invalid rate bw=1, mcs=9, nss=2 (unwind_backtrace) from (cfg80211_calculate_bitrate+0x174/0x220) (cfg80211_calculate_bitrate) from (nl80211_put_sta_rate+0x44/0x1dc)from (nl80211_put_sta_rate) from (nl80211_send_station+0x388/0xaf0) (nl80211_get_station+0xa8/0xec) [ end trace da8257d6a850e91a ] Fixes: 842be75c77cb ("cfg80211: make RATE_INFO_BW_20 the default") Signed-off-by: Christian Lamparter Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 42 ++++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 64996aba1485..5e02e26158f6 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -724,6 +724,28 @@ struct amsdu_subframe_hdr { #define GROUP_ID_IS_SU_MIMO(x) ((x) == 0 || (x) == 63) +static inline u8 ath10k_bw_to_mac80211_bw(u8 bw) +{ + u8 ret = 0; + + switch (bw) { + case 0: + ret = RATE_INFO_BW_20; + break; + case 1: + ret = RATE_INFO_BW_40; + break; + case 2: + ret = RATE_INFO_BW_80; + break; + case 3: + ret = RATE_INFO_BW_160; + break; + } + + return ret; +} + static void ath10k_htt_rx_h_rates(struct ath10k *ar, struct ieee80211_rx_status *status, struct htt_rx_desc *rxd) @@ -826,23 +848,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, if (sgi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - switch (bw) { - /* 20MHZ */ - case 0: - break; - /* 40MHZ */ - case 1: - status->bw = RATE_INFO_BW_40; - break; - /* 80MHZ */ - case 2: - status->bw = RATE_INFO_BW_80; - break; - case 3: - status->bw = RATE_INFO_BW_160; - break; - } - + status->bw = ath10k_bw_to_mac80211_bw(bw); status->encoding = RX_ENC_VHT; break; default: @@ -2550,7 +2556,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; arsta->txrate.nss = txrate.nss; - arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20; + arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw); } static void ath10k_htt_fetch_peer_stats(struct ath10k *ar, From 1b3fdb50f88195a9814a8301fad6325868881bb6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 28 Mar 2018 12:40:24 +0300 Subject: [PATCH 17/18] ath10k: fix vdev stats for 10.4 firmware Currently vdev stats displayed in fw_stats are applicable only for TLV based firmware and fix it for 10.4 firmware as of now. The vdev stats in 10.4 firmware is split into two parts (vdev_stats, vdev_stats_extended). The actual stats are captured only in extended vdev stats. In order to enable vdev stats, appropriate feature bit will be set on extended resource config. As FTM related counters are available only on newer 10.4 based firmware, these counters will be displayed only on valid data. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 +- drivers/net/wireless/ath/ath10k/core.h | 21 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 151 +++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.h | 27 ++++- 4 files changed, 184 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 830b7fe466f3..8a3020dbd4cf 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2041,7 +2041,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->fw_stats_req_mask = WMI_10_4_STAT_PEER | - WMI_10_4_STAT_PEER_EXTD; + WMI_10_4_STAT_PEER_EXTD | + WMI_10_4_STAT_VDEV_EXTD; ar->max_spatial_stream = ar->hw_params.max_spatial_stream; ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS; @@ -2282,6 +2283,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (ath10k_peer_stats_enabled(ar)) val = WMI_10_4_PEER_STATS; + /* Enable vdev stats by default */ + val |= WMI_10_4_VDEV_STATS; + if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map)) val |= WMI_10_4_BSS_CHANNEL_INFO_64; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 73712c830be7..c17d805d68cc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -222,6 +222,27 @@ struct ath10k_fw_stats_vdev { u32 beacon_rssi_history[10]; }; +struct ath10k_fw_stats_vdev_extd { + struct list_head list; + + u32 vdev_id; + u32 ppdu_aggr_cnt; + u32 ppdu_noack; + u32 mpdu_queued; + u32 ppdu_nonaggr_cnt; + u32 mpdu_sw_requeued; + u32 mpdu_suc_retry; + u32 mpdu_suc_multitry; + u32 mpdu_fail_retry; + u32 tx_ftm_suc; + u32 tx_ftm_suc_retry; + u32 tx_ftm_fail; + u32 rx_ftmr_cnt; + u32 rx_ftmr_dup_cnt; + u32 rx_iftmr_cnt; + u32 rx_iftmr_dup_cnt; +}; + struct ath10k_fw_stats_pdev { struct list_head list; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 5947d33d6810..c5e1ca5945db 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2708,6 +2708,28 @@ ath10k_wmi_10_4_pull_peer_stats(const struct wmi_10_4_peer_stats *src, dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); } +static void +ath10k_wmi_10_4_pull_vdev_stats(const struct wmi_vdev_stats_extd *src, + struct ath10k_fw_stats_vdev_extd *dst) +{ + dst->vdev_id = __le32_to_cpu(src->vdev_id); + dst->ppdu_aggr_cnt = __le32_to_cpu(src->ppdu_aggr_cnt); + dst->ppdu_noack = __le32_to_cpu(src->ppdu_noack); + dst->mpdu_queued = __le32_to_cpu(src->mpdu_queued); + dst->ppdu_nonaggr_cnt = __le32_to_cpu(src->ppdu_nonaggr_cnt); + dst->mpdu_sw_requeued = __le32_to_cpu(src->mpdu_sw_requeued); + dst->mpdu_suc_retry = __le32_to_cpu(src->mpdu_suc_retry); + dst->mpdu_suc_multitry = __le32_to_cpu(src->mpdu_suc_multitry); + dst->mpdu_fail_retry = __le32_to_cpu(src->mpdu_fail_retry); + dst->tx_ftm_suc = __le32_to_cpu(src->tx_ftm_suc); + dst->tx_ftm_suc_retry = __le32_to_cpu(src->tx_ftm_suc_retry); + dst->tx_ftm_fail = __le32_to_cpu(src->tx_ftm_fail); + dst->rx_ftmr_cnt = __le32_to_cpu(src->rx_ftmr_cnt); + dst->rx_ftmr_dup_cnt = __le32_to_cpu(src->rx_ftmr_dup_cnt); + dst->rx_iftmr_cnt = __le32_to_cpu(src->rx_iftmr_cnt); + dst->rx_iftmr_dup_cnt = __le32_to_cpu(src->rx_iftmr_dup_cnt); +} + static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, struct ath10k_fw_stats *stats) @@ -3047,7 +3069,16 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, */ } - /* fw doesn't implement vdev stats */ + for (i = 0; i < num_vdev_stats; i++) { + const struct wmi_vdev_stats *src; + + /* Ignore vdev stats here as it has only vdev id. Actual vdev + * stats will be retrieved from vdev extended stats. + */ + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + } for (i = 0; i < num_peer_stats; i++) { const struct wmi_10_4_peer_stats *src; @@ -3079,26 +3110,43 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, */ } - if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0) - return 0; + if (stats_id & WMI_10_4_STAT_PEER_EXTD) { + stats->extended = true; - stats->extended = true; + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_4_peer_extd_stats *src; + struct ath10k_fw_extd_stats_peer *dst; - for (i = 0; i < num_peer_stats; i++) { - const struct wmi_10_4_peer_extd_stats *src; - struct ath10k_fw_extd_stats_peer *dst; + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; - src = (void *)skb->data; - if (!skb_pull(skb, sizeof(*src))) - return -EPROTO; + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; - dst = kzalloc(sizeof(*dst), GFP_ATOMIC); - if (!dst) - continue; + ether_addr_copy(dst->peer_macaddr, + src->peer_macaddr.addr); + dst->rx_duration = __le32_to_cpu(src->rx_duration); + list_add_tail(&dst->list, &stats->peers_extd); + } + } - ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); - dst->rx_duration = __le32_to_cpu(src->rx_duration); - list_add_tail(&dst->list, &stats->peers_extd); + if (stats_id & WMI_10_4_STAT_VDEV_EXTD) { + for (i = 0; i < num_vdev_stats; i++) { + const struct wmi_vdev_stats_extd *src; + struct ath10k_fw_stats_vdev_extd *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + ath10k_wmi_10_4_pull_vdev_stats(src, dst); + list_add_tail(&dst->list, &stats->vdevs); + } } return 0; @@ -8004,6 +8052,72 @@ ath10k_wmi_op_gen_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable, return skb; } +static void +ath10k_wmi_fw_vdev_stats_extd_fill(const struct ath10k_fw_stats_vdev_extd *vdev, + char *buf, u32 *length) +{ + u32 len = *length; + u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; + u32 val; + + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "vdev id", vdev->vdev_id); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu aggr count", vdev->ppdu_aggr_cnt); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu noack", vdev->ppdu_noack); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu queued", vdev->mpdu_queued); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu nonaggr count", vdev->ppdu_nonaggr_cnt); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu sw requeued", vdev->mpdu_sw_requeued); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu success retry", vdev->mpdu_suc_retry); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu success multitry", vdev->mpdu_suc_multitry); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu fail retry", vdev->mpdu_fail_retry); + val = vdev->tx_ftm_suc; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm success", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->tx_ftm_suc_retry; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm success retry", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->tx_ftm_fail; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm fail", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_ftmr_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx ftm request count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_ftmr_dup_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx ftm request dup count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_iftmr_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx initial ftm req count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_iftmr_dup_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx initial ftm req dup cnt", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + len += scnprintf(buf + len, buf_len - len, "\n"); + + *length = len; +} + void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, char *buf) @@ -8011,7 +8125,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, u32 len = 0; u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; const struct ath10k_fw_stats_pdev *pdev; - const struct ath10k_fw_stats_vdev *vdev; + const struct ath10k_fw_stats_vdev_extd *vdev; const struct ath10k_fw_stats_peer *peer; size_t num_peers; size_t num_vdevs; @@ -8064,9 +8178,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, "ath10k VDEV stats", num_vdevs); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); - list_for_each_entry(vdev, &fw_stats->vdevs, list) { - ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len); + ath10k_wmi_fw_vdev_stats_extd_fill(vdev, buf, &len); } len += scnprintf(buf + len, buf_len - len, "\n"); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6da2583c341f..6fbc84c29521 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4413,6 +4413,7 @@ enum wmi_10_4_stats_id { WMI_10_4_STAT_AP = BIT(1), WMI_10_4_STAT_INST = BIT(2), WMI_10_4_STAT_PEER_EXTD = BIT(3), + WMI_10_4_STAT_VDEV_EXTD = BIT(4), }; struct wlan_inst_rssi_args { @@ -4552,12 +4553,36 @@ struct wmi_10_4_pdev_stats { /* * VDEV statistics - * TODO: add all VDEV stats here */ + +#define WMI_VDEV_STATS_FTM_COUNT_VALID BIT(31) +#define WMI_VDEV_STATS_FTM_COUNT_LSB 0 +#define WMI_VDEV_STATS_FTM_COUNT_MASK 0x7fffffff + struct wmi_vdev_stats { __le32 vdev_id; } __packed; +struct wmi_vdev_stats_extd { + __le32 vdev_id; + __le32 ppdu_aggr_cnt; + __le32 ppdu_noack; + __le32 mpdu_queued; + __le32 ppdu_nonaggr_cnt; + __le32 mpdu_sw_requeued; + __le32 mpdu_suc_retry; + __le32 mpdu_suc_multitry; + __le32 mpdu_fail_retry; + __le32 tx_ftm_suc; + __le32 tx_ftm_suc_retry; + __le32 tx_ftm_fail; + __le32 rx_ftmr_cnt; + __le32 rx_ftmr_dup_cnt; + __le32 rx_iftmr_cnt; + __le32 rx_iftmr_dup_cnt; + __le32 reserved[6]; +} __packed; + /* * peer statistics. * TODO: add more stats From a72c92629108bb8ad756f31b74791c51e1de2af4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Mar 2018 03:32:52 -0700 Subject: [PATCH 18/18] ath: Remove unnecessary ath_bcast_mac and use eth_broadcast_addr Remove the static array and use the generic routine to set the Ethernet broadcast address. Signed-off-by: Joe Perches Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath.h | 2 -- drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +- drivers/net/wireless/ath/ath9k/init.c | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index f3f2784f6ebd..7a364eca46d6 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -33,8 +33,6 @@ */ #define ATH_KEYMAX 128 /* max key cache size we handle */ -static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct ath_ani { bool caldone; unsigned int longcal_timer; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 233054bd6b52..12d3a6c92ba4 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -327,7 +327,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) ath5k_hw_set_lladdr(ah, zero_mac); /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ - memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->curbssid); ath5k_hw_set_bssid(ah); ath5k_hw_set_opmode(ah, ah->opmode); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index f246e9ed4a81..214c68269a69 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -591,7 +591,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index b71b16715f6a..c070a9e51ebf 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -428,7 +428,7 @@ static void ath9k_init_misc(struct ath_softc *sc) timer_setup(&common->ani.timer, ath_ani_calibrate, 0); common->last_rssi = ATH_RSSI_DUMMY_MARKER; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); sc->beacon.slottime = 9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)