1 /*
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>
20 
21 #include "core.h"
22 #include "debug.h"
23 
24 /* ms */
25 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
26 
27 static int ath10k_printk(const char *level, const char *fmt, ...)
28 {
29 	struct va_format vaf;
30 	va_list args;
31 	int rtn;
32 
33 	va_start(args, fmt);
34 
35 	vaf.fmt = fmt;
36 	vaf.va = &args;
37 
38 	rtn = printk("%sath10k: %pV", level, &vaf);
39 
40 	va_end(args);
41 
42 	return rtn;
43 }
44 
45 int ath10k_info(const char *fmt, ...)
46 {
47 	struct va_format vaf = {
48 		.fmt = fmt,
49 	};
50 	va_list args;
51 	int ret;
52 
53 	va_start(args, fmt);
54 	vaf.va = &args;
55 	ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
56 	trace_ath10k_log_info(&vaf);
57 	va_end(args);
58 
59 	return ret;
60 }
61 EXPORT_SYMBOL(ath10k_info);
62 
63 int ath10k_err(const char *fmt, ...)
64 {
65 	struct va_format vaf = {
66 		.fmt = fmt,
67 	};
68 	va_list args;
69 	int ret;
70 
71 	va_start(args, fmt);
72 	vaf.va = &args;
73 	ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
74 	trace_ath10k_log_err(&vaf);
75 	va_end(args);
76 
77 	return ret;
78 }
79 EXPORT_SYMBOL(ath10k_err);
80 
81 int ath10k_warn(const char *fmt, ...)
82 {
83 	struct va_format vaf = {
84 		.fmt = fmt,
85 	};
86 	va_list args;
87 	int ret = 0;
88 
89 	va_start(args, fmt);
90 	vaf.va = &args;
91 
92 	if (net_ratelimit())
93 		ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
94 
95 	trace_ath10k_log_warn(&vaf);
96 
97 	va_end(args);
98 
99 	return ret;
100 }
101 EXPORT_SYMBOL(ath10k_warn);
102 
103 #ifdef CONFIG_ATH10K_DEBUGFS
104 
105 void ath10k_debug_read_service_map(struct ath10k *ar,
106 				   void *service_map,
107 				   size_t map_size)
108 {
109 	memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
110 }
111 
112 static ssize_t ath10k_read_wmi_services(struct file *file,
113 					char __user *user_buf,
114 					size_t count, loff_t *ppos)
115 {
116 	struct ath10k *ar = file->private_data;
117 	char *buf;
118 	unsigned int len = 0, buf_len = 1500;
119 	const char *status;
120 	ssize_t ret_cnt;
121 	int i;
122 
123 	buf = kzalloc(buf_len, GFP_KERNEL);
124 	if (!buf)
125 		return -ENOMEM;
126 
127 	mutex_lock(&ar->conf_mutex);
128 
129 	if (len > buf_len)
130 		len = buf_len;
131 
132 	for (i = 0; i < WMI_SERVICE_LAST; i++) {
133 		if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
134 			status = "enabled";
135 		else
136 			status = "disabled";
137 
138 		len += scnprintf(buf + len, buf_len - len,
139 				 "0x%02x - %20s - %s\n",
140 				 i, wmi_service_name(i), status);
141 	}
142 
143 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
144 
145 	mutex_unlock(&ar->conf_mutex);
146 
147 	kfree(buf);
148 	return ret_cnt;
149 }
150 
151 static const struct file_operations fops_wmi_services = {
152 	.read = ath10k_read_wmi_services,
153 	.open = simple_open,
154 	.owner = THIS_MODULE,
155 	.llseek = default_llseek,
156 };
157 
158 void ath10k_debug_read_target_stats(struct ath10k *ar,
159 				    struct wmi_stats_event *ev)
160 {
161 	u8 *tmp = ev->data;
162 	struct ath10k_target_stats *stats;
163 	int num_pdev_stats, num_vdev_stats, num_peer_stats;
164 	struct wmi_pdev_stats *ps;
165 	int i;
166 
167 	spin_lock_bh(&ar->data_lock);
168 
169 	stats = &ar->debug.target_stats;
170 
171 	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
172 	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
173 	num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
174 
175 	if (num_pdev_stats) {
176 		ps = (struct wmi_pdev_stats *)tmp;
177 
178 		stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
179 		stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
180 		stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
181 		stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
182 		stats->cycle_count = __le32_to_cpu(ps->cycle_count);
183 		stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
184 		stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
185 
186 		stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
187 		stats->comp_delivered =
188 			__le32_to_cpu(ps->wal.tx.comp_delivered);
189 		stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
190 		stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
191 		stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
192 		stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
193 		stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
194 		stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
195 		stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
196 		stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
197 		stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
198 		stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
199 		stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
200 		stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
201 		stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
202 		stats->sw_retry_failure =
203 			__le32_to_cpu(ps->wal.tx.sw_retry_failure);
204 		stats->illgl_rate_phy_err =
205 			__le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
206 		stats->pdev_cont_xretry =
207 			__le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
208 		stats->pdev_tx_timeout =
209 			__le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
210 		stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
211 		stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
212 		stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
213 
214 		stats->mid_ppdu_route_change =
215 			__le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
216 		stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
217 		stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
218 		stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
219 		stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
220 		stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
221 		stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
222 		stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
223 		stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
224 		stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
225 		stats->oversize_amsdu =
226 			__le32_to_cpu(ps->wal.rx.oversize_amsdu);
227 		stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
228 		stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
229 		stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
230 
231 		tmp += sizeof(struct wmi_pdev_stats);
232 	}
233 
234 	/* 0 or max vdevs */
235 	/* Currently firmware does not support VDEV stats */
236 	if (num_vdev_stats) {
237 		struct wmi_vdev_stats *vdev_stats;
238 
239 		for (i = 0; i < num_vdev_stats; i++) {
240 			vdev_stats = (struct wmi_vdev_stats *)tmp;
241 			tmp += sizeof(struct wmi_vdev_stats);
242 		}
243 	}
244 
245 	if (num_peer_stats) {
246 		struct wmi_peer_stats *peer_stats;
247 		struct ath10k_peer_stat *s;
248 
249 		stats->peers = num_peer_stats;
250 
251 		for (i = 0; i < num_peer_stats; i++) {
252 			peer_stats = (struct wmi_peer_stats *)tmp;
253 			s = &stats->peer_stat[i];
254 
255 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
256 						   s->peer_macaddr);
257 			s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
258 			s->peer_tx_rate =
259 				__le32_to_cpu(peer_stats->peer_tx_rate);
260 
261 			tmp += sizeof(struct wmi_peer_stats);
262 		}
263 	}
264 
265 	spin_unlock_bh(&ar->data_lock);
266 	complete(&ar->debug.event_stats_compl);
267 }
268 
269 static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
270 				    size_t count, loff_t *ppos)
271 {
272 	struct ath10k *ar = file->private_data;
273 	struct ath10k_target_stats *fw_stats;
274 	char *buf = NULL;
275 	unsigned int len = 0, buf_len = 2500;
276 	ssize_t ret_cnt = 0;
277 	long left;
278 	int i;
279 	int ret;
280 
281 	fw_stats = &ar->debug.target_stats;
282 
283 	mutex_lock(&ar->conf_mutex);
284 
285 	if (ar->state != ATH10K_STATE_ON)
286 		goto exit;
287 
288 	buf = kzalloc(buf_len, GFP_KERNEL);
289 	if (!buf)
290 		goto exit;
291 
292 	ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
293 	if (ret) {
294 		ath10k_warn("could not request stats (%d)\n", ret);
295 		goto exit;
296 	}
297 
298 	left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
299 	if (left <= 0)
300 		goto exit;
301 
302 	spin_lock_bh(&ar->data_lock);
303 	len += scnprintf(buf + len, buf_len - len, "\n");
304 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
305 			 "ath10k PDEV stats");
306 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
307 				 "=================");
308 
309 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
310 			 "Channel noise floor", fw_stats->ch_noise_floor);
311 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
312 			 "Channel TX power", fw_stats->chan_tx_power);
313 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
314 			 "TX frame count", fw_stats->tx_frame_count);
315 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
316 			 "RX frame count", fw_stats->rx_frame_count);
317 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
318 			 "RX clear count", fw_stats->rx_clear_count);
319 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
320 			 "Cycle count", fw_stats->cycle_count);
321 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
322 			 "PHY error count", fw_stats->phy_err_count);
323 
324 	len += scnprintf(buf + len, buf_len - len, "\n");
325 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
326 			 "ath10k PDEV TX stats");
327 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
328 				 "=================");
329 
330 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
331 			 "HTT cookies queued", fw_stats->comp_queued);
332 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
333 			 "HTT cookies disp.", fw_stats->comp_delivered);
334 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
335 			 "MSDU queued", fw_stats->msdu_enqued);
336 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
337 			 "MPDU queued", fw_stats->mpdu_enqued);
338 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
339 			 "MSDUs dropped", fw_stats->wmm_drop);
340 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
341 			 "Local enqued", fw_stats->local_enqued);
342 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
343 			 "Local freed", fw_stats->local_freed);
344 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
345 			 "HW queued", fw_stats->hw_queued);
346 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
347 			 "PPDUs reaped", fw_stats->hw_reaped);
348 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
349 			 "Num underruns", fw_stats->underrun);
350 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
351 			 "PPDUs cleaned", fw_stats->tx_abort);
352 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
353 			 "MPDUs requed", fw_stats->mpdus_requed);
354 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
355 			 "Excessive retries", fw_stats->tx_ko);
356 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
357 			 "HW rate", fw_stats->data_rc);
358 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
359 			 "Sched self tiggers", fw_stats->self_triggers);
360 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
361 			 "Dropped due to SW retries",
362 			 fw_stats->sw_retry_failure);
363 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
364 			 "Illegal rate phy errors",
365 			 fw_stats->illgl_rate_phy_err);
366 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
367 			 "Pdev continous xretry", fw_stats->pdev_cont_xretry);
368 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
369 			 "TX timeout", fw_stats->pdev_tx_timeout);
370 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
371 			 "PDEV resets", fw_stats->pdev_resets);
372 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
373 			 "PHY underrun", fw_stats->phy_underrun);
374 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
375 			 "MPDU is more than txop limit", fw_stats->txop_ovf);
376 
377 	len += scnprintf(buf + len, buf_len - len, "\n");
378 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
379 			 "ath10k PDEV RX stats");
380 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
381 				 "=================");
382 
383 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
384 			 "Mid PPDU route change",
385 			 fw_stats->mid_ppdu_route_change);
386 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
387 			 "Tot. number of statuses", fw_stats->status_rcvd);
388 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
389 			 "Extra frags on rings 0", fw_stats->r0_frags);
390 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
391 			 "Extra frags on rings 1", fw_stats->r1_frags);
392 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
393 			 "Extra frags on rings 2", fw_stats->r2_frags);
394 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
395 			 "Extra frags on rings 3", fw_stats->r3_frags);
396 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
397 			 "MSDUs delivered to HTT", fw_stats->htt_msdus);
398 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
399 			 "MPDUs delivered to HTT", fw_stats->htt_mpdus);
400 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
401 			 "MSDUs delivered to stack", fw_stats->loc_msdus);
402 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
403 			 "MPDUs delivered to stack", fw_stats->loc_mpdus);
404 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
405 			 "Oversized AMSUs", fw_stats->oversize_amsdu);
406 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
407 			 "PHY errors", fw_stats->phy_errs);
408 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
409 			 "PHY errors drops", fw_stats->phy_err_drop);
410 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
411 			 "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
412 
413 	len += scnprintf(buf + len, buf_len - len, "\n");
414 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
415 			 "ath10k PEER stats");
416 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
417 				 "=================");
418 
419 	for (i = 0; i < fw_stats->peers; i++) {
420 		len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
421 				 "Peer MAC address",
422 				 fw_stats->peer_stat[i].peer_macaddr);
423 		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
424 				 "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
425 		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
426 				 "Peer TX rate",
427 				 fw_stats->peer_stat[i].peer_tx_rate);
428 		len += scnprintf(buf + len, buf_len - len, "\n");
429 	}
430 	spin_unlock_bh(&ar->data_lock);
431 
432 	if (len > buf_len)
433 		len = buf_len;
434 
435 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
436 
437 exit:
438 	mutex_unlock(&ar->conf_mutex);
439 	kfree(buf);
440 	return ret_cnt;
441 }
442 
443 static const struct file_operations fops_fw_stats = {
444 	.read = ath10k_read_fw_stats,
445 	.open = simple_open,
446 	.owner = THIS_MODULE,
447 	.llseek = default_llseek,
448 };
449 
450 static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
451 					     char __user *user_buf,
452 					     size_t count, loff_t *ppos)
453 {
454 	const char buf[] = "To simulate firmware crash write the keyword"
455 			   " `crash` to this file.\nThis will force firmware"
456 			   " to report a crash to the host system.\n";
457 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
458 }
459 
460 static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
461 					      const char __user *user_buf,
462 					      size_t count, loff_t *ppos)
463 {
464 	struct ath10k *ar = file->private_data;
465 	char buf[32] = {};
466 	int ret;
467 
468 	mutex_lock(&ar->conf_mutex);
469 
470 	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
471 	if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) {
472 		ret = -EINVAL;
473 		goto exit;
474 	}
475 
476 	if (ar->state != ATH10K_STATE_ON &&
477 	    ar->state != ATH10K_STATE_RESTARTED) {
478 		ret = -ENETDOWN;
479 		goto exit;
480 	}
481 
482 	ath10k_info("simulating firmware crash\n");
483 
484 	ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
485 	if (ret)
486 		ath10k_warn("failed to force fw hang (%d)\n", ret);
487 
488 	if (ret == 0)
489 		ret = count;
490 
491 exit:
492 	mutex_unlock(&ar->conf_mutex);
493 	return ret;
494 }
495 
496 static const struct file_operations fops_simulate_fw_crash = {
497 	.read = ath10k_read_simulate_fw_crash,
498 	.write = ath10k_write_simulate_fw_crash,
499 	.open = simple_open,
500 	.owner = THIS_MODULE,
501 	.llseek = default_llseek,
502 };
503 
504 static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
505 				   size_t count, loff_t *ppos)
506 {
507 	struct ath10k *ar = file->private_data;
508 	unsigned int len;
509 	char buf[50];
510 
511 	len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
512 
513 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
514 }
515 
516 static const struct file_operations fops_chip_id = {
517 	.read = ath10k_read_chip_id,
518 	.open = simple_open,
519 	.owner = THIS_MODULE,
520 	.llseek = default_llseek,
521 };
522 
523 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
524 {
525 	u64 cookie;
526 	int ret;
527 
528 	lockdep_assert_held(&ar->conf_mutex);
529 
530 	if (ar->debug.htt_stats_mask == 0)
531 		/* htt stats are disabled */
532 		return 0;
533 
534 	if (ar->state != ATH10K_STATE_ON)
535 		return 0;
536 
537 	cookie = get_jiffies_64();
538 
539 	ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
540 				       cookie);
541 	if (ret) {
542 		ath10k_warn("failed to send htt stats request: %d\n", ret);
543 		return ret;
544 	}
545 
546 	queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,
547 			   msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));
548 
549 	return 0;
550 }
551 
552 static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
553 {
554 	struct ath10k *ar = container_of(work, struct ath10k,
555 					 debug.htt_stats_dwork.work);
556 
557 	mutex_lock(&ar->conf_mutex);
558 
559 	ath10k_debug_htt_stats_req(ar);
560 
561 	mutex_unlock(&ar->conf_mutex);
562 }
563 
564 static ssize_t ath10k_read_htt_stats_mask(struct file *file,
565 					    char __user *user_buf,
566 					    size_t count, loff_t *ppos)
567 {
568 	struct ath10k *ar = file->private_data;
569 	char buf[32];
570 	unsigned int len;
571 
572 	len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
573 
574 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
575 }
576 
577 static ssize_t ath10k_write_htt_stats_mask(struct file *file,
578 					     const char __user *user_buf,
579 					     size_t count, loff_t *ppos)
580 {
581 	struct ath10k *ar = file->private_data;
582 	unsigned long mask;
583 	int ret;
584 
585 	ret = kstrtoul_from_user(user_buf, count, 0, &mask);
586 	if (ret)
587 		return ret;
588 
589 	/* max 8 bit masks (for now) */
590 	if (mask > 0xff)
591 		return -E2BIG;
592 
593 	mutex_lock(&ar->conf_mutex);
594 
595 	ar->debug.htt_stats_mask = mask;
596 
597 	ret = ath10k_debug_htt_stats_req(ar);
598 	if (ret)
599 		goto out;
600 
601 	ret = count;
602 
603 out:
604 	mutex_unlock(&ar->conf_mutex);
605 
606 	return ret;
607 }
608 
609 static const struct file_operations fops_htt_stats_mask = {
610 	.read = ath10k_read_htt_stats_mask,
611 	.write = ath10k_write_htt_stats_mask,
612 	.open = simple_open,
613 	.owner = THIS_MODULE,
614 	.llseek = default_llseek,
615 };
616 
617 int ath10k_debug_start(struct ath10k *ar)
618 {
619 	int ret;
620 
621 	lockdep_assert_held(&ar->conf_mutex);
622 
623 	ret = ath10k_debug_htt_stats_req(ar);
624 	if (ret)
625 		/* continue normally anyway, this isn't serious */
626 		ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
627 
628 	return 0;
629 }
630 
631 void ath10k_debug_stop(struct ath10k *ar)
632 {
633 	lockdep_assert_held(&ar->conf_mutex);
634 
635 	/* Must not use _sync to avoid deadlock, we do that in
636 	 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
637 	 * warning from del_timer(). */
638 	if (ar->debug.htt_stats_mask != 0)
639 		cancel_delayed_work(&ar->debug.htt_stats_dwork);
640 }
641 
642 int ath10k_debug_create(struct ath10k *ar)
643 {
644 	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
645 						   ar->hw->wiphy->debugfsdir);
646 
647 	if (!ar->debug.debugfs_phy)
648 		return -ENOMEM;
649 
650 	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
651 			  ath10k_debug_htt_stats_dwork);
652 
653 	init_completion(&ar->debug.event_stats_compl);
654 
655 	debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
656 			    &fops_fw_stats);
657 
658 	debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
659 			    &fops_wmi_services);
660 
661 	debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
662 			    ar, &fops_simulate_fw_crash);
663 
664 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
665 			    ar, &fops_chip_id);
666 
667 	debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
668 			    ar, &fops_htt_stats_mask);
669 
670 	return 0;
671 }
672 
673 void ath10k_debug_destroy(struct ath10k *ar)
674 {
675 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
676 }
677 
678 #endif /* CONFIG_ATH10K_DEBUGFS */
679 
680 #ifdef CONFIG_ATH10K_DEBUG
681 void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
682 {
683 	struct va_format vaf;
684 	va_list args;
685 
686 	va_start(args, fmt);
687 
688 	vaf.fmt = fmt;
689 	vaf.va = &args;
690 
691 	if (ath10k_debug_mask & mask)
692 		ath10k_printk(KERN_DEBUG, "%pV", &vaf);
693 
694 	trace_ath10k_log_dbg(mask, &vaf);
695 
696 	va_end(args);
697 }
698 EXPORT_SYMBOL(ath10k_dbg);
699 
700 void ath10k_dbg_dump(enum ath10k_debug_mask mask,
701 		     const char *msg, const char *prefix,
702 		     const void *buf, size_t len)
703 {
704 	if (ath10k_debug_mask & mask) {
705 		if (msg)
706 			ath10k_dbg(mask, "%s\n", msg);
707 
708 		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
709 	}
710 
711 	/* tracing code doesn't like null strings :/ */
712 	trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
713 				  buf, len);
714 }
715 EXPORT_SYMBOL(ath10k_dbg_dump);
716 
717 #endif /* CONFIG_ATH10K_DEBUG */
718