linux/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
<<
>>
Prefs
   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
  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        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
 393static 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"
 403static 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
 426void 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
 435int 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
 453void 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
 482void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv)
 483{
 484        ath9k_cmn_spectral_deinit_debug(&priv->spec_priv);
 485}
 486
 487int 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", 0400, priv->debug.debugfs_phy,
 500                            priv, &fops_tgt_int_stats);
 501        debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy,
 502                            priv, &fops_tgt_tx_stats);
 503        debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy,
 504                            priv, &fops_tgt_rx_stats);
 505        debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy,
 506                            priv, &fops_xmit);
 507        debugfs_create_file("skb_rx", 0400, 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", 0400, priv->debug.debugfs_phy,
 514                            priv, &fops_slot);
 515        debugfs_create_file("queue", 0400, priv->debug.debugfs_phy,
 516                            priv, &fops_queue);
 517        debugfs_create_file("debug", 0600, 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