518 lines · c
1/*2 * Copyright (c) 2010-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#include "htc.h"18 19static 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 70static 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 77static 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 140static 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 147static 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 186static 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 193static 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 238static 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 245void 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 251static 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 282static 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 289static 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 306static 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 313static 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 353static 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 360static 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 372static 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 388static 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"398static 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 421void 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 430int 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_stats439#define SRXBASE priv->debug.rx_stats440#define SKBTXBASE priv->debug.tx_stats441#define SKBRXBASE priv->debug.skbrx_stats442#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 448void 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 477void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv)478{479 ath9k_cmn_spectral_deinit_debug(&priv->spec_priv);480}481 482int ath9k_htc_init_debug(struct ath_hw *ah)483{484 struct ath_common *common = ath9k_hw_common(ah);485 struct ath9k_htc_priv *priv = common->priv;486 487 priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,488 priv->hw->wiphy->debugfsdir);489 490 ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy);491 492 debugfs_create_file("tgt_int_stats", 0400, priv->debug.debugfs_phy,493 priv, &fops_tgt_int_stats);494 debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy,495 priv, &fops_tgt_tx_stats);496 debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy,497 priv, &fops_tgt_rx_stats);498 debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy,499 priv, &fops_xmit);500 debugfs_create_file("skb_rx", 0400, priv->debug.debugfs_phy,501 priv, &fops_skb_rx);502 503 ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats);504 ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats);505 506 debugfs_create_file("slot", 0400, priv->debug.debugfs_phy,507 priv, &fops_slot);508 debugfs_create_file("queue", 0400, priv->debug.debugfs_phy,509 priv, &fops_queue);510 debugfs_create_file("debug", 0600, priv->debug.debugfs_phy,511 priv, &fops_debug);512 513 ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah);514 ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah);515 516 return 0;517}518