ath10k: add cal_data debugfs file
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / debug.c
index c5d0105..22b4888 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "core.h"
 #include "debug.h"
+#include "hif.h"
 
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
@@ -126,14 +127,18 @@ EXPORT_SYMBOL(ath10k_info);
 
 void ath10k_print_driver_info(struct ath10k *ar)
 {
-       ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+       ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d\n",
                    ar->hw_params.name,
                    ar->target_version,
                    ar->chip_id,
                    ar->hw->wiphy->fw_version,
                    ar->fw_api,
                    ar->htt.target_version_major,
-                   ar->htt.target_version_minor);
+                   ar->htt.target_version_minor,
+                   ar->fw_version_major,
+                   ar->fw_version_minor,
+                   ar->fw_version_release,
+                   ar->fw_version_build);
        ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
                    config_enabled(CONFIG_ATH10K_DEBUG),
                    config_enabled(CONFIG_ATH10K_DEBUGFS),
@@ -182,7 +187,7 @@ EXPORT_SYMBOL(ath10k_warn);
 #ifdef CONFIG_ATH10K_DEBUGFS
 
 void ath10k_debug_read_service_map(struct ath10k *ar,
-                                  void *service_map,
+                                  const void *service_map,
                                   size_t map_size)
 {
        memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
@@ -589,15 +594,11 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
                                             char __user *user_buf,
                                             size_t count, loff_t *ppos)
 {
-       const char buf[] = "To simulate firmware crash write one of the"
-                          " keywords to this file:\n `soft` - this will send"
-                          " WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
-                          " supports that command.\n `hard` - this will send"
-                          " to firmware command with illegal parameters"
-                          " causing firmware crash.\n"
-                          "`assert` - this will send special illegal parameter"
-                          " to firmware to cause assert failure"
-                          " and crash.\n";
+       const char buf[] =
+               "To simulate firmware crash write one of the keywords to this file:\n"
+               "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"
+               "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"
+               "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n";
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 }
@@ -645,7 +646,8 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
                 * firmware variants in order to force a firmware crash.
                 */
                ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
-                                       ar->wmi.vdev_param->rts_threshold, 0);
+                                               ar->wmi.vdev_param->rts_threshold,
+                                               0);
        } else if (!strcmp(buf, "assert")) {
                ath10k_info(ar, "simulating firmware assert crash\n");
                ret = ath10k_debug_fw_assert(ar);
@@ -867,8 +869,8 @@ static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
 }
 
 static ssize_t ath10k_read_htt_stats_mask(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
 {
        struct ath10k *ar = file->private_data;
        char buf[32];
@@ -880,8 +882,8 @@ static ssize_t ath10k_read_htt_stats_mask(struct file *file,
 }
 
 static ssize_t ath10k_write_htt_stats_mask(struct file *file,
-                                            const char __user *user_buf,
-                                            size_t count, loff_t *ppos)
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
 {
        struct ath10k *ar = file->private_data;
        unsigned long mask;
@@ -986,8 +988,8 @@ static const struct file_operations fops_htt_max_amsdu_ampdu = {
 };
 
 static ssize_t ath10k_read_fw_dbglog(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
 {
        struct ath10k *ar = file->private_data;
        unsigned int len;
@@ -1040,6 +1042,84 @@ static const struct file_operations fops_fw_dbglog = {
        .llseek = default_llseek,
 };
 
+static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
+{
+       struct ath10k *ar = inode->i_private;
+       void *buf;
+       u32 hi_addr;
+       __le32 addr;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH10K_STATE_ON &&
+           ar->state != ATH10K_STATE_UTF) {
+               ret = -ENETDOWN;
+               goto err;
+       }
+
+       buf = vmalloc(QCA988X_CAL_DATA_LEN);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
+
+       ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
+       if (ret) {
+               ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret);
+               goto err_vfree;
+       }
+
+       ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
+                                  QCA988X_CAL_DATA_LEN);
+       if (ret) {
+               ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
+               goto err_vfree;
+       }
+
+       file->private_data = buf;
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+
+err_vfree:
+       vfree(buf);
+
+err:
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static ssize_t ath10k_debug_cal_data_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       void *buf = file->private_data;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      buf, QCA988X_CAL_DATA_LEN);
+}
+
+static int ath10k_debug_cal_data_release(struct inode *inode,
+                                        struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static const struct file_operations fops_cal_data = {
+       .open = ath10k_debug_cal_data_open,
+       .read = ath10k_debug_cal_data_read,
+       .release = ath10k_debug_cal_data_release,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 int ath10k_debug_start(struct ath10k *ar)
 {
        int ret;
@@ -1176,8 +1256,12 @@ int ath10k_debug_register(struct ath10k *ar)
 {
        ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
                                                   ar->hw->wiphy->debugfsdir);
-       if (!ar->debug.debugfs_phy)
+       if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {
+               if (IS_ERR(ar->debug.debugfs_phy))
+                       return PTR_ERR(ar->debug.debugfs_phy);
+
                return -ENOMEM;
+       }
 
        INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
                          ath10k_debug_htt_stats_dwork);
@@ -1209,6 +1293,9 @@ int ath10k_debug_register(struct ath10k *ar)
        debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_fw_dbglog);
 
+       debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_cal_data);
+
        if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
                debugfs_create_file("dfs_simulate_radar", S_IWUSR,
                                    ar->debug.debugfs_phy, ar,
@@ -1259,11 +1346,26 @@ void ath10k_dbg_dump(struct ath10k *ar,
                     const char *msg, const char *prefix,
                     const void *buf, size_t len)
 {
+       char linebuf[256];
+       unsigned int linebuflen;
+       const void *ptr;
+
        if (ath10k_debug_mask & mask) {
                if (msg)
                        ath10k_dbg(ar, mask, "%s\n", msg);
 
-               print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
+               for (ptr = buf; (ptr - buf) < len; ptr += 16) {
+                       linebuflen = 0;
+                       linebuflen += scnprintf(linebuf + linebuflen,
+                                               sizeof(linebuf) - linebuflen,
+                                               "%s%08x: ",
+                                               (prefix ? prefix : ""),
+                                               (unsigned int)(ptr - buf));
+                       hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
+                                          linebuf + linebuflen,
+                                          sizeof(linebuf) - linebuflen, true);
+                       dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
+               }
        }
 
        /* tracing code doesn't like null strings :/ */