summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mwifiex/scan.c
diff options
context:
space:
mode:
authorAvinash Patil <patila@marvell.com>2014-10-31 13:38:26 +0300
committerJohn W. Linville <linville@tuxdriver.com>2014-10-31 23:07:49 +0300
commitbf35443314acb43fa8a3f9f8046e14cbe178762b (patch)
tree1312ca6d9de7ab6ff736befee045d8bdc774a022 /drivers/net/wireless/mwifiex/scan.c
parent15a892e728299c5879187c8301c10c14af399a0c (diff)
downloadlinux-bf35443314acb43fa8a3f9f8046e14cbe178762b.tar.xz
mwifiex: channel statistics support for mwifiex
This patch adds support to record channel statistics during scan. With extended scan, scan results are returned as events from FW while channel statistics are part of scan command response. We store these channel statistics in adapter. Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Xinmin Hu <huxm@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex/scan.c')
-rw-r--r--drivers/net/wireless/mwifiex/scan.c76
1 files changed, 75 insertions, 1 deletions
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index ca64d4c94112..3a17821157d7 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1755,6 +1755,7 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
+ adapter->survey_idx = 0;
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
if (!priv->scan_request) {
@@ -1976,10 +1977,53 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
return 0;
}
+static void
+mwifiex_update_chan_statistics(struct mwifiex_private *priv,
+ struct mwifiex_ietypes_chanstats *tlv_stat)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 i, num_chan;
+ struct mwifiex_fw_chan_stats *fw_chan_stats;
+ struct mwifiex_chan_stats chan_stats;
+
+ fw_chan_stats = (void *)((u8 *)tlv_stat +
+ sizeof(struct mwifiex_ie_types_header));
+ num_chan = le16_to_cpu(tlv_stat->header.len) /
+ sizeof(struct mwifiex_chan_stats);
+
+ for (i = 0 ; i < num_chan; i++) {
+ chan_stats.chan_num = fw_chan_stats->chan_num;
+ chan_stats.bandcfg = fw_chan_stats->bandcfg;
+ chan_stats.flags = fw_chan_stats->flags;
+ chan_stats.noise = fw_chan_stats->noise;
+ chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss);
+ chan_stats.cca_scan_dur =
+ le16_to_cpu(fw_chan_stats->cca_scan_dur);
+ chan_stats.cca_busy_dur =
+ le16_to_cpu(fw_chan_stats->cca_busy_dur);
+ dev_dbg(adapter->dev,
+ "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+ chan_stats.chan_num,
+ chan_stats.noise,
+ chan_stats.total_bss,
+ chan_stats.cca_scan_dur,
+ chan_stats.cca_busy_dur);
+ memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
+ sizeof(struct mwifiex_chan_stats));
+ fw_chan_stats++;
+ }
+}
+
/* This function handles the command response of extended scan */
-int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
{
struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_scan_ext *ext_scan_resp;
+ struct mwifiex_ie_types_header *tlv;
+ struct mwifiex_ietypes_chanstats *tlv_stat;
+ u16 buf_left, type, len;
+
struct host_cmd_ds_command *cmd_ptr;
struct cmd_ctrl_node *cmd_node;
unsigned long cmd_flags, scan_flags;
@@ -1987,6 +2031,36 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
+ ext_scan_resp = &resp->params.ext_scan;
+
+ tlv = (void *)ext_scan_resp->tlv_buffer;
+ buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
+ - 1);
+
+ while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+ type = le16_to_cpu(tlv->type);
+ len = le16_to_cpu(tlv->len);
+
+ if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
+ dev_err(adapter->dev,
+ "error processing scan response TLVs");
+ break;
+ }
+
+ switch (type) {
+ case TLV_TYPE_CHANNEL_STATS:
+ tlv_stat = (void *)tlv;
+ mwifiex_update_chan_statistics(priv, tlv_stat);
+ break;
+ default:
+ break;
+ }
+
+ buf_left -= len + sizeof(struct mwifiex_ie_types_header);
+ tlv = (void *)((u8 *)tlv + len +
+ sizeof(struct mwifiex_ie_types_header));
+ }
+
spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
if (list_empty(&adapter->scan_pending_q)) {