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 char buf[32]; 379 ssize_t len; 380 381 len = min(count, sizeof(buf) - 1); 382 if (copy_from_user(buf, user_buf, len)) 383 return -EFAULT; 384 385 buf[len] = '\0'; 386 if (kstrtoul(buf, 0, &mask)) 387 return -EINVAL; 388 389 common->debug_mask = mask; 390 return count; 391 } 392 393 static const struct file_operations fops_debug = { 394 .read = read_file_debug, 395 .write = write_file_debug, 396 .open = simple_open, 397 .owner = THIS_MODULE, 398 .llseek = default_llseek, 399 }; 400 401 /* Ethtool support for get-stats */ 402 #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" 403 static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { 404 "tx_pkts_nic", 405 "tx_bytes_nic", 406 "rx_pkts_nic", 407 "rx_bytes_nic", 408 409 AMKSTR(d_tx_pkts), 410 411 "d_rx_crc_err", 412 "d_rx_decrypt_crc_err", 413 "d_rx_phy_err", 414 "d_rx_mic_err", 415 "d_rx_pre_delim_crc_err", 416 "d_rx_post_delim_crc_err", 417 "d_rx_decrypt_busy_err", 418 419 "d_rx_phyerr_radar", 420 "d_rx_phyerr_ofdm_timing", 421 "d_rx_phyerr_cck_timing", 422 423 }; 424 #define ATH9K_HTC_SSTATS_LEN ARRAY_SIZE(ath9k_htc_gstrings_stats) 425 426 void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, 427 struct ieee80211_vif *vif, 428 u32 sset, u8 *data) 429 { 430 if (sset == ETH_SS_STATS) 431 memcpy(data, *ath9k_htc_gstrings_stats, 432 sizeof(ath9k_htc_gstrings_stats)); 433 } 434 435 int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw, 436 struct ieee80211_vif *vif, int sset) 437 { 438 if (sset == ETH_SS_STATS) 439 return ATH9K_HTC_SSTATS_LEN; 440 return 0; 441 } 442 443 #define STXBASE priv->debug.tx_stats 444 #define SRXBASE priv->debug.rx_stats 445 #define SKBTXBASE priv->debug.tx_stats 446 #define SKBRXBASE priv->debug.skbrx_stats 447 #define ASTXQ(a) \ 448 data[i++] = STXBASE.a[IEEE80211_AC_BE]; \ 449 data[i++] = STXBASE.a[IEEE80211_AC_BK]; \ 450 data[i++] = STXBASE.a[IEEE80211_AC_VI]; \ 451 data[i++] = STXBASE.a[IEEE80211_AC_VO] 452 453 void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, 454 struct ieee80211_vif *vif, 455 struct ethtool_stats *stats, u64 *data) 456 { 457 struct ath9k_htc_priv *priv = hw->priv; 458 int i = 0; 459 460 data[i++] = SKBTXBASE.skb_success; 461 data[i++] = SKBTXBASE.skb_success_bytes; 462 data[i++] = SKBRXBASE.skb_completed; 463 data[i++] = SKBRXBASE.skb_completed_bytes; 464 465 ASTXQ(queue_stats); 466 467 data[i++] = SRXBASE.crc_err; 468 data[i++] = SRXBASE.decrypt_crc_err; 469 data[i++] = SRXBASE.phy_err; 470 data[i++] = SRXBASE.mic_err; 471 data[i++] = SRXBASE.pre_delim_crc_err; 472 data[i++] = SRXBASE.post_delim_crc_err; 473 data[i++] = SRXBASE.decrypt_busy_err; 474 475 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; 476 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; 477 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING]; 478 479 WARN_ON(i != ATH9K_HTC_SSTATS_LEN); 480 } 481 482 void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) 483 { 484 ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); 485 } 486 487 int ath9k_htc_init_debug(struct ath_hw *ah) 488 { 489 struct ath_common *common = ath9k_hw_common(ah); 490 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 491 492 priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, 493 priv->hw->wiphy->debugfsdir); 494 if (!priv->debug.debugfs_phy) 495 return -ENOMEM; 496 497 ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); 498 499 debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, 500 priv, &fops_tgt_int_stats); 501 debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, 502 priv, &fops_tgt_tx_stats); 503 debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, 504 priv, &fops_tgt_rx_stats); 505 debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, 506 priv, &fops_xmit); 507 debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy, 508 priv, &fops_skb_rx); 509 510 ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); 511 ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); 512 513 debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, 514 priv, &fops_slot); 515 debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, 516 priv, &fops_queue); 517 debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, 518 priv, &fops_debug); 519 520 ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); 521 ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); 522 523 return 0; 524 } 525