summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorAshutosh Kumar <askuma@codeaurora.org>2017-02-25 10:44:32 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2017-03-24 02:34:27 -0700
commit80501bb4e45b245d4e79d94b8e7c7d2a46aee801 (patch)
tree66080d1e8db64d101682bf395d7aa55c208cabcc /drivers/net
parent27489753bffb6dcf909a49e4e32a2c974675824a (diff)
ath10k: Add rx rate histogram for data packet
Add the rate histogram for rate_index, band, ht, vht and vht_nss for received data packet. CRs-Fixed: 2019645 Change-Id: I52ae3b94c886b8a200162cd7d2a220548296bf91 Signed-off-by: Ashutosh Kumar <askuma@codeaurora.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h31
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c243
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h13
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c2
5 files changed, 288 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index d37ed66d767b..af889abd5a01 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2390,6 +2390,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
mutex_init(&ar->conf_mutex);
spin_lock_init(&ar->data_lock);
spin_lock_init(&ar->txqs_lock);
+ spin_lock_init(&ar->datapath_rx_stat_lock);
INIT_LIST_HEAD(&ar->txqs);
INIT_LIST_HEAD(&ar->peers);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index a20ac680cfb9..01d5ecc4f6b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -70,6 +70,20 @@
#define ATH10K_NAPI_BUDGET 64
#define ATH10K_NAPI_QUOTA_LIMIT 60
+#define ATH10K_RX_MCS_MIN 0
+#define ATH10K_RX_HT_MCS_MAX 32
+#define ATH10K_RX_VHT_RATEIDX_MAX 9
+#define ATH10K_RX_VHT_MCS_MAX 20 /* For 2x2 */
+#define ATH10K_RX_NSS_MIN 0
+#define ATH10K_RX_NSS_MAX 5
+
+enum ath10k_datapath_rx_band {
+ ATH10K_BAND_MIN,
+ ATH10K_BAND_2GHZ = ATH10K_BAND_MIN,
+ ATH10K_BAND_5GHZ,
+ ATH10K_BAND_MAX,
+};
+
struct ath10k;
enum ath10k_bus {
@@ -703,6 +717,20 @@ struct ath10k_fw_components {
struct ath10k_fw_file fw_file;
};
+struct datapath_rx_stats {
+ u32 no_of_packets;
+ u32 short_gi_pkts;
+ u32 ht_rate_indx[ATH10K_RX_HT_MCS_MAX + 1];
+ u32 vht_rate_indx[ATH10K_RX_VHT_MCS_MAX + 1];
+ u32 ht_rate_packets;
+ u32 vht_rate_packets;
+ u32 legacy_pkt;
+ u32 nss[ATH10K_RX_NSS_MAX + 1];
+ u32 num_pkts_40Mhz;
+ u32 num_pkts_80Mhz;
+ u32 band[ATH10K_BAND_MAX + 1];
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -900,7 +928,10 @@ struct ath10k {
enum ath10k_spectral_mode mode;
struct ath10k_spec_scan config;
} spectral;
+ struct datapath_rx_stats *rx_stats;
#endif
+ /* prevent concurrency histogram for receiving data packet */
+ spinlock_t datapath_rx_stat_lock;
struct {
/* protected by conf_mutex */
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 8d97822cbbde..ec8063e7986a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -537,6 +537,230 @@ static const struct file_operations fops_fw_stats = {
.llseek = default_llseek,
};
+static inline int is_vht_rate_valid(u32 rate_indx)
+{
+ if ((rate_indx >= ATH10K_RX_MCS_MIN) &&
+ (rate_indx <= ATH10K_RX_VHT_RATEIDX_MAX))
+ return 1;
+ else
+ return 0;
+}
+
+void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status)
+{
+ struct datapath_rx_stats *stat_cnt = ar->rx_stats;
+
+ spin_lock_bh(&ar->datapath_rx_stat_lock);
+
+ stat_cnt->no_of_packets += 1;
+ if (!(stat_cnt->no_of_packets)) {
+ memset(stat_cnt, 0, sizeof(*stat_cnt));
+ stat_cnt->no_of_packets += 1;
+ }
+
+ if (status->flag & RX_FLAG_SHORT_GI)
+ stat_cnt->short_gi_pkts += 1;
+
+ if ((status->vht_nss >= ATH10K_RX_NSS_MIN) &&
+ (status->vht_nss < ATH10K_RX_NSS_MAX)) {
+ stat_cnt->nss[status->vht_nss] += 1;
+ if (status->flag & RX_FLAG_VHT) {
+ stat_cnt->vht_rate_packets += 1;
+ if (is_vht_rate_valid(status->rate_idx)) {
+ stat_cnt->vht_rate_indx[((status->vht_nss - 1) *
+ 10) + status->rate_idx] += 1;
+ } else {
+ /*if we get index other than (>=0 and <=9)*/
+ stat_cnt->vht_rate_indx[ATH10K_RX_VHT_MCS_MAX] += 1;
+ }
+ } else if (status->flag & RX_FLAG_HT) {
+ stat_cnt->ht_rate_packets += 1;
+ if ((status->rate_idx >= ATH10K_RX_MCS_MIN) &&
+ (status->rate_idx < ATH10K_RX_HT_MCS_MAX))
+ stat_cnt->ht_rate_indx[status->rate_idx] += 1;
+ else {
+ /*if we get index other than (>=0 and <=31)*/
+ stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX] += 1;
+ }
+ } else {
+ /* if pkt is other than HT and VHT */
+ stat_cnt->legacy_pkt += 1;
+ }
+ } else {
+ stat_cnt->nss[ATH10K_RX_NSS_MAX] += 1;
+ }
+
+ if (status->flag & RX_FLAG_40MHZ)
+ stat_cnt->num_pkts_40Mhz += 1;
+ if (status->vht_flag & RX_VHT_FLAG_80MHZ)
+ stat_cnt->num_pkts_80Mhz += 1;
+ if ((status->band >= ATH10K_BAND_MIN) &&
+ (status->band < ATH10K_BAND_MAX)) {
+ stat_cnt->band[status->band] += 1;
+ } else {
+ /*if band is other than 0,1 */
+ stat_cnt->band[ATH10K_BAND_MAX] += 1;
+ }
+
+ spin_unlock_bh(&ar->datapath_rx_stat_lock);
+}
+
+size_t get_datapath_stat(char *buf, struct ath10k *ar)
+{
+ u8 i;
+ struct datapath_rx_stats *stat_cnt = ar->rx_stats;
+ size_t j = 0;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ j = snprintf(buf, ATH10K_DATAPATH_BUF_SIZE, "\nNo of packets: %u\t"
+ "No of short_gi packets: %u\n"
+ "\nHT Packets: %u \t VHT Packets: %u\n"
+ "\n40Mhz Packets: %u \t 80Mhz Packets: %u\n"
+ "\n2.4GHz: %u \t 5GHz: %u \t band-error: %u\n\n",
+ stat_cnt->no_of_packets,
+ stat_cnt->short_gi_pkts,
+ stat_cnt->ht_rate_packets,
+ stat_cnt->vht_rate_packets,
+ stat_cnt->num_pkts_40Mhz,
+ stat_cnt->num_pkts_80Mhz,
+ stat_cnt->band[ATH10K_BAND_2GHZ],
+ stat_cnt->band[ATH10K_BAND_5GHZ],
+ stat_cnt->band[ATH10K_BAND_MAX]);
+
+ for (i = 0; i <= ATH10K_RX_NSS_MAX; i++) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "NSS-%u: %u\t", i, stat_cnt->nss[i]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\n\n----HT Rate index------\n");
+
+ for (i = ATH10K_RX_MCS_MIN; i < ATH10K_RX_HT_MCS_MAX;
+ i += 4) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\t"
+ "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\n",
+ i, stat_cnt->ht_rate_indx[i],
+ i + 1, stat_cnt->ht_rate_indx[i + 1],
+ i + 2, stat_cnt->ht_rate_indx[i + 2],
+ i + 3, stat_cnt->ht_rate_indx[i + 3]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "ht_rate_indx[OOB]: %10u\n",
+ stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX]);
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\n----VHT Rate index------\n");
+
+ for (i = ATH10K_RX_MCS_MIN;
+ i <= ATH10K_RX_VHT_RATEIDX_MAX; i++) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "vht_rate_indx[%02u]: %10u\tvht_rate_indx[%02u]: %10u\n",
+ i, stat_cnt->vht_rate_indx[i],
+ i + 10, stat_cnt->vht_rate_indx[i + 10]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "vht_rate_indx[%02u]: %10u\n",
+ i + 10, stat_cnt->vht_rate_indx[i + 10]);
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\nnumber of pkt other than HT and VHT(legacy) : %u\n"
+ "----------------------\n",
+ stat_cnt->legacy_pkt);
+
+ spin_unlock(&ar->datapath_rx_stat_lock);
+
+ return j;
+}
+
+static int ath10k_datapath_stats_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ int ret;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ file->private_data = ar;
+
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return 0;
+
+err_unlock:
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return ret;
+}
+
+static ssize_t ath10k_datapath_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ size_t buf_len;
+ unsigned int ret;
+ void *buf = NULL;
+
+ buf = vmalloc(ATH10K_DATAPATH_BUF_SIZE);
+ if (!buf)
+ return 0;
+
+ buf_len = get_datapath_stat(buf, ar);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, buf_len);
+ vfree(buf);
+
+ return ret;
+}
+
+static ssize_t ath10k_datapath_stats_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 filter;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &filter))
+ return -EINVAL;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = count;
+ goto err_unlock;
+ }
+
+ if (!filter)
+ memset(ar->rx_stats, 0, sizeof(*ar->rx_stats));
+
+ ret = count;
+
+err_unlock:
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return ret;
+}
+
+static int ath10k_datapath_stats_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations fops_datapath_stats = {
+ .open = ath10k_datapath_stats_open,
+ .read = ath10k_datapath_stats_read,
+ .write = ath10k_datapath_stats_write,
+ .release = ath10k_datapath_stats_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -2401,7 +2625,11 @@ int ath10k_debug_create(struct ath10k *ar)
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
if (!ar->debug.cal_data)
- return -ENOMEM;
+ goto err_cal_data;
+
+ ar->rx_stats = vzalloc(sizeof(*ar->rx_stats));
+ if (!ar->rx_stats)
+ goto err_rx_stats;
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
@@ -2409,6 +2637,13 @@ int ath10k_debug_create(struct ath10k *ar)
INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
return 0;
+
+err_rx_stats:
+ vfree(ar->debug.cal_data);
+
+err_cal_data:
+ vfree(ar->debug.fw_crash_data);
+ return -ENOMEM;
}
void ath10k_debug_destroy(struct ath10k *ar)
@@ -2419,6 +2654,9 @@ void ath10k_debug_destroy(struct ath10k *ar)
vfree(ar->debug.cal_data);
ar->debug.cal_data = NULL;
+ vfree(ar->rx_stats);
+ ar->rx_stats = NULL;
+
ath10k_debug_fw_stats_reset(ar);
kfree(ar->debug.tpc_stats);
@@ -2441,6 +2679,9 @@ int ath10k_debug_register(struct ath10k *ar)
init_completion(&ar->debug.tpc_complete);
init_completion(&ar->debug.fw_stats_complete);
+ debugfs_create_file("datapath_rx_stats", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_datapath_stats);
+
debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_fw_stats);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index b1db01a167ac..1e580192efd8 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -59,6 +59,7 @@ enum ath10k_dbg_aggr_mode {
/* FIXME: How to calculate the buffer size sanely? */
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
+#define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024)
extern unsigned int ath10k_debug_mask;
@@ -95,6 +96,8 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status);
+size_t get_datapath_stat(char *buf, struct ath10k *ar);
#else
static inline int ath10k_debug_start(struct ath10k *ar)
{
@@ -145,6 +148,16 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
return NULL;
}
+static inline void fill_datapath_stats(struct ath10k *ar,
+ struct ieee80211_rx_status *status)
+{
+}
+
+static inline size_t get_datapath_stat(char *buf, struct ath10k *ar)
+{
+ return 0;
+}
+
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#define ath10k_debug_get_et_strings NULL
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index ddf097e3a143..437ea2c192b3 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -940,7 +940,7 @@ static void ath10k_process_rx(struct ath10k *ar,
status = IEEE80211_SKB_RXCB(skb);
*status = *rx_status;
-
+ fill_datapath_stats(ar, status);
ath10k_dbg(ar, ATH10K_DBG_DATA,
"rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
skb,