iwlwifi: mvm: Add RX statistics debugfs entry
authorMatti Gottlieb <matti.gottlieb@intel.com>
Tue, 30 Jul 2013 12:29:37 +0000 (15:29 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 6 Aug 2013 08:30:21 +0000 (10:30 +0200)
Add a debugfs entry for the RX statistics received from
the firmware.

Signed-off-by: Matti Gottlieb <matti.gottlieb@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/rx.c

index 15d52ba..2ee256d 100644 (file)
@@ -592,6 +592,142 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
 }
 #undef BT_MBOX_PRINT
 
+#define PRINT_STATS_LE32(_str, _val)                                   \
+                        pos += scnprintf(buf + pos, bufsz - pos,       \
+                                         fmt_table, _str,              \
+                                         le32_to_cpu(_val))
+
+static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
+                                         char __user *user_buf, size_t count,
+                                         loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       static const char *fmt_table = "\t%-30s %10u\n";
+       static const char *fmt_header = "%-32s\n";
+       int pos = 0;
+       char *buf;
+       int ret;
+       int bufsz = sizeof(struct mvm_statistics_rx_phy) * 20 +
+                   sizeof(struct mvm_statistics_rx_non_phy) * 10 +
+                   sizeof(struct mvm_statistics_rx_ht_phy) * 10 + 200;
+       struct mvm_statistics_rx_phy *ofdm;
+       struct mvm_statistics_rx_phy *cck;
+       struct mvm_statistics_rx_non_phy *general;
+       struct mvm_statistics_rx_ht_phy *ht;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&mvm->mutex);
+
+       ofdm = &mvm->rx_stats.ofdm;
+       cck = &mvm->rx_stats.cck;
+       general = &mvm->rx_stats.general;
+       ht = &mvm->rx_stats.ofdm_ht;
+
+       pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
+                        "Statistics_Rx - OFDM");
+       PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt);
+       PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt);
+       PRINT_STATS_LE32("plcp_err", ofdm->plcp_err);
+       PRINT_STATS_LE32("crc32_err", ofdm->crc32_err);
+       PRINT_STATS_LE32("overrun_err", ofdm->overrun_err);
+       PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err);
+       PRINT_STATS_LE32("crc32_good", ofdm->crc32_good);
+       PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt);
+       PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt);
+       PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout);
+       PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout);
+       PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts);
+       PRINT_STATS_LE32("rxe_frame_lmt_overrun",
+                        ofdm->rxe_frame_limit_overrun);
+       PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt);
+       PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt);
+       PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt);
+       PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill);
+       PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err);
+       PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum);
+       PRINT_STATS_LE32("reserved", ofdm->reserved);
+
+       pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
+                        "Statistics_Rx - CCK");
+       PRINT_STATS_LE32("ina_cnt", cck->ina_cnt);
+       PRINT_STATS_LE32("fina_cnt", cck->fina_cnt);
+       PRINT_STATS_LE32("plcp_err", cck->plcp_err);
+       PRINT_STATS_LE32("crc32_err", cck->crc32_err);
+       PRINT_STATS_LE32("overrun_err", cck->overrun_err);
+       PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err);
+       PRINT_STATS_LE32("crc32_good", cck->crc32_good);
+       PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt);
+       PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt);
+       PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout);
+       PRINT_STATS_LE32("fina_timeout", cck->fina_timeout);
+       PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts);
+       PRINT_STATS_LE32("rxe_frame_lmt_overrun",
+                        cck->rxe_frame_limit_overrun);
+       PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt);
+       PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt);
+       PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt);
+       PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill);
+       PRINT_STATS_LE32("mh_format_err", cck->mh_format_err);
+       PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum);
+       PRINT_STATS_LE32("reserved", cck->reserved);
+
+       pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
+                        "Statistics_Rx - GENERAL");
+       PRINT_STATS_LE32("bogus_cts", general->bogus_cts);
+       PRINT_STATS_LE32("bogus_ack", general->bogus_ack);
+       PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames);
+       PRINT_STATS_LE32("filtered_frames", general->filtered_frames);
+       PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons);
+       PRINT_STATS_LE32("channel_beacons", general->channel_beacons);
+       PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon);
+       PRINT_STATS_LE32("adc_rx_saturation_time",
+                        general->adc_rx_saturation_time);
+       PRINT_STATS_LE32("ina_detection_search_time",
+                        general->ina_detection_search_time);
+       PRINT_STATS_LE32("beacon_silence_rssi_a",
+                        general->beacon_silence_rssi_a);
+       PRINT_STATS_LE32("beacon_silence_rssi_b",
+                        general->beacon_silence_rssi_b);
+       PRINT_STATS_LE32("beacon_silence_rssi_c",
+                        general->beacon_silence_rssi_c);
+       PRINT_STATS_LE32("interference_data_flag",
+                        general->interference_data_flag);
+       PRINT_STATS_LE32("channel_load", general->channel_load);
+       PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms);
+       PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a);
+       PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b);
+       PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c);
+       PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a);
+       PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
+       PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
+       PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
+       PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
+
+       pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
+                        "Statistics_Rx - HT");
+       PRINT_STATS_LE32("plcp_err", ht->plcp_err);
+       PRINT_STATS_LE32("overrun_err", ht->overrun_err);
+       PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err);
+       PRINT_STATS_LE32("crc32_good", ht->crc32_good);
+       PRINT_STATS_LE32("crc32_err", ht->crc32_err);
+       PRINT_STATS_LE32("mh_format_err", ht->mh_format_err);
+       PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good);
+       PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt);
+       PRINT_STATS_LE32("agg_cnt", ht->agg_cnt);
+       PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs);
+
+       mutex_unlock(&mvm->mutex);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+}
+#undef PRINT_STAT_LE32
+
 static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
                                          const char __user *user_buf,
                                          size_t count, loff_t *ppos)
@@ -924,6 +1060,7 @@ MVM_DEBUGFS_READ_FILE_OPS(stations);
 MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
+MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
 MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
 #ifdef CONFIG_PM_SLEEP
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram);
@@ -947,6 +1084,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 #ifdef CONFIG_PM_SLEEP
        MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
index 5dc5dfd..76f6a1f 100644 (file)
@@ -421,6 +421,8 @@ struct iwl_mvm {
 
        struct iwl_notif_wait_data notif_wait;
 
+       struct mvm_statistics_rx rx_stats;
+
        unsigned long transport_queue_stop;
        u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
        atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
index 65e5fb8..2fcc8ef 100644 (file)
@@ -440,6 +440,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        else
                mvm->pm_ops = &pm_legacy_ops;
 
+       memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
+
        return op_mode;
 
  out_unregister:
index 6fd7fae..5057fd3 100644 (file)
@@ -378,6 +378,18 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        return 0;
 }
 
+static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm,
+                                        struct iwl_notif_statistics *stats)
+{
+       /*
+        * NOTE FW aggregates the statistics - BUT the statistics are cleared
+        * when the driver issues REPLY_STATISTICS_CMD 0x9c with CLEAR_STATS
+        * bit set.
+        */
+       lockdep_assert_held(&mvm->mutex);
+       memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx));
+}
+
 /*
  * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler
  *
@@ -396,6 +408,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
                mvm->temperature = le32_to_cpu(common->temperature);
                iwl_mvm_tt_handler(mvm);
        }
+       iwl_mvm_update_rx_statistics(mvm, stats);
 
        return 0;
 }