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 = 0; 295 296 spin_lock_bh(&priv->tx.tx_lock); 297 298 len += scnprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); 299 300 len += bitmap_scnprintf(buf + len, sizeof(buf) - len, 301 priv->tx.tx_slot, MAX_TX_BUF_NUM); 302 303 len += scnprintf(buf + len, sizeof(buf) - len, "\n"); 304 305 len += scnprintf(buf + len, sizeof(buf) - len, 306 "Used slots : %d\n", 307 bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); 308 309 spin_unlock_bh(&priv->tx.tx_lock); 310 311 if (len > sizeof(buf)) 312 len = sizeof(buf); 313 314 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 315 } 316 317 static const struct file_operations fops_slot = { 318 .read = read_file_slot, 319 .open = simple_open, 320 .owner = THIS_MODULE, 321 .llseek = default_llseek, 322 }; 323 324 static ssize_t read_file_queue(struct file *file, char __user *user_buf, 325 size_t count, loff_t *ppos) 326 { 327 struct ath9k_htc_priv *priv = file->private_data; 328 char buf[512]; 329 unsigned int len = 0; 330 331 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 332 "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); 333 334 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 335 "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); 336 337 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 338 "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); 339 340 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 341 "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); 342 343 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 344 "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); 345 346 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 347 "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); 348 349 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 350 "Failed queue", skb_queue_len(&priv->tx.tx_failed)); 351 352 spin_lock_bh(&priv->tx.tx_lock); 353 len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", 354 "Queued count", priv->tx.queued_cnt); 355 spin_unlock_bh(&priv->tx.tx_lock); 356 357 if (len > sizeof(buf)) 358 len = sizeof(buf); 359 360 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 361 362 } 363 364 static const struct file_operations fops_queue = { 365 .read = read_file_queue, 366 .open = simple_open, 367 .owner = THIS_MODULE, 368 .llseek = default_llseek, 369 }; 370 371 static ssize_t read_file_debug(struct file *file, char __user *user_buf, 372 size_t count, loff_t *ppos) 373 { 374 struct ath9k_htc_priv *priv = file->private_data; 375 struct ath_common *common = ath9k_hw_common(priv->ah); 376 char buf[32]; 377 unsigned int len; 378 379 len = sprintf(buf, "0x%08x\n", common->debug_mask); 380 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 381 } 382 383 static ssize_t write_file_debug(struct file *file, const char __user *user_buf, 384 size_t count, loff_t *ppos) 385 { 386 struct ath9k_htc_priv *priv = file->private_data; 387 struct ath_common *common = ath9k_hw_common(priv->ah); 388 unsigned long mask; 389 char buf[32]; 390 ssize_t len; 391 392 len = min(count, sizeof(buf) - 1); 393 if (copy_from_user(buf, user_buf, len)) 394 return -EFAULT; 395 396 buf[len] = '\0'; 397 if (kstrtoul(buf, 0, &mask)) 398 return -EINVAL; 399 400 common->debug_mask = mask; 401 return count; 402 } 403 404 static const struct file_operations fops_debug = { 405 .read = read_file_debug, 406 .write = write_file_debug, 407 .open = simple_open, 408 .owner = THIS_MODULE, 409 .llseek = default_llseek, 410 }; 411 412 /* Ethtool support for get-stats */ 413 #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" 414 static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { 415 "tx_pkts_nic", 416 "tx_bytes_nic", 417 "rx_pkts_nic", 418 "rx_bytes_nic", 419 420 AMKSTR(d_tx_pkts), 421 422 "d_rx_crc_err", 423 "d_rx_decrypt_crc_err", 424 "d_rx_phy_err", 425 "d_rx_mic_err", 426 "d_rx_pre_delim_crc_err", 427 "d_rx_post_delim_crc_err", 428 "d_rx_decrypt_busy_err", 429 430 "d_rx_phyerr_radar", 431 "d_rx_phyerr_ofdm_timing", 432 "d_rx_phyerr_cck_timing", 433 434 }; 435 #define ATH9K_HTC_SSTATS_LEN ARRAY_SIZE(ath9k_htc_gstrings_stats) 436 437 void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, 438 struct ieee80211_vif *vif, 439 u32 sset, u8 *data) 440 { 441 if (sset == ETH_SS_STATS) 442 memcpy(data, *ath9k_htc_gstrings_stats, 443 sizeof(ath9k_htc_gstrings_stats)); 444 } 445 446 int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw, 447 struct ieee80211_vif *vif, int sset) 448 { 449 if (sset == ETH_SS_STATS) 450 return ATH9K_HTC_SSTATS_LEN; 451 return 0; 452 } 453 454 #define STXBASE priv->debug.tx_stats 455 #define SRXBASE priv->debug.rx_stats 456 #define SKBTXBASE priv->debug.tx_stats 457 #define SKBRXBASE priv->debug.skbrx_stats 458 #define ASTXQ(a) \ 459 data[i++] = STXBASE.a[IEEE80211_AC_BE]; \ 460 data[i++] = STXBASE.a[IEEE80211_AC_BK]; \ 461 data[i++] = STXBASE.a[IEEE80211_AC_VI]; \ 462 data[i++] = STXBASE.a[IEEE80211_AC_VO] 463 464 void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, 465 struct ieee80211_vif *vif, 466 struct ethtool_stats *stats, u64 *data) 467 { 468 struct ath9k_htc_priv *priv = hw->priv; 469 int i = 0; 470 471 data[i++] = SKBTXBASE.skb_success; 472 data[i++] = SKBTXBASE.skb_success_bytes; 473 data[i++] = SKBRXBASE.skb_completed; 474 data[i++] = SKBRXBASE.skb_completed_bytes; 475 476 ASTXQ(queue_stats); 477 478 data[i++] = SRXBASE.crc_err; 479 data[i++] = SRXBASE.decrypt_crc_err; 480 data[i++] = SRXBASE.phy_err; 481 data[i++] = SRXBASE.mic_err; 482 data[i++] = SRXBASE.pre_delim_crc_err; 483 data[i++] = SRXBASE.post_delim_crc_err; 484 data[i++] = SRXBASE.decrypt_busy_err; 485 486 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; 487 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; 488 data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING]; 489 490 WARN_ON(i != ATH9K_HTC_SSTATS_LEN); 491 } 492 493 494 int ath9k_htc_init_debug(struct ath_hw *ah) 495 { 496 struct ath_common *common = ath9k_hw_common(ah); 497 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; 498 499 priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, 500 priv->hw->wiphy->debugfsdir); 501 if (!priv->debug.debugfs_phy) 502 return -ENOMEM; 503 504 debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, 505 priv, &fops_tgt_int_stats); 506 debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, 507 priv, &fops_tgt_tx_stats); 508 debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, 509 priv, &fops_tgt_rx_stats); 510 debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, 511 priv, &fops_xmit); 512 debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy, 513 priv, &fops_skb_rx); 514 515 ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); 516 ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); 517 518 debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, 519 priv, &fops_slot); 520 debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, 521 priv, &fops_queue); 522 debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, 523 priv, &fops_debug); 524 525 ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); 526 ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); 527 528 return 0; 529 } 530