Commit cbf6e055 authored by Xinming Hu's avatar Xinming Hu Committed by Kalle Valo

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: default avatarXinming Hu <huxm@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent d35b6392
...@@ -2386,6 +2386,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2386,6 +2386,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; 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; return 0;
} }
EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
......
...@@ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) ...@@ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
return k; 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 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, ...@@ -366,6 +366,103 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf,
return ret; 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; static struct mwifiex_debug_info info;
/* /*
...@@ -832,6 +929,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump); ...@@ -832,6 +929,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom); MWIFIEX_DFS_FILE_OPS(rdeeprom);
MWIFIEX_DFS_FILE_OPS(hscfg); MWIFIEX_DFS_FILE_OPS(hscfg);
MWIFIEX_DFS_FILE_OPS(histogram);
/* /*
* This function creates the debug FS directory structure and the files. * This function creates the debug FS directory structure and the files.
...@@ -855,6 +953,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) ...@@ -855,6 +953,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
MWIFIEX_DFS_ADD_FILE(rdeeprom); MWIFIEX_DFS_ADD_FILE(rdeeprom);
MWIFIEX_DFS_ADD_FILE(fw_dump); MWIFIEX_DFS_ADD_FILE(fw_dump);
MWIFIEX_DFS_ADD_FILE(hscfg); MWIFIEX_DFS_ADD_FILE(hscfg);
MWIFIEX_DFS_ADD_FILE(histogram);
} }
/* /*
......
...@@ -93,6 +93,14 @@ ...@@ -93,6 +93,14 @@
#define MWIFIEX_TDLS_MAX_FAIL_COUNT 4 #define MWIFIEX_TDLS_MAX_FAIL_COUNT 4
#define MWIFIEX_AUTO_TDLS_IDLE_TIME 10 #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 { enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1, MWIFIEX_BSS_TYPE_UAP = 1,
...@@ -205,4 +213,20 @@ struct mwifiex_chan_stats { ...@@ -205,4 +213,20 @@ struct mwifiex_chan_stats {
u16 cca_scan_dur; u16 cca_scan_dur;
u16 cca_busy_dur; u16 cca_busy_dur;
} __packed; } __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_ */ #endif /* !_MWIFIEX_DECL_H_ */
...@@ -847,6 +847,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { ...@@ -847,6 +847,7 @@ static const struct net_device_ops mwifiex_netdev_ops = {
* - Nick name : Set to null * - Nick name : Set to null
* - Number of Tx timeout : Set to 0 * - Number of Tx timeout : Set to 0
* - Device address : Set to current address * - Device address : Set to current address
* - Rx histogram statistc : Set to 0
* *
* In addition, the CFG80211 work queue is also created. * In addition, the CFG80211 work queue is also created.
*/ */
...@@ -867,6 +868,13 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, ...@@ -867,6 +868,13 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0; priv->num_tx_timeout = 0;
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); 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 { ...@@ -582,6 +582,8 @@ struct mwifiex_private {
struct idr ack_status_frames; struct idr ack_status_frames;
/* spin lock for ack status */ /* spin lock for ack status */
spinlock_t ack_status_lock; spinlock_t ack_status_lock;
/** rx histogram data */
struct mwifiex_histogram_data *hist_data;
}; };
enum mwifiex_ba_status { enum mwifiex_ba_status {
...@@ -1350,6 +1352,14 @@ struct sk_buff * ...@@ -1350,6 +1352,14 @@ struct sk_buff *
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
struct sk_buff *skb, u8 flag, u64 *cookie); 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 #ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void); void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void); void mwifiex_debugfs_remove(void);
......
...@@ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) ...@@ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
priv->is_data_rate_auto = true; priv->is_data_rate_auto = true;
priv->data_rate = 0; 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) { if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
priv->adhoc_state = ADHOC_IDLE; priv->adhoc_state = ADHOC_IDLE;
priv->adhoc_is_link_sensed = false; priv->adhoc_is_link_sensed = false;
......
...@@ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, ...@@ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
struct ethhdr *eth; struct ethhdr *eth;
u16 rx_pkt_off, rx_pkt_len; u16 rx_pkt_off, rx_pkt_len;
u8 *offset; u8 *offset;
u8 adj_rx_rate = 0;
local_rx_pd = (struct rxpd *) (skb->data); local_rx_pd = (struct rxpd *) (skb->data);
...@@ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, ...@@ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
priv->rxpd_htinfo = local_rx_pd->ht_info; 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); ret = mwifiex_recv_packet(priv, skb);
if (ret == -1) if (ret == -1)
dev_err(priv->adapter->dev, "recv packet failed\n"); dev_err(priv->adapter->dev, "recv packet failed\n");
......
...@@ -132,6 +132,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) ...@@ -132,6 +132,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body + 2, memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
ETH_ALEN); ETH_ALEN);
if (priv->hist_data)
mwifiex_hist_data_reset(priv);
break; break;
case EVENT_UAP_MIC_COUNTERMEASURES: case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */ /* For future development */
......
...@@ -406,3 +406,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv) ...@@ -406,3 +406,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return; 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment