diff mbox

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

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

Commit Message

Bartosz Markowski Sept. 3, 2013, 8:21 a.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 |   70 ++++++++++++++++++++++---
 drivers/net/wireless/ath/ath10k/wmi.c   |    4 +-
 drivers/net/wireless/ath/ath10k/wmi.h   |   87 ++++++++++++++++++++++++++-----
 4 files changed, 167 insertions(+), 21 deletions(-)

Comments

Kalle Valo Sept. 6, 2013, 9:48 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>
> ---

[...]

>  		for (i = 0; i < num_peer_stats; i++) {
> -			peer_stats = (struct wmi_peer_stats *)tmp;
> +			peer_stats = (struct wmi_peer_stats_common *)tmp;

You still have the evil cast here :)

(Evil here meaning that that you make the implicit assumption that _v1
and _v2 start with the _common struct.)

Let me send v5 and you can review that before I commit.
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 174c4b4..1a327a9 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 09f535a..1582a97 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -228,25 +228,39 @@  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_common *peer_stats;
+		struct wmi_peer_stats_v1 *peer_v1;
+		struct wmi_peer_stats_v2 *peer_v2;
 
 		stats->peers = num_peer_stats;
 
 		for (i = 0; i < num_peer_stats; i++) {
-			peer_stats = (struct wmi_peer_stats *)tmp;
+			peer_stats = (struct wmi_peer_stats_common *)tmp;
+
 			s = &stats->peer_stat[i];
 
 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
@@ -255,7 +269,19 @@  void ath10k_debug_read_target_stats(struct ath10k *ar,
 			s->peer_tx_rate =
 				__le32_to_cpu(peer_stats->peer_tx_rate);
 
-			tmp += sizeof(struct wmi_peer_stats);
+			if (test_bit(ATH10K_FW_FEATURE_VDEV_STATS,
+				     ar->fw_features)) {
+				peer_v2 = (struct wmi_peer_stats_v2 *)tmp;
+				peer_stats = &peer_v2->common;
+				s->peer_rx_rate =
+				    __le32_to_cpu(peer_v2->peer_rx_rate);
+
+				tmp += sizeof(*peer_v2);
+			} else {
+				peer_v1 = (struct wmi_peer_stats_v1 *)tmp;
+				peer_stats = &peer_v1->common;
+				tmp += sizeof(*peer_v1);
+			}
 		}
 	}
 
@@ -269,7 +295,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 +433,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 +464,18 @@  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..2b429e4 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_v1 {
+	struct wmi_peer_stats_common common;
+} __packed;
+
+
+struct wmi_peer_stats_v2 {
+	struct wmi_peer_stats_common common;
+	__le32 peer_rx_rate;
+} __packed;
+
+
 struct wmi_vdev_create_cmd {
 	__le32 vdev_id;
 	__le32 vdev_type;