Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8026470 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ath10k: Add rx rate histogram for data packet"

parents d0ae02c1 80501bb4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2389,6 +2389,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);
+31 −0
Original line number Diff line number Diff line
@@ -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 */
+242 −1
Original line number Diff line number Diff line
@@ -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);

+13 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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,