From 1b3fdb50f88195a9814a8301fad6325868881bb6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 28 Mar 2018 12:40:24 +0300 Subject: [PATCH] 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