mwifiex: add rx histogram statistics support
This patch add a new debugfs item histogram used for reporting rx data packet statitics(rx rate, snr, noise floor, signal strenth) to userspace. Signed-off-by: Xinming Hu <huxm@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
		
							parent
							
								
									d35b639228
								
							
						
					
					
						commit
						cbf6e05527
					
				| @ -2386,6 +2386,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) | ||||
| 
 | ||||
| 	priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||||
| 
 | ||||
| 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | ||||
| 	    GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) | ||||
| 		kfree(priv->hist_data); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); | ||||
|  | ||||
| @ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) | ||||
| 
 | ||||
| 	return k; | ||||
| } | ||||
| 
 | ||||
| u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, | ||||
| 			    u8 rx_rate, u8 rate_info) | ||||
| { | ||||
| 	u8 rate_index = 0; | ||||
| 
 | ||||
| 	/* HT40 */ | ||||
| 	if ((rate_info & BIT(0)) && (rate_info & BIT(1))) | ||||
| 		rate_index = MWIFIEX_RATE_INDEX_MCS0 + | ||||
| 			     MWIFIEX_BW20_MCS_NUM + rx_rate; | ||||
| 	else if (rate_info & BIT(0)) /* HT20 */ | ||||
| 		rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate; | ||||
| 	else | ||||
| 		rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ? | ||||
| 			      rx_rate - 1 : rx_rate; | ||||
| 
 | ||||
| 	return rate_index; | ||||
| } | ||||
|  | ||||
| @ -366,6 +366,103 @@ free_and_exit: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* Sysfs histogram file read handler.
 | ||||
|  * | ||||
|  * This function is called when the 'histogram' file is opened for reading | ||||
|  * It prints the following histogram information - | ||||
|  *      - Number of histogram samples | ||||
|  *      - Receive packet number of each rx_rate | ||||
|  *      - Receive packet number of each snr | ||||
|  *      - Receive packet number of each nosie_flr | ||||
|  *      - Receive packet number of each signal streath | ||||
|  */ | ||||
| static ssize_t | ||||
| mwifiex_histogram_read(struct file *file, char __user *ubuf, | ||||
| 		       size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct mwifiex_private *priv = | ||||
| 		(struct mwifiex_private *)file->private_data; | ||||
| 	ssize_t ret; | ||||
| 	struct mwifiex_histogram_data *phist_data; | ||||
| 	int i, value; | ||||
| 	unsigned long page = get_zeroed_page(GFP_KERNEL); | ||||
| 	char *p = (char *)page; | ||||
| 
 | ||||
| 	if (!p) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (!priv || !priv->hist_data) | ||||
| 		return -EFAULT; | ||||
| 	phist_data = priv->hist_data; | ||||
| 
 | ||||
| 	p += sprintf(p, "\n" | ||||
| 		     "total samples = %d\n", | ||||
| 		     atomic_read(&phist_data->num_samples)); | ||||
| 
 | ||||
| 	p += sprintf(p, "rx rates (in Mbps): 0=1M   1=2M"); | ||||
| 	p += sprintf(p, "2=5.5M  3=11M   4=6M   5=9M  6=12M\n"); | ||||
| 	p += sprintf(p, "7=18M  8=24M  9=36M  10=48M  11=54M"); | ||||
| 	p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); | ||||
| 
 | ||||
| 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { | ||||
| 		p += sprintf(p, "44-53=MCS0-9(VHT:BW20)"); | ||||
| 		p += sprintf(p, "54-63=MCS0-9(VHT:BW40)"); | ||||
| 		p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n"); | ||||
| 	} else { | ||||
| 		p += sprintf(p, "\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { | ||||
| 		value = atomic_read(&phist_data->rx_rate[i]); | ||||
| 		if (value) | ||||
| 			p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { | ||||
| 		for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; | ||||
| 		     i++) { | ||||
| 			value = atomic_read(&phist_data->rx_rate[i]); | ||||
| 			if (value) | ||||
| 				p += sprintf(p, "rx_rate[%02d] = %d\n", | ||||
| 					   i, value); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < MWIFIEX_MAX_SNR; i++) { | ||||
| 		value =  atomic_read(&phist_data->snr[i]); | ||||
| 		if (value) | ||||
| 			p += sprintf(p, "snr[%02ddB] = %d\n", i, value); | ||||
| 	} | ||||
| 	for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { | ||||
| 		value = atomic_read(&phist_data->noise_flr[i]); | ||||
| 		if (value) | ||||
| 			p += sprintf(p, "noise_flr[-%02ddBm] = %d\n", | ||||
| 				(int)(i-128), value); | ||||
| 	} | ||||
| 	for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { | ||||
| 		value = atomic_read(&phist_data->sig_str[i]); | ||||
| 		if (value) | ||||
| 			p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", | ||||
| 				i, value); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, | ||||
| 				      (unsigned long)p - page); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| mwifiex_histogram_write(struct file *file, const char __user *ubuf, | ||||
| 			size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct mwifiex_private *priv = (void *)file->private_data; | ||||
| 
 | ||||
| 	if (priv && priv->hist_data) | ||||
| 		mwifiex_hist_data_reset(priv); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct mwifiex_debug_info info; | ||||
| 
 | ||||
| /*
 | ||||
| @ -832,6 +929,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump); | ||||
| MWIFIEX_DFS_FILE_OPS(regrdwr); | ||||
| MWIFIEX_DFS_FILE_OPS(rdeeprom); | ||||
| MWIFIEX_DFS_FILE_OPS(hscfg); | ||||
| MWIFIEX_DFS_FILE_OPS(histogram); | ||||
| 
 | ||||
| /*
 | ||||
|  * This function creates the debug FS directory structure and the files. | ||||
| @ -855,6 +953,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) | ||||
| 	MWIFIEX_DFS_ADD_FILE(rdeeprom); | ||||
| 	MWIFIEX_DFS_ADD_FILE(fw_dump); | ||||
| 	MWIFIEX_DFS_ADD_FILE(hscfg); | ||||
| 	MWIFIEX_DFS_ADD_FILE(histogram); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -93,6 +93,14 @@ | ||||
| #define MWIFIEX_TDLS_MAX_FAIL_COUNT      4 | ||||
| #define MWIFIEX_AUTO_TDLS_IDLE_TIME     10 | ||||
| 
 | ||||
| /* 54M rates, index from 0 to 11 */ | ||||
| #define MWIFIEX_RATE_INDEX_MCS0 12 | ||||
| /* 12-27=MCS0-15(BW20) */ | ||||
| #define MWIFIEX_BW20_MCS_NUM 15 | ||||
| 
 | ||||
| /* Rate index for OFDM 0 */ | ||||
| #define MWIFIEX_RATE_INDEX_OFDM0   4 | ||||
| 
 | ||||
| enum mwifiex_bss_type { | ||||
| 	MWIFIEX_BSS_TYPE_STA = 0, | ||||
| 	MWIFIEX_BSS_TYPE_UAP = 1, | ||||
| @ -205,4 +213,20 @@ struct mwifiex_chan_stats { | ||||
| 	u16 cca_scan_dur; | ||||
| 	u16 cca_busy_dur; | ||||
| } __packed; | ||||
| 
 | ||||
| #define MWIFIEX_HIST_MAX_SAMPLES	1048576 | ||||
| #define MWIFIEX_MAX_RX_RATES		     44 | ||||
| #define MWIFIEX_MAX_AC_RX_RATES		     74 | ||||
| #define MWIFIEX_MAX_SNR			    256 | ||||
| #define MWIFIEX_MAX_NOISE_FLR		    256 | ||||
| #define MWIFIEX_MAX_SIG_STRENGTH	    256 | ||||
| 
 | ||||
| struct mwifiex_histogram_data { | ||||
| 	atomic_t rx_rate[MWIFIEX_MAX_AC_RX_RATES]; | ||||
| 	atomic_t snr[MWIFIEX_MAX_SNR]; | ||||
| 	atomic_t noise_flr[MWIFIEX_MAX_NOISE_FLR]; | ||||
| 	atomic_t sig_str[MWIFIEX_MAX_SIG_STRENGTH]; | ||||
| 	atomic_t num_samples; | ||||
| }; | ||||
| 
 | ||||
| #endif /* !_MWIFIEX_DECL_H_ */ | ||||
|  | ||||
| @ -847,6 +847,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { | ||||
|  *      - Nick name             : Set to null | ||||
|  *      - Number of Tx timeout  : Set to 0 | ||||
|  *      - Device address        : Set to current address | ||||
|  *      - Rx histogram statistc : Set to 0 | ||||
|  * | ||||
|  * In addition, the CFG80211 work queue is also created. | ||||
|  */ | ||||
| @ -867,6 +868,13 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, | ||||
| 	priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; | ||||
| 	priv->num_tx_timeout = 0; | ||||
| 	memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); | ||||
| 
 | ||||
| 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | ||||
| 	    GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { | ||||
| 		priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); | ||||
| 		if (priv->hist_data) | ||||
| 			mwifiex_hist_data_reset(priv); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -582,6 +582,8 @@ struct mwifiex_private { | ||||
| 	struct idr ack_status_frames; | ||||
| 	/* spin lock for ack status */ | ||||
| 	spinlock_t ack_status_lock; | ||||
| 	/** rx histogram data */ | ||||
| 	struct mwifiex_histogram_data *hist_data; | ||||
| }; | ||||
| 
 | ||||
| enum mwifiex_ba_status { | ||||
| @ -1350,6 +1352,14 @@ struct sk_buff * | ||||
| mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, | ||||
| 				struct sk_buff *skb, u8 flag, u64 *cookie); | ||||
| 
 | ||||
| void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, | ||||
| 			   s8 nflr); | ||||
| void mwifiex_hist_data_reset(struct mwifiex_private *priv); | ||||
| void mwifiex_hist_data_add(struct mwifiex_private *priv, | ||||
| 			   u8 rx_rate, s8 snr, s8 nflr); | ||||
| u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, | ||||
| 			    u8 rx_rate, u8 ht_info); | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| void mwifiex_debugfs_init(void); | ||||
| void mwifiex_debugfs_remove(void); | ||||
|  | ||||
| @ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) | ||||
| 	priv->is_data_rate_auto = true; | ||||
| 	priv->data_rate = 0; | ||||
| 
 | ||||
| 	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | ||||
| 	     GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) | ||||
| 		mwifiex_hist_data_reset(priv); | ||||
| 
 | ||||
| 	if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { | ||||
| 		priv->adhoc_state = ADHOC_IDLE; | ||||
| 		priv->adhoc_is_link_sensed = false; | ||||
|  | ||||
| @ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, | ||||
| 	struct ethhdr *eth; | ||||
| 	u16 rx_pkt_off, rx_pkt_len; | ||||
| 	u8 *offset; | ||||
| 	u8 adj_rx_rate = 0; | ||||
| 
 | ||||
| 	local_rx_pd = (struct rxpd *) (skb->data); | ||||
| 
 | ||||
| @ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, | ||||
| 
 | ||||
| 	priv->rxpd_htinfo = local_rx_pd->ht_info; | ||||
| 
 | ||||
| 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || | ||||
| 	    GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { | ||||
| 		adj_rx_rate = mwifiex_adjust_data_rate(priv, priv->rxpd_rate, | ||||
| 						       priv->rxpd_htinfo); | ||||
| 		mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr, | ||||
| 				      local_rx_pd->nf); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = mwifiex_recv_packet(priv, skb); | ||||
| 	if (ret == -1) | ||||
| 		dev_err(priv->adapter->dev, "recv packet failed\n"); | ||||
|  | ||||
| @ -132,6 +132,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) | ||||
| 		dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); | ||||
| 		memcpy(priv->netdev->dev_addr, adapter->event_body + 2, | ||||
| 		       ETH_ALEN); | ||||
| 		if (priv->hist_data) | ||||
| 			mwifiex_hist_data_reset(priv); | ||||
| 		break; | ||||
| 	case EVENT_UAP_MIC_COUNTERMEASURES: | ||||
| 		/* For future development */ | ||||
|  | ||||
| @ -406,3 +406,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv) | ||||
| 	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| /* This function adds histogram data to histogram array*/ | ||||
| void mwifiex_hist_data_add(struct mwifiex_private *priv, | ||||
| 			   u8 rx_rate, s8 snr, s8 nflr) | ||||
| { | ||||
| 	struct mwifiex_histogram_data *phist_data = priv->hist_data; | ||||
| 
 | ||||
| 	if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES) | ||||
| 		mwifiex_hist_data_reset(priv); | ||||
| 	mwifiex_hist_data_set(priv, rx_rate, snr, nflr); | ||||
| } | ||||
| 
 | ||||
| /* function to add histogram record */ | ||||
| void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, | ||||
| 			   s8 nflr) | ||||
| { | ||||
| 	struct mwifiex_histogram_data *phist_data = priv->hist_data; | ||||
| 
 | ||||
| 	atomic_inc(&phist_data->num_samples); | ||||
| 	atomic_inc(&phist_data->rx_rate[rx_rate]); | ||||
| 	atomic_inc(&phist_data->snr[snr]); | ||||
| 	atomic_inc(&phist_data->noise_flr[128 + nflr]); | ||||
| 	atomic_inc(&phist_data->sig_str[nflr - snr]); | ||||
| } | ||||
| 
 | ||||
| /* function to reset histogram data during init/reset */ | ||||
| void mwifiex_hist_data_reset(struct mwifiex_private *priv) | ||||
| { | ||||
| 	int ix; | ||||
| 	struct mwifiex_histogram_data *phist_data = priv->hist_data; | ||||
| 
 | ||||
| 	atomic_set(&phist_data->num_samples, 0); | ||||
| 	for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++) | ||||
| 		atomic_set(&phist_data->rx_rate[ix], 0); | ||||
| 	for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++) | ||||
| 		atomic_set(&phist_data->snr[ix], 0); | ||||
| 	for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++) | ||||
| 		atomic_set(&phist_data->noise_flr[ix], 0); | ||||
| 	for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) | ||||
| 		atomic_set(&phist_data->sig_str[ix], 0); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user