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>
This commit is contained in:
parent
27489753bf
commit
80501bb4e4
5 changed files with 288 additions and 2 deletions
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue