iwlwifi: mvm: add debugfs to trigger fw debug logs collection
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 4 Dec 2014 08:07:47 +0000 (10:07 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 28 Dec 2014 18:00:13 +0000 (20:00 +0200)
This allows to collect the logs even if the firmware hasn't
crashed. Of course, crashing the firmware is an option, but
this is easier and nicer.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mvm.h

index ea3b9706cbd8431e33a60ac0257a6a814a1841d3..83ab4239082c969dd61b9fc3415c4b745ebcb55c 100644 (file)
@@ -366,11 +366,15 @@ enum secure_load_status_reg {
 #define RXF_FIFO_RD_FENCE_ADDR         (0xa00c0c)
 
 /* FW monitor */
+#define MON_BUFF_SAMPLE_CTL            (0xa03c00)
 #define MON_BUFF_BASE_ADDR             (0xa03c3c)
 #define MON_BUFF_END_ADDR              (0xa03c40)
 #define MON_BUFF_WRPTR                 (0xa03c44)
 #define MON_BUFF_CYCLE_CNT             (0xa03c48)
 
+#define DBGC_IN_SAMPLE                 (0xa03c00)
+#define DBGC_OUT_CTRL                  (0xa03c0c)
+
 /* FW chicken bits */
 #define LMPM_CHICK                     0xA01FF8
 enum {
index 0507647228af1f9b912d7d23bb191b4d9affafb1..a1b276c4dee04d93c01d6faa0b17825a24677815 100644 (file)
@@ -945,6 +945,56 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
        return count;
 }
 
+static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       enum iwl_fw_dbg_conf conf;
+       char buf[8];
+       const size_t bufsz = sizeof(buf);
+       int pos = 0;
+
+       mutex_lock(&mvm->mutex);
+       conf = mvm->fw_dbg_conf;
+       mutex_unlock(&mvm->mutex);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
+                                          char *buf, size_t count,
+                                          loff_t *ppos)
+{
+       int ret, conf_id;
+
+       ret = kstrtoint(buf, 0, &conf_id);
+       if (ret)
+               return ret;
+
+       if (WARN_ON(conf_id >= FW_DBG_MAX))
+               return -EINVAL;
+
+       mutex_lock(&mvm->mutex);
+       ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
+                                             char *buf, size_t count,
+                                             loff_t *ppos)
+{
+       mutex_lock(&mvm->mutex);
+       iwl_mvm_fw_dbg_collect(mvm);
+       mutex_unlock(&mvm->mutex);
+
+       return count;
+}
+
 #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@@ -1459,6 +1509,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
 MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1500,6 +1552,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                             S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
index 60d0c9fdc2e78383e31fec3cb98e41b8b11d25e1..534ee3123a63fef57318aae3c374b308fc73715c 100644 (file)
@@ -70,6 +70,7 @@
 #include "iwl-debug.h"
 #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
 #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-prph.h"
 #include "iwl-eeprom-parse.h"
 
 #include "mvm.h"
@@ -399,8 +400,26 @@ out:
        return ret;
 }
 
-static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm,
-                                    enum iwl_fw_dbg_conf conf_id)
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       /* stop recording */
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+               iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+       }
+
+       iwl_mvm_fw_error_dump(mvm);
+
+       /* start recording again */
+       WARN_ON_ONCE(mvm->fw->dbg_dest_tlv &&
+                    iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+}
+
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
 {
        u8 *ptr;
        int ret;
index f3cb08976e239533c0065b07af0df9aa099c3dde..ff1a40970ac1b08d554dbcd8574ab036a4e833f3 100644 (file)
@@ -1371,4 +1371,7 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
 
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id);
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm);
+
 #endif /* __IWL_MVM_H__ */