iwlwifi: mvm: port to devcoredump framework
authorJohannes Berg <johannes.berg@intel.com>
Thu, 9 Oct 2014 15:01:36 +0000 (17:01 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 29 Oct 2014 12:13:43 +0000 (14:13 +0200)
iwlwifi features a debug mechanism that allows to dump
binary data which is helpful to debug the firmware.
Until now, this data was made available for the userspace
through debugfs. For this exact purpose, devcoredump was
created. Move to the new infrastructure.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index 267e48a..139de90 100644 (file)
@@ -59,6 +59,7 @@ config IWLDVM
 
 config IWLMVM
        tristate "Intel Wireless WiFi MVM Firmware support"
+       select BACKPORT_WANT_DEV_COREDUMP
        help
          This is the driver that supports the MVM firmware which is
          currently only available for 7260 and 3160 devices.
index d8fc548..0768f83 100644 (file)
@@ -535,9 +535,7 @@ struct iwl_trans_ops {
        void (*ref)(struct iwl_trans *trans);
        void (*unref)(struct iwl_trans *trans);
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
-#endif
 };
 
 /**
@@ -704,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
                trans->ops->unref(trans);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 static inline struct iwl_trans_dump_data *
 iwl_trans_dump_data(struct iwl_trans *trans)
 {
@@ -712,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans)
                return NULL;
        return trans->ops->dump_data(trans);
 }
-#endif
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
                                     struct iwl_host_cmd *cmd)
index 2a61bac..51b7116 100644 (file)
@@ -121,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
        return ret;
 }
 
-static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
-{
-       struct iwl_mvm *mvm = inode->i_private;
-       int ret;
-
-       if (!mvm)
-               return -EINVAL;
-
-       mutex_lock(&mvm->mutex);
-       if (!mvm->fw_error_dump) {
-               ret = -ENODATA;
-               goto out;
-       }
-
-       file->private_data = mvm->fw_error_dump;
-       mvm->fw_error_dump = NULL;
-       ret = 0;
-
-out:
-       mutex_unlock(&mvm->mutex);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-       ssize_t bytes_read = 0;
-       ssize_t bytes_read_trans = 0;
-
-       if (*ppos < dump_ptrs->op_mode_len)
-               bytes_read +=
-                       simple_read_from_buffer(user_buf, count, ppos,
-                                               dump_ptrs->op_mode_ptr,
-                                               dump_ptrs->op_mode_len);
-
-       if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
-               return bytes_read;
-
-       if (dump_ptrs->trans_ptr) {
-               *ppos -= dump_ptrs->op_mode_len;
-               bytes_read_trans =
-                       simple_read_from_buffer(user_buf + bytes_read,
-                                               count - bytes_read, ppos,
-                                               dump_ptrs->trans_ptr->data,
-                                               dump_ptrs->trans_ptr->len);
-               *ppos += dump_ptrs->op_mode_len;
-
-               if (bytes_read_trans >= 0)
-                       bytes_read += bytes_read_trans;
-               else if (!bytes_read)
-                       /* propagate the failure */
-                       return bytes_read_trans;
-       }
-
-       return bytes_read;
-
-}
-
-static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
-                                          struct file *file)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-
-       vfree(dump_ptrs->op_mode_ptr);
-       vfree(dump_ptrs->trans_ptr);
-       kfree(dump_ptrs);
-
-       return 0;
-}
-
 static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
                                   size_t count, loff_t *ppos)
 {
@@ -1535,12 +1463,6 @@ 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);
 
-static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
-       .open = iwl_dbgfs_fw_error_dump_open,
-       .read = iwl_dbgfs_fw_error_dump_read,
-       .release = iwl_dbgfs_fw_error_dump_release,
-};
-
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
@@ -1567,7 +1489,6 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                             S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
-       MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
index 14be108..3276b31 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
+#include <linux/devcoredump.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/tcp.h>
@@ -679,10 +680,51 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
        memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
+static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count,
+                                    const void *data, size_t datalen)
+{
+       const struct iwl_mvm_dump_ptrs *dump_ptrs = data;
+       ssize_t bytes_read;
+       ssize_t bytes_read_trans;
+
+       if (offset < dump_ptrs->op_mode_len) {
+               bytes_read = min_t(ssize_t, count,
+                                  dump_ptrs->op_mode_len - offset);
+               memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset,
+                      bytes_read);
+               offset += bytes_read;
+               count -= bytes_read;
+
+               if (count == 0)
+                       return bytes_read;
+       } else {
+               bytes_read = 0;
+       }
+
+       if (!dump_ptrs->trans_ptr)
+               return bytes_read;
+
+       offset -= dump_ptrs->op_mode_len;
+       bytes_read_trans = min_t(ssize_t, count,
+                                dump_ptrs->trans_ptr->len - offset);
+       memcpy(buffer + bytes_read,
+              (u8 *)dump_ptrs->trans_ptr->data + offset,
+              bytes_read_trans);
+
+       return bytes_read + bytes_read_trans;
+}
+
+static void iwl_mvm_free_coredump(const void *data)
+{
+       const struct iwl_mvm_dump_ptrs *fw_error_dump = data;
+
+       vfree(fw_error_dump->op_mode_ptr);
+       vfree(fw_error_dump->trans_ptr);
+       kfree(fw_error_dump);
+}
+
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 {
-       static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
        struct iwl_fw_error_dump_file *dump_file;
        struct iwl_fw_error_dump_data *dump_data;
        struct iwl_fw_error_dump_info *dump_info;
@@ -695,10 +737,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvm->fw_error_dump)
-               return;
-
-       fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
+       fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
        if (!fw_error_dump)
                return;
 
@@ -773,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        if (fw_error_dump->trans_ptr)
                file_len += fw_error_dump->trans_ptr->len;
        dump_file->file_len = cpu_to_le32(file_len);
-       mvm->fw_error_dump = fw_error_dump;
 
-       /* notify the userspace about the error we had */
-       kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
+       dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
+                     GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
 }
-#endif
 
 static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 {
index d14dc06..256765a 100644 (file)
@@ -648,7 +648,6 @@ struct iwl_mvm {
        /* -1 for always, 0 for never, >0 for that many times */
        s8 restart_fw;
        struct work_struct fw_error_dump_wk;
-       struct iwl_mvm_dump_ptrs *fw_error_dump;
 
 #ifdef CONFIG_IWLWIFI_LEDS
        struct led_classdev led;
@@ -1216,10 +1215,6 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
 struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
 
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
-#else
-static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
-#endif
 
 #endif /* __IWL_MVM_H__ */
index 91b28e8..bd52ecf 100644 (file)
@@ -587,11 +587,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        ieee80211_unregister_hw(mvm->hw);
 
        kfree(mvm->scan_cmd);
-       if (mvm->fw_error_dump) {
-               vfree(mvm->fw_error_dump->op_mode_ptr);
-               vfree(mvm->fw_error_dump->trans_ptr);
-               kfree(mvm->fw_error_dump);
-       }
        kfree(mvm->mcast_filter_cmd);
        mvm->mcast_filter_cmd = NULL;
 
index 8027138..40a2906 100644 (file)
@@ -1764,6 +1764,13 @@ err:
        IWL_ERR(trans, "failed to create the trans debugfs entry\n");
        return -ENOMEM;
 }
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                        struct dentry *dir)
+{
+       return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
 {
@@ -2042,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
 
        return dump_data;
 }
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                        struct dentry *dir)
-{
-       return 0;
-}
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
@@ -2085,9 +2085,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .release_nic_access = iwl_trans_pcie_release_nic_access,
        .set_bits_mask = iwl_trans_pcie_set_bits_mask,
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        .dump_data = iwl_trans_pcie_dump_data,
-#endif
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,