diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/debug.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.c | 339 |
1 files changed, 291 insertions, 48 deletions
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3030158c478e..f3f0a80f8bab 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c | |||
@@ -17,6 +17,9 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/debugfs.h> | 19 | #include <linux/debugfs.h> |
20 | #include <linux/version.h> | ||
21 | #include <linux/vermagic.h> | ||
22 | #include <linux/vmalloc.h> | ||
20 | 23 | ||
21 | #include "core.h" | 24 | #include "core.h" |
22 | #include "debug.h" | 25 | #include "debug.h" |
@@ -24,25 +27,86 @@ | |||
24 | /* ms */ | 27 | /* ms */ |
25 | #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 | 28 | #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 |
26 | 29 | ||
27 | static int ath10k_printk(const char *level, const char *fmt, ...) | 30 | #define ATH10K_FW_CRASH_DUMP_VERSION 1 |
28 | { | ||
29 | struct va_format vaf; | ||
30 | va_list args; | ||
31 | int rtn; | ||
32 | 31 | ||
33 | va_start(args, fmt); | 32 | /** |
33 | * enum ath10k_fw_crash_dump_type - types of data in the dump file | ||
34 | * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format | ||
35 | */ | ||
36 | enum ath10k_fw_crash_dump_type { | ||
37 | ATH10K_FW_CRASH_DUMP_REGISTERS = 0, | ||
34 | 38 | ||
35 | vaf.fmt = fmt; | 39 | ATH10K_FW_CRASH_DUMP_MAX, |
36 | vaf.va = &args; | 40 | }; |
37 | 41 | ||
38 | rtn = printk("%sath10k: %pV", level, &vaf); | 42 | struct ath10k_tlv_dump_data { |
43 | /* see ath10k_fw_crash_dump_type above */ | ||
44 | __le32 type; | ||
39 | 45 | ||
40 | va_end(args); | 46 | /* in bytes */ |
47 | __le32 tlv_len; | ||
41 | 48 | ||
42 | return rtn; | 49 | /* pad to 32-bit boundaries as needed */ |
43 | } | 50 | u8 tlv_data[]; |
51 | } __packed; | ||
52 | |||
53 | struct ath10k_dump_file_data { | ||
54 | /* dump file information */ | ||
55 | |||
56 | /* "ATH10K-FW-DUMP" */ | ||
57 | char df_magic[16]; | ||
58 | |||
59 | __le32 len; | ||
60 | |||
61 | /* file dump version */ | ||
62 | __le32 version; | ||
63 | |||
64 | /* some info we can get from ath10k struct that might help */ | ||
65 | |||
66 | u8 uuid[16]; | ||
67 | |||
68 | __le32 chip_id; | ||
69 | |||
70 | /* 0 for now, in place for later hardware */ | ||
71 | __le32 bus_type; | ||
72 | |||
73 | __le32 target_version; | ||
74 | __le32 fw_version_major; | ||
75 | __le32 fw_version_minor; | ||
76 | __le32 fw_version_release; | ||
77 | __le32 fw_version_build; | ||
78 | __le32 phy_capability; | ||
79 | __le32 hw_min_tx_power; | ||
80 | __le32 hw_max_tx_power; | ||
81 | __le32 ht_cap_info; | ||
82 | __le32 vht_cap_info; | ||
83 | __le32 num_rf_chains; | ||
84 | |||
85 | /* firmware version string */ | ||
86 | char fw_ver[ETHTOOL_FWVERS_LEN]; | ||
87 | |||
88 | /* Kernel related information */ | ||
89 | |||
90 | /* time-of-day stamp */ | ||
91 | __le64 tv_sec; | ||
44 | 92 | ||
45 | int ath10k_info(const char *fmt, ...) | 93 | /* time-of-day stamp, nano-seconds */ |
94 | __le64 tv_nsec; | ||
95 | |||
96 | /* LINUX_VERSION_CODE */ | ||
97 | __le32 kernel_ver_code; | ||
98 | |||
99 | /* VERMAGIC_STRING */ | ||
100 | char kernel_ver[64]; | ||
101 | |||
102 | /* room for growth w/out changing binary format */ | ||
103 | u8 unused[128]; | ||
104 | |||
105 | /* struct ath10k_tlv_dump_data + more */ | ||
106 | u8 data[0]; | ||
107 | } __packed; | ||
108 | |||
109 | int ath10k_info(struct ath10k *ar, const char *fmt, ...) | ||
46 | { | 110 | { |
47 | struct va_format vaf = { | 111 | struct va_format vaf = { |
48 | .fmt = fmt, | 112 | .fmt = fmt, |
@@ -52,7 +116,7 @@ int ath10k_info(const char *fmt, ...) | |||
52 | 116 | ||
53 | va_start(args, fmt); | 117 | va_start(args, fmt); |
54 | vaf.va = &args; | 118 | vaf.va = &args; |
55 | ret = ath10k_printk(KERN_INFO, "%pV", &vaf); | 119 | ret = dev_info(ar->dev, "%pV", &vaf); |
56 | trace_ath10k_log_info(&vaf); | 120 | trace_ath10k_log_info(&vaf); |
57 | va_end(args); | 121 | va_end(args); |
58 | 122 | ||
@@ -60,7 +124,25 @@ int ath10k_info(const char *fmt, ...) | |||
60 | } | 124 | } |
61 | EXPORT_SYMBOL(ath10k_info); | 125 | EXPORT_SYMBOL(ath10k_info); |
62 | 126 | ||
63 | int ath10k_err(const char *fmt, ...) | 127 | void ath10k_print_driver_info(struct ath10k *ar) |
128 | { | ||
129 | ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", | ||
130 | ar->hw_params.name, | ||
131 | ar->target_version, | ||
132 | ar->chip_id, | ||
133 | ar->hw->wiphy->fw_version, | ||
134 | ar->fw_api, | ||
135 | ar->htt.target_version_major, | ||
136 | ar->htt.target_version_minor); | ||
137 | ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n", | ||
138 | config_enabled(CONFIG_ATH10K_DEBUG), | ||
139 | config_enabled(CONFIG_ATH10K_DEBUGFS), | ||
140 | config_enabled(CONFIG_ATH10K_TRACING), | ||
141 | config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); | ||
142 | } | ||
143 | EXPORT_SYMBOL(ath10k_print_driver_info); | ||
144 | |||
145 | int ath10k_err(struct ath10k *ar, const char *fmt, ...) | ||
64 | { | 146 | { |
65 | struct va_format vaf = { | 147 | struct va_format vaf = { |
66 | .fmt = fmt, | 148 | .fmt = fmt, |
@@ -70,7 +152,7 @@ int ath10k_err(const char *fmt, ...) | |||
70 | 152 | ||
71 | va_start(args, fmt); | 153 | va_start(args, fmt); |
72 | vaf.va = &args; | 154 | vaf.va = &args; |
73 | ret = ath10k_printk(KERN_ERR, "%pV", &vaf); | 155 | ret = dev_err(ar->dev, "%pV", &vaf); |
74 | trace_ath10k_log_err(&vaf); | 156 | trace_ath10k_log_err(&vaf); |
75 | va_end(args); | 157 | va_end(args); |
76 | 158 | ||
@@ -78,25 +160,21 @@ int ath10k_err(const char *fmt, ...) | |||
78 | } | 160 | } |
79 | EXPORT_SYMBOL(ath10k_err); | 161 | EXPORT_SYMBOL(ath10k_err); |
80 | 162 | ||
81 | int ath10k_warn(const char *fmt, ...) | 163 | int ath10k_warn(struct ath10k *ar, const char *fmt, ...) |
82 | { | 164 | { |
83 | struct va_format vaf = { | 165 | struct va_format vaf = { |
84 | .fmt = fmt, | 166 | .fmt = fmt, |
85 | }; | 167 | }; |
86 | va_list args; | 168 | va_list args; |
87 | int ret = 0; | ||
88 | 169 | ||
89 | va_start(args, fmt); | 170 | va_start(args, fmt); |
90 | vaf.va = &args; | 171 | vaf.va = &args; |
91 | 172 | dev_warn_ratelimited(ar->dev, "%pV", &vaf); | |
92 | if (net_ratelimit()) | ||
93 | ret = ath10k_printk(KERN_WARNING, "%pV", &vaf); | ||
94 | |||
95 | trace_ath10k_log_warn(&vaf); | 173 | trace_ath10k_log_warn(&vaf); |
96 | 174 | ||
97 | va_end(args); | 175 | va_end(args); |
98 | 176 | ||
99 | return ret; | 177 | return 0; |
100 | } | 178 | } |
101 | EXPORT_SYMBOL(ath10k_warn); | 179 | EXPORT_SYMBOL(ath10k_warn); |
102 | 180 | ||
@@ -115,9 +193,10 @@ static ssize_t ath10k_read_wmi_services(struct file *file, | |||
115 | { | 193 | { |
116 | struct ath10k *ar = file->private_data; | 194 | struct ath10k *ar = file->private_data; |
117 | char *buf; | 195 | char *buf; |
118 | unsigned int len = 0, buf_len = 1500; | 196 | unsigned int len = 0, buf_len = 4096; |
119 | const char *status; | 197 | const char *name; |
120 | ssize_t ret_cnt; | 198 | ssize_t ret_cnt; |
199 | bool enabled; | ||
121 | int i; | 200 | int i; |
122 | 201 | ||
123 | buf = kzalloc(buf_len, GFP_KERNEL); | 202 | buf = kzalloc(buf_len, GFP_KERNEL); |
@@ -129,15 +208,22 @@ static ssize_t ath10k_read_wmi_services(struct file *file, | |||
129 | if (len > buf_len) | 208 | if (len > buf_len) |
130 | len = buf_len; | 209 | len = buf_len; |
131 | 210 | ||
132 | for (i = 0; i < WMI_SERVICE_LAST; i++) { | 211 | for (i = 0; i < WMI_MAX_SERVICE; i++) { |
133 | if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i)) | 212 | enabled = test_bit(i, ar->debug.wmi_service_bitmap); |
134 | status = "enabled"; | 213 | name = wmi_service_name(i); |
135 | else | 214 | |
136 | status = "disabled"; | 215 | if (!name) { |
216 | if (enabled) | ||
217 | len += scnprintf(buf + len, buf_len - len, | ||
218 | "%-40s %s (bit %d)\n", | ||
219 | "unknown", "enabled", i); | ||
220 | |||
221 | continue; | ||
222 | } | ||
137 | 223 | ||
138 | len += scnprintf(buf + len, buf_len - len, | 224 | len += scnprintf(buf + len, buf_len - len, |
139 | "0x%02x - %20s - %s\n", | 225 | "%-40s %s\n", |
140 | i, wmi_service_name(i), status); | 226 | name, enabled ? "enabled" : "-"); |
141 | } | 227 | } |
142 | 228 | ||
143 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | 229 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); |
@@ -309,7 +395,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, | |||
309 | 395 | ||
310 | ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); | 396 | ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); |
311 | if (ret) { | 397 | if (ret) { |
312 | ath10k_warn("could not request stats (%d)\n", ret); | 398 | ath10k_warn(ar, "could not request stats (%d)\n", ret); |
313 | goto exit; | 399 | goto exit; |
314 | } | 400 | } |
315 | 401 | ||
@@ -527,11 +613,14 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, | |||
527 | } | 613 | } |
528 | 614 | ||
529 | if (!strcmp(buf, "soft")) { | 615 | if (!strcmp(buf, "soft")) { |
530 | ath10k_info("simulating soft firmware crash\n"); | 616 | ath10k_info(ar, "simulating soft firmware crash\n"); |
531 | ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); | 617 | ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); |
532 | } else if (!strcmp(buf, "hard")) { | 618 | } else if (!strcmp(buf, "hard")) { |
533 | ath10k_info("simulating hard firmware crash\n"); | 619 | ath10k_info(ar, "simulating hard firmware crash\n"); |
534 | ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, | 620 | /* 0x7fff is vdev id, and it is always out of range for all |
621 | * firmware variants in order to force a firmware crash. | ||
622 | */ | ||
623 | ret = ath10k_wmi_vdev_set_param(ar, 0x7fff, | ||
535 | ar->wmi.vdev_param->rts_threshold, 0); | 624 | ar->wmi.vdev_param->rts_threshold, 0); |
536 | } else { | 625 | } else { |
537 | ret = -EINVAL; | 626 | ret = -EINVAL; |
@@ -539,7 +628,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, | |||
539 | } | 628 | } |
540 | 629 | ||
541 | if (ret) { | 630 | if (ret) { |
542 | ath10k_warn("failed to simulate firmware crash: %d\n", ret); | 631 | ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret); |
543 | goto exit; | 632 | goto exit; |
544 | } | 633 | } |
545 | 634 | ||
@@ -577,6 +666,138 @@ static const struct file_operations fops_chip_id = { | |||
577 | .llseek = default_llseek, | 666 | .llseek = default_llseek, |
578 | }; | 667 | }; |
579 | 668 | ||
669 | struct ath10k_fw_crash_data * | ||
670 | ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) | ||
671 | { | ||
672 | struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; | ||
673 | |||
674 | lockdep_assert_held(&ar->data_lock); | ||
675 | |||
676 | crash_data->crashed_since_read = true; | ||
677 | uuid_le_gen(&crash_data->uuid); | ||
678 | getnstimeofday(&crash_data->timestamp); | ||
679 | |||
680 | return crash_data; | ||
681 | } | ||
682 | EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data); | ||
683 | |||
684 | static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar) | ||
685 | { | ||
686 | struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; | ||
687 | struct ath10k_dump_file_data *dump_data; | ||
688 | struct ath10k_tlv_dump_data *dump_tlv; | ||
689 | int hdr_len = sizeof(*dump_data); | ||
690 | unsigned int len, sofar = 0; | ||
691 | unsigned char *buf; | ||
692 | |||
693 | len = hdr_len; | ||
694 | len += sizeof(*dump_tlv) + sizeof(crash_data->registers); | ||
695 | |||
696 | sofar += hdr_len; | ||
697 | |||
698 | /* This is going to get big when we start dumping FW RAM and such, | ||
699 | * so go ahead and use vmalloc. | ||
700 | */ | ||
701 | buf = vzalloc(len); | ||
702 | if (!buf) | ||
703 | return NULL; | ||
704 | |||
705 | spin_lock_bh(&ar->data_lock); | ||
706 | |||
707 | if (!crash_data->crashed_since_read) { | ||
708 | spin_unlock_bh(&ar->data_lock); | ||
709 | vfree(buf); | ||
710 | return NULL; | ||
711 | } | ||
712 | |||
713 | dump_data = (struct ath10k_dump_file_data *)(buf); | ||
714 | strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", | ||
715 | sizeof(dump_data->df_magic)); | ||
716 | dump_data->len = cpu_to_le32(len); | ||
717 | |||
718 | dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); | ||
719 | |||
720 | memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid)); | ||
721 | dump_data->chip_id = cpu_to_le32(ar->chip_id); | ||
722 | dump_data->bus_type = cpu_to_le32(0); | ||
723 | dump_data->target_version = cpu_to_le32(ar->target_version); | ||
724 | dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major); | ||
725 | dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor); | ||
726 | dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release); | ||
727 | dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build); | ||
728 | dump_data->phy_capability = cpu_to_le32(ar->phy_capability); | ||
729 | dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power); | ||
730 | dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power); | ||
731 | dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info); | ||
732 | dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info); | ||
733 | dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains); | ||
734 | |||
735 | strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, | ||
736 | sizeof(dump_data->fw_ver)); | ||
737 | |||
738 | dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE); | ||
739 | strlcpy(dump_data->kernel_ver, VERMAGIC_STRING, | ||
740 | sizeof(dump_data->kernel_ver)); | ||
741 | |||
742 | dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); | ||
743 | dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); | ||
744 | |||
745 | /* Gather crash-dump */ | ||
746 | dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); | ||
747 | dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); | ||
748 | dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); | ||
749 | memcpy(dump_tlv->tlv_data, &crash_data->registers, | ||
750 | sizeof(crash_data->registers)); | ||
751 | sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); | ||
752 | |||
753 | ar->debug.fw_crash_data->crashed_since_read = false; | ||
754 | |||
755 | spin_unlock_bh(&ar->data_lock); | ||
756 | |||
757 | return dump_data; | ||
758 | } | ||
759 | |||
760 | static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file) | ||
761 | { | ||
762 | struct ath10k *ar = inode->i_private; | ||
763 | struct ath10k_dump_file_data *dump; | ||
764 | |||
765 | dump = ath10k_build_dump_file(ar); | ||
766 | if (!dump) | ||
767 | return -ENODATA; | ||
768 | |||
769 | file->private_data = dump; | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static ssize_t ath10k_fw_crash_dump_read(struct file *file, | ||
775 | char __user *user_buf, | ||
776 | size_t count, loff_t *ppos) | ||
777 | { | ||
778 | struct ath10k_dump_file_data *dump_file = file->private_data; | ||
779 | |||
780 | return simple_read_from_buffer(user_buf, count, ppos, | ||
781 | dump_file, | ||
782 | le32_to_cpu(dump_file->len)); | ||
783 | } | ||
784 | |||
785 | static int ath10k_fw_crash_dump_release(struct inode *inode, | ||
786 | struct file *file) | ||
787 | { | ||
788 | vfree(file->private_data); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static const struct file_operations fops_fw_crash_dump = { | ||
794 | .open = ath10k_fw_crash_dump_open, | ||
795 | .read = ath10k_fw_crash_dump_read, | ||
796 | .release = ath10k_fw_crash_dump_release, | ||
797 | .owner = THIS_MODULE, | ||
798 | .llseek = default_llseek, | ||
799 | }; | ||
800 | |||
580 | static int ath10k_debug_htt_stats_req(struct ath10k *ar) | 801 | static int ath10k_debug_htt_stats_req(struct ath10k *ar) |
581 | { | 802 | { |
582 | u64 cookie; | 803 | u64 cookie; |
@@ -596,7 +817,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar) | |||
596 | ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, | 817 | ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, |
597 | cookie); | 818 | cookie); |
598 | if (ret) { | 819 | if (ret) { |
599 | ath10k_warn("failed to send htt stats request: %d\n", ret); | 820 | ath10k_warn(ar, "failed to send htt stats request: %d\n", ret); |
600 | return ret; | 821 | return ret; |
601 | } | 822 | } |
602 | 823 | ||
@@ -770,7 +991,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, | |||
770 | if (ar->state == ATH10K_STATE_ON) { | 991 | if (ar->state == ATH10K_STATE_ON) { |
771 | ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); | 992 | ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); |
772 | if (ret) { | 993 | if (ret) { |
773 | ath10k_warn("dbglog cfg failed from debugfs: %d\n", | 994 | ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", |
774 | ret); | 995 | ret); |
775 | goto exit; | 996 | goto exit; |
776 | } | 997 | } |
@@ -801,13 +1022,14 @@ int ath10k_debug_start(struct ath10k *ar) | |||
801 | ret = ath10k_debug_htt_stats_req(ar); | 1022 | ret = ath10k_debug_htt_stats_req(ar); |
802 | if (ret) | 1023 | if (ret) |
803 | /* continue normally anyway, this isn't serious */ | 1024 | /* continue normally anyway, this isn't serious */ |
804 | ath10k_warn("failed to start htt stats workqueue: %d\n", ret); | 1025 | ath10k_warn(ar, "failed to start htt stats workqueue: %d\n", |
1026 | ret); | ||
805 | 1027 | ||
806 | if (ar->debug.fw_dbglog_mask) { | 1028 | if (ar->debug.fw_dbglog_mask) { |
807 | ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); | 1029 | ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); |
808 | if (ret) | 1030 | if (ret) |
809 | /* not serious */ | 1031 | /* not serious */ |
810 | ath10k_warn("failed to enable dbglog during start: %d", | 1032 | ath10k_warn(ar, "failed to enable dbglog during start: %d", |
811 | ret); | 1033 | ret); |
812 | } | 1034 | } |
813 | 1035 | ||
@@ -910,11 +1132,20 @@ static const struct file_operations fops_dfs_stats = { | |||
910 | 1132 | ||
911 | int ath10k_debug_create(struct ath10k *ar) | 1133 | int ath10k_debug_create(struct ath10k *ar) |
912 | { | 1134 | { |
1135 | int ret; | ||
1136 | |||
1137 | ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); | ||
1138 | if (!ar->debug.fw_crash_data) { | ||
1139 | ret = -ENOMEM; | ||
1140 | goto err; | ||
1141 | } | ||
1142 | |||
913 | ar->debug.debugfs_phy = debugfs_create_dir("ath10k", | 1143 | ar->debug.debugfs_phy = debugfs_create_dir("ath10k", |
914 | ar->hw->wiphy->debugfsdir); | 1144 | ar->hw->wiphy->debugfsdir); |
915 | 1145 | if (!ar->debug.debugfs_phy) { | |
916 | if (!ar->debug.debugfs_phy) | 1146 | ret = -ENOMEM; |
917 | return -ENOMEM; | 1147 | goto err_free_fw_crash_data; |
1148 | } | ||
918 | 1149 | ||
919 | INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, | 1150 | INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, |
920 | ath10k_debug_htt_stats_dwork); | 1151 | ath10k_debug_htt_stats_dwork); |
@@ -930,6 +1161,9 @@ int ath10k_debug_create(struct ath10k *ar) | |||
930 | debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, | 1161 | debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, |
931 | ar, &fops_simulate_fw_crash); | 1162 | ar, &fops_simulate_fw_crash); |
932 | 1163 | ||
1164 | debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, | ||
1165 | ar, &fops_fw_crash_dump); | ||
1166 | |||
933 | debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, | 1167 | debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, |
934 | ar, &fops_chip_id); | 1168 | ar, &fops_chip_id); |
935 | 1169 | ||
@@ -958,17 +1192,25 @@ int ath10k_debug_create(struct ath10k *ar) | |||
958 | } | 1192 | } |
959 | 1193 | ||
960 | return 0; | 1194 | return 0; |
1195 | |||
1196 | err_free_fw_crash_data: | ||
1197 | vfree(ar->debug.fw_crash_data); | ||
1198 | |||
1199 | err: | ||
1200 | return ret; | ||
961 | } | 1201 | } |
962 | 1202 | ||
963 | void ath10k_debug_destroy(struct ath10k *ar) | 1203 | void ath10k_debug_destroy(struct ath10k *ar) |
964 | { | 1204 | { |
1205 | vfree(ar->debug.fw_crash_data); | ||
965 | cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); | 1206 | cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); |
966 | } | 1207 | } |
967 | 1208 | ||
968 | #endif /* CONFIG_ATH10K_DEBUGFS */ | 1209 | #endif /* CONFIG_ATH10K_DEBUGFS */ |
969 | 1210 | ||
970 | #ifdef CONFIG_ATH10K_DEBUG | 1211 | #ifdef CONFIG_ATH10K_DEBUG |
971 | void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) | 1212 | void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask, |
1213 | const char *fmt, ...) | ||
972 | { | 1214 | { |
973 | struct va_format vaf; | 1215 | struct va_format vaf; |
974 | va_list args; | 1216 | va_list args; |
@@ -979,7 +1221,7 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) | |||
979 | vaf.va = &args; | 1221 | vaf.va = &args; |
980 | 1222 | ||
981 | if (ath10k_debug_mask & mask) | 1223 | if (ath10k_debug_mask & mask) |
982 | ath10k_printk(KERN_DEBUG, "%pV", &vaf); | 1224 | dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf); |
983 | 1225 | ||
984 | trace_ath10k_log_dbg(mask, &vaf); | 1226 | trace_ath10k_log_dbg(mask, &vaf); |
985 | 1227 | ||
@@ -987,13 +1229,14 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...) | |||
987 | } | 1229 | } |
988 | EXPORT_SYMBOL(ath10k_dbg); | 1230 | EXPORT_SYMBOL(ath10k_dbg); |
989 | 1231 | ||
990 | void ath10k_dbg_dump(enum ath10k_debug_mask mask, | 1232 | void ath10k_dbg_dump(struct ath10k *ar, |
1233 | enum ath10k_debug_mask mask, | ||
991 | const char *msg, const char *prefix, | 1234 | const char *msg, const char *prefix, |
992 | const void *buf, size_t len) | 1235 | const void *buf, size_t len) |
993 | { | 1236 | { |
994 | if (ath10k_debug_mask & mask) { | 1237 | if (ath10k_debug_mask & mask) { |
995 | if (msg) | 1238 | if (msg) |
996 | ath10k_dbg(mask, "%s\n", msg); | 1239 | ath10k_dbg(ar, mask, "%s\n", msg); |
997 | 1240 | ||
998 | print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); | 1241 | print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); |
999 | } | 1242 | } |