]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ath10k: add memory dump debugfs interface
authorYanbo Li <yanbol@qti.qualcomm.com>
Tue, 25 Nov 2014 10:24:48 +0000 (12:24 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Wed, 26 Nov 2014 06:40:04 +0000 (08:40 +0200)
Add mem_val debugfs file for dumping the firmware (target) memory and also for
writing to the memory. The firmware memory is accessed through one file which
uses position of the file as the firmware memory address. For example, with dd
use skip parameter for the address.

Beucase target memory width is 32 bits it's strongly recommended to use
blocksize divisable with 4 when using this interface. For example, when using
dd use bs=4 to set the block size to 4 and remember to divide both count and
skip values with four.

To read 4 kB chunk from address 0x400000:

dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1

To write value 0x01020304 to address 0x400400:

echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832

To read 4 KB chunk of memory and then write back after edit:

dd if=mem_value of=tmp.bin bs=4 count=1024 skip=1048576
emacs tmp.bin
dd if=tmp.bin of=mem_value bs=4 count=1024 seek=1048576

Signed-off-by: Yanbo Li <yanbol@qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/pci.c

index d0397d11986293927de95ec6de3f0660b0c31f09..ff831ca507f704d7d2aab7832a4d66cdc31ca68f 100644 (file)
@@ -1047,6 +1047,117 @@ static const struct file_operations fops_reg_value = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath10k_mem_value_read(struct file *file,
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       u8 *buf;
+       int ret;
+
+       if (*ppos < 0)
+               return -EINVAL;
+
+       if (!count)
+               return 0;
+
+       mutex_lock(&ar->conf_mutex);
+
+       buf = vmalloc(count);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       if (ar->state != ATH10K_STATE_ON &&
+           ar->state != ATH10K_STATE_UTF) {
+               ret = -ENETDOWN;
+               goto exit;
+       }
+
+       ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
+       if (ret) {
+               ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
+                           (u32)(*ppos), ret);
+               goto exit;
+       }
+
+       ret = copy_to_user(user_buf, buf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       count -= ret;
+       *ppos += count;
+       ret = count;
+
+exit:
+       vfree(buf);
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static ssize_t ath10k_mem_value_write(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       u8 *buf;
+       int ret;
+
+       if (*ppos < 0)
+               return -EINVAL;
+
+       if (!count)
+               return 0;
+
+       mutex_lock(&ar->conf_mutex);
+
+       buf = vmalloc(count);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       if (ar->state != ATH10K_STATE_ON &&
+           ar->state != ATH10K_STATE_UTF) {
+               ret = -ENETDOWN;
+               goto exit;
+       }
+
+       ret = copy_from_user(buf, user_buf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
+       if (ret) {
+               ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
+                           (u32)(*ppos), ret);
+               goto exit;
+       }
+
+       *ppos += count;
+       ret = count;
+
+exit:
+       vfree(buf);
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static const struct file_operations fops_mem_value = {
+       .read = ath10k_mem_value_read,
+       .write = ath10k_mem_value_write,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
        u64 cookie;
@@ -1754,6 +1865,9 @@ int ath10k_debug_register(struct ath10k *ar)
        debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
                            ar->debug.debugfs_phy, ar, &fops_reg_value);
 
+       debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
+                           ar->debug.debugfs_phy, ar, &fops_mem_value);
+
        debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_chip_id);
 
index bad071906540ed009f5f40b261e3d31917e62f26..6ac552304546931c1795a9cf554567957e3a8910 100644 (file)
@@ -48,6 +48,8 @@ struct ath10k_hif_ops {
        int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
                         size_t buf_len);
 
+       int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
+                         int nbytes);
        /*
         * API to handle HIF-specific BMI message exchanges, this API is
         * synchronous and only allowed to be called from a context that
@@ -113,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
        return ar->hif.ops->diag_read(ar, address, buf, buf_len);
 }
 
+static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
+                                       const void *data, int nbytes)
+{
+       if (!ar->hif.ops->diag_write)
+               return -EOPNOTSUPP;
+
+       return ar->hif.ops->diag_write(ar, address, data, nbytes);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
                                              void *request, u32 request_len,
                                              void *response, u32 *response_len)
index 328ab6c5d0535c41fd55381047213f298ae69269..0816098af578e30c708adb851c0e3c0216591463 100644 (file)
@@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
        .tx_sg                  = ath10k_pci_hif_tx_sg,
        .diag_read              = ath10k_pci_hif_diag_read,
+       .diag_write             = ath10k_pci_diag_write_mem,
        .exchange_bmi_msg       = ath10k_pci_hif_exchange_bmi_msg,
        .start                  = ath10k_pci_hif_start,
        .stop                   = ath10k_pci_hif_stop,