diff mbox

[v3,2/2] ath10k: implement per-VDEV FW statistics

Message ID 1377778061-22331-3-git-send-email-bartosz.markowski@tieto.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Bartosz Markowski Aug. 29, 2013, 12:07 p.m. UTC
The WMI_REQUEST_PEER_STAT command with latst (1.0.0.716) FW
can return per-VDEV statistics. Using debugfs we can fetch this info now.

This is a backward compatible change. In case of older FW the VDEV
statistics are simply not returned.

Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |   27 ++++++++++
 drivers/net/wireless/ath/ath10k/debug.c |   78 ++++++++++++++++++++++-----
 drivers/net/wireless/ath/ath10k/wmi.c   |    4 +-
 drivers/net/wireless/ath/ath10k/wmi.h   |   87 ++++++++++++++++++++++++++-----
 4 files changed, 170 insertions(+), 26 deletions(-)

Comments

Kalle Valo Sept. 3, 2013, 7:13 a.m. UTC | #1
Bartosz Markowski <bartosz.markowski@tieto.com> writes:

> The WMI_REQUEST_PEER_STAT command with latst (1.0.0.716) FW
> can return per-VDEV statistics. Using debugfs we can fetch this info now.
>
> This is a backward compatible change. In case of older FW the VDEV
> statistics are simply not returned.
>
> Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>

[...]

>  	if (num_peer_stats) {
> -		struct wmi_peer_stats *peer_stats;
>  		struct ath10k_peer_stat *s;
> +		struct wmi_peer_stats_1 *peer_stats_1;
> +		struct wmi_peer_stats_2 *peer_stats_2;
>  
>  		stats->peers = num_peer_stats;
>  
>  		for (i = 0; i < num_peer_stats; i++) {
> -			peer_stats = (struct wmi_peer_stats *)tmp;
> +			peer_stats_1 = (struct wmi_peer_stats_1 *)tmp;

You still have this evil cast here which assumes struct wmi_peer_stats_1
starts with the same content as _2. It's better to spell that out in the
code, for example like this:

if (test_bit(ATH10K_FW_FEATURE_VDEV_STATS, ar->fw_features)) {
             peer_v2 = (struct wmi_peer_stats_v2 *)tmp;
             peer_stats = &peer_v2->common;
             tmp += sizeof(*peer_v2);
} else {
             peer_v1 = (struct wmi_peer_stats_v1 *)tmp;
             peer_stats = &peer_v1->common;
             tmp += sizeof(*peer_v1);
}

> +struct wmi_peer_stats_1 {

struct wmi_peer_stats_v1

> +struct wmi_peer_stats_2 {

struct wmi_peer_stats_v2
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index ab05c4c..523c79d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -119,10 +119,32 @@  struct ath10k_wmi {
 	struct work_struct wmi_event_work;
 };
 
+struct ath10k_snr_info {
+	s32 beacon_snr;
+	s32 data_snr;
+};
+
+struct ath10k_vdev_stat {
+	u32 vdev_id;
+	struct ath10k_snr_info vdev_snr;
+	u32 tx_frames_count[MAX_AC];
+	u32 rx_frames_count;
+	u32 multiple_retry_cnt[MAX_AC];
+	u32 fail_count[MAX_AC];
+	u32 rts_fail_count;
+	u32 rts_success_count;
+	u32 rts_err_count;
+	u32 rx_discard_count;
+	u32 ack_fail_count;
+	u32 tx_rate_history[MAX_TX_RATE_VALUES];
+	u32 bcn_rssi_history[MAX_RSSI_VALUES];
+};
+
 struct ath10k_peer_stat {
 	u8 peer_macaddr[ETH_ALEN];
 	u32 peer_rssi;
 	u32 peer_tx_rate;
+	u32 peer_rx_rate;
 };
 
 struct ath10k_target_stats {
@@ -176,6 +198,8 @@  struct ath10k_target_stats {
 	s32 mpdu_errs;
 
 	/* VDEV STATS */
+	struct ath10k_vdev_stat vdev_stat[TARGET_NUM_VDEVS];
+	u8 vdevs;
 
 	/* PEER STATS */
 	u8 peers;
@@ -274,6 +298,9 @@  enum ath10k_fw_features {
 	/* wmi_mgmt_rx_hdr contains extra RSSI information */
 	ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
 
+	/* firmware support per-VEDV statistics */
+	ATH10K_FW_FEATURE_VDEV_STATS = 1,
+
 	/* keep last */
 	ATH10K_FW_FEATURE_COUNT,
 };
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index fcb40cc..0f2b169 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -228,34 +228,59 @@  void ath10k_debug_read_target_stats(struct ath10k *ar,
 		tmp += sizeof(struct wmi_pdev_stats);
 	}
 
-	/* 0 or max vdevs */
-	/* Currently firmware does not support VDEV stats */
 	if (num_vdev_stats) {
 		struct wmi_vdev_stats *vdev_stats;
+		struct ath10k_vdev_stat *s;
+
+		stats->vdevs = num_vdev_stats;
 
 		for (i = 0; i < num_vdev_stats; i++) {
 			vdev_stats = (struct wmi_vdev_stats *)tmp;
+			s = &stats->vdev_stat[i];
+
+			s->vdev_id = __le32_to_cpu(vdev_stats->vdev_id);
+			s->vdev_snr.beacon_snr =
+				__le32_to_cpu(vdev_stats->vdev_snr.beacon_snr);
+			s->vdev_snr.data_snr =
+				__le32_to_cpu(vdev_stats->vdev_snr.data_snr);
+
+			/* TODO:read remaining vdev stats */
+
 			tmp += sizeof(struct wmi_vdev_stats);
 		}
 	}
 
 	if (num_peer_stats) {
-		struct wmi_peer_stats *peer_stats;
 		struct ath10k_peer_stat *s;
+		struct wmi_peer_stats_1 *peer_stats_1;
+		struct wmi_peer_stats_2 *peer_stats_2;
 
 		stats->peers = num_peer_stats;
 
 		for (i = 0; i < num_peer_stats; i++) {
-			peer_stats = (struct wmi_peer_stats *)tmp;
+			peer_stats_1 = (struct wmi_peer_stats_1 *)tmp;
+
 			s = &stats->peer_stat[i];
 
-			WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
-						   s->peer_macaddr);
-			s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
+			WMI_MAC_ADDR_TO_CHAR_ARRAY(
+				&peer_stats_1->common.peer_macaddr,
+				s->peer_macaddr);
+			s->peer_rssi =
+				__le32_to_cpu(peer_stats_1->common.peer_rssi);
 			s->peer_tx_rate =
-				__le32_to_cpu(peer_stats->peer_tx_rate);
-
-			tmp += sizeof(struct wmi_peer_stats);
+				__le32_to_cpu(peer_stats_1->common.peer_tx_rate);
+
+			if (test_bit(ATH10K_FW_FEATURE_VDEV_STATS,
+				     ar->fw_features)) {
+				peer_stats_2 = (struct wmi_peer_stats_2 *)tmp;
+				s->peer_rx_rate =
+				    __le32_to_cpu(peer_stats_2->peer_rx_rate);
+
+				tmp += sizeof(struct wmi_peer_stats_2);
+			}
+			else {
+				tmp += sizeof(struct wmi_peer_stats_1);
+			}
 		}
 	}
 
@@ -269,7 +294,7 @@  static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
 	struct ath10k *ar = file->private_data;
 	struct ath10k_target_stats *fw_stats;
 	char *buf = NULL;
-	unsigned int len = 0, buf_len = 2500;
+	unsigned int len = 0, buf_len = 3000;
 	ssize_t ret_cnt = 0;
 	long left;
 	int i;
@@ -407,6 +432,27 @@  static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
 			 "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
 
+	if (fw_stats->vdevs) {
+		len += scnprintf(buf + len, buf_len - len, "\n");
+		len += scnprintf(buf + len, buf_len - len, "%30s\n",
+				 "ath10k VDEV stats");
+		len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+				 "=================");
+	}
+
+	for (i = 0; i < fw_stats->vdevs; i++) {
+		len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+				 "VDEV ID", fw_stats->vdev_stat[i].vdev_id);
+		len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+				 "Beacon SNR",
+				 fw_stats->vdev_stat[i].vdev_snr.beacon_snr);
+		len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+				 "Data SNR",
+				 fw_stats->vdev_stat[i].vdev_snr.data_snr);
+		len += scnprintf(buf + len, buf_len - len, "\n");
+	}
+
+
 	len += scnprintf(buf + len, buf_len - len, "\n");
 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
 			 "ath10k PEER stats");
@@ -417,11 +463,17 @@  static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
 		len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
 				 "Peer MAC address",
 				 fw_stats->peer_stat[i].peer_macaddr);
-		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+		len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
 				 "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
-		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+		len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
 				 "Peer TX rate",
 				 fw_stats->peer_stat[i].peer_tx_rate);
+
+		if (test_bit(ATH10K_FW_FEATURE_VDEV_STATS, ar->fw_features))
+			len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+					 "Peer RX rate",
+					 fw_stats->peer_stat[i].peer_rx_rate);
+
 		len += scnprintf(buf + len, buf_len - len, "\n");
 	}
 	spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 32fd5e7..3ebab3d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -957,8 +957,10 @@  static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
 	ar->phy_capability = __le32_to_cpu(ev->phy_capability);
 	ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
 
-	if (ar->fw_version_build > 636)
+	if (ar->fw_version_build > 636) {
 		set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
+		set_bit(ATH10K_FW_FEATURE_VDEV_STATS, ar->fw_features);
+	}
 
 	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
 		ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 5b94707..99c7ba1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -60,6 +60,11 @@ 
  *
  */
 
+#define MAX_AC 4 /* Maximum value of access category */
+
+#define MAX_TX_RATE_VALUES      10 /* Max Tx rates */
+#define MAX_RSSI_VALUES         10 /* Max RSSI values */
+
 /* Control Path */
 struct wmi_cmd_hdr {
 	__le32 cmd_id;
@@ -1828,11 +1833,10 @@  enum wmi_stats_id {
 
 struct wmi_request_stats_cmd {
 	__le32 stats_id;
-
-	/*
-	 * Space to add parameters like
-	 * peer mac addr
-	 */
+	/* unique id identifying the VDEV, generated by the caller */
+	__le32 vdev_id;
+	/* peer MAC address */
+	struct wmi_mac_addr peer_macaddr;
 } __packed;
 
 /* Suspend option */
@@ -1881,7 +1885,6 @@  struct wmi_stats_event {
 
 /*
  * PDEV statistics
- * TODO: add all PDEV stats here
  */
 struct wmi_pdev_stats {
 	__le32 chan_nf;        /* Channel noise floor */
@@ -1894,24 +1897,84 @@  struct wmi_pdev_stats {
 	struct wal_dbg_stats wal; /* WAL dbg stats */
 } __packed;
 
-/*
- * VDEV statistics
- * TODO: add all VDEV stats here
- */
+struct wmi_snr_info {
+	__le32 beacon_snr;
+	__le32 data_snr;
+} __packed;
+
 struct wmi_vdev_stats {
+	/* unique id identifying the VDEV, generated by the caller */
 	__le32 vdev_id;
+	struct wmi_snr_info vdev_snr;
+	/*
+	 * Total number of packets(per AC) that were successfully transmitted
+	 * (with and without retries, including multi-cast, broadcast)
+	 */
+	__le32 tx_frm_cnt[MAX_AC];
+	/*
+	 * Total number of packets that were successfully received
+	 * (after appropriate filter rules including multi-cast, broadcast)
+	 */
+	__le32 rx_frm_cnt;
+	/*
+	 * The number of MSDU packets and MMPDU frames per AC that the 802.11
+	 * station successfully transmitted after more than one retransmission
+	 * attempt
+	 */
+	__le32 multiple_retry_cnt[MAX_AC];
+	/* Total number packets(per AC) failed to transmit */
+	__le32 fail_cnt[MAX_AC];
+	/*
+	 * Total number of RTS/CTS sequence failures for transmission of a
+	 * packet
+	 */
+	__le32 rts_fail_cnt;
+	/*
+	 * Total number of RTS/CTS sequence success for transmission of a
+	 * packet
+	 */
+	__le32 rts_succ_cnt;
+	/*
+	 * The receive error count.
+	 * HAL will provide the RxP FCS error global
+	 */
+	__le32 rx_err_cnt;
+	/*
+	 * The sum of the receive error count and dropped-receive-buffer
+	 * error count. (FCS error)
+	 */
+	__le32 rx_discard_cnt;
+	/*
+	 * Total number packets failed transmit because of no ACK
+	 * from the remote entity
+	 */
+	__le32 ack_fail_cnt;
+	/* History of last ten transmit rate, in units of 500 kbit/sec */
+	__le32 tx_rate_history[MAX_TX_RATE_VALUES];
+	/* History of last ten Beacon rssi of the connected Bss */
+	__le32 bcn_rssi_history[MAX_RSSI_VALUES];
 } __packed;
 
 /*
  * peer statistics.
- * TODO: add more stats
  */
-struct wmi_peer_stats {
+struct wmi_peer_stats_common {
 	struct wmi_mac_addr peer_macaddr;
 	__le32 peer_rssi;
 	__le32 peer_tx_rate;
 } __packed;
 
+struct wmi_peer_stats_1 {
+	struct wmi_peer_stats_common common;
+} __packed;
+
+
+struct wmi_peer_stats_2 {
+	struct wmi_peer_stats_common common;
+	__le32 peer_rx_rate;
+} __packed;
+
+
 struct wmi_vdev_create_cmd {
 	__le32 vdev_id;
 	__le32 vdev_type;