2 * Copyright (c) 2005-2011 Atheros Communications Inc.
3 * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
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.
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.
18 #include <linux/module.h>
19 #include <linux/debugfs.h>
24 static int ath10k_printk(const char *level
, const char *fmt
, ...)
35 rtn
= printk("%sath10k: %pV", level
, &vaf
);
42 int ath10k_info(const char *fmt
, ...)
44 struct va_format vaf
= {
52 ret
= ath10k_printk(KERN_INFO
, "%pV", &vaf
);
53 trace_ath10k_log_info(&vaf
);
58 EXPORT_SYMBOL(ath10k_info
);
60 int ath10k_err(const char *fmt
, ...)
62 struct va_format vaf
= {
70 ret
= ath10k_printk(KERN_ERR
, "%pV", &vaf
);
71 trace_ath10k_log_err(&vaf
);
76 EXPORT_SYMBOL(ath10k_err
);
78 int ath10k_warn(const char *fmt
, ...)
80 struct va_format vaf
= {
90 ret
= ath10k_printk(KERN_WARNING
, "%pV", &vaf
);
92 trace_ath10k_log_warn(&vaf
);
98 EXPORT_SYMBOL(ath10k_warn
);
100 #ifdef CONFIG_ATH10K_DEBUGFS
102 void ath10k_debug_read_service_map(struct ath10k
*ar
,
106 memcpy(ar
->debug
.wmi_service_bitmap
, service_map
, map_size
);
109 static ssize_t
ath10k_read_wmi_services(struct file
*file
,
110 char __user
*user_buf
,
111 size_t count
, loff_t
*ppos
)
113 struct ath10k
*ar
= file
->private_data
;
115 unsigned int len
= 0, buf_len
= 1500;
120 buf
= kzalloc(buf_len
, GFP_KERNEL
);
124 mutex_lock(&ar
->conf_mutex
);
129 for (i
= 0; i
< WMI_SERVICE_LAST
; i
++) {
130 if (WMI_SERVICE_IS_ENABLED(ar
->debug
.wmi_service_bitmap
, i
))
135 len
+= scnprintf(buf
+ len
, buf_len
- len
,
136 "0x%02x - %20s - %s\n",
137 i
, wmi_service_name(i
), status
);
140 ret_cnt
= simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
142 mutex_unlock(&ar
->conf_mutex
);
148 static const struct file_operations fops_wmi_services
= {
149 .read
= ath10k_read_wmi_services
,
151 .owner
= THIS_MODULE
,
152 .llseek
= default_llseek
,
155 void ath10k_debug_read_target_stats(struct ath10k
*ar
,
156 struct wmi_stats_event
*ev
)
159 struct ath10k_target_stats
*stats
;
160 int num_pdev_stats
, num_vdev_stats
, num_peer_stats
;
161 struct wmi_pdev_stats
*ps
;
164 mutex_lock(&ar
->conf_mutex
);
166 stats
= &ar
->debug
.target_stats
;
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 */
172 if (num_pdev_stats
) {
173 ps
= (struct wmi_pdev_stats
*)tmp
;
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
);
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
);
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
);
228 tmp
+= sizeof(struct wmi_pdev_stats
);
232 /* Currently firmware does not support VDEV stats */
233 if (num_vdev_stats
) {
234 struct wmi_vdev_stats
*vdev_stats
;
236 for (i
= 0; i
< num_vdev_stats
; i
++) {
237 vdev_stats
= (struct wmi_vdev_stats
*)tmp
;
238 tmp
+= sizeof(struct wmi_vdev_stats
);
242 if (num_peer_stats
) {
243 struct wmi_peer_stats
*peer_stats
;
244 struct ath10k_peer_stat
*s
;
246 stats
->peers
= num_peer_stats
;
248 for (i
= 0; i
< num_peer_stats
; i
++) {
249 peer_stats
= (struct wmi_peer_stats
*)tmp
;
250 s
= &stats
->peer_stat
[i
];
252 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats
->peer_macaddr
,
254 s
->peer_rssi
= __le32_to_cpu(peer_stats
->peer_rssi
);
256 __le32_to_cpu(peer_stats
->peer_tx_rate
);
258 tmp
+= sizeof(struct wmi_peer_stats
);
262 mutex_unlock(&ar
->conf_mutex
);
263 complete(&ar
->debug
.event_stats_compl
);
266 static ssize_t
ath10k_read_fw_stats(struct file
*file
, char __user
*user_buf
,
267 size_t count
, loff_t
*ppos
)
269 struct ath10k
*ar
= file
->private_data
;
270 struct ath10k_target_stats
*fw_stats
;
272 unsigned int len
= 0, buf_len
= 2500;
278 fw_stats
= &ar
->debug
.target_stats
;
280 buf
= kzalloc(buf_len
, GFP_KERNEL
);
284 ret
= ath10k_wmi_request_stats(ar
, WMI_REQUEST_PEER_STAT
);
286 ath10k_warn("could not request stats (%d)\n", ret
);
291 left
= wait_for_completion_timeout(&ar
->debug
.event_stats_compl
, 1*HZ
);
298 mutex_lock(&ar
->conf_mutex
);
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 "=================");
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
);
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 "=================");
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
);
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 "=================");
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
);
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 "=================");
416 for (i
= 0; i
< fw_stats
->peers
; i
++) {
417 len
+= scnprintf(buf
+ len
, buf_len
- len
, "%30s %pM\n",
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",
424 fw_stats
->peer_stat
[i
].peer_tx_rate
);
425 len
+= scnprintf(buf
+ len
, buf_len
- len
, "\n");
431 ret_cnt
= simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
433 mutex_unlock(&ar
->conf_mutex
);
439 static const struct file_operations fops_fw_stats
= {
440 .read
= ath10k_read_fw_stats
,
442 .owner
= THIS_MODULE
,
443 .llseek
= default_llseek
,
446 int ath10k_debug_create(struct ath10k
*ar
)
448 ar
->debug
.debugfs_phy
= debugfs_create_dir("ath10k",
449 ar
->hw
->wiphy
->debugfsdir
);
451 if (!ar
->debug
.debugfs_phy
)
454 init_completion(&ar
->debug
.event_stats_compl
);
456 debugfs_create_file("fw_stats", S_IRUSR
, ar
->debug
.debugfs_phy
, ar
,
459 debugfs_create_file("wmi_services", S_IRUSR
, ar
->debug
.debugfs_phy
, ar
,
464 #endif /* CONFIG_ATH10K_DEBUGFS */
466 #ifdef CONFIG_ATH10K_DEBUG
467 void ath10k_dbg(enum ath10k_debug_mask mask
, const char *fmt
, ...)
469 struct va_format vaf
;
477 if (ath10k_debug_mask
& mask
)
478 ath10k_printk(KERN_DEBUG
, "%pV", &vaf
);
480 trace_ath10k_log_dbg(mask
, &vaf
);
484 EXPORT_SYMBOL(ath10k_dbg
);
486 void ath10k_dbg_dump(enum ath10k_debug_mask mask
,
487 const char *msg
, const char *prefix
,
488 const void *buf
, size_t len
)
490 if (ath10k_debug_mask
& mask
) {
492 ath10k_dbg(mask
, "%s\n", msg
);
494 print_hex_dump_bytes(prefix
, DUMP_PREFIX_OFFSET
, buf
, len
);
497 /* tracing code doesn't like null strings :/ */
498 trace_ath10k_log_dbg_dump(msg
? msg
: "", prefix
? prefix
: "",
501 EXPORT_SYMBOL(ath10k_dbg_dump
);
503 #endif /* CONFIG_ATH10K_DEBUG */