1 /* 2 * Copyright (c) 2010-2011 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "htc.h" 18 19 static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, 20 size_t count, loff_t *ppos) 21 { 22 struct ath9k_htc_priv *priv = file->private_data; 23 struct ath9k_htc_target_int_stats cmd_rsp; 24 char buf[512]; 25 unsigned int len = 0; 26 int ret = 0; 27 28 memset(&cmd_rsp, 0, sizeof(cmd_rsp)); 29 30 ath9k_htc_ps_wakeup(priv); 31 32 WMI_CMD(WMI_INT_STATS_CMDID); 33 if (ret) { 34 ath9k_htc_ps_restore(priv); 35 return -EINVAL; 36 } 37 38 ath9k_htc_ps_restore(priv); 39 40 len += scnprintf(buf + len, sizeof(buf) - len, 41 "%20s : %10u\n", "RX", 42 be32_to_cpu(cmd_rsp.rx)); 43 44 len += scnprintf(buf + len, sizeof(buf) - len, 45 "%20s : %10u\n", "RXORN", 46 be32_to_cpu(cmd_rsp.rxorn)); 47 48 len += scnprintf(buf + len, sizeof(buf) - len, 49 "%20s : %10u\n", "RXEOL", 50 be32_to_cpu(cmd_rsp.rxeol)); 51 52 len += scnprintf(buf + len, sizeof(buf) - len, 53 "%20s : %10u\n", "TXURN", 54 be32_to_cpu(cmd_rsp.txurn)); 55 56 len += scnprintf(buf + len, sizeof(buf) - len, 57 "%20s : %10u\n", "TXTO", 58 be32_to_cpu(cmd_rsp.txto)); 59 60 len += scnprintf(buf + len, sizeof(buf) - len, 61 "%20s : %10u\n", "CST", 62 be32_to_cpu(cmd_rsp.cst)); 63 64 if (len > sizeof(buf)) 65 len = sizeof(buf); 66 67 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 68 } 69 70 static const struct file_operations fops_tgt_int_stats = { 71 .read = read_file_tgt_int_stats, 72 .open = simple_open, 73 .owner = THIS_MODULE, 74 .llseek = default_llseek, 75 }; 76 77 static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, 78 size_t count, loff_t *ppos) 79 { 80 struct ath9k_htc_priv *priv = file->private_data; 81 struct ath9k_htc_target_tx_stats cmd_rsp; 82 char buf[512]; 83 unsigned int len = 0; 84 int ret = 0; 85 86 memset(&cmd_rsp, 0, sizeof(cmd_rsp)); 87 88 ath9k_htc_ps_wakeup(priv); 89 90 WMI_CMD(WMI_TX_STATS_CMDID); 91 if (ret) { 92 ath9k_htc_ps_restore(priv); 93 return -EINVAL; 94 } 95 96 ath9k_htc_ps_restore(priv); 97 98 len += scnprintf(buf + len, sizeof(buf) - len, 99 "%20s : %10u\n", "Xretries", 100 be32_to_cpu(cmd_rsp.xretries)); 101 102 len += scnprintf(buf + len, sizeof(buf) - len, 103 "%20s : %10u\n", "FifoErr", 104 be32_to_cpu(cmd_rsp.fifoerr)); 105 106 len += scnprintf(buf + len, sizeof(buf) - len, 107 "%20s : %10u\n", "Filtered", 108 be32_to_cpu(cmd_rsp.filtered)); 109 110 len += scnprintf(buf + len, sizeof(buf) - len, 111 "%20s : %10u\n", "TimerExp", 112 be32_to_cpu(cmd_rsp.timer_exp)); 113 114 len += scnprintf(buf + len, sizeof(buf) - len, 115 "%20s : %10u\n", "ShortRetries", 116 be32_to_cpu(cmd_rsp.shortretries)); 117 118 len += scnprintf(buf + len, sizeof(buf) - len, 119 "%20s : %10u\n", "LongRetries", 120 be32_to_cpu(cmd_rsp.longretries)); 121 122 len += scnprintf(buf + len, sizeof(buf) - len, 123 "%20s : %10u\n", "QueueNull", 124 be32_to_cpu(cmd_rsp.qnull)); 125 126 len += scnprintf(buf + len, sizeof(buf) - len, 127 "%20s : %10u\n", "EncapFail", 128 be32_to_cpu(cmd_rsp.encap_fail)); 129 130 len += scnprintf(buf + len, sizeof(buf) - len, 131 "%20s : %10u\n", "NoBuf", 132 be32_to_cpu(cmd_rsp.nobuf)); 133 134 if (len > sizeof(buf)) 135 len = sizeof(buf); 136 137 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 138 } 139 140 static const struct file_operations fops_tgt_tx_stats = { 141 .read = read_file_tgt_tx_stats, 142 .open = simple_open, 143 .owner = THIS_MODULE, 144 .llseek = default_llseek, 145 }; 146 147 static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, 148 size_t count, loff_t *ppos) 149 { 150 struct ath9k_htc_priv *priv = file->private_data; 151 struct ath9k_htc_target_rx_stats cmd_rsp; 152 char buf[512]; 153 unsigned int len = 0; 154 int ret = 0; 155 156 memset(&cmd_rsp, 0, sizeof(cmd_rsp)); 157 158 ath9k_htc_ps_wakeup(priv); 159 160 WMI_CMD(WMI_RX_STATS_CMDID); 161 if (ret) { 162 ath9k_htc_ps_restore(priv); 163 return -EINVAL; 164 } 165 166 ath9k_htc_ps_restore(priv); 167 168 len += scnprintf(buf + len, sizeof(buf) - len, 169 "%20s : %10u\n", "NoBuf", 170 be32_to_cpu(cmd_rsp.nobuf)); 171 172 len += scnprintf(buf + len, sizeof(buf) - len, 173 "%20s : %10u\n", "HostSend", 174 be32_to_cpu(cmd_rsp.host_send)); 175 176 len += scnprintf(buf + len, sizeof(buf) - len, 177 "%20s : %10u\n", "HostDone", 178 be32_to_cpu(cmd_rsp.host_done)); 179 180 if (len > sizeof(buf)) 181 len = sizeof(buf); 182 183 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 184 } 185 186 static const struct file_operations fops_tgt_rx_stats = { 187 .read = read_file_tgt_rx_stats, 188 .open = simple_open, 189 .owner = THIS_MODULE, 190 .llseek = default_llseek, 191 }; 192 193 static ssize_t read_file_xmit(struct file *file, char __user *user_buf, 194 size_t count, loff_t *ppos) 195 { 196 struct ath9k_htc_priv *priv = file->private_data; 197 char buf[512]; 198 unsigned int len = 0; 199 200 len += scnprintf(buf + len, sizeof(buf) - len, 201 "%20s : %10u\n", "Buffers queued", 202 priv->debug.tx_stats.buf_queued); 203 len += scnprintf(buf + len, sizeof(buf) - len, 204 "%20s : %10u\n", "Buffers completed", 205 priv->debug.tx_stats.buf_completed); 206 len += scnprintf(buf + len, sizeof(buf) - len, 207 "%20s : %10u\n", "SKBs queued", 208 priv->debug.tx_stats.skb_queued); 209 len += scnprintf(buf + len, sizeof(buf) - len, 210 "%20s : %10u\n", "SKBs success", 211 priv->debug.tx_stats.skb_success); 212 len += scnprintf(buf + len, sizeof(buf) - len, 213 "%20s : %10u\n", "SKBs failed", 214 priv->debug.tx_stats.skb_failed); 215 len += scnprintf(buf + len, sizeof(buf) - len, 216 "%20s : %10u\n", "CAB queued", 217 priv->debug.tx_stats.cab_queued); 218 219 len += scnprintf(buf + len, sizeof(buf) - len, 220 "%20s : %10u\n", "BE queued", 221 priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); 222 len += scnprintf(buf + len, sizeof(buf) - len, 223 "%20s : %10u\n", "BK queued", 224 priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); 225 len += scnprintf(buf + len, sizeof(buf) - len, 226 "%20s : %10u\n", "VI queued", 227 priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); 228 len += scnprintf(buf + len, sizeof(buf) - len, 229 "%20s : %10u\n", "VO queued", 230 priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); 231 232 if (len > sizeof(buf)) 233 len = sizeof(buf); 234 235 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 236 } 237 238 static const struct file_operations fops_xmit = { 239 .read = read_file_xmit, 240 .open = simple_open, 241 .owner = THIS_MODULE, 242 .llseek = default_llseek, 243 }; 244 245 void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, 246 struct ath_rx_status *rs) 247 { 248 ath9k_cmn_debug_stat_rx(&priv->debug.rx_stats, rs); 249 } 250 251 static ssize_t read_file_skb_rx(struct file *file, char __user *user_buf, 252 size_t count, loff_t *ppos) 253 { 254 struct ath9k_htc_priv *priv = file->private_data; 255 char *buf; 256 unsigned int len = 0, size = 1500; 257 ssize_t retval = 0; 258 259 buf = kzalloc(size, GFP_KERNEL); 260 if (buf == NULL) 261 return -ENOMEM; 262 263 len += scnprintf(buf + len, size - len, 264 "%20s : %10u\n", "SKBs allocated", 265 priv->debug.skbrx_stats.skb_allocated); 266 len += scnprintf(buf + len, size - len, 267 "%20s : %10u\n", "SKBs completed", 268 priv->debug.skbrx_stats.skb_completed); 269 len += scnprintf(buf + len, size - len, 270 "%20s : %10u\n", "SKBs Dropped", 271 priv->debug.skbrx_stats.skb_dropped); 272 273 if (len > size) 274 len = size; 275 276 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 277 kfree(buf); 278 279 return retval; 280 } 281 282 static const struct file_operations fops_skb_rx = { 283 .read = read_file_skb_rx, 284 .open = simple_open, 285 .owner = THIS_MODULE, 286 .llseek = default_llseek, 287 }; 288 289 static ssize_t read_file_slot(struct file *file, char __user *user_buf, 290 size_t count, loff_t *ppos) 291 { 292 struct ath9k_htc_priv *priv = file->private_data; 293 char buf[512]; 294 unsigned int len; 295 296 spin_lock_bh(&priv->tx.tx_lock); 297 len = scnprintf(buf, sizeof(buf), 298 "TX slot bitmap : %*pb\n" 299 "Used slots : %d\n", 300 MAX_TX_BUF_NUM, priv->tx.tx_slot, 301 bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); 302 spin_unlock_bh(&priv->tx.tx_lock); 303 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 304 } 305 306 static const struct file_operations fops_slot = { 307 .read = read_file_slot, 308 .open = simple_open, 309 .owner = THIS_MODULE, 310 .llseek = default_llseek, 311 }; 312 313 static ssize_t read_file_queue(struct file *file, char __user *user_buf, 314 size_t count, loff_t *ppos) 315 { 316 struct ath9k_htc_priv *priv = file->private_data; 317 char buf[512]; 318 unsigned int len = 0; 319 320 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 321 "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); 322 323 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 324 "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); 325 326 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 327 "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); 328 329 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 330 "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); 331 332 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 333 "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); 334 335 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 336 "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); 337 338 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 339 "Failed queue", skb_queue_len(&priv->tx.tx_failed)); 340 341 spin_lock_bh(&priv->tx.tx_lock); 342 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 343 "Queued count", priv->tx.queued_cnt); 344 spin_unlock_bh(&priv->tx.tx_lock); 345 346 if (len > sizeof(buf)) 347 len = sizeof(buf); 348 349 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 350 351 } 352 353 static const struct file_operations fops_queue = { 354 .read = read_file_queue, 355 .open = simple_open, 356 .owner = THIS_MODULE, 357 .llseek = default_llseek, 358 }; 359 360 static ssize_t read_file_debug(struct file *file, char __user *user_buf, 361 size_t count, loff_t *ppos) 362 { 363 struct ath9k_htc_priv *priv = file->private_data; 364 struct ath_common *common = ath9k_hw_common(priv->ah); 365 char buf[32]; 366 unsigned int len; 367 368 len = sprintf(buf, "0x%08x\n", common->debug_mask); 369 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 370 } 371 372 static ssize_t write_file_debug(struct file *file, const char __user *user_buf, 373 size_t count, loff_t *ppos) 374 { 375 struct ath9k_htc_priv *priv = file->private_data; 376 struct ath_common *common = ath9k_hw_common(priv->ah); 377 unsigned long mask; 378 ssize_t ret; 379 380 ret = kstrtoul_from_user(user_buf, count, 0, &mask); 381 if (ret) 382 return ret; 383 384 common->debug_mask = mask; 385 return count; 386 } 387 388 static const struct file_operations fops_debug = { 389 .read = read_file_debug, 390 .write = write_file_debug, 391 .open = simple_open, 392 .owner = THIS_MODULE, 393 .llseek = default_llseek, 394 }; 395 396 /* Ethtool support for get-stats */ 397 #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" 398 static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { 399 "tx_pkts_nic", 400 "tx_bytes_nic", 401 "rx_pkts_nic", 402 "rx_bytes_nic", 403 404 AMKSTR(d_tx_pkts), 405 406 "d_rx_crc_err", 407 "d_rx_decrypt_crc_err", 408 "d_rx_phy_err", 409 "d_rx_mic_err", 410 "d_rx_pre_delim_crc_err", 411 "d_rx_post_delim_crc_err", 412 "d_rx_decrypt_busy_err", 413 414 "d_rx_phyerr_radar", 415 "d_rx_phyerr_ofdm_timing", 416 "d_rx_phyerr_cck_timing", 417 418 }; 419 #define ATH9K_HTC_SSTATS_LEN ARRAY_SIZE(ath9k_htc_gstrings_stats) 420 421 void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, 422 struct ieee80211_vif *vif, 423 u32 sset, u8 *data) 424 { 425 if (sset == ETH_SS_STATS) 426 memcpy(data, *ath9k_htc_gstrings_stats, 427 sizeof(ath9k_htc_gstrings_stats)); 428 } 429 430 int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw, 431 struct ieee80211_vif *vif, int sset) 432 { 433 if (sset == ETH_SS_STATS) 434 return ATH9K_HTC_SSTATS_LEN; 435 return 0; 436 } 437 438 #define STXBASE priv->debug.tx_stats 439 #define SRXBASE priv->debug.rx_stats 440 #define SKBTXBASE priv->debug.tx_stats 441 #define SKBRXBASE priv->debug.skbrx_stats 442 #define ASTXQ(a) \ 443 data[i++] = STXBASE.a[IEEE80211_AC_BE]; \ 444 data[i++] = STXBASE.a[IEEE80211_AC_BK]; \ 445 data[i++] = STXBASE.a[IEEE80211_AC_VI]; \ 446 data[i++] = STXBASE.a[IEEE80211_AC_VO] 447 448 void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, 449 struct ieee80211_vif *vif, 450 struct ethtool_stats *stats, u64 *data) 451 { 452 struct ath9k_htc_priv *priv = hw->priv; 453 int i = 0; 454 455 data[i++] = SKBTXBASE.skb_success; 456 data[i++] = SKBTXBASE.skb_success_bytes; 457 data[i++] = SKBRXBASE.skb_completed; 458 data[i++] = SKBRXBASE.skb_completed_bytes; 459 460 ASTXQ(queue_stats); 461 462 data[i++] = SRXBASE.crc_err; 463 data[i++] = SRXBASE.decrypt_crc_err; 464 data[i++] = SRXBASE.phy_err; 465 data[i++] = SRXBASE.mic_err; 466 data[i++] = SRXBASE.pre_delim_crc_err; 467 data[i++] = SRXBASE.post_delim_crc_err; 468 data[i++] = SRXBASE.decrypt_busy_err; 469 470 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; 471 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; 472 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING]; 473 474 WARN_ON(i != ATH9K_HTC_SSTATS_LEN); 475 } 476 477 void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) 478 { 479 ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); 480 } 481 482 int ath9k_htc_init_debug(struct ath_hw *ah) 483 { 484 struct ath_common *common = ath9k_hw_common(ah); 485 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 486 487 priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, 488 priv->hw->wiphy->debugfsdir); 489 if (IS_ERR(priv->debug.debugfs_phy)) 490 return -ENOMEM; 491 492 ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); 493 494 debugfs_create_file("tgt_int_stats", 0400, priv->debug.debugfs_phy, 495 priv, &fops_tgt_int_stats); 496 debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy, 497 priv, &fops_tgt_tx_stats); 498 debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy, 499 priv, &fops_tgt_rx_stats); 500 debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy, 501 priv, &fops_xmit); 502 debugfs_create_file("skb_rx", 0400, priv->debug.debugfs_phy, 503 priv, &fops_skb_rx); 504 505 ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); 506 ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); 507 508 debugfs_create_file("slot", 0400, priv->debug.debugfs_phy, 509 priv, &fops_slot); 510 debugfs_create_file("queue", 0400, priv->debug.debugfs_phy, 511 priv, &fops_queue); 512 debugfs_create_file("debug", 0600, priv->debug.debugfs_phy, 513 priv, &fops_debug); 514 515 ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); 516 ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); 517 518 return 0; 519 } 520