|
@@ -54,6 +54,27 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_ATH6KL_DEBUG
|
|
|
+
|
|
|
+#define REG_OUTPUT_LEN_PER_LINE 25
|
|
|
+#define REGTYPE_STR_LEN 100
|
|
|
+
|
|
|
+struct ath6kl_diag_reg_info {
|
|
|
+ u32 reg_start;
|
|
|
+ u32 reg_end;
|
|
|
+ const char *reg_info;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct ath6kl_diag_reg_info diag_reg[] = {
|
|
|
+ { 0x20000, 0x200fc, "General DMA and Rx registers" },
|
|
|
+ { 0x28000, 0x28900, "MAC PCU register & keycache" },
|
|
|
+ { 0x20800, 0x20a40, "QCU" },
|
|
|
+ { 0x21000, 0x212f0, "DCU" },
|
|
|
+ { 0x4000, 0x42e4, "RTC" },
|
|
|
+ { 0x540000, 0x540000 + (256 * 1024), "RAM" },
|
|
|
+ { 0x29800, 0x2B210, "Base Band" },
|
|
|
+ { 0x1C000, 0x1C748, "Analog" },
|
|
|
+};
|
|
|
+
|
|
|
void ath6kl_dump_registers(struct ath6kl_device *dev,
|
|
|
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
|
|
struct ath6kl_irq_enable_reg *irq_enable_reg)
|
|
@@ -528,6 +549,171 @@ static const struct file_operations fops_credit_dist_stats = {
|
|
|
.llseek = default_llseek,
|
|
|
};
|
|
|
|
|
|
+static unsigned long ath6kl_get_num_reg(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ unsigned long n_reg = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
|
|
|
+ n_reg = n_reg +
|
|
|
+ (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
|
|
|
+
|
|
|
+ return n_reg;
|
|
|
+}
|
|
|
+
|
|
|
+static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
|
|
|
+ if (reg_addr >= diag_reg[i].reg_start &&
|
|
|
+ reg_addr <= diag_reg[i].reg_end)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct ath6kl *ar = file->private_data;
|
|
|
+ u8 buf[50];
|
|
|
+ unsigned int len = 0;
|
|
|
+
|
|
|
+ if (ar->debug.dbgfs_diag_reg)
|
|
|
+ len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
|
|
|
+ ar->debug.dbgfs_diag_reg);
|
|
|
+ else
|
|
|
+ len += scnprintf(buf + len, sizeof(buf) - len,
|
|
|
+ "All diag registers\n");
|
|
|
+
|
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ath6kl_regread_write(struct file *file,
|
|
|
+ const char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct ath6kl *ar = file->private_data;
|
|
|
+ u8 buf[50];
|
|
|
+ unsigned int len;
|
|
|
+ unsigned long reg_addr;
|
|
|
+
|
|
|
+ len = min(count, sizeof(buf) - 1);
|
|
|
+ if (copy_from_user(buf, user_buf, len))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ buf[len] = '\0';
|
|
|
+
|
|
|
+ if (strict_strtoul(buf, 0, ®_addr))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if ((reg_addr % 4) != 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ar->debug.dbgfs_diag_reg = reg_addr;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations fops_diag_reg_read = {
|
|
|
+ .read = ath6kl_regread_read,
|
|
|
+ .write = ath6kl_regread_write,
|
|
|
+ .open = ath6kl_debugfs_open,
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .llseek = default_llseek,
|
|
|
+};
|
|
|
+
|
|
|
+static int ath6kl_regdump_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ struct ath6kl *ar = inode->i_private;
|
|
|
+ u8 *buf;
|
|
|
+ unsigned long int reg_len;
|
|
|
+ unsigned int len = 0, n_reg;
|
|
|
+ u32 addr;
|
|
|
+ __le32 reg_val;
|
|
|
+ int i, status;
|
|
|
+
|
|
|
+ /* Dump all the registers if no register is specified */
|
|
|
+ if (!ar->debug.dbgfs_diag_reg)
|
|
|
+ n_reg = ath6kl_get_num_reg();
|
|
|
+ else
|
|
|
+ n_reg = 1;
|
|
|
+
|
|
|
+ reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
|
|
|
+ if (n_reg > 1)
|
|
|
+ reg_len += REGTYPE_STR_LEN;
|
|
|
+
|
|
|
+ buf = vmalloc(reg_len);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (n_reg == 1) {
|
|
|
+ addr = ar->debug.dbgfs_diag_reg;
|
|
|
+
|
|
|
+ status = ath6kl_diag_read32(ar,
|
|
|
+ TARG_VTOP(ar->target_type, addr),
|
|
|
+ (u32 *)®_val);
|
|
|
+ if (status)
|
|
|
+ goto fail_reg_read;
|
|
|
+
|
|
|
+ len += scnprintf(buf + len, reg_len - len,
|
|
|
+ "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
|
|
|
+ len += scnprintf(buf + len, reg_len - len,
|
|
|
+ "%s\n", diag_reg[i].reg_info);
|
|
|
+ for (addr = diag_reg[i].reg_start;
|
|
|
+ addr <= diag_reg[i].reg_end; addr += 4) {
|
|
|
+ status = ath6kl_diag_read32(ar,
|
|
|
+ TARG_VTOP(ar->target_type, addr),
|
|
|
+ (u32 *)®_val);
|
|
|
+ if (status)
|
|
|
+ goto fail_reg_read;
|
|
|
+
|
|
|
+ len += scnprintf(buf + len, reg_len - len,
|
|
|
+ "0x%06x 0x%08x\n",
|
|
|
+ addr, le32_to_cpu(reg_val));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+done:
|
|
|
+ file->private_data = buf;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+fail_reg_read:
|
|
|
+ ath6kl_warn("Unable to read memory:%u\n", addr);
|
|
|
+ vfree(buf);
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ u8 *buf = file->private_data;
|
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
|
|
+}
|
|
|
+
|
|
|
+static int ath6kl_regdump_release(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ vfree(file->private_data);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations fops_reg_dump = {
|
|
|
+ .open = ath6kl_regdump_open,
|
|
|
+ .read = ath6kl_regdump_read,
|
|
|
+ .release = ath6kl_regdump_release,
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .llseek = default_llseek,
|
|
|
+};
|
|
|
+
|
|
|
int ath6kl_debug_init(struct ath6kl *ar)
|
|
|
{
|
|
|
ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
|
|
@@ -568,6 +754,12 @@ int ath6kl_debug_init(struct ath6kl *ar)
|
|
|
debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
|
|
|
ar, &fops_fwlog_mask);
|
|
|
|
|
|
+ debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
|
|
|
+ &fops_diag_reg_read);
|
|
|
+
|
|
|
+ debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
|
|
|
+ &fops_reg_dump);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|