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 267e48a2915e7885993979337619d777c8cb74c8..139de90c2aaff46e8bed7c3def3c85499313c7a9 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 d8fc548c0d6cd561993eebb6df185e3ccad0d6ac..0768f83e709d3f117139d6e331f610aaac750a97 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 2a61baca508120e086352be85cc2f098226429b1..51b7116965ed8a9d68383f043d139c11071a5ac1 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 14be10829510c2366944662a09a57f9ba35ba04e..3276b31898da2d557cf44984d9cb79d698e422e6 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 d14dc061d1c2254312e4e90ce9dbc4cdfc7db5b4..256765accbc659f9d431899d110ced3afa26c8f0 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 91b28e8699695442662ba1fe4c5d77fe10066cbc..bd52ecfabedba1b3d6d36c416e42a6a011e06d08 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 8027138c47e9aee0a85d74932c54b0341acf938d..40a290603eade3ffc9eb173e846ad9dd2a711a9f 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,