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 static int ath10k_printk(const char *level, const char *fmt, ...)
25 {
26 	struct va_format vaf;
27 	va_list args;
28 	int rtn;
29 
30 	va_start(args, fmt);
31 
32 	vaf.fmt = fmt;
33 	vaf.va = &args;
34 
35 	rtn = printk("%sath10k: %pV", level, &vaf);
36 
37 	va_end(args);
38 
39 	return rtn;
40 }
41 
42 int ath10k_info(const char *fmt, ...)
43 {
44 	struct va_format vaf = {
45 		.fmt = fmt,
46 	};
47 	va_list args;
48 	int ret;
49 
50 	va_start(args, fmt);
51 	vaf.va = &args;
52 	ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
53 	trace_ath10k_log_info(&vaf);
54 	va_end(args);
55 
56 	return ret;
57 }
58 EXPORT_SYMBOL(ath10k_info);
59 
60 int ath10k_err(const char *fmt, ...)
61 {
62 	struct va_format vaf = {
63 		.fmt = fmt,
64 	};
65 	va_list args;
66 	int ret;
67 
68 	va_start(args, fmt);
69 	vaf.va = &args;
70 	ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
71 	trace_ath10k_log_err(&vaf);
72 	va_end(args);
73 
74 	return ret;
75 }
76 EXPORT_SYMBOL(ath10k_err);
77 
78 int ath10k_warn(const char *fmt, ...)
79 {
80 	struct va_format vaf = {
81 		.fmt = fmt,
82 	};
83 	va_list args;
84 	int ret = 0;
85 
86 	va_start(args, fmt);
87 	vaf.va = &args;
88 
89 	if (net_ratelimit())
90 		ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
91 
92 	trace_ath10k_log_warn(&vaf);
93 
94 	va_end(args);
95 
96 	return ret;
97 }
98 EXPORT_SYMBOL(ath10k_warn);
99 
100 #ifdef CONFIG_ATH10K_DEBUGFS
101 
102 void ath10k_debug_read_service_map(struct ath10k *ar,
103 				   void *service_map,
104 				   size_t map_size)
105 {
106 	memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
107 }
108 
109 static ssize_t ath10k_read_wmi_services(struct file *file,
110 					char __user *user_buf,
111 					size_t count, loff_t *ppos)
112 {
113 	struct ath10k *ar = file->private_data;
114 	char *buf;
115 	unsigned int len = 0, buf_len = 1500;
116 	const char *status;
117 	ssize_t ret_cnt;
118 	int i;
119 
120 	buf = kzalloc(buf_len, GFP_KERNEL);
121 	if (!buf)
122 		return -ENOMEM;
123 
124 	mutex_lock(&ar->conf_mutex);
125 
126 	if (len > buf_len)
127 		len = buf_len;
128 
129 	for (i = 0; i < WMI_SERVICE_LAST; i++) {
130 		if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
131 			status = "enabled";
132 		else
133 			status = "disabled";
134 
135 		len += scnprintf(buf + len, buf_len - len,
136 				 "0x%02x - %20s - %s\n",
137 				 i, wmi_service_name(i), status);
138 	}
139 
140 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
141 
142 	mutex_unlock(&ar->conf_mutex);
143 
144 	kfree(buf);
145 	return ret_cnt;
146 }
147 
148 static const struct file_operations fops_wmi_services = {
149 	.read = ath10k_read_wmi_services,
150 	.open = simple_open,
151 	.owner = THIS_MODULE,
152 	.llseek = default_llseek,
153 };
154 
155 void ath10k_debug_read_target_stats(struct ath10k *ar,
156 				    struct wmi_stats_event *ev)
157 {
158 	u8 *tmp = ev->data;
159 	struct ath10k_target_stats *stats;
160 	int num_pdev_stats, num_vdev_stats, num_peer_stats;
161 	struct wmi_pdev_stats *ps;
162 	int i;
163 
164 	mutex_lock(&ar->conf_mutex);
165 
166 	stats = &ar->debug.target_stats;
167 
168 	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
169 	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
170 	num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
171 
172 	if (num_pdev_stats) {
173 		ps = (struct wmi_pdev_stats *)tmp;
174 
175 		stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
176 		stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
177 		stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
178 		stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
179 		stats->cycle_count = __le32_to_cpu(ps->cycle_count);
180 		stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
181 		stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
182 
183 		stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
184 		stats->comp_delivered =
185 			__le32_to_cpu(ps->wal.tx.comp_delivered);
186 		stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
187 		stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
188 		stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
189 		stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
190 		stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
191 		stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
192 		stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
193 		stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
194 		stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
195 		stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
196 		stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
197 		stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
198 		stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
199 		stats->sw_retry_failure =
200 			__le32_to_cpu(ps->wal.tx.sw_retry_failure);
201 		stats->illgl_rate_phy_err =
202 			__le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
203 		stats->pdev_cont_xretry =
204 			__le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
205 		stats->pdev_tx_timeout =
206 			__le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
207 		stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
208 		stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
209 		stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
210 
211 		stats->mid_ppdu_route_change =
212 			__le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
213 		stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
214 		stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
215 		stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
216 		stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
217 		stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
218 		stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
219 		stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
220 		stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
221 		stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
222 		stats->oversize_amsdu =
223 			__le32_to_cpu(ps->wal.rx.oversize_amsdu);
224 		stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
225 		stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
226 		stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
227 
228 		tmp += sizeof(struct wmi_pdev_stats);
229 	}
230 
231 	/* 0 or max vdevs */
232 	/* Currently firmware does not support VDEV stats */
233 	if (num_vdev_stats) {
234 		struct wmi_vdev_stats *vdev_stats;
235 
236 		for (i = 0; i < num_vdev_stats; i++) {
237 			vdev_stats = (struct wmi_vdev_stats *)tmp;
238 			tmp += sizeof(struct wmi_vdev_stats);
239 		}
240 	}
241 
242 	if (num_peer_stats) {
243 		struct wmi_peer_stats *peer_stats;
244 		struct ath10k_peer_stat *s;
245 
246 		stats->peers = num_peer_stats;
247 
248 		for (i = 0; i < num_peer_stats; i++) {
249 			peer_stats = (struct wmi_peer_stats *)tmp;
250 			s = &stats->peer_stat[i];
251 
252 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
253 						   s->peer_macaddr);
254 			s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
255 			s->peer_tx_rate =
256 				__le32_to_cpu(peer_stats->peer_tx_rate);
257 
258 			tmp += sizeof(struct wmi_peer_stats);
259 		}
260 	}
261 
262 	mutex_unlock(&ar->conf_mutex);
263 	complete(&ar->debug.event_stats_compl);
264 }
265 
266 static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
267 				    size_t count, loff_t *ppos)
268 {
269 	struct ath10k *ar = file->private_data;
270 	struct ath10k_target_stats *fw_stats;
271 	char *buf;
272 	unsigned int len = 0, buf_len = 2500;
273 	ssize_t ret_cnt;
274 	long left;
275 	int i;
276 	int ret;
277 
278 	fw_stats = &ar->debug.target_stats;
279 
280 	buf = kzalloc(buf_len, GFP_KERNEL);
281 	if (!buf)
282 		return -ENOMEM;
283 
284 	ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
285 	if (ret) {
286 		ath10k_warn("could not request stats (%d)\n", ret);
287 		kfree(buf);
288 		return -EIO;
289 	}
290 
291 	left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
292 
293 	if (left <= 0) {
294 		kfree(buf);
295 		return -ETIMEDOUT;
296 	}
297 
298 	mutex_lock(&ar->conf_mutex);
299 
300 	len += scnprintf(buf + len, buf_len - len, "\n");
301 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
302 			 "ath10k PDEV stats");
303 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
304 				 "=================");
305 
306 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
307 			 "Channel noise floor", fw_stats->ch_noise_floor);
308 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
309 			 "Channel TX power", fw_stats->chan_tx_power);
310 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
311 			 "TX frame count", fw_stats->tx_frame_count);
312 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
313 			 "RX frame count", fw_stats->rx_frame_count);
314 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
315 			 "RX clear count", fw_stats->rx_clear_count);
316 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
317 			 "Cycle count", fw_stats->cycle_count);
318 	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
319 			 "PHY error count", fw_stats->phy_err_count);
320 
321 	len += scnprintf(buf + len, buf_len - len, "\n");
322 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
323 			 "ath10k PDEV TX stats");
324 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
325 				 "=================");
326 
327 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
328 			 "HTT cookies queued", fw_stats->comp_queued);
329 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
330 			 "HTT cookies disp.", fw_stats->comp_delivered);
331 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
332 			 "MSDU queued", fw_stats->msdu_enqued);
333 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
334 			 "MPDU queued", fw_stats->mpdu_enqued);
335 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
336 			 "MSDUs dropped", fw_stats->wmm_drop);
337 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
338 			 "Local enqued", fw_stats->local_enqued);
339 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
340 			 "Local freed", fw_stats->local_freed);
341 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
342 			 "HW queued", fw_stats->hw_queued);
343 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
344 			 "PPDUs reaped", fw_stats->hw_reaped);
345 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
346 			 "Num underruns", fw_stats->underrun);
347 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
348 			 "PPDUs cleaned", fw_stats->tx_abort);
349 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
350 			 "MPDUs requed", fw_stats->mpdus_requed);
351 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
352 			 "Excessive retries", fw_stats->tx_ko);
353 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
354 			 "HW rate", fw_stats->data_rc);
355 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
356 			 "Sched self tiggers", fw_stats->self_triggers);
357 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
358 			 "Dropped due to SW retries",
359 			 fw_stats->sw_retry_failure);
360 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
361 			 "Illegal rate phy errors",
362 			 fw_stats->illgl_rate_phy_err);
363 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
364 			 "Pdev continous xretry", fw_stats->pdev_cont_xretry);
365 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
366 			 "TX timeout", fw_stats->pdev_tx_timeout);
367 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
368 			 "PDEV resets", fw_stats->pdev_resets);
369 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
370 			 "PHY underrun", fw_stats->phy_underrun);
371 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
372 			 "MPDU is more than txop limit", fw_stats->txop_ovf);
373 
374 	len += scnprintf(buf + len, buf_len - len, "\n");
375 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
376 			 "ath10k PDEV RX stats");
377 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
378 				 "=================");
379 
380 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
381 			 "Mid PPDU route change",
382 			 fw_stats->mid_ppdu_route_change);
383 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
384 			 "Tot. number of statuses", fw_stats->status_rcvd);
385 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
386 			 "Extra frags on rings 0", fw_stats->r0_frags);
387 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
388 			 "Extra frags on rings 1", fw_stats->r1_frags);
389 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
390 			 "Extra frags on rings 2", fw_stats->r2_frags);
391 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
392 			 "Extra frags on rings 3", fw_stats->r3_frags);
393 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
394 			 "MSDUs delivered to HTT", fw_stats->htt_msdus);
395 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
396 			 "MPDUs delivered to HTT", fw_stats->htt_mpdus);
397 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
398 			 "MSDUs delivered to stack", fw_stats->loc_msdus);
399 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
400 			 "MPDUs delivered to stack", fw_stats->loc_mpdus);
401 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
402 			 "Oversized AMSUs", fw_stats->oversize_amsdu);
403 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
404 			 "PHY errors", fw_stats->phy_errs);
405 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
406 			 "PHY errors drops", fw_stats->phy_err_drop);
407 	len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
408 			 "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
409 
410 	len += scnprintf(buf + len, buf_len - len, "\n");
411 	len += scnprintf(buf + len, buf_len - len, "%30s\n",
412 			 "ath10k PEER stats");
413 	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
414 				 "=================");
415 
416 	for (i = 0; i < fw_stats->peers; i++) {
417 		len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
418 				 "Peer MAC address",
419 				 fw_stats->peer_stat[i].peer_macaddr);
420 		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
421 				 "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
422 		len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
423 				 "Peer TX rate",
424 				 fw_stats->peer_stat[i].peer_tx_rate);
425 		len += scnprintf(buf + len, buf_len - len, "\n");
426 	}
427 
428 	if (len > buf_len)
429 		len = buf_len;
430 
431 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
432 
433 	mutex_unlock(&ar->conf_mutex);
434 
435 	kfree(buf);
436 	return ret_cnt;
437 }
438 
439 static const struct file_operations fops_fw_stats = {
440 	.read = ath10k_read_fw_stats,
441 	.open = simple_open,
442 	.owner = THIS_MODULE,
443 	.llseek = default_llseek,
444 };
445 
446 int ath10k_debug_create(struct ath10k *ar)
447 {
448 	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
449 						   ar->hw->wiphy->debugfsdir);
450 
451 	if (!ar->debug.debugfs_phy)
452 		return -ENOMEM;
453 
454 	init_completion(&ar->debug.event_stats_compl);
455 
456 	debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
457 			    &fops_fw_stats);
458 
459 	debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
460 			    &fops_wmi_services);
461 
462 	return 0;
463 }
464 #endif /* CONFIG_ATH10K_DEBUGFS */
465 
466 #ifdef CONFIG_ATH10K_DEBUG
467 void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
468 {
469 	struct va_format vaf;
470 	va_list args;
471 
472 	va_start(args, fmt);
473 
474 	vaf.fmt = fmt;
475 	vaf.va = &args;
476 
477 	if (ath10k_debug_mask & mask)
478 		ath10k_printk(KERN_DEBUG, "%pV", &vaf);
479 
480 	trace_ath10k_log_dbg(mask, &vaf);
481 
482 	va_end(args);
483 }
484 EXPORT_SYMBOL(ath10k_dbg);
485 
486 void ath10k_dbg_dump(enum ath10k_debug_mask mask,
487 		     const char *msg, const char *prefix,
488 		     const void *buf, size_t len)
489 {
490 	if (ath10k_debug_mask & mask) {
491 		if (msg)
492 			ath10k_dbg(mask, "%s\n", msg);
493 
494 		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
495 	}
496 
497 	/* tracing code doesn't like null strings :/ */
498 	trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
499 				  buf, len);
500 }
501 EXPORT_SYMBOL(ath10k_dbg_dump);
502 
503 #endif /* CONFIG_ATH10K_DEBUG */
504