Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 27static 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
 45int 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}
 61EXPORT_SYMBOL(ath10k_info);
 62
 63int 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}
 79EXPORT_SYMBOL(ath10k_err);
 80
 81int 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}
101EXPORT_SYMBOL(ath10k_warn);
102
103#ifdef CONFIG_ATH10K_DEBUGFS
104
105void 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
112static 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
151static 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
158void 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
269static 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
437exit:
438	mutex_unlock(&ar->conf_mutex);
439	kfree(buf);
440	return ret_cnt;
441}
442
443static 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
450static 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
460static 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
491exit:
492	mutex_unlock(&ar->conf_mutex);
493	return ret;
494}
495
496static 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
504static 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
516static 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
523static 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
552static 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
564static 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
577static 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
603out:
604	mutex_unlock(&ar->conf_mutex);
605
606	return ret;
607}
608
609static 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
617static ssize_t ath10k_read_fw_dbglog(struct file *file,
618					    char __user *user_buf,
619					    size_t count, loff_t *ppos)
620{
621	struct ath10k *ar = file->private_data;
622	unsigned int len;
623	char buf[32];
624
625	len = scnprintf(buf, sizeof(buf), "0x%08x\n",
626			ar->debug.fw_dbglog_mask);
627
628	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
629}
630
631static ssize_t ath10k_write_fw_dbglog(struct file *file,
632				      const char __user *user_buf,
633				      size_t count, loff_t *ppos)
634{
635	struct ath10k *ar = file->private_data;
636	unsigned long mask;
637	int ret;
638
639	ret = kstrtoul_from_user(user_buf, count, 0, &mask);
640	if (ret)
641		return ret;
642
643	mutex_lock(&ar->conf_mutex);
644
645	ar->debug.fw_dbglog_mask = mask;
646
647	if (ar->state == ATH10K_STATE_ON) {
648		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
649		if (ret) {
650			ath10k_warn("dbglog cfg failed from debugfs: %d\n",
651				    ret);
652			goto exit;
653		}
654	}
655
656	ret = count;
657
658exit:
659	mutex_unlock(&ar->conf_mutex);
660
661	return ret;
662}
663
664static const struct file_operations fops_fw_dbglog = {
665	.read = ath10k_read_fw_dbglog,
666	.write = ath10k_write_fw_dbglog,
667	.open = simple_open,
668	.owner = THIS_MODULE,
669	.llseek = default_llseek,
670};
671
672int ath10k_debug_start(struct ath10k *ar)
673{
674	int ret;
675
676	lockdep_assert_held(&ar->conf_mutex);
677
678	ret = ath10k_debug_htt_stats_req(ar);
679	if (ret)
680		/* continue normally anyway, this isn't serious */
681		ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
682
683	if (ar->debug.fw_dbglog_mask) {
684		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
685		if (ret)
686			/* not serious */
687			ath10k_warn("failed to enable dbglog during start: %d",
688				    ret);
689	}
690
691	return 0;
692}
693
694void ath10k_debug_stop(struct ath10k *ar)
695{
696	lockdep_assert_held(&ar->conf_mutex);
697
698	/* Must not use _sync to avoid deadlock, we do that in
699	 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
700	 * warning from del_timer(). */
701	if (ar->debug.htt_stats_mask != 0)
702		cancel_delayed_work(&ar->debug.htt_stats_dwork);
703}
704
705static ssize_t ath10k_write_simulate_radar(struct file *file,
706					   const char __user *user_buf,
707					   size_t count, loff_t *ppos)
708{
709	struct ath10k *ar = file->private_data;
710
711	ieee80211_radar_detected(ar->hw);
712
713	return count;
714}
715
716static const struct file_operations fops_simulate_radar = {
717	.write = ath10k_write_simulate_radar,
718	.open = simple_open,
719	.owner = THIS_MODULE,
720	.llseek = default_llseek,
721};
722
723#define ATH10K_DFS_STAT(s, p) (\
724	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
725			 ar->debug.dfs_stats.p))
726
727#define ATH10K_DFS_POOL_STAT(s, p) (\
728	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
729			 ar->debug.dfs_pool_stats.p))
730
731static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
732				     size_t count, loff_t *ppos)
733{
734	int retval = 0, len = 0;
735	const int size = 8000;
736	struct ath10k *ar = file->private_data;
737	char *buf;
738
739	buf = kzalloc(size, GFP_KERNEL);
740	if (buf == NULL)
741		return -ENOMEM;
742
743	if (!ar->dfs_detector) {
744		len += scnprintf(buf + len, size - len, "DFS not enabled\n");
745		goto exit;
746	}
747
748	ar->debug.dfs_pool_stats =
749			ar->dfs_detector->get_stats(ar->dfs_detector);
750
751	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
752
753	ATH10K_DFS_STAT("reported phy errors", phy_errors);
754	ATH10K_DFS_STAT("pulse events reported", pulses_total);
755	ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);
756	ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);
757	ATH10K_DFS_STAT("Radars detected", radar_detected);
758
759	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
760	ATH10K_DFS_POOL_STAT("Pool references", pool_reference);
761	ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);
762	ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);
763	ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);
764	ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);
765	ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
766	ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);
767
768exit:
769	if (len > size)
770		len = size;
771
772	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
773	kfree(buf);
774
775	return retval;
776}
777
778static const struct file_operations fops_dfs_stats = {
779	.read = ath10k_read_dfs_stats,
780	.open = simple_open,
781	.owner = THIS_MODULE,
782	.llseek = default_llseek,
783};
784
785int ath10k_debug_create(struct ath10k *ar)
786{
787	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
788						   ar->hw->wiphy->debugfsdir);
789
790	if (!ar->debug.debugfs_phy)
791		return -ENOMEM;
792
793	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
794			  ath10k_debug_htt_stats_dwork);
795
796	init_completion(&ar->debug.event_stats_compl);
797
798	debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
799			    &fops_fw_stats);
800
801	debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
802			    &fops_wmi_services);
803
804	debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
805			    ar, &fops_simulate_fw_crash);
806
807	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
808			    ar, &fops_chip_id);
809
810	debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
811			    ar, &fops_htt_stats_mask);
812
813	debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
814			    ar, &fops_fw_dbglog);
815
816	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
817		debugfs_create_file("dfs_simulate_radar", S_IWUSR,
818				    ar->debug.debugfs_phy, ar,
819				    &fops_simulate_radar);
820
821		debugfs_create_bool("dfs_block_radar_events", S_IWUSR,
822				    ar->debug.debugfs_phy,
823				    &ar->dfs_block_radar_events);
824
825		debugfs_create_file("dfs_stats", S_IRUSR,
826				    ar->debug.debugfs_phy, ar,
827				    &fops_dfs_stats);
828	}
829
830	return 0;
831}
832
833void ath10k_debug_destroy(struct ath10k *ar)
834{
835	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
836}
837
838#endif /* CONFIG_ATH10K_DEBUGFS */
839
840#ifdef CONFIG_ATH10K_DEBUG
841void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
842{
843	struct va_format vaf;
844	va_list args;
845
846	va_start(args, fmt);
847
848	vaf.fmt = fmt;
849	vaf.va = &args;
850
851	if (ath10k_debug_mask & mask)
852		ath10k_printk(KERN_DEBUG, "%pV", &vaf);
853
854	trace_ath10k_log_dbg(mask, &vaf);
855
856	va_end(args);
857}
858EXPORT_SYMBOL(ath10k_dbg);
859
860void ath10k_dbg_dump(enum ath10k_debug_mask mask,
861		     const char *msg, const char *prefix,
862		     const void *buf, size_t len)
863{
864	if (ath10k_debug_mask & mask) {
865		if (msg)
866			ath10k_dbg(mask, "%s\n", msg);
867
868		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
869	}
870
871	/* tracing code doesn't like null strings :/ */
872	trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
873				  buf, len);
874}
875EXPORT_SYMBOL(ath10k_dbg_dump);
876
877#endif /* CONFIG_ATH10K_DEBUG */