blob: d922ef4574985bb90ba01334e65a8e73f8a04030 [file] [log] [blame]
Kalle Valo5e3dd152013-06-12 20:52:10 +03001/*
2 * Copyright (c) 2005-2011 Atheros Communications Inc.
3 * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <linux/module.h>
19#include <linux/debugfs.h>
Ben Greear384914b2014-08-25 08:37:32 +030020#include <linux/version.h>
21#include <linux/vermagic.h>
22#include <linux/vmalloc.h>
Kalle Valo5e3dd152013-06-12 20:52:10 +030023
24#include "core.h"
25#include "debug.h"
26
Kalle Valoa3d135e2013-09-03 11:44:10 +030027/* ms */
28#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
29
Ben Greear384914b2014-08-25 08:37:32 +030030#define ATH10K_FW_CRASH_DUMP_VERSION 1
31
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 */
36enum ath10k_fw_crash_dump_type {
37 ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
38
39 ATH10K_FW_CRASH_DUMP_MAX,
40};
41
42struct ath10k_tlv_dump_data {
43 /* see ath10k_fw_crash_dump_type above */
44 __le32 type;
45
46 /* in bytes */
47 __le32 tlv_len;
48
49 /* pad to 32-bit boundaries as needed */
50 u8 tlv_data[];
51} __packed;
52
53struct 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;
92
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
Michal Kazior7aa7a722014-08-25 12:09:38 +0200109int ath10k_info(struct ath10k *ar, const char *fmt, ...)
Kalle Valo5e3dd152013-06-12 20:52:10 +0300110{
111 struct va_format vaf = {
112 .fmt = fmt,
113 };
114 va_list args;
115 int ret;
116
117 va_start(args, fmt);
118 vaf.va = &args;
Michal Kazior7aa7a722014-08-25 12:09:38 +0200119 ret = dev_info(ar->dev, "%pV", &vaf);
Michal Kaziord35a6c12014-09-02 11:00:21 +0300120 trace_ath10k_log_info(ar, &vaf);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300121 va_end(args);
122
123 return ret;
124}
125EXPORT_SYMBOL(ath10k_info);
126
Kalle Valo8a0c7972014-08-25 08:37:45 +0300127void ath10k_print_driver_info(struct ath10k *ar)
128{
Michal Kazior7aa7a722014-08-25 12:09:38 +0200129 ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
Kalle Valo8a0c7972014-08-25 08:37:45 +0300130 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);
Michal Kazior7aa7a722014-08-25 12:09:38 +0200137 ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n",
Kalle Valo8a0c7972014-08-25 08:37:45 +0300138 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}
143EXPORT_SYMBOL(ath10k_print_driver_info);
144
Michal Kazior7aa7a722014-08-25 12:09:38 +0200145int ath10k_err(struct ath10k *ar, const char *fmt, ...)
Kalle Valo5e3dd152013-06-12 20:52:10 +0300146{
147 struct va_format vaf = {
148 .fmt = fmt,
149 };
150 va_list args;
151 int ret;
152
153 va_start(args, fmt);
154 vaf.va = &args;
Michal Kazior7aa7a722014-08-25 12:09:38 +0200155 ret = dev_err(ar->dev, "%pV", &vaf);
Michal Kaziord35a6c12014-09-02 11:00:21 +0300156 trace_ath10k_log_err(ar, &vaf);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300157 va_end(args);
158
159 return ret;
160}
161EXPORT_SYMBOL(ath10k_err);
162
Michal Kazior7aa7a722014-08-25 12:09:38 +0200163int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
Kalle Valo5e3dd152013-06-12 20:52:10 +0300164{
165 struct va_format vaf = {
166 .fmt = fmt,
167 };
168 va_list args;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300169
170 va_start(args, fmt);
171 vaf.va = &args;
Michal Kazior7aa7a722014-08-25 12:09:38 +0200172 dev_warn_ratelimited(ar->dev, "%pV", &vaf);
Michal Kaziord35a6c12014-09-02 11:00:21 +0300173 trace_ath10k_log_warn(ar, &vaf);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300174
175 va_end(args);
176
Michal Kazior7aa7a722014-08-25 12:09:38 +0200177 return 0;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300178}
179EXPORT_SYMBOL(ath10k_warn);
180
181#ifdef CONFIG_ATH10K_DEBUGFS
182
183void ath10k_debug_read_service_map(struct ath10k *ar,
184 void *service_map,
185 size_t map_size)
186{
187 memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
188}
189
190static ssize_t ath10k_read_wmi_services(struct file *file,
191 char __user *user_buf,
192 size_t count, loff_t *ppos)
193{
194 struct ath10k *ar = file->private_data;
195 char *buf;
Michal Kaziorcff990c2014-08-04 09:18:33 +0300196 unsigned int len = 0, buf_len = 4096;
197 const char *name;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300198 ssize_t ret_cnt;
Michal Kaziorcff990c2014-08-04 09:18:33 +0300199 bool enabled;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300200 int i;
201
202 buf = kzalloc(buf_len, GFP_KERNEL);
203 if (!buf)
204 return -ENOMEM;
205
206 mutex_lock(&ar->conf_mutex);
207
208 if (len > buf_len)
209 len = buf_len;
210
Michal Kaziorcff990c2014-08-04 09:18:33 +0300211 for (i = 0; i < WMI_MAX_SERVICE; i++) {
212 enabled = test_bit(i, ar->debug.wmi_service_bitmap);
213 name = wmi_service_name(i);
214
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 }
Kalle Valo5e3dd152013-06-12 20:52:10 +0300223
224 len += scnprintf(buf + len, buf_len - len,
Michal Kaziorcff990c2014-08-04 09:18:33 +0300225 "%-40s %s\n",
226 name, enabled ? "enabled" : "-");
Kalle Valo5e3dd152013-06-12 20:52:10 +0300227 }
228
229 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
230
231 mutex_unlock(&ar->conf_mutex);
232
233 kfree(buf);
234 return ret_cnt;
235}
236
237static const struct file_operations fops_wmi_services = {
238 .read = ath10k_read_wmi_services,
239 .open = simple_open,
240 .owner = THIS_MODULE,
241 .llseek = default_llseek,
242};
243
244void ath10k_debug_read_target_stats(struct ath10k *ar,
245 struct wmi_stats_event *ev)
246{
247 u8 *tmp = ev->data;
248 struct ath10k_target_stats *stats;
249 int num_pdev_stats, num_vdev_stats, num_peer_stats;
Chun-Yeow Yeoh52e346d2014-03-28 14:35:16 +0200250 struct wmi_pdev_stats_10x *ps;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300251 int i;
252
Michal Kazior87571bf2013-07-16 09:38:59 +0200253 spin_lock_bh(&ar->data_lock);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300254
255 stats = &ar->debug.target_stats;
256
257 num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
258 num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
259 num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
260
261 if (num_pdev_stats) {
Chun-Yeow Yeoh52e346d2014-03-28 14:35:16 +0200262 ps = (struct wmi_pdev_stats_10x *)tmp;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300263
264 stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
265 stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
266 stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
267 stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
268 stats->cycle_count = __le32_to_cpu(ps->cycle_count);
269 stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
270 stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
271
272 stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
273 stats->comp_delivered =
274 __le32_to_cpu(ps->wal.tx.comp_delivered);
275 stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
276 stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
277 stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
278 stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
279 stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
280 stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
281 stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
282 stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
283 stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
284 stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
285 stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
286 stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
287 stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
288 stats->sw_retry_failure =
289 __le32_to_cpu(ps->wal.tx.sw_retry_failure);
290 stats->illgl_rate_phy_err =
291 __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
292 stats->pdev_cont_xretry =
293 __le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
294 stats->pdev_tx_timeout =
295 __le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
296 stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
297 stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
298 stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
299
300 stats->mid_ppdu_route_change =
301 __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
302 stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
303 stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
304 stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
305 stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
306 stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
307 stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
308 stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
309 stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
310 stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
311 stats->oversize_amsdu =
312 __le32_to_cpu(ps->wal.rx.oversize_amsdu);
313 stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
314 stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
315 stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
316
Chun-Yeow Yeoh52e346d2014-03-28 14:35:16 +0200317 if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
318 ar->fw_features)) {
319 stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
320 stats->rts_bad = __le32_to_cpu(ps->rts_bad);
321 stats->rts_good = __le32_to_cpu(ps->rts_good);
322 stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
323 stats->no_beacons = __le32_to_cpu(ps->no_beacons);
324 stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
325 tmp += sizeof(struct wmi_pdev_stats_10x);
326 } else {
327 tmp += sizeof(struct wmi_pdev_stats_old);
328 }
Kalle Valo5e3dd152013-06-12 20:52:10 +0300329 }
330
331 /* 0 or max vdevs */
332 /* Currently firmware does not support VDEV stats */
333 if (num_vdev_stats) {
334 struct wmi_vdev_stats *vdev_stats;
335
336 for (i = 0; i < num_vdev_stats; i++) {
337 vdev_stats = (struct wmi_vdev_stats *)tmp;
338 tmp += sizeof(struct wmi_vdev_stats);
339 }
340 }
341
342 if (num_peer_stats) {
Ben Greear23c3aae2014-03-28 14:35:15 +0200343 struct wmi_peer_stats_10x *peer_stats;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300344 struct ath10k_peer_stat *s;
345
346 stats->peers = num_peer_stats;
347
348 for (i = 0; i < num_peer_stats; i++) {
Ben Greear23c3aae2014-03-28 14:35:15 +0200349 peer_stats = (struct wmi_peer_stats_10x *)tmp;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300350 s = &stats->peer_stat[i];
351
Chun-Yeow Yeohcf0fd562014-03-21 17:46:58 +0200352 memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
353 ETH_ALEN);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300354 s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
355 s->peer_tx_rate =
356 __le32_to_cpu(peer_stats->peer_tx_rate);
Ben Greear23c3aae2014-03-28 14:35:15 +0200357 if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
358 ar->fw_features)) {
359 s->peer_rx_rate =
360 __le32_to_cpu(peer_stats->peer_rx_rate);
361 tmp += sizeof(struct wmi_peer_stats_10x);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300362
Ben Greear23c3aae2014-03-28 14:35:15 +0200363 } else {
364 tmp += sizeof(struct wmi_peer_stats_old);
365 }
Kalle Valo5e3dd152013-06-12 20:52:10 +0300366 }
367 }
368
Michal Kazior87571bf2013-07-16 09:38:59 +0200369 spin_unlock_bh(&ar->data_lock);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300370 complete(&ar->debug.event_stats_compl);
371}
372
373static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
374 size_t count, loff_t *ppos)
375{
376 struct ath10k *ar = file->private_data;
377 struct ath10k_target_stats *fw_stats;
Michal Kazior87571bf2013-07-16 09:38:59 +0200378 char *buf = NULL;
Ben Greear23c3aae2014-03-28 14:35:15 +0200379 unsigned int len = 0, buf_len = 8000;
Michal Kazior87571bf2013-07-16 09:38:59 +0200380 ssize_t ret_cnt = 0;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300381 long left;
382 int i;
383 int ret;
384
385 fw_stats = &ar->debug.target_stats;
386
Michal Kazior87571bf2013-07-16 09:38:59 +0200387 mutex_lock(&ar->conf_mutex);
388
389 if (ar->state != ATH10K_STATE_ON)
390 goto exit;
391
Kalle Valo5e3dd152013-06-12 20:52:10 +0300392 buf = kzalloc(buf_len, GFP_KERNEL);
393 if (!buf)
Michal Kazior87571bf2013-07-16 09:38:59 +0200394 goto exit;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300395
396 ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
397 if (ret) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200398 ath10k_warn(ar, "could not request stats (%d)\n", ret);
Michal Kazior87571bf2013-07-16 09:38:59 +0200399 goto exit;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300400 }
401
402 left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
Michal Kazior87571bf2013-07-16 09:38:59 +0200403 if (left <= 0)
404 goto exit;
Kalle Valo5e3dd152013-06-12 20:52:10 +0300405
Michal Kazior87571bf2013-07-16 09:38:59 +0200406 spin_lock_bh(&ar->data_lock);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300407 len += scnprintf(buf + len, buf_len - len, "\n");
408 len += scnprintf(buf + len, buf_len - len, "%30s\n",
409 "ath10k PDEV stats");
410 len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
411 "=================");
412
413 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
414 "Channel noise floor", fw_stats->ch_noise_floor);
415 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
416 "Channel TX power", fw_stats->chan_tx_power);
417 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
418 "TX frame count", fw_stats->tx_frame_count);
419 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
420 "RX frame count", fw_stats->rx_frame_count);
421 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
422 "RX clear count", fw_stats->rx_clear_count);
423 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
424 "Cycle count", fw_stats->cycle_count);
425 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
426 "PHY error count", fw_stats->phy_err_count);
Chun-Yeow Yeoh52e346d2014-03-28 14:35:16 +0200427 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
428 "RTS bad count", fw_stats->rts_bad);
429 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
430 "RTS good count", fw_stats->rts_good);
431 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
432 "FCS bad count", fw_stats->fcs_bad);
433 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
434 "No beacon count", fw_stats->no_beacons);
435 len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
436 "MIB int count", fw_stats->mib_int_count);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300437
438 len += scnprintf(buf + len, buf_len - len, "\n");
439 len += scnprintf(buf + len, buf_len - len, "%30s\n",
440 "ath10k PDEV TX stats");
441 len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
442 "=================");
443
444 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
445 "HTT cookies queued", fw_stats->comp_queued);
446 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
447 "HTT cookies disp.", fw_stats->comp_delivered);
448 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
449 "MSDU queued", fw_stats->msdu_enqued);
450 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
451 "MPDU queued", fw_stats->mpdu_enqued);
452 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
453 "MSDUs dropped", fw_stats->wmm_drop);
454 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
455 "Local enqued", fw_stats->local_enqued);
456 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
457 "Local freed", fw_stats->local_freed);
458 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
459 "HW queued", fw_stats->hw_queued);
460 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
461 "PPDUs reaped", fw_stats->hw_reaped);
462 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
463 "Num underruns", fw_stats->underrun);
464 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
465 "PPDUs cleaned", fw_stats->tx_abort);
466 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
467 "MPDUs requed", fw_stats->mpdus_requed);
468 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
469 "Excessive retries", fw_stats->tx_ko);
470 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
471 "HW rate", fw_stats->data_rc);
472 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
473 "Sched self tiggers", fw_stats->self_triggers);
474 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
475 "Dropped due to SW retries",
476 fw_stats->sw_retry_failure);
477 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
478 "Illegal rate phy errors",
479 fw_stats->illgl_rate_phy_err);
480 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
481 "Pdev continous xretry", fw_stats->pdev_cont_xretry);
482 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
483 "TX timeout", fw_stats->pdev_tx_timeout);
484 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
485 "PDEV resets", fw_stats->pdev_resets);
486 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
487 "PHY underrun", fw_stats->phy_underrun);
488 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
489 "MPDU is more than txop limit", fw_stats->txop_ovf);
490
491 len += scnprintf(buf + len, buf_len - len, "\n");
492 len += scnprintf(buf + len, buf_len - len, "%30s\n",
493 "ath10k PDEV RX stats");
494 len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
495 "=================");
496
497 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
498 "Mid PPDU route change",
499 fw_stats->mid_ppdu_route_change);
500 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
501 "Tot. number of statuses", fw_stats->status_rcvd);
502 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
503 "Extra frags on rings 0", fw_stats->r0_frags);
504 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
505 "Extra frags on rings 1", fw_stats->r1_frags);
506 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
507 "Extra frags on rings 2", fw_stats->r2_frags);
508 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
509 "Extra frags on rings 3", fw_stats->r3_frags);
510 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
511 "MSDUs delivered to HTT", fw_stats->htt_msdus);
512 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
513 "MPDUs delivered to HTT", fw_stats->htt_mpdus);
514 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
515 "MSDUs delivered to stack", fw_stats->loc_msdus);
516 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
517 "MPDUs delivered to stack", fw_stats->loc_mpdus);
518 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
519 "Oversized AMSUs", fw_stats->oversize_amsdu);
520 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
521 "PHY errors", fw_stats->phy_errs);
522 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
523 "PHY errors drops", fw_stats->phy_err_drop);
524 len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
525 "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
526
527 len += scnprintf(buf + len, buf_len - len, "\n");
Ben Greear23c3aae2014-03-28 14:35:15 +0200528 len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
529 "ath10k PEER stats", fw_stats->peers);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300530 len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
531 "=================");
532
533 for (i = 0; i < fw_stats->peers; i++) {
534 len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
535 "Peer MAC address",
536 fw_stats->peer_stat[i].peer_macaddr);
537 len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
538 "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
539 len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
540 "Peer TX rate",
541 fw_stats->peer_stat[i].peer_tx_rate);
Ben Greear23c3aae2014-03-28 14:35:15 +0200542 len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
543 "Peer RX rate",
544 fw_stats->peer_stat[i].peer_rx_rate);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300545 len += scnprintf(buf + len, buf_len - len, "\n");
546 }
Michal Kazior87571bf2013-07-16 09:38:59 +0200547 spin_unlock_bh(&ar->data_lock);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300548
549 if (len > buf_len)
550 len = buf_len;
551
552 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
553
Michal Kazior87571bf2013-07-16 09:38:59 +0200554exit:
Kalle Valo5e3dd152013-06-12 20:52:10 +0300555 mutex_unlock(&ar->conf_mutex);
Kalle Valo5e3dd152013-06-12 20:52:10 +0300556 kfree(buf);
557 return ret_cnt;
558}
559
560static const struct file_operations fops_fw_stats = {
561 .read = ath10k_read_fw_stats,
562 .open = simple_open,
563 .owner = THIS_MODULE,
564 .llseek = default_llseek,
565};
566
Michal Kazior278c4a82013-07-22 14:08:51 +0200567static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
568 char __user *user_buf,
569 size_t count, loff_t *ppos)
570{
Marek Puzyniak8c656992014-03-21 17:46:56 +0200571 const char buf[] = "To simulate firmware crash write one of the"
572 " keywords to this file:\n `soft` - this will send"
573 " WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
574 " supports that command.\n `hard` - this will send"
575 " to firmware command with illegal parameters"
576 " causing firmware crash.\n";
577
Michal Kazior278c4a82013-07-22 14:08:51 +0200578 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
579}
580
Marek Puzyniak8c656992014-03-21 17:46:56 +0200581/* Simulate firmware crash:
582 * 'soft': Call wmi command causing firmware hang. This firmware hang is
583 * recoverable by warm firmware reset.
584 * 'hard': Force firmware crash by setting any vdev parameter for not allowed
585 * vdev id. This is hard firmware crash because it is recoverable only by cold
586 * firmware reset.
587 */
Michal Kazior278c4a82013-07-22 14:08:51 +0200588static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
589 const char __user *user_buf,
590 size_t count, loff_t *ppos)
591{
592 struct ath10k *ar = file->private_data;
Marek Puzyniak8c656992014-03-21 17:46:56 +0200593 char buf[32];
Michal Kazior278c4a82013-07-22 14:08:51 +0200594 int ret;
595
596 mutex_lock(&ar->conf_mutex);
597
598 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
Marek Puzyniak8c656992014-03-21 17:46:56 +0200599
600 /* make sure that buf is null terminated */
601 buf[sizeof(buf) - 1] = 0;
Michal Kazior278c4a82013-07-22 14:08:51 +0200602
603 if (ar->state != ATH10K_STATE_ON &&
604 ar->state != ATH10K_STATE_RESTARTED) {
605 ret = -ENETDOWN;
606 goto exit;
607 }
608
Marek Puzyniak8c656992014-03-21 17:46:56 +0200609 /* drop the possible '\n' from the end */
610 if (buf[count - 1] == '\n') {
611 buf[count - 1] = 0;
612 count--;
613 }
Michal Kazior278c4a82013-07-22 14:08:51 +0200614
Marek Puzyniak8c656992014-03-21 17:46:56 +0200615 if (!strcmp(buf, "soft")) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200616 ath10k_info(ar, "simulating soft firmware crash\n");
Marek Puzyniak8c656992014-03-21 17:46:56 +0200617 ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
618 } else if (!strcmp(buf, "hard")) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200619 ath10k_info(ar, "simulating hard firmware crash\n");
Ben Greear611b3682014-07-25 11:56:40 +0300620 /* 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,
Marek Puzyniak8c656992014-03-21 17:46:56 +0200624 ar->wmi.vdev_param->rts_threshold, 0);
625 } else {
626 ret = -EINVAL;
627 goto exit;
628 }
Michal Kazior278c4a82013-07-22 14:08:51 +0200629
Marek Puzyniak8c656992014-03-21 17:46:56 +0200630 if (ret) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200631 ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
Marek Puzyniak8c656992014-03-21 17:46:56 +0200632 goto exit;
633 }
634
635 ret = count;
Michal Kazior278c4a82013-07-22 14:08:51 +0200636
637exit:
638 mutex_unlock(&ar->conf_mutex);
639 return ret;
640}
641
642static const struct file_operations fops_simulate_fw_crash = {
643 .read = ath10k_read_simulate_fw_crash,
644 .write = ath10k_write_simulate_fw_crash,
645 .open = simple_open,
646 .owner = THIS_MODULE,
647 .llseek = default_llseek,
648};
649
Kalle Valo763b8cd2013-09-01 11:22:21 +0300650static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
651 size_t count, loff_t *ppos)
652{
653 struct ath10k *ar = file->private_data;
654 unsigned int len;
655 char buf[50];
656
657 len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
658
659 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
660}
661
662static const struct file_operations fops_chip_id = {
663 .read = ath10k_read_chip_id,
664 .open = simple_open,
665 .owner = THIS_MODULE,
666 .llseek = default_llseek,
667};
668
Ben Greear384914b2014-08-25 08:37:32 +0300669struct ath10k_fw_crash_data *
670ath10k_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}
682EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
683
684static 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
760static 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
774static 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
785static 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
793static 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
Kalle Valoa3d135e2013-09-03 11:44:10 +0300801static int ath10k_debug_htt_stats_req(struct ath10k *ar)
802{
803 u64 cookie;
804 int ret;
805
806 lockdep_assert_held(&ar->conf_mutex);
807
808 if (ar->debug.htt_stats_mask == 0)
809 /* htt stats are disabled */
810 return 0;
811
812 if (ar->state != ATH10K_STATE_ON)
813 return 0;
814
815 cookie = get_jiffies_64();
816
817 ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
818 cookie);
819 if (ret) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200820 ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
Kalle Valoa3d135e2013-09-03 11:44:10 +0300821 return ret;
822 }
823
824 queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,
825 msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));
826
827 return 0;
828}
829
830static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
831{
832 struct ath10k *ar = container_of(work, struct ath10k,
833 debug.htt_stats_dwork.work);
834
835 mutex_lock(&ar->conf_mutex);
836
837 ath10k_debug_htt_stats_req(ar);
838
839 mutex_unlock(&ar->conf_mutex);
840}
841
842static ssize_t ath10k_read_htt_stats_mask(struct file *file,
843 char __user *user_buf,
844 size_t count, loff_t *ppos)
845{
846 struct ath10k *ar = file->private_data;
847 char buf[32];
848 unsigned int len;
849
850 len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
851
852 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
853}
854
855static ssize_t ath10k_write_htt_stats_mask(struct file *file,
856 const char __user *user_buf,
857 size_t count, loff_t *ppos)
858{
859 struct ath10k *ar = file->private_data;
860 unsigned long mask;
861 int ret;
862
863 ret = kstrtoul_from_user(user_buf, count, 0, &mask);
864 if (ret)
865 return ret;
866
867 /* max 8 bit masks (for now) */
868 if (mask > 0xff)
869 return -E2BIG;
870
871 mutex_lock(&ar->conf_mutex);
872
873 ar->debug.htt_stats_mask = mask;
874
875 ret = ath10k_debug_htt_stats_req(ar);
876 if (ret)
877 goto out;
878
879 ret = count;
880
881out:
882 mutex_unlock(&ar->conf_mutex);
883
884 return ret;
885}
886
887static const struct file_operations fops_htt_stats_mask = {
888 .read = ath10k_read_htt_stats_mask,
889 .write = ath10k_write_htt_stats_mask,
890 .open = simple_open,
891 .owner = THIS_MODULE,
892 .llseek = default_llseek,
893};
894
Janusz Dziedzicd3856232014-06-02 21:19:46 +0300895static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
896 char __user *user_buf,
897 size_t count, loff_t *ppos)
898{
899 struct ath10k *ar = file->private_data;
900 char buf[64];
901 u8 amsdu = 3, ampdu = 64;
902 unsigned int len;
903
904 mutex_lock(&ar->conf_mutex);
905
906 if (ar->debug.htt_max_amsdu)
907 amsdu = ar->debug.htt_max_amsdu;
908
909 if (ar->debug.htt_max_ampdu)
910 ampdu = ar->debug.htt_max_ampdu;
911
912 mutex_unlock(&ar->conf_mutex);
913
914 len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);
915
916 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
917}
918
919static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,
920 const char __user *user_buf,
921 size_t count, loff_t *ppos)
922{
923 struct ath10k *ar = file->private_data;
924 int res;
925 char buf[64];
926 unsigned int amsdu, ampdu;
927
928 simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
929
930 /* make sure that buf is null terminated */
931 buf[sizeof(buf) - 1] = 0;
932
933 res = sscanf(buf, "%u %u", &amsdu, &ampdu);
934
935 if (res != 2)
936 return -EINVAL;
937
938 mutex_lock(&ar->conf_mutex);
939
940 res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);
941 if (res)
942 goto out;
943
944 res = count;
945 ar->debug.htt_max_amsdu = amsdu;
946 ar->debug.htt_max_ampdu = ampdu;
947
948out:
949 mutex_unlock(&ar->conf_mutex);
950 return res;
951}
952
953static const struct file_operations fops_htt_max_amsdu_ampdu = {
954 .read = ath10k_read_htt_max_amsdu_ampdu,
955 .write = ath10k_write_htt_max_amsdu_ampdu,
956 .open = simple_open,
957 .owner = THIS_MODULE,
958 .llseek = default_llseek,
959};
960
Kalle Valof118a3e2014-01-03 12:59:31 +0200961static ssize_t ath10k_read_fw_dbglog(struct file *file,
962 char __user *user_buf,
963 size_t count, loff_t *ppos)
964{
965 struct ath10k *ar = file->private_data;
966 unsigned int len;
967 char buf[32];
968
969 len = scnprintf(buf, sizeof(buf), "0x%08x\n",
970 ar->debug.fw_dbglog_mask);
971
972 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
973}
974
975static ssize_t ath10k_write_fw_dbglog(struct file *file,
976 const char __user *user_buf,
977 size_t count, loff_t *ppos)
978{
979 struct ath10k *ar = file->private_data;
980 unsigned long mask;
981 int ret;
982
983 ret = kstrtoul_from_user(user_buf, count, 0, &mask);
984 if (ret)
985 return ret;
986
987 mutex_lock(&ar->conf_mutex);
988
989 ar->debug.fw_dbglog_mask = mask;
990
991 if (ar->state == ATH10K_STATE_ON) {
992 ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
993 if (ret) {
Michal Kazior7aa7a722014-08-25 12:09:38 +0200994 ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
Kalle Valof118a3e2014-01-03 12:59:31 +0200995 ret);
996 goto exit;
997 }
998 }
999
1000 ret = count;
1001
1002exit:
1003 mutex_unlock(&ar->conf_mutex);
1004
1005 return ret;
1006}
1007
1008static const struct file_operations fops_fw_dbglog = {
1009 .read = ath10k_read_fw_dbglog,
1010 .write = ath10k_write_fw_dbglog,
1011 .open = simple_open,
1012 .owner = THIS_MODULE,
1013 .llseek = default_llseek,
1014};
1015
Kalle Valodb66ea02013-09-03 11:44:03 +03001016int ath10k_debug_start(struct ath10k *ar)
1017{
Kalle Valoa3d135e2013-09-03 11:44:10 +03001018 int ret;
1019
Kalle Valo60631c52013-10-08 21:45:25 +03001020 lockdep_assert_held(&ar->conf_mutex);
1021
Kalle Valoa3d135e2013-09-03 11:44:10 +03001022 ret = ath10k_debug_htt_stats_req(ar);
1023 if (ret)
1024 /* continue normally anyway, this isn't serious */
Michal Kazior7aa7a722014-08-25 12:09:38 +02001025 ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
1026 ret);
Kalle Valoa3d135e2013-09-03 11:44:10 +03001027
Kalle Valof118a3e2014-01-03 12:59:31 +02001028 if (ar->debug.fw_dbglog_mask) {
1029 ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
1030 if (ret)
1031 /* not serious */
Michal Kazior7aa7a722014-08-25 12:09:38 +02001032 ath10k_warn(ar, "failed to enable dbglog during start: %d",
Kalle Valof118a3e2014-01-03 12:59:31 +02001033 ret);
1034 }
1035
Kalle Valodb66ea02013-09-03 11:44:03 +03001036 return 0;
1037}
1038
1039void ath10k_debug_stop(struct ath10k *ar)
1040{
Kalle Valo60631c52013-10-08 21:45:25 +03001041 lockdep_assert_held(&ar->conf_mutex);
1042
1043 /* Must not use _sync to avoid deadlock, we do that in
1044 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
1045 * warning from del_timer(). */
1046 if (ar->debug.htt_stats_mask != 0)
1047 cancel_delayed_work(&ar->debug.htt_stats_dwork);
Janusz Dziedzicd3856232014-06-02 21:19:46 +03001048
1049 ar->debug.htt_max_amsdu = 0;
1050 ar->debug.htt_max_ampdu = 0;
Kalle Valodb66ea02013-09-03 11:44:03 +03001051}
1052
Janusz Dziedzic9702c682013-11-20 09:59:41 +02001053static ssize_t ath10k_write_simulate_radar(struct file *file,
1054 const char __user *user_buf,
1055 size_t count, loff_t *ppos)
1056{
1057 struct ath10k *ar = file->private_data;
1058
1059 ieee80211_radar_detected(ar->hw);
1060
1061 return count;
1062}
1063
1064static const struct file_operations fops_simulate_radar = {
1065 .write = ath10k_write_simulate_radar,
1066 .open = simple_open,
1067 .owner = THIS_MODULE,
1068 .llseek = default_llseek,
1069};
1070
1071#define ATH10K_DFS_STAT(s, p) (\
1072 len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
1073 ar->debug.dfs_stats.p))
1074
1075#define ATH10K_DFS_POOL_STAT(s, p) (\
1076 len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
1077 ar->debug.dfs_pool_stats.p))
1078
1079static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
1080 size_t count, loff_t *ppos)
1081{
1082 int retval = 0, len = 0;
1083 const int size = 8000;
1084 struct ath10k *ar = file->private_data;
1085 char *buf;
1086
1087 buf = kzalloc(size, GFP_KERNEL);
1088 if (buf == NULL)
1089 return -ENOMEM;
1090
1091 if (!ar->dfs_detector) {
1092 len += scnprintf(buf + len, size - len, "DFS not enabled\n");
1093 goto exit;
1094 }
1095
1096 ar->debug.dfs_pool_stats =
1097 ar->dfs_detector->get_stats(ar->dfs_detector);
1098
1099 len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
1100
1101 ATH10K_DFS_STAT("reported phy errors", phy_errors);
1102 ATH10K_DFS_STAT("pulse events reported", pulses_total);
1103 ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);
1104 ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);
1105 ATH10K_DFS_STAT("Radars detected", radar_detected);
1106
1107 len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
1108 ATH10K_DFS_POOL_STAT("Pool references", pool_reference);
1109 ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);
1110 ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);
1111 ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);
1112 ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);
1113 ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
1114 ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);
1115
1116exit:
1117 if (len > size)
1118 len = size;
1119
1120 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1121 kfree(buf);
1122
1123 return retval;
1124}
1125
1126static const struct file_operations fops_dfs_stats = {
1127 .read = ath10k_read_dfs_stats,
1128 .open = simple_open,
1129 .owner = THIS_MODULE,
1130 .llseek = default_llseek,
1131};
1132
Kalle Valo5e3dd152013-06-12 20:52:10 +03001133int ath10k_debug_create(struct ath10k *ar)
1134{
Ben Greear384914b2014-08-25 08:37:32 +03001135 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
Kalle Valo5e3dd152013-06-12 20:52:10 +03001143 ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
1144 ar->hw->wiphy->debugfsdir);
Ben Greear384914b2014-08-25 08:37:32 +03001145 if (!ar->debug.debugfs_phy) {
1146 ret = -ENOMEM;
1147 goto err_free_fw_crash_data;
1148 }
Kalle Valo5e3dd152013-06-12 20:52:10 +03001149
Kalle Valoa3d135e2013-09-03 11:44:10 +03001150 INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
1151 ath10k_debug_htt_stats_dwork);
1152
Kalle Valo5e3dd152013-06-12 20:52:10 +03001153 init_completion(&ar->debug.event_stats_compl);
1154
1155 debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
1156 &fops_fw_stats);
1157
1158 debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
1159 &fops_wmi_services);
1160
Michal Kazior278c4a82013-07-22 14:08:51 +02001161 debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
1162 ar, &fops_simulate_fw_crash);
1163
Ben Greear384914b2014-08-25 08:37:32 +03001164 debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
1165 ar, &fops_fw_crash_dump);
1166
Kalle Valo763b8cd2013-09-01 11:22:21 +03001167 debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
1168 ar, &fops_chip_id);
1169
Kalle Valoa3d135e2013-09-03 11:44:10 +03001170 debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
1171 ar, &fops_htt_stats_mask);
1172
Janusz Dziedzicd3856232014-06-02 21:19:46 +03001173 debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR,
1174 ar->debug.debugfs_phy, ar,
1175 &fops_htt_max_amsdu_ampdu);
1176
Kalle Valof118a3e2014-01-03 12:59:31 +02001177 debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
1178 ar, &fops_fw_dbglog);
1179
Janusz Dziedzic9702c682013-11-20 09:59:41 +02001180 if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
1181 debugfs_create_file("dfs_simulate_radar", S_IWUSR,
1182 ar->debug.debugfs_phy, ar,
1183 &fops_simulate_radar);
1184
Marek Puzyniak7d9b40b2013-11-20 10:00:28 +02001185 debugfs_create_bool("dfs_block_radar_events", S_IWUSR,
1186 ar->debug.debugfs_phy,
1187 &ar->dfs_block_radar_events);
1188
Janusz Dziedzic9702c682013-11-20 09:59:41 +02001189 debugfs_create_file("dfs_stats", S_IRUSR,
1190 ar->debug.debugfs_phy, ar,
1191 &fops_dfs_stats);
1192 }
1193
Kalle Valo5e3dd152013-06-12 20:52:10 +03001194 return 0;
Ben Greear384914b2014-08-25 08:37:32 +03001195
1196err_free_fw_crash_data:
1197 vfree(ar->debug.fw_crash_data);
1198
1199err:
1200 return ret;
Kalle Valo5e3dd152013-06-12 20:52:10 +03001201}
Kalle Valodb66ea02013-09-03 11:44:03 +03001202
Kalle Valo60631c52013-10-08 21:45:25 +03001203void ath10k_debug_destroy(struct ath10k *ar)
1204{
Ben Greear384914b2014-08-25 08:37:32 +03001205 vfree(ar->debug.fw_crash_data);
Kalle Valo60631c52013-10-08 21:45:25 +03001206 cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
1207}
1208
Kalle Valo5e3dd152013-06-12 20:52:10 +03001209#endif /* CONFIG_ATH10K_DEBUGFS */
1210
1211#ifdef CONFIG_ATH10K_DEBUG
Michal Kazior7aa7a722014-08-25 12:09:38 +02001212void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
1213 const char *fmt, ...)
Kalle Valo5e3dd152013-06-12 20:52:10 +03001214{
1215 struct va_format vaf;
1216 va_list args;
1217
1218 va_start(args, fmt);
1219
1220 vaf.fmt = fmt;
1221 vaf.va = &args;
1222
1223 if (ath10k_debug_mask & mask)
Michal Kazior7aa7a722014-08-25 12:09:38 +02001224 dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
Kalle Valo5e3dd152013-06-12 20:52:10 +03001225
Michal Kaziord35a6c12014-09-02 11:00:21 +03001226 trace_ath10k_log_dbg(ar, mask, &vaf);
Kalle Valo5e3dd152013-06-12 20:52:10 +03001227
1228 va_end(args);
1229}
1230EXPORT_SYMBOL(ath10k_dbg);
1231
Michal Kazior7aa7a722014-08-25 12:09:38 +02001232void ath10k_dbg_dump(struct ath10k *ar,
1233 enum ath10k_debug_mask mask,
Kalle Valo5e3dd152013-06-12 20:52:10 +03001234 const char *msg, const char *prefix,
1235 const void *buf, size_t len)
1236{
1237 if (ath10k_debug_mask & mask) {
1238 if (msg)
Michal Kazior7aa7a722014-08-25 12:09:38 +02001239 ath10k_dbg(ar, mask, "%s\n", msg);
Kalle Valo5e3dd152013-06-12 20:52:10 +03001240
1241 print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
1242 }
1243
1244 /* tracing code doesn't like null strings :/ */
Michal Kaziord35a6c12014-09-02 11:00:21 +03001245 trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",
Kalle Valo5e3dd152013-06-12 20:52:10 +03001246 buf, len);
1247}
1248EXPORT_SYMBOL(ath10k_dbg_dump);
1249
1250#endif /* CONFIG_ATH10K_DEBUG */