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